diff --git a/4000-sw_64.patch b/4000-sw_64.patch new file mode 100755 index 0000000000000000000000000000000000000000..31d9cf173e9d3c588e76f525988be2c7947af2b6 --- /dev/null +++ b/4000-sw_64.patch @@ -0,0 +1,96575 @@ +diff -uNr openjdk/Changelog.md afu11u/Changelog.md +--- openjdk/Changelog.md 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/Changelog.md 2025-05-09 10:06:54.160292503 +0800 +@@ -0,0 +1,27 @@ ++swjdk11.0.15-sw1.3.0(20240328)版主要修改 ++1.8A与6B代码同源,通过读取cpuinfo自动适配8A ++2.实现部分Core4新增指令优化 ++ ++swjdk11.0.15-sw1.2.0(20240304)版主要修改: ++1.按照6B平台本地方法栈帧结构,实现NMT及JFR; ++2.解决地址动态patch非原子性引起的偶发sigill错,使用SafePatch选项控制,默认开启,对性能有约2%的影响; ++3.解决SPECjvm2008 sunflow偶发错; ++4.解决jdk stram NullPointerException错,添加2处memb指令(UseNecessaryMembar,使得6B平台SPECjbb2015的Max-Jops及critical-Jops下降约7%); ++5.解决test/jdk/java/lang/Math/FusedMultiplyAddTests.java在-Xcomp选项下的错误; ++6.增加ReservedCodeCacheSize大小到240M,防止发生性能异常下降; ++ ++swjdk11.0.15-sw1.1.0-SP.1(20230710)版主要修改: ++1.实现兼容8A的锁序列(commit id:1a11503de47d69d52702b357eaf6f3782399443b) ++ ++========================================================================== ++swjdk11.0.15-sw1.0.0版主要修改: ++ ++1.按照《申威基础软件版本标识规范v1.0.0-beta.4》要求修改java -version 格式; ++ ++2.解决使用gcc1030编译的jdk在自举及cpubench测试报段违例问题; ++ ++3.feature新增jni-check,cmsgc,jvmti,serivices; ++ ++4.默认使能UseCompressedOops; ++ ++5.实现UseCRC32Intrinsics优化; +diff -uNr openjdk/cross_compile afu11u/cross_compile +--- openjdk/cross_compile 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/cross_compile 2025-05-09 10:05:55.524290522 +0800 +@@ -0,0 +1,20 @@ ++#!/bin/bash ++level=${1?usage: $0 release/slowdebug images-jdk} ++dest=${2?usage: $0 release/slowdebug images-jdk} ++ ++#level=release ++#dest=images-jdk-release ++#level=slowdebug ++#dest=images-jdk ++ ++variant=custom ++remote_ip=172.16.130.191 ++#remote_ip=172.16.12.167 ++ ++#make LOG="debug" CONF=linux-sw64-normal-$variant-$level jdk &&\ ++make LOG="debug" CONF=linux-sw64-normal-$variant-$level hotspot && \ ++echo -e "\n\n>>>>>build success<<<<<\n\n" &&\ ++cp build/linux-sw64-normal-$variant-$level/support/modules_libs/java.base/server/libjvm.so $dest/lib/server/ && \ ++echo -e "\n\n>>>>>copy success<<<<<\n\n" && \ ++ping -c 1 -W 1 $remote_ip && \ ++ ssh lsp@$remote_ip "$(pwd)/$dest/bin/java -XX:+PrintCompilation -Xcomp -version" +diff -uNr openjdk/cross_configure afu11u/cross_configure +--- openjdk/cross_configure 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/cross_configure 2025-05-09 10:06:54.160292503 +0800 +@@ -0,0 +1,36 @@ ++#!/bin/bash ++level=${1?usage: $0 release/slowdebug} ++#crosscompiler=swgcc710-ali-cross ++crosscompiler=swgcc710-6a-cross ++# for c version (i.e. 9916) ++ # --with-jvm-variants JVM variants (separated by commas) to build ++ # (server,client,minimal,core,zero,custom) [server] ++ # --with-jvm-features "aot cds cmsgc compiler1 compiler2 epsilongc g1gc graal jfr \ ++ # jni-check jvmci jvmti management nmt parallelgc serialgc services vm-structs zgc" ++ # --enable-aot=no \ ++ # --enable-cds=no \ ++ # --disable-ccache \ ++ builddate=`date +%Y-%m-%d` ++ buildtag=sw1.3.0 ++ bash configure \ ++ --with-zlib=bundled \ ++ --with-native-debug-symbols=internal \ ++ --with-debug-level=$level \ ++ --with-jvm-variants=custom \ ++ --with-jvm-features=serialgc,g1gc,parallelgc,compiler2,management,nmt,jvmti,services,cmsgc,jfr\ ++ --enable-sjavac=no \ ++ --with-version-date=$builddate \ ++ --with-version-opt=$buildtag \ ++ --with-version-pre=no \ ++ --disable-javac-server \ ++ --with-extra-cflags=" -mieee -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=type-limits -Wno-error=format-security -Wno-error=conversion-null -Wno-error=sign-compare -Wno-error=int-to-pointer-cast" \ ++ --with-extra-cxxflags="-mieee -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=type-limits -Wno-error=format-security -Wno-error=conversion-null -Wno-error=sign-compare -Wno-error=int-to-pointer-cast" \ ++ --with-extra-ldflags=" -mieee" \ ++ --openjdk-target=sw_64-unknown-linux-gnu \ ++ --with-devkit=/usr/sw/$crosscompiler/usr/ \ ++ --x-includes=/usr/sw/$crosscompiler/usr/include \ ++ --x-libraries=/usr/sw/$crosscompiler/usr/lib \ ++ --with-freetype-include=/usr/sw/$crosscompiler/usr/include/freetype2 \ ++ --with-freetype-lib=/usr/sw/$crosscompiler/usr/lib/sw_64-linux-gnu \ ++ --disable-warnings-as-errors ++ +diff -uNr openjdk/.git/config afu11u/.git/config +--- openjdk/.git/config 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/config 2025-05-09 10:05:55.424290519 +0800 +@@ -0,0 +1,11 @@ ++[core] ++ repositoryformatversion = 0 ++ filemode = true ++ bare = false ++ logallrefupdates = true ++[remote "origin"] ++ url = git@172.16.130.122:openjdk/afu11u.git ++ fetch = +refs/heads/*:refs/remotes/origin/* ++[branch "sw-master"] ++ remote = origin ++ merge = refs/heads/sw-master +diff -uNr openjdk/.git/description afu11u/.git/description +--- openjdk/.git/description 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/description 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1 @@ ++Unnamed repository; edit this file 'description' to name the repository. +diff -uNr openjdk/.git/HEAD afu11u/.git/HEAD +--- openjdk/.git/HEAD 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/HEAD 2025-05-09 10:06:54.812292525 +0800 +@@ -0,0 +1 @@ ++ref: refs/heads/tag-swjdk-11.0.17-ga +diff -uNr openjdk/.git/hooks/applypatch-msg.sample afu11u/.git/hooks/applypatch-msg.sample +--- openjdk/.git/hooks/applypatch-msg.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/applypatch-msg.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,15 @@ ++#!/bin/sh ++# ++# An example hook script to check the commit log message taken by ++# applypatch from an e-mail message. ++# ++# The hook should exit with non-zero status after issuing an ++# appropriate message if it wants to stop the commit. The hook is ++# allowed to edit the commit message file. ++# ++# To enable this hook, rename this file to "applypatch-msg". ++ ++. git-sh-setup ++commitmsg="$(git rev-parse --git-path hooks/commit-msg)" ++test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} ++: +diff -uNr openjdk/.git/hooks/commit-msg.sample afu11u/.git/hooks/commit-msg.sample +--- openjdk/.git/hooks/commit-msg.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/commit-msg.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,24 @@ ++#!/bin/sh ++# ++# An example hook script to check the commit log message. ++# Called by "git commit" with one argument, the name of the file ++# that has the commit message. The hook should exit with non-zero ++# status after issuing an appropriate message if it wants to stop the ++# commit. The hook is allowed to edit the commit message file. ++# ++# To enable this hook, rename this file to "commit-msg". ++ ++# Uncomment the below to add a Signed-off-by line to the message. ++# Doing this in a hook is a bad idea in general, but the prepare-commit-msg ++# hook is more suited to it. ++# ++# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') ++# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" ++ ++# This example catches duplicate Signed-off-by lines. ++ ++test "" = "$(grep '^Signed-off-by: ' "$1" | ++ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { ++ echo >&2 Duplicate Signed-off-by lines. ++ exit 1 ++} +diff -uNr openjdk/.git/hooks/fsmonitor-watchman.sample afu11u/.git/hooks/fsmonitor-watchman.sample +--- openjdk/.git/hooks/fsmonitor-watchman.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/fsmonitor-watchman.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,114 @@ ++#!/usr/bin/perl ++ ++use strict; ++use warnings; ++use IPC::Open2; ++ ++# An example hook script to integrate Watchman ++# (https://facebook.github.io/watchman/) with git to speed up detecting ++# new and modified files. ++# ++# The hook is passed a version (currently 1) and a time in nanoseconds ++# formatted as a string and outputs to stdout all files that have been ++# modified since the given time. Paths must be relative to the root of ++# the working tree and separated by a single NUL. ++# ++# To enable this hook, rename this file to "query-watchman" and set ++# 'git config core.fsmonitor .git/hooks/query-watchman' ++# ++my ($version, $time) = @ARGV; ++ ++# Check the hook interface version ++ ++if ($version == 1) { ++ # convert nanoseconds to seconds ++ $time = int $time / 1000000000; ++} else { ++ die "Unsupported query-fsmonitor hook version '$version'.\n" . ++ "Falling back to scanning...\n"; ++} ++ ++my $git_work_tree; ++if ($^O =~ 'msys' || $^O =~ 'cygwin') { ++ $git_work_tree = Win32::GetCwd(); ++ $git_work_tree =~ tr/\\/\//; ++} else { ++ require Cwd; ++ $git_work_tree = Cwd::cwd(); ++} ++ ++my $retry = 1; ++ ++launch_watchman(); ++ ++sub launch_watchman { ++ ++ my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') ++ or die "open2() failed: $!\n" . ++ "Falling back to scanning...\n"; ++ ++ # In the query expression below we're asking for names of files that ++ # changed since $time but were not transient (ie created after ++ # $time but no longer exist). ++ # ++ # To accomplish this, we're using the "since" generator to use the ++ # recency index to select candidate nodes and "fields" to limit the ++ # output to file names only. Then we're using the "expression" term to ++ # further constrain the results. ++ # ++ # The category of transient files that we want to ignore will have a ++ # creation clock (cclock) newer than $time_t value and will also not ++ # currently exist. ++ ++ my $query = <<" END"; ++ ["query", "$git_work_tree", { ++ "since": $time, ++ "fields": ["name"], ++ "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]] ++ }] ++ END ++ ++ print CHLD_IN $query; ++ close CHLD_IN; ++ my $response = do {local $/; }; ++ ++ die "Watchman: command returned no output.\n" . ++ "Falling back to scanning...\n" if $response eq ""; ++ die "Watchman: command returned invalid output: $response\n" . ++ "Falling back to scanning...\n" unless $response =~ /^\{/; ++ ++ my $json_pkg; ++ eval { ++ require JSON::XS; ++ $json_pkg = "JSON::XS"; ++ 1; ++ } or do { ++ require JSON::PP; ++ $json_pkg = "JSON::PP"; ++ }; ++ ++ my $o = $json_pkg->new->utf8->decode($response); ++ ++ if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { ++ print STDERR "Adding '$git_work_tree' to watchman's watch list.\n"; ++ $retry--; ++ qx/watchman watch "$git_work_tree"/; ++ die "Failed to make watchman watch '$git_work_tree'.\n" . ++ "Falling back to scanning...\n" if $? != 0; ++ ++ # Watchman will always return all files on the first query so ++ # return the fast "everything is dirty" flag to git and do the ++ # Watchman query just to get it over with now so we won't pay ++ # the cost in git to look up each individual file. ++ print "/\0"; ++ eval { launch_watchman() }; ++ exit 0; ++ } ++ ++ die "Watchman: $o->{error}.\n" . ++ "Falling back to scanning...\n" if $o->{error}; ++ ++ binmode STDOUT, ":utf8"; ++ local $, = "\0"; ++ print @{$o->{files}}; ++} +diff -uNr openjdk/.git/hooks/post-update.sample afu11u/.git/hooks/post-update.sample +--- openjdk/.git/hooks/post-update.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/post-update.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,8 @@ ++#!/bin/sh ++# ++# An example hook script to prepare a packed repository for use over ++# dumb transports. ++# ++# To enable this hook, rename this file to "post-update". ++ ++exec git update-server-info +diff -uNr openjdk/.git/hooks/pre-applypatch.sample afu11u/.git/hooks/pre-applypatch.sample +--- openjdk/.git/hooks/pre-applypatch.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/pre-applypatch.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,14 @@ ++#!/bin/sh ++# ++# An example hook script to verify what is about to be committed ++# by applypatch from an e-mail message. ++# ++# The hook should exit with non-zero status after issuing an ++# appropriate message if it wants to stop the commit. ++# ++# To enable this hook, rename this file to "pre-applypatch". ++ ++. git-sh-setup ++precommit="$(git rev-parse --git-path hooks/pre-commit)" ++test -x "$precommit" && exec "$precommit" ${1+"$@"} ++: +diff -uNr openjdk/.git/hooks/pre-commit.sample afu11u/.git/hooks/pre-commit.sample +--- openjdk/.git/hooks/pre-commit.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/pre-commit.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,49 @@ ++#!/bin/sh ++# ++# An example hook script to verify what is about to be committed. ++# Called by "git commit" with no arguments. The hook should ++# exit with non-zero status after issuing an appropriate message if ++# it wants to stop the commit. ++# ++# To enable this hook, rename this file to "pre-commit". ++ ++if git rev-parse --verify HEAD >/dev/null 2>&1 ++then ++ against=HEAD ++else ++ # Initial commit: diff against an empty tree object ++ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 ++fi ++ ++# If you want to allow non-ASCII filenames set this variable to true. ++allownonascii=$(git config --bool hooks.allownonascii) ++ ++# Redirect output to stderr. ++exec 1>&2 ++ ++# Cross platform projects tend to avoid non-ASCII filenames; prevent ++# them from being added to the repository. We exploit the fact that the ++# printable range starts at the space character and ends with tilde. ++if [ "$allownonascii" != "true" ] && ++ # Note that the use of brackets around a tr range is ok here, (it's ++ # even required, for portability to Solaris 10's /usr/bin/tr), since ++ # the square bracket bytes happen to fall in the designated range. ++ test $(git diff --cached --name-only --diff-filter=A -z $against | ++ LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 ++then ++ cat <<\EOF ++Error: Attempt to add a non-ASCII file name. ++ ++This can cause problems if you want to work with people on other platforms. ++ ++To be portable it is advisable to rename the file. ++ ++If you know what you are doing you can disable this check using: ++ ++ git config hooks.allownonascii true ++EOF ++ exit 1 ++fi ++ ++# If there are whitespace errors, print the offending file names and fail. ++exec git diff-index --check --cached $against -- +diff -uNr openjdk/.git/hooks/prepare-commit-msg.sample afu11u/.git/hooks/prepare-commit-msg.sample +--- openjdk/.git/hooks/prepare-commit-msg.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/prepare-commit-msg.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,42 @@ ++#!/bin/sh ++# ++# An example hook script to prepare the commit log message. ++# Called by "git commit" with the name of the file that has the ++# commit message, followed by the description of the commit ++# message's source. The hook's purpose is to edit the commit ++# message file. If the hook fails with a non-zero status, ++# the commit is aborted. ++# ++# To enable this hook, rename this file to "prepare-commit-msg". ++ ++# This hook includes three examples. The first one removes the ++# "# Please enter the commit message..." help message. ++# ++# The second includes the output of "git diff --name-status -r" ++# into the message, just before the "git status" output. It is ++# commented because it doesn't cope with --amend or with squashed ++# commits. ++# ++# The third example adds a Signed-off-by line to the message, that can ++# still be edited. This is rarely a good idea. ++ ++COMMIT_MSG_FILE=$1 ++COMMIT_SOURCE=$2 ++SHA1=$3 ++ ++/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" ++ ++# case "$COMMIT_SOURCE,$SHA1" in ++# ,|template,) ++# /usr/bin/perl -i.bak -pe ' ++# print "\n" . `git diff --cached --name-status -r` ++# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; ++# *) ;; ++# esac ++ ++# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') ++# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" ++# if test -z "$COMMIT_SOURCE" ++# then ++# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" ++# fi +diff -uNr openjdk/.git/hooks/pre-push.sample afu11u/.git/hooks/pre-push.sample +--- openjdk/.git/hooks/pre-push.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/pre-push.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,53 @@ ++#!/bin/sh ++ ++# An example hook script to verify what is about to be pushed. Called by "git ++# push" after it has checked the remote status, but before anything has been ++# pushed. If this script exits with a non-zero status nothing will be pushed. ++# ++# This hook is called with the following parameters: ++# ++# $1 -- Name of the remote to which the push is being done ++# $2 -- URL to which the push is being done ++# ++# If pushing without using a named remote those arguments will be equal. ++# ++# Information about the commits which are being pushed is supplied as lines to ++# the standard input in the form: ++# ++# ++# ++# This sample shows how to prevent push of commits where the log message starts ++# with "WIP" (work in progress). ++ ++remote="$1" ++url="$2" ++ ++z40=0000000000000000000000000000000000000000 ++ ++while read local_ref local_sha remote_ref remote_sha ++do ++ if [ "$local_sha" = $z40 ] ++ then ++ # Handle delete ++ : ++ else ++ if [ "$remote_sha" = $z40 ] ++ then ++ # New branch, examine all commits ++ range="$local_sha" ++ else ++ # Update to existing branch, examine new commits ++ range="$remote_sha..$local_sha" ++ fi ++ ++ # Check for WIP commit ++ commit=`git rev-list -n 1 --grep '^WIP' "$range"` ++ if [ -n "$commit" ] ++ then ++ echo >&2 "Found WIP commit in $local_ref, not pushing" ++ exit 1 ++ fi ++ fi ++done ++ ++exit 0 +diff -uNr openjdk/.git/hooks/pre-rebase.sample afu11u/.git/hooks/pre-rebase.sample +--- openjdk/.git/hooks/pre-rebase.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/pre-rebase.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,169 @@ ++#!/bin/sh ++# ++# Copyright (c) 2006, 2008 Junio C Hamano ++# ++# The "pre-rebase" hook is run just before "git rebase" starts doing ++# its job, and can prevent the command from running by exiting with ++# non-zero status. ++# ++# The hook is called with the following parameters: ++# ++# $1 -- the upstream the series was forked from. ++# $2 -- the branch being rebased (or empty when rebasing the current branch). ++# ++# This sample shows how to prevent topic branches that are already ++# merged to 'next' branch from getting rebased, because allowing it ++# would result in rebasing already published history. ++ ++publish=next ++basebranch="$1" ++if test "$#" = 2 ++then ++ topic="refs/heads/$2" ++else ++ topic=`git symbolic-ref HEAD` || ++ exit 0 ;# we do not interrupt rebasing detached HEAD ++fi ++ ++case "$topic" in ++refs/heads/??/*) ++ ;; ++*) ++ exit 0 ;# we do not interrupt others. ++ ;; ++esac ++ ++# Now we are dealing with a topic branch being rebased ++# on top of master. Is it OK to rebase it? ++ ++# Does the topic really exist? ++git show-ref -q "$topic" || { ++ echo >&2 "No such branch $topic" ++ exit 1 ++} ++ ++# Is topic fully merged to master? ++not_in_master=`git rev-list --pretty=oneline ^master "$topic"` ++if test -z "$not_in_master" ++then ++ echo >&2 "$topic is fully merged to master; better remove it." ++ exit 1 ;# we could allow it, but there is no point. ++fi ++ ++# Is topic ever merged to next? If so you should not be rebasing it. ++only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` ++only_next_2=`git rev-list ^master ${publish} | sort` ++if test "$only_next_1" = "$only_next_2" ++then ++ not_in_topic=`git rev-list "^$topic" master` ++ if test -z "$not_in_topic" ++ then ++ echo >&2 "$topic is already up to date with master" ++ exit 1 ;# we could allow it, but there is no point. ++ else ++ exit 0 ++ fi ++else ++ not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` ++ /usr/bin/perl -e ' ++ my $topic = $ARGV[0]; ++ my $msg = "* $topic has commits already merged to public branch:\n"; ++ my (%not_in_next) = map { ++ /^([0-9a-f]+) /; ++ ($1 => 1); ++ } split(/\n/, $ARGV[1]); ++ for my $elem (map { ++ /^([0-9a-f]+) (.*)$/; ++ [$1 => $2]; ++ } split(/\n/, $ARGV[2])) { ++ if (!exists $not_in_next{$elem->[0]}) { ++ if ($msg) { ++ print STDERR $msg; ++ undef $msg; ++ } ++ print STDERR " $elem->[1]\n"; ++ } ++ } ++ ' "$topic" "$not_in_next" "$not_in_master" ++ exit 1 ++fi ++ ++<<\DOC_END ++ ++This sample hook safeguards topic branches that have been ++published from being rewound. ++ ++The workflow assumed here is: ++ ++ * Once a topic branch forks from "master", "master" is never ++ merged into it again (either directly or indirectly). ++ ++ * Once a topic branch is fully cooked and merged into "master", ++ it is deleted. If you need to build on top of it to correct ++ earlier mistakes, a new topic branch is created by forking at ++ the tip of the "master". This is not strictly necessary, but ++ it makes it easier to keep your history simple. ++ ++ * Whenever you need to test or publish your changes to topic ++ branches, merge them into "next" branch. ++ ++The script, being an example, hardcodes the publish branch name ++to be "next", but it is trivial to make it configurable via ++$GIT_DIR/config mechanism. ++ ++With this workflow, you would want to know: ++ ++(1) ... if a topic branch has ever been merged to "next". Young ++ topic branches can have stupid mistakes you would rather ++ clean up before publishing, and things that have not been ++ merged into other branches can be easily rebased without ++ affecting other people. But once it is published, you would ++ not want to rewind it. ++ ++(2) ... if a topic branch has been fully merged to "master". ++ Then you can delete it. More importantly, you should not ++ build on top of it -- other people may already want to ++ change things related to the topic as patches against your ++ "master", so if you need further changes, it is better to ++ fork the topic (perhaps with the same name) afresh from the ++ tip of "master". ++ ++Let's look at this example: ++ ++ o---o---o---o---o---o---o---o---o---o "next" ++ / / / / ++ / a---a---b A / / ++ / / / / ++ / / c---c---c---c B / ++ / / / \ / ++ / / / b---b C \ / ++ / / / / \ / ++ ---o---o---o---o---o---o---o---o---o---o---o "master" ++ ++ ++A, B and C are topic branches. ++ ++ * A has one fix since it was merged up to "next". ++ ++ * B has finished. It has been fully merged up to "master" and "next", ++ and is ready to be deleted. ++ ++ * C has not merged to "next" at all. ++ ++We would want to allow C to be rebased, refuse A, and encourage ++B to be deleted. ++ ++To compute (1): ++ ++ git rev-list ^master ^topic next ++ git rev-list ^master next ++ ++ if these match, topic has not merged in next at all. ++ ++To compute (2): ++ ++ git rev-list master..topic ++ ++ if this is empty, it is fully merged to "master". ++ ++DOC_END +diff -uNr openjdk/.git/hooks/pre-receive.sample afu11u/.git/hooks/pre-receive.sample +--- openjdk/.git/hooks/pre-receive.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/pre-receive.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,24 @@ ++#!/bin/sh ++# ++# An example hook script to make use of push options. ++# The example simply echoes all push options that start with 'echoback=' ++# and rejects all pushes when the "reject" push option is used. ++# ++# To enable this hook, rename this file to "pre-receive". ++ ++if test -n "$GIT_PUSH_OPTION_COUNT" ++then ++ i=0 ++ while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" ++ do ++ eval "value=\$GIT_PUSH_OPTION_$i" ++ case "$value" in ++ echoback=*) ++ echo "echo from the pre-receive-hook: ${value#*=}" >&2 ++ ;; ++ reject) ++ exit 1 ++ esac ++ i=$((i + 1)) ++ done ++fi +diff -uNr openjdk/.git/hooks/update.sample afu11u/.git/hooks/update.sample +--- openjdk/.git/hooks/update.sample 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/hooks/update.sample 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,128 @@ ++#!/bin/sh ++# ++# An example hook script to block unannotated tags from entering. ++# Called by "git receive-pack" with arguments: refname sha1-old sha1-new ++# ++# To enable this hook, rename this file to "update". ++# ++# Config ++# ------ ++# hooks.allowunannotated ++# This boolean sets whether unannotated tags will be allowed into the ++# repository. By default they won't be. ++# hooks.allowdeletetag ++# This boolean sets whether deleting tags will be allowed in the ++# repository. By default they won't be. ++# hooks.allowmodifytag ++# This boolean sets whether a tag may be modified after creation. By default ++# it won't be. ++# hooks.allowdeletebranch ++# This boolean sets whether deleting branches will be allowed in the ++# repository. By default they won't be. ++# hooks.denycreatebranch ++# This boolean sets whether remotely creating branches will be denied ++# in the repository. By default this is allowed. ++# ++ ++# --- Command line ++refname="$1" ++oldrev="$2" ++newrev="$3" ++ ++# --- Safety check ++if [ -z "$GIT_DIR" ]; then ++ echo "Don't run this script from the command line." >&2 ++ echo " (if you want, you could supply GIT_DIR then run" >&2 ++ echo " $0 )" >&2 ++ exit 1 ++fi ++ ++if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then ++ echo "usage: $0 " >&2 ++ exit 1 ++fi ++ ++# --- Config ++allowunannotated=$(git config --bool hooks.allowunannotated) ++allowdeletebranch=$(git config --bool hooks.allowdeletebranch) ++denycreatebranch=$(git config --bool hooks.denycreatebranch) ++allowdeletetag=$(git config --bool hooks.allowdeletetag) ++allowmodifytag=$(git config --bool hooks.allowmodifytag) ++ ++# check for no description ++projectdesc=$(sed -e '1q' "$GIT_DIR/description") ++case "$projectdesc" in ++"Unnamed repository"* | "") ++ echo "*** Project description file hasn't been set" >&2 ++ exit 1 ++ ;; ++esac ++ ++# --- Check types ++# if $newrev is 0000...0000, it's a commit to delete a ref. ++zero="0000000000000000000000000000000000000000" ++if [ "$newrev" = "$zero" ]; then ++ newrev_type=delete ++else ++ newrev_type=$(git cat-file -t $newrev) ++fi ++ ++case "$refname","$newrev_type" in ++ refs/tags/*,commit) ++ # un-annotated tag ++ short_refname=${refname##refs/tags/} ++ if [ "$allowunannotated" != "true" ]; then ++ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 ++ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 ++ exit 1 ++ fi ++ ;; ++ refs/tags/*,delete) ++ # delete tag ++ if [ "$allowdeletetag" != "true" ]; then ++ echo "*** Deleting a tag is not allowed in this repository" >&2 ++ exit 1 ++ fi ++ ;; ++ refs/tags/*,tag) ++ # annotated tag ++ if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 ++ then ++ echo "*** Tag '$refname' already exists." >&2 ++ echo "*** Modifying a tag is not allowed in this repository." >&2 ++ exit 1 ++ fi ++ ;; ++ refs/heads/*,commit) ++ # branch ++ if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then ++ echo "*** Creating a branch is not allowed in this repository" >&2 ++ exit 1 ++ fi ++ ;; ++ refs/heads/*,delete) ++ # delete branch ++ if [ "$allowdeletebranch" != "true" ]; then ++ echo "*** Deleting a branch is not allowed in this repository" >&2 ++ exit 1 ++ fi ++ ;; ++ refs/remotes/*,commit) ++ # tracking branch ++ ;; ++ refs/remotes/*,delete) ++ # delete tracking branch ++ if [ "$allowdeletebranch" != "true" ]; then ++ echo "*** Deleting a tracking branch is not allowed in this repository" >&2 ++ exit 1 ++ fi ++ ;; ++ *) ++ # Anything else (is there anything else?) ++ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 ++ exit 1 ++ ;; ++esac ++ ++# --- Finished ++exit 0 +二进制文件 openjdk/.git/index 和 afu11u/.git/index 不同 +diff -uNr openjdk/.git/info/exclude afu11u/.git/info/exclude +--- openjdk/.git/info/exclude 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/info/exclude 2025-05-09 10:05:23.276289433 +0800 +@@ -0,0 +1,6 @@ ++# git ls-files --others --exclude-from=.git/info/exclude ++# Lines that start with '#' are comments. ++# For a project mostly in C, the following would be a good set of ++# exclude patterns (uncomment them if you want to use them): ++# *.[oa] ++# *~ +diff -uNr openjdk/.git/logs/HEAD afu11u/.git/logs/HEAD +--- openjdk/.git/logs/HEAD 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/logs/HEAD 2025-05-09 10:06:54.812292525 +0800 +@@ -0,0 +1,2 @@ ++0000000000000000000000000000000000000000 531a81f289670e918b667eb3b5e298773a9f7400 zh 1746756355 +0800 clone: from git@172.16.130.122:openjdk/afu11u.git ++531a81f289670e918b667eb3b5e298773a9f7400 91d63cb90669dcc2cc54e1b0d7e6331a9543e198 zh 1746756414 +0800 checkout: moving from sw-master to tag-swjdk-11.0.17-ga +diff -uNr openjdk/.git/logs/refs/heads/sw-master afu11u/.git/logs/refs/heads/sw-master +--- openjdk/.git/logs/refs/heads/sw-master 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/logs/refs/heads/sw-master 2025-05-09 10:05:55.424290519 +0800 +@@ -0,0 +1 @@ ++0000000000000000000000000000000000000000 531a81f289670e918b667eb3b5e298773a9f7400 zh 1746756355 +0800 clone: from git@172.16.130.122:openjdk/afu11u.git +diff -uNr openjdk/.git/logs/refs/heads/tag-swjdk-11.0.17-ga afu11u/.git/logs/refs/heads/tag-swjdk-11.0.17-ga +--- openjdk/.git/logs/refs/heads/tag-swjdk-11.0.17-ga 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/logs/refs/heads/tag-swjdk-11.0.17-ga 2025-05-09 10:06:54.812292525 +0800 +@@ -0,0 +1 @@ ++0000000000000000000000000000000000000000 91d63cb90669dcc2cc54e1b0d7e6331a9543e198 zh 1746756414 +0800 branch: Created from swjdk-11.0.17-ga +diff -uNr openjdk/.git/logs/refs/remotes/origin/HEAD afu11u/.git/logs/refs/remotes/origin/HEAD +--- openjdk/.git/logs/refs/remotes/origin/HEAD 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/logs/refs/remotes/origin/HEAD 2025-05-09 10:05:55.420290519 +0800 +@@ -0,0 +1 @@ ++0000000000000000000000000000000000000000 531a81f289670e918b667eb3b5e298773a9f7400 zh 1746756355 +0800 clone: from git@172.16.130.122:openjdk/afu11u.git +二进制文件 openjdk/.git/objects/pack/pack-6c1cf43ce498d2daaf2be27b3279a870db2f08ed.idx 和 afu11u/.git/objects/pack/pack-6c1cf43ce498d2daaf2be27b3279a870db2f08ed.idx 不同 +二进制文件 openjdk/.git/objects/pack/pack-6c1cf43ce498d2daaf2be27b3279a870db2f08ed.pack 和 afu11u/.git/objects/pack/pack-6c1cf43ce498d2daaf2be27b3279a870db2f08ed.pack 不同 +diff -uNr openjdk/.git/packed-refs afu11u/.git/packed-refs +--- openjdk/.git/packed-refs 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/packed-refs 2025-05-09 10:05:55.420290519 +0800 +@@ -0,0 +1,1654 @@ ++# pack-refs with: peeled fully-peeled sorted ++5e8f75a3170cd03ec120a4e1490559931c1bab83 refs/remotes/origin/001-fcmp ++2f281856245f18d3c149fac65c47ef1fab1a1f51 refs/remotes/origin/8A-unwind ++3f8a41f87cf7208c9f00662a396700710ad51c8a refs/remotes/origin/8A-zh ++913dda950138b3e585b29230376e3041b3a51e75 refs/remotes/origin/SPECpowerPeak ++9eec74daed69eba161180930d5b906f9d441de1e refs/remotes/origin/cch-C1 ++95bcc6eaba2bb6f36f0bbeaaa28efd2e4407468e refs/remotes/origin/cch-sa ++aba5f8ee3b20e73e671397e5c54b86ec5284ae51 refs/remotes/origin/dx-c1 ++659a4669208645420e151e78ab5fd3ac3808b310 refs/remotes/origin/master ++87ae256cb579cf93aee74757fdff5e015d7e596b refs/remotes/origin/sw ++531a81f289670e918b667eb3b5e298773a9f7400 refs/remotes/origin/sw-master ++4cc486bd98ff19e17a6181735bb5db9b4a3cca2b refs/remotes/origin/sw-update ++fddd7c766058a56d4645602eaef3b4ae9b5f6731 refs/remotes/origin/sw-update-new ++81fe331dd20f3de0c0b238b20288c6a2ba073eaa refs/remotes/origin/swFor8AUnwind ++caf629914846cce26b35b6c5fc1b192834b9ca04 refs/remotes/origin/yj ++20557750ecd0dcf3f9228aa4cc279a41b2a4cabf refs/remotes/origin/zl_sw ++22119e038506cb3c439bf6d32f91963f76482909 refs/tags/aarch64jdk-11.0.8+1 ++cbfedbbe6ebcd34cf8073ceb3b9778338f0de722 refs/tags/jdk-10+0 ++^62007a12b80f381c687f60825b20fe0bbeeb5eaa ++a5719b8b503113d34a7037cd95ae9a75df465847 refs/tags/jdk-10+1 ++^d6fbebf0bfa820bc7382fc15ba9db76adde9a436 ++5f7f102d588428f8f5e700c3b0be76f1e5bfddcb refs/tags/jdk-10+10 ++^a449b1007959923b441321f5746c1fa71c7b1f16 ++461ee9721bb0693c2e3f2addf4bbb47b645c6885 refs/tags/jdk-10+11 ++^fe00fb8af65018ccaf3c6dfb09554579a5dacd5d ++ee812681b38e719e0abf0382c72dfb196ec09f83 refs/tags/jdk-10+12 ++^d11402b6163ead2e76ec566de07dd2e5802601d5 ++ffc5b1ebdf0a02687aa9b177dbda3ba1cc2ae32a refs/tags/jdk-10+13 ++^4771f81a6dfda8fa958670fbde9c96d8bc6ad505 ++ad42d50c857e6e36088008a5d130f4cd60bb7c6e refs/tags/jdk-10+14 ++^0a79d06e97edd75047db89d54e7246c98c90317e ++689d3132b150d15c6934225e3e7b1092fa266e5b refs/tags/jdk-10+15 ++^aaf6826eb5933674c9e219d8869088d7fc3d628b ++f75cf7c4e209f2aab57a0f4a9322b4879155381f refs/tags/jdk-10+16 ++^d05e1d6b08838b7f1ac8c155953327687ff532ab ++b781e3196724e8a790a4495b021e6559ba09c576 refs/tags/jdk-10+17 ++^4452b9e46a34bd8f2be1f05fceba330fd3730f1d ++15d921aa5c5f5e7a74d87d0a73b4ff9906ca2fe1 refs/tags/jdk-10+18 ++^792b65cd445eaf2d056701060ddf566270b92df9 ++ba483867b8a25a048cd7bd6671c4e17764061613 refs/tags/jdk-10+19 ++^c04bb089fb3a84643c523c3430dafb01827f6b28 ++bae6cc13b2ba7f664d2623cbda0023c83e26d4a0 refs/tags/jdk-10+2 ++^4e1bc5c2a910df3516a82532ca760c29b7903eab ++cd8f3bc879e19551b62a198a3863c155d31f1d02 refs/tags/jdk-10+20 ++^d7cd632a4ae5ce50a14d5adf975baa8c836c4086 ++1130c75bbfd94f9c6a65e9df6762ebbecaae8964 refs/tags/jdk-10+21 ++^7bfd42d9412528d327664e3b085a079337472c42 ++6bd3c79ea6c0a224d5d514b7a98abe90d69a220b refs/tags/jdk-10+22 ++^363d9c80bea693b8aca40874aefe30f5f20df47f ++231077803760a76522c821f84690e26c1c1e0a52 refs/tags/jdk-10+23 ++^bafb5a1395997a0316f998a3f24a2e2e50a0795f ++718653b0a4a7a38565cee21e3d4ed3dd1fc04462 refs/tags/jdk-10+24 ++^c111277919d05a6d70bb22e7e8feafb412a8534c ++246bf35cafa3014c3fe3b9dfd1ec3fac36362cca refs/tags/jdk-10+25 ++^cea7897f087263d0a3f2ba8c46666d4906929fda ++bde716bfd7f14babf6faff698678fefd16e3b378 refs/tags/jdk-10+26 ++^9f2615c4de4b0410302bee90b58c4ced98d21fd6 ++b766e20264e4d39b1bf9f4abd308826ed5a11d08 refs/tags/jdk-10+27 ++^848a4d9bae63b72d7d780f267df3609e0bcb172c ++0dc742847b06a50065ca74aafcb8dca3e71067cf refs/tags/jdk-10+28 ++^3263ea9b0c142bdd864b30bb5f9b2a970d59099e ++81b9baadc7dc1244b7cd7d09524ebb85172f1f53 refs/tags/jdk-10+29 ++^9615ad79e8c2f0d180e39730db92fa68f47b3af4 ++7cb8df7b70b7d5e2f3bedbded6b158e602a4a42b refs/tags/jdk-10+3 ++^3ff7e077ea5520b7e0cddd5238f6099b7319527e ++043b027354c20f2b5e783c7907939883f5a276e9 refs/tags/jdk-10+30 ++^c6be2c363a69ec0f847a6dc3cd67dc7c8b2e77ae ++bef1b5fd5dc3ea1490463582580fa41a8f73640a refs/tags/jdk-10+31 ++^6a9a00c61c69776a433827fab03e97e3060440ad ++7f0753fe91b1f21f0f68afc23ae7ce0b44b25cd5 refs/tags/jdk-10+32 ++^433bf8ab6507be962521090fc91009054d48b8f7 ++e4e26b55570f355cb4ecd5a3ecf1ea349b4ba872 refs/tags/jdk-10+33 ++^14e7d88c9e02427adc243395aef489ae0a77ff7e ++ba3bbce687e2cda73c01cea5d0c24013cd921880 refs/tags/jdk-10+34 ++^5102cb91209a4ba59d88b9a2b7f0d5217041a457 ++816969fd128423e65120d8f19e640098edb6d8be refs/tags/jdk-10+35 ++^8c50b3e660b97bd395f8de86cc2cfa88ed1266f0 ++3445bfaf8df7db3a1cb0b471b24c9e2a40cbe804 refs/tags/jdk-10+36 ++^1a5f4b8fa27e2f9b0866409ae06b720871b736f9 ++70da379c77f67531247e81071daf06be409b3cb3 refs/tags/jdk-10+37 ++^7302c9c8c5d9a1d724ba570cf363bf93c6a7f004 ++7697dd9b119d9751acafc4022ba14262dabdfae9 refs/tags/jdk-10+38 ++^f6c82cde4560a39d91f36ce9d9b3ae0c19846228 ++d805e7b1c1541aa19a57c029a38adfb554823d0a refs/tags/jdk-10+39 ++^e2f5722888ff0e2368b1e2413c7005aae1c85d1d ++ae0756036271062a547477d8e38f654b88ccbf50 refs/tags/jdk-10+4 ++^c6675bd02f24af1fb4c47094cd70ba8d1c8fa416 ++183052ebe1206f10bad0c83c46173dd70d2d7ccd refs/tags/jdk-10+40 ++^72ba3f508c4a665adc5f906f8b98bd90302c42b8 ++6be7e65ea3fd883297dd504dba6d5b30423f8fdd refs/tags/jdk-10+41 ++^7acb09ea5e78d5aec16a852c8434970f0d38b662 ++509bcd78f50671ab1dbf8c15d752283b61910db0 refs/tags/jdk-10+42 ++^4bea8ffc4c310fc8c87119543692114d20fcf7ca ++d40c4d80b4f57e9264a378cc0be60ca61312ddd4 refs/tags/jdk-10+43 ++^d5ec9dbfb53e9a4e89d2867f12cfc8c40fe1fcd2 ++52a2d5920ada7d7da398716cf696494bae9a9305 refs/tags/jdk-10+44 ++^edb1509a0e6ee28d545cf760b5a4ee963e28bd05 ++dbd70868fedd49d4c08f9adcbdb50e5fb4f7120f refs/tags/jdk-10+45 ++^2a3b12aec89f61478ca16ceb86d06556a3e397a7 ++b4570198455731919f37dca90c840a72ab297062 refs/tags/jdk-10+46 ++^7a145c6805ba8c81680294e87e801bdef56c9954 ++281982de41c8193c72b36665ea3deba77e9d3f3f refs/tags/jdk-10+5 ++^d4f0061790c809657181aba8d0a81781c25e24e7 ++3ff805ece2993979993b8d4a38a19eedf5cee82c refs/tags/jdk-10+6 ++^cd84fed3c7a2f1b2da5021c61e0be00efd45e143 ++a16f7f3960bd905f55f99bbc3fcea0b8612cc001 refs/tags/jdk-10+7 ++^36b23cad4725ae42f80f7a706d0b1207ce53c141 ++790b6cb0b07c60cd8498ac22ec9e3bff95239aa3 refs/tags/jdk-10+8 ++^5a0726a47a87615a24ce5ec91029036c1d491ce0 ++692a723c417f00062a3b3ca4b401ea627c06396e refs/tags/jdk-10+9 ++^573dafdea13c41547978ae5135b0bc111a3a7f3f ++636e73a47d3dade503954ea722bfd75d966a33bb refs/tags/jdk-11+0 ++^a9a271179d2a7952154b7509a999b100cc98b13c ++0c84d5a8fbbe5952f59de922a5211e8f6bfc6aec refs/tags/jdk-11+1 ++^0b78370b748f38ccd107e1cd5c005bc6dd55185d ++716bd61607e0f6e576b027b27e7e6793497cad0c refs/tags/jdk-11+10 ++^a0a4b1981b86ec8644add87a7a77975303e0fa16 ++f88d3455eeb1b8973b47ddf386a6b7309c295800 refs/tags/jdk-11+11 ++^673e292ffeaedf10d71bc179ec9bc847e938deae ++625cd4ed27f85acaea94524557e284966af8f48e refs/tags/jdk-11+12 ++^36b8ebf5c9da1de3e8dfe6a084f380d165ce4b36 ++2cc5c44863b8cb25c3c02ad6368226ce38e70ee1 refs/tags/jdk-11+13 ++^b34a8c43f17cb76d11f69ad4fc95f75635962c7b ++1ebeb43bd0ccd5d1e52e349c52f4ced3385e2f89 refs/tags/jdk-11+14 ++^12a799b4e1ad4a201ef25f5ce587b6e4396fbf4c ++23fc97ad76fe2fd50c66f6df9eed8af0b82e3e79 refs/tags/jdk-11+15 ++^de1b88636899e042e8015e23ebd2da940d79e677 ++b13c8b270d477d104059e8e675f8819dd4f375bc refs/tags/jdk-11+16 ++^b67da0de17fea5540e3e17235764b232082ed330 ++c3aadd37733cd620c4d6baa37367fb598031924f refs/tags/jdk-11+17 ++^111654125439abd9270beafc4efcf1b56e30e5ba ++00bd95880c2d6a113a84983cff091d816aee69ca refs/tags/jdk-11+18 ++^765618a8abf8afbe6fa3fd708c2b6eec70355590 ++ed1cdef8f8e0ba88a9731e00762775d2b59dca71 refs/tags/jdk-11+19 ++^267fe08ad98da988fc7f9d17140cd62f3c52e5d3 ++a72091d2b51267c2e265e31f8ab95e2e2a4cd9e6 refs/tags/jdk-11+2 ++^25da45e26f37c6dac5648436d0edd269d9efa545 ++38a7f0b2631b5e8a0d401f619300a5c1fc863d79 refs/tags/jdk-11+20 ++^69438af9ece8a6aa93c636bd663465d0a35ef92f ++e32e4a2efd2e744aea1b975ab5d094512f029ad9 refs/tags/jdk-11+21 ++^4dedba9ebe11750f4b39c41feb4a4314ccdb3a08 ++db1d8cc927f44eb5956931ed03997e683fa346cd refs/tags/jdk-11+22 ++^bb12ce24ef7f85a726afc0fe436bdb8b424fa38f ++66fb7c8d4800be881ab519e2da50f98e104b5ebf refs/tags/jdk-11+23 ++^8818f46285cce69516885d56967dde0c671c3080 ++744bba07a673601512c3e5a6bd1845788635c4b1 refs/tags/jdk-11+24 ++^d4beeed2db07283e7c5ef08037782edc7062d930 ++5626d9f41e656d488b2b3335ca41b4726e05a63e refs/tags/jdk-11+25 ++^b6532bdf48d443f50816389d1a2978ca67fe09e8 ++f88fcdf49eda0fe30f154a9d935631c2a4a38bbb refs/tags/jdk-11+26 ++^2f1aae720b6f71fd6806e8b8a9efce50e0b2ec90 ++ee78424c97284d9195b87003be54acfb8e34cd1e refs/tags/jdk-11+27 ++^42de356cbd3d750cc3567ac814f7c85323877cea ++6953356297f51be519e94a63b2c570d7ac1da826 refs/tags/jdk-11+28 ++^da75f3c4ad5bdf25167a3ed80e51f567ab3dbd01 ++e3876a0edd9ba8e5a6aa9e7a5beba399b6f94e83 refs/tags/jdk-11+3 ++^3e7c7c6cdfd71425b13c4160a8381bff10027c7d ++33da2a75eb810478c7e88061f17cc69636ad091c refs/tags/jdk-11+4 ++^1926d24306b0d3954992ea519263acd519f3403d ++21959c24fc09d9e0a549cf12ab082e1c676eef6f refs/tags/jdk-11+5 ++^ec605aa039c4abf8dc881f9dd02c8ac028863917 ++b7a0de44609fc98aa8345e5495acb0b8c330c740 refs/tags/jdk-11+6 ++^05b129ec25d8e3d55a189d424cd257a900aac6f8 ++d122002f38565da5b8eab75cceb249a0111e0e8d refs/tags/jdk-11+7 ++^1cd649af57ed5168566d32af58146b46f335201b ++a3b03133fbd37b54a10a9cad84b9b32b5b2b11ea refs/tags/jdk-11+8 ++^277ac7e034c61b1d4c9fb346a19566aba2413c8a ++be6f6354ffa2eccd8d8672c9715a91f568e2a196 refs/tags/jdk-11+9 ++^8483faa4a978627c0f35c1c854f1c0b4e9018ed7 ++907bc00963e12c5ee10f31cd18e656011c7bb13d refs/tags/jdk-11.0.1+0 ++^821b7ac2b5e48f6ea76d7c95af6f1bbbd6ccd7f0 ++a6b16a6ddc449b94836fd54ab52e901b59c94da8 refs/tags/jdk-11.0.1+1 ++^0ec4029c816f4e2198fc59a2124cf7d938403401 ++2b587b5afcd7a29991dfa3b34885f7a70a7c5aeb refs/tags/jdk-11.0.1+10 ++^1ec7dbab23c2f4b74698c1f685671e43436e6631 ++0072d80279ca504f221fd21cb27d4c3808ce3526 refs/tags/jdk-11.0.1+11 ++^0864917e44020011517824dcc0a32ccfb5a42063 ++cb17c9e72a9806252fb23f14217695d6bbe96f3a refs/tags/jdk-11.0.1+12 ++^35d6a546eb564e123548693a84569da0dd053079 ++e7c6c6c3d94f9e59419f6c4479bf17d815a3b110 refs/tags/jdk-11.0.1+13 ++^5e068301206357329154b1d2387647b7ecf60643 ++0581bc7a465170ad9911c12709855bdef54a181f refs/tags/jdk-11.0.1+3 ++^0eddb97c9799d3c33591d863d50fb56548166d19 ++2c065877d37aff5384fd8bbe6a9ead642f7b0d5b refs/tags/jdk-11.0.1+4 ++^944408c6e00d129224caa2aef79cf5bfbb895718 ++79d3533be9c1cf30beebb2e8be38da40ef1d45c1 refs/tags/jdk-11.0.1+5 ++^5dbc1f256b1a538eebf11d770a5b7689ed322312 ++d401a2f31ee2559e5ed8ade71a4dd5a3c590221d refs/tags/jdk-11.0.1+6 ++^ffd27904befd75cdf6cb2a8f964a2fec22d40683 ++41f39258b3a06a1ec9f2b78da9dbe7f70e4c0b8f refs/tags/jdk-11.0.1+7 ++^19b176af8b83db38b3f664c2477ba9ea506bd78b ++bd6895975f21e2c9060f5b64109613ceeec65ab5 refs/tags/jdk-11.0.1+8 ++^5bc98172e38e49a490ed12fb55163f26a70920c9 ++50485104b6d5057a54a84c39027fe95056393833 refs/tags/jdk-11.0.1+9 ++^4f8dc731e6dc20905952d9d04f25ce4bb8606476 ++701d805a7d69f2ab63a818e67fe2fdd245bd7bdb refs/tags/jdk-11.0.10+0 ++^3f7a3ffee85042a0ee4bf39c02473df4a945f160 ++8e9155567868945fa3b0a30279e9cf03e8781912 refs/tags/jdk-11.0.10+1 ++^def9d7832e814b69336a1301b1ce121ba51c0fea ++4f49e156eccfb93dd47e3cdb72988a876998e3e8 refs/tags/jdk-11.0.10+2 ++^81025467bc898c7890ee1823c2353ce1e63762f5 ++b940c4e14098a124b813f987d5ad268827d6e148 refs/tags/jdk-11.0.10+3 ++^f9db906ae6cff45357c9d970d8069697fd061c1d ++1adf8fac010ccc6f43404b00c469ea11e3b98ce9 refs/tags/jdk-11.0.10+4 ++^79d002ccbf6be3d89ee1bfd1b6002d1075c5e16b ++33d68537d113ff9ae5e965928d12b0f9745fb80e refs/tags/jdk-11.0.10+5 ++^7b6e6fe78017ed0ec46873459ac5261d0b7a3526 ++fb1f993d8b7fbc2b62a00baa8b6f8887f51a8b2d refs/tags/jdk-11.0.10+6 ++^706d936ebe9d0b85231c18ff1805325571456586 ++d8713da4ca3b4fedb8e04c01eccbf707cec4971e refs/tags/jdk-11.0.10+7 ++^461518002d3ab302015780f6d4157015c802545a ++2018c6bebf298124615e59a28bff692ca6dc653b refs/tags/jdk-11.0.10+8 ++^5a3ad95175d0c383f0be8a07b4065c28dba9e71a ++d00559444097df93f6160ae7e0d82b06d6be6a42 refs/tags/jdk-11.0.10+9 ++^b3adcf1ecba07f2d4eff5d463309d52af2be4211 ++717d58e153bb2ca153ff9a177a653aa98f66bbe5 refs/tags/jdk-11.0.10-ga ++^b3adcf1ecba07f2d4eff5d463309d52af2be4211 ++37211022ee7603fc644230d9ccae79d9093c67e9 refs/tags/jdk-11.0.11+0 ++^4ba3297ffae28c19263f5e444550ef276a466fb3 ++3a3c6311637f79fd6ec35be953b828412a8616c9 refs/tags/jdk-11.0.11+1 ++^92016c1d441170f168ec8fb578f26caa48c98567 ++e1c0c687b25aa14f485ed8487516bc349cb1c642 refs/tags/jdk-11.0.11+2 ++^74ce033c3e3ba9731a2f618394023e42ad186606 ++51213abf2b19b1517112cc8c0a390ee75fd82825 refs/tags/jdk-11.0.11+3 ++^07c0152fcc4b66418247603cbe34ebdffbf8af67 ++87b4f0f21f844cc54f7499b5ef72a82aa600c633 refs/tags/jdk-11.0.11+4 ++^83efecbcae851da8548107165426e92a5d1a4fab ++5b7963c36da1e94880fcdf01d05a3bd8d7277bb9 refs/tags/jdk-11.0.11+5 ++^520701d4037645083f9721aefc3d3d1cbaf9e791 ++49e342b7cf6fc186226c5a6f10f3fbca78e0534c refs/tags/jdk-11.0.11+6 ++^d1db307ad5c6ec18f9ed4d4e61411067b1a9a8be ++76ceab06be445bc85801171c7e2960fb5bb70b08 refs/tags/jdk-11.0.11+7 ++^d609620d0fc1e68467664e9fd8e15f382fa8697a ++37e817a7467d24260551d63601435ea279620a7d refs/tags/jdk-11.0.11+8 ++^78c200a469997b6d8aa7c202d30855104d92068b ++6a139aa6f9bb31d7dffdf974b821cddfb77329eb refs/tags/jdk-11.0.11+9 ++^96cd8afba66dc13d80b8ebe07df1bd8d8a42660f ++429f36e74ee426e9a598549dbf235a666d208008 refs/tags/jdk-11.0.11-ga ++^96cd8afba66dc13d80b8ebe07df1bd8d8a42660f ++bea795c82e29d0b0e5181d1b60c07e1ec2db25c3 refs/tags/jdk-11.0.12+0 ++^a4f2cc65079328cb428cf0317df39af93472ab1e ++4ed80885077bc2ad179388771d0203e9eaee9e1c refs/tags/jdk-11.0.12+1 ++^d27533f1967411dfd1b50b3fe0f0cebb936f1d3a ++54e270e13dd33925c0814c8b30ce923323ea6849 refs/tags/jdk-11.0.12+2 ++^a8ab8ee610a20a51fee21f2725df0bc9ee190c55 ++c2f3c0c6a165dfaf08d75fb15a252c1b4cd8a34b refs/tags/jdk-11.0.12+3 ++^430d07111fdb0cb9fe4f275f371106a12446474a ++8b46d7108d388f074f9e6f4717560a73185f84b1 refs/tags/jdk-11.0.12+4 ++^269b414c31a4ed31fa32f52a5cd89e3bcac35750 ++bc35ce45fdd45c5bc4da6b4c550ab22cde1771c0 refs/tags/jdk-11.0.12+5 ++^e0af8b4a15e271e750596bb8883742dda243b599 ++9b124266b502e60ede6c5724aa782ceb7083aa09 refs/tags/jdk-11.0.12+6 ++^bb5b2cb9d3a1cfcd040d295ab6f6b54eaf88483f ++b7638c68f09c26ddfc89669e0d39e04f8195e0d6 refs/tags/jdk-11.0.12+7 ++^d1541f3012754e0bbda2524bb865c6a971fc4574 ++6257c4c0eb916bb7a3aeec0a7f01a33ca5a39c80 refs/tags/jdk-11.0.12-ga ++^d1541f3012754e0bbda2524bb865c6a971fc4574 ++8c998c722b8cff29de7ff8c5d8bc833ad087c745 refs/tags/jdk-11.0.13+0 ++^c88fbe60b22a042f3f82089f4a06af390ff571d4 ++a5904281f30d3ade4634eee4d0a1ef6a7d889a8b refs/tags/jdk-11.0.13+1 ++^815d3e1c6cd8272f962eaec80758cafa97c1dda5 ++8bbab8aa07767c9bc4f82a564502ac7531d06c7d refs/tags/jdk-11.0.13+2 ++^5f9429b58f68a2d71b3dae96e15353b780c745a3 ++18b175f10ce249023b177c30958a8617e836be93 refs/tags/jdk-11.0.13+3 ++^3a32efcd73fb33243bcf6598907b773080be926c ++f9472f30c558ab2a7a7b53465f54e2004cfb47bc refs/tags/jdk-11.0.13+4 ++^c55b1e5c064f9929e9bc1c2610a6b1431cd437c5 ++55d0d2487332780490b80564986b5896c49f18ed refs/tags/jdk-11.0.13+5 ++^63fc945c1d4cdc893d89796804acfe0ce9341860 ++57c9f87cc6a0c2adce6a806002d84fb9cd346be6 refs/tags/jdk-11.0.13+6 ++^f336c729e35b6793d0910beec167b2c739ec95e7 ++6ba6f9801c766f992d0317426a4e1b63c46421c8 refs/tags/jdk-11.0.13+7 ++^c9c728849c137e21535cc402664dd54ee421b0d3 ++a6b1411139d3ab1d10e637944cdbc59b90c844fb refs/tags/jdk-11.0.13+8 ++^71f2c75111e87091616f0f3b86bea6c4d345dad1 ++8a9b37d87ab912a960ad791167f54d9c49b71a5a refs/tags/jdk-11.0.13-ga ++^71f2c75111e87091616f0f3b86bea6c4d345dad1 ++5e02289752a8d6906a38def18c6c96714de623e3 refs/tags/jdk-11.0.14+0 ++^63fc945c1d4cdc893d89796804acfe0ce9341860 ++f6c8bf341ac7214fb46b95e1a29cc8a7d533cc5f refs/tags/jdk-11.0.14+1 ++^36e54fbd936cebfa8e66483d0daa4d22dcc3100a ++21802308e3a51ace6835aa9339ef4b8613e760ee refs/tags/jdk-11.0.14+2 ++^c406da13284934c11f04146daa9ebc960d0f5f4f ++d3d7b87f1fad2b5545f0043635720632607eedcd refs/tags/jdk-11.0.14+3 ++^3593e1eac182e7ed25a9c5533fd92d37013a1811 ++2f0e83baf4fd47d3a65e56786868dc63804bc5bd refs/tags/jdk-11.0.14+4 ++^dcc010d7c84195cdec0844d0e497e57dbc173743 ++1483635a0992e1bef5045427a18a905c81e83cac refs/tags/jdk-11.0.14+5 ++^22186cb1fe22b4b30fc72c67ce9946cd4f03199d ++36acf5ecae1f768afdfd5d22fd8b3473c2227999 refs/tags/jdk-11.0.14+6 ++^f5664eafd58bb779431f1df1e03cd8e9270f24c1 ++98f9c68d7acab159154de49d13fcf5b4cb3be3c1 refs/tags/jdk-11.0.14+7 ++^d665a4ec39523630af6f30ad7d732053bb62559e ++fe3b96f8692e306a19addd5b034aeb38c154f4e8 refs/tags/jdk-11.0.14+8 ++^175e23fdf4cb0929ff1cca9538a884ee3833337d ++d003057d6d9def268249476e775977ddb0662145 refs/tags/jdk-11.0.14+9 ++^1453335629e17be9a3b8718ad0c326f26cc68cd7 ++ae6829890fe761b993666b63db455924cb308e42 refs/tags/jdk-11.0.14-ga ++^1453335629e17be9a3b8718ad0c326f26cc68cd7 ++a75ecd5550b9f65e28943955fd370e8db54f71ce refs/tags/jdk-11.0.14.1+0 ++^1453335629e17be9a3b8718ad0c326f26cc68cd7 ++42240d2ec719480126b1856e9b018fbf1d5e37fa refs/tags/jdk-11.0.14.1+1 ++^b8cdf1ae18bb8301e289b827751a2e0aa9f3f50b ++13fd1d58f78c406c033b08d062423068b22d1365 refs/tags/jdk-11.0.14.1-ga ++^b8cdf1ae18bb8301e289b827751a2e0aa9f3f50b ++d5c29abadc582df221712183c42ac7834feca1f9 refs/tags/jdk-11.0.15+0 ++^22186cb1fe22b4b30fc72c67ce9946cd4f03199d ++0acbb286abaed6d727eb3522331931815a8c9f30 refs/tags/jdk-11.0.15+1 ++^288c9f7d6ac6057216d3c7756ea667cfb65fc6a3 ++bf82a6de8c0ab11755da26c8480886c2b73395f8 refs/tags/jdk-11.0.15+10 ++^224e1a3fcb2c9c43e97e7b0e69d7aad66560f6fc ++0089bf7558a291b5033e5dff43b91b6e69773bc5 refs/tags/jdk-11.0.15+2 ++^eb0708f75aa3c196e41014addfaa5667fd940cc2 ++13d0e874af4e84409e0febcd9be3b6a2632d6c73 refs/tags/jdk-11.0.15+3 ++^26e599dce20b0ba21273df30ad3cc7242c67a98f ++7fd4dde155f7c222bb85920627833f27f1642538 refs/tags/jdk-11.0.15+4 ++^5cad68f586b1d75403ba7339828221ff6f167c53 ++8d97ea6fae7c071ff1fba81fdbce3fcd832a7556 refs/tags/jdk-11.0.15+5 ++^1cff5631dcd0a122715a06be38894cd7bff2bcec ++9f929da2926de73765abd47721af7af08bd46a8f refs/tags/jdk-11.0.15+6 ++^f7346f087a14f1878029a00104005e04468d333f ++b3f720f2d55002564b8dc236fc603759ee5cfc2d refs/tags/jdk-11.0.15+7 ++^9a7bd43d277135ac2bbb9c8289430b9f8dd5af3d ++b9cee6bbe1f27c3d990abe618f1461557114ce8a refs/tags/jdk-11.0.15+8 ++^487c3344fee3502b4843e7e11acceb77ad16100c ++f10322973998ae5ddbd1e1afb4048fc2a7d8f00b refs/tags/jdk-11.0.15+9 ++^91d65505f779887e9c79d6e7181cd2a81f1ea118 ++bafdd5362651d53d4a22c390eac2f7237a464674 refs/tags/jdk-11.0.15-ga ++^224e1a3fcb2c9c43e97e7b0e69d7aad66560f6fc ++143aaeba9441d35e4ca05e607be80eb7a89abfe9 refs/tags/jdk-11.0.16+0 ++^5cad68f586b1d75403ba7339828221ff6f167c53 ++2af3c017b27bae8ba9b9e0c4a33a019cb3e4e508 refs/tags/jdk-11.0.16+1 ++^87e0662a7336cbdb3de30a0c597f1588b44483e9 ++3aafbb931948961c43b83f4f01cc2b34ee10d62d refs/tags/jdk-11.0.16+2 ++^c95c7967bbd1004f23250f8898c7246420da9e83 ++ce85603edf64e60ef38b75be143b492dcfe09926 refs/tags/jdk-11.0.16+3 ++^0056b9b4f91ed9132364984fb45e1ce1ad563af4 ++653faa28b9cda0c0533ea86228c841081bd4051f refs/tags/jdk-11.0.16+4 ++^b2c51c4daa4ef7d57ffeda8f7a5126e5ce4ac70d ++a1ebfffa5be85b4d8561528b1e886d2c1c5f6d56 refs/tags/jdk-11.0.16+5 ++^1c93a6e011588ef3c491768d156552681f2480c4 ++bc9b351bdb7feb334c99a25b67ae904c42e5d049 refs/tags/jdk-11.0.16+6 ++^e996d6fe056e9dfce6928c6ab950421125da7234 ++587dfe71e8b9ace69b8dadd73ab15f76ca03ad77 refs/tags/jdk-11.0.16+7 ++^1dd942d3541431b21403f39b4cc5943271b59801 ++42b031224503fa2a3273ba5b40eaf44b4c93892a refs/tags/jdk-11.0.16+8 ++^edd32ef60b3e3c5002505c4fcf88d6c81e94d355 ++0d319233d6d7ce7b1db2a731d04856ef483ad21e refs/tags/jdk-11.0.16-ga ++^edd32ef60b3e3c5002505c4fcf88d6c81e94d355 ++45dd557a71dfee8f0bd7511cbbcc366fca0b228a refs/tags/jdk-11.0.16.1+0 ++^edd32ef60b3e3c5002505c4fcf88d6c81e94d355 ++41d25ed6184669db2078f07b7bf47e3227a1d875 refs/tags/jdk-11.0.16.1+1 ++^63e4b5c8acdb678f17541b755205e0e4feb5809c ++44781661ad2ee87c9530c6ebb35341c58c3153cb refs/tags/jdk-11.0.16.1-ga ++^63e4b5c8acdb678f17541b755205e0e4feb5809c ++9321ffcfe6a3f52fa60bd8b9513478a062f97228 refs/tags/jdk-11.0.17+0 ++^c95c7967bbd1004f23250f8898c7246420da9e83 ++639854c039d9f4a6517309ebb2f4a1993e3bd868 refs/tags/jdk-11.0.17+1 ++^954d57ae503e5e25c263d662a8e2eba978bd62b2 ++9c764ee8e3c9f537555291f1cfa92f5dd9391ecf refs/tags/jdk-11.0.17+2 ++^74daa996b5212deddc19c806b07f7f1f924ce1e6 ++c00d64392f7c114238c8224797411544e9563593 refs/tags/jdk-11.0.17+3 ++^faf1f86f95117a5e2a0d52b67647dee893311545 ++b8dd6246b4f9a76f97c74b4547f2120f290317b4 refs/tags/jdk-11.0.17+4 ++^75e4cb38910948634b816e4f4db36b8525d232c8 ++c2fa5381f85ae96b27bf3afeed951ae0fa4d469f refs/tags/jdk-11.0.17+5 ++^2f0f34ce4cbe0f51a1bcc3145eb4d7ade9287d5d ++2381c5296e338651df9e1e5c697c106216b91bf6 refs/tags/jdk-11.0.17+6 ++^e9ba915905afa1535e288802765f59b52538f73c ++cd0903bbaa009bfc754387fa22d6e7dc5a0b3cdf refs/tags/jdk-11.0.17+7 ++^2f695bbaad2620507e8427610ae988332aaa001c ++dfff50cd8b05ce21d5336661ee872a447a2ede21 refs/tags/jdk-11.0.17+8 ++^69ce82b96fceb82c0363d0b33b977111685d516a ++6b20f91bb4b6c0954668717e9fa19cfb9271fbab refs/tags/jdk-11.0.17-ga ++^69ce82b96fceb82c0363d0b33b977111685d516a ++21f55dabbfee39a2d11a18957bfd83521e7876da refs/tags/jdk-11.0.18+0 ++^2f0f34ce4cbe0f51a1bcc3145eb4d7ade9287d5d ++3d8071ff6e70fb0343654be81072866433e0a964 refs/tags/jdk-11.0.18+1 ++^b928a88fd564fab88f00086a62c0695ed5cc9353 ++20e9d63200e3710cef3c9acc34c65ab13dbe7d69 refs/tags/jdk-11.0.18+10 ++^50b3039415616831fdd96c36df0a42f00fea60ea ++bc5ef31b239b71b4ebff3c15cb56f870b4460b05 refs/tags/jdk-11.0.18+2 ++^dde20e471dd77528baa922dde484e9ea92c005aa ++eb43415abe09cf87f83c9d1fb1ec0415f0670392 refs/tags/jdk-11.0.18+3 ++^b7b00f7fb4e6509becdfdb28eb1a336a7b07b315 ++4104922da8ee2e4f152a4a2cedd7844d50ab1143 refs/tags/jdk-11.0.18+4 ++^18055b84a4e6d7e9136fd7b02ba68579c4812880 ++a3e1d09d74cfc892b8107d4e77ea44f4dd9bfd89 refs/tags/jdk-11.0.18+5 ++^b5555c191537c27e6b7dcf7ac15c4dfe2967688e ++edd617307203e5a5a68751236a319ba84d86475d refs/tags/jdk-11.0.18+6 ++^87c8450c3e776f6b5ad6c01c5cdc5a157c9e84cb ++5d8bec0625178aaec05635b670cc7acd5033a9ae refs/tags/jdk-11.0.18+7 ++^6400cdc724f5ffeb03dec742494590a301cb3417 ++4508fd618ced1cc82a4ea11ffd5fe3688f83a178 refs/tags/jdk-11.0.18+8 ++^88954e1e812296abb4e876ed1f37cd6458d00c89 ++cc3ce529001e794c48da348224f53765060ec01a refs/tags/jdk-11.0.18+9 ++^445ab521954ba92a0d7435b811bd38ccfccb5b95 ++810b592c7a1937916cb152453b6975f0965249f7 refs/tags/jdk-11.0.18-ga ++^50b3039415616831fdd96c36df0a42f00fea60ea ++f08f2219ee6bbaa86ea04c8625edfab37a7ff93b refs/tags/jdk-11.0.19+0 ++^87c8450c3e776f6b5ad6c01c5cdc5a157c9e84cb ++c1da3cd90afc3fd0be2efb2d399a6fea1112a8b2 refs/tags/jdk-11.0.19+1 ++^ebac392d65ab085369ae1b33cc7601d574778d0f ++72349b136f50f39c5fe2786b4cdf52b0573a0050 refs/tags/jdk-11.0.19+2 ++^c58a06666d93d7c339f9ce3133555083f30ca0e5 ++70994a17c9f494ce95b3be67eded1732c2d0181c refs/tags/jdk-11.0.19+3 ++^bc29f1eb26714ef4a4f1494d9e9cd8aaf9050d7d ++91617c4a47ca15a7d28391eae39ee496bceb86c5 refs/tags/jdk-11.0.19+4 ++^5802a9a92604585d5cb7ff03a26926486a50e1e8 ++5bb720b3eabfbd185fb25ab922a8f97ec217bea9 refs/tags/jdk-11.0.19+5 ++^8a726afcdf653bf3fe7ba6ed3419732edf625b11 ++e7a966b63a7fa494aee1b2af6bb9339cddcc39d2 refs/tags/jdk-11.0.19+6 ++^f1c92b472d03e3387237cc4d7c6401310cf86f19 ++44dfb51221353b4d93609fcb6c77cb737bc92668 refs/tags/jdk-11.0.19+7 ++^2081c00707d17c0445cd119ecc25dffeb604e01c ++fef9fe62c7365e2a501e1f2af6df996a5a05a260 refs/tags/jdk-11.0.19-ga ++^2081c00707d17c0445cd119ecc25dffeb604e01c ++64d889b524895a2a48f0a762a33b15678e77a975 refs/tags/jdk-11.0.2+0 ++^fefb969cddb4769980dad9351055658c1017d338 ++fe44dcec15aa5bc2aef9dcdb79f0f8a14ef9df9b refs/tags/jdk-11.0.2+1 ++^689d90b1594759c5de948c137c4a1e12ed059757 ++3ae8e88c8e4bea77b3b513e82b9c01109004eb45 refs/tags/jdk-11.0.2+2 ++^1d096f0881c1325b0f858dcea6d9db9923c77cb4 ++c5ccc9917a9075f7f45cb437801a97f2006691d6 refs/tags/jdk-11.0.2+3 ++^9e1d019a3528408d51c6c67cf97a03e70ab44455 ++c29b19b38ebdd4333a2d1777c120b155c2cdfc93 refs/tags/jdk-11.0.2+4 ++^eccb56da8f9723925399ac38a7334e108c0816e6 ++0558e81c4ffd15344f4c6d78cc1f8ceeef325870 refs/tags/jdk-11.0.2+5 ++^266d3abf72b24b7b982b7eb4bb2c0400e9ba3cc3 ++d70ed7e671925d937b68cbd15409c5f63762574b refs/tags/jdk-11.0.2+6 ++^3e548af5fcccdba58d618ccb3995b9c4c5997bcd ++57e9759b9da764395bdbd49cc769ce534c32ccbb refs/tags/jdk-11.0.2+7 ++^c8c49303343d9f5a214633d2d6d28e696f14bfaa ++a7347d3ddbc93aa03e657e6b77ccf0915c67dc45 refs/tags/jdk-11.0.2+8 ++^ea817c1f234907116d3bb0e88014ccc649282c07 ++a9d407f07037c762f2ec16002a40a55560d63416 refs/tags/jdk-11.0.2+9 ++^6c39ffc5af5281b3b825ba0c71976de71c80daf7 ++78bb7d47b17d9e80f1952011348c9cb7503a01e9 refs/tags/jdk-11.0.2-ga ++^6c39ffc5af5281b3b825ba0c71976de71c80daf7 ++80238cd0083bdedf49a8f6240a8f45a36c94de35 refs/tags/jdk-11.0.20+0 ++^8a726afcdf653bf3fe7ba6ed3419732edf625b11 ++262387b87ad29eb5a3a60c295563901449474398 refs/tags/jdk-11.0.20+1 ++^fc85d952d946ce0a8445a6c516538cfdfdcbe8b5 ++3868087ffd5180ff8a2952368327dde73e7aa446 refs/tags/jdk-11.0.20+2 ++^1f601e90a587af2ea941e520ac9cf7ad3a119144 ++d3f60fbe3b741bea060b3127a7364922856f8b76 refs/tags/jdk-11.0.20+3 ++^31396660db3eae3977bbbf8b978b581dfd941d2d ++99f2dbaa8f433835b6d218f29b81f13daadc1e98 refs/tags/jdk-11.0.20+4 ++^589894526da90bc9beb69033ce76d540c4a19501 ++690191f585b281e925bfc8d6d32665c7e15c9fc1 refs/tags/jdk-11.0.20+5 ++^1000b1c0074af4b954c5f210d1684b5623e9723b ++6dfd4cac623ca554bfc21a101243ced2a704d339 refs/tags/jdk-11.0.20+6 ++^0770b1f04fed2d6e59ef15a872b4806f2d4767b9 ++f3355057766ae0021e6e02021f3b87421eb7a243 refs/tags/jdk-11.0.20+7 ++^d286dded5f7714d54fe57b999a5553653d45218b ++63d93c08ae0b63dc9315009e5d46db2d791f5d23 refs/tags/jdk-11.0.20+8 ++^a829804de566fb89ad0fe45d242a09db24a5867c ++82184e00c1fc466ea8b2c9c0ee9a82f60fc393e6 refs/tags/jdk-11.0.20-ga ++^a829804de566fb89ad0fe45d242a09db24a5867c ++8edcf8a624a2c209b9e7bc943fdb9fc875a80b6b refs/tags/jdk-11.0.20.1+0 ++^a829804de566fb89ad0fe45d242a09db24a5867c ++38c6f342fdeb24ec52eca64e5c919bfcd9916bbe refs/tags/jdk-11.0.20.1+1 ++^fffaff3d5e823187acbf7783339ee3df77580a00 ++c0c10517976cf53bf1c84314cdc418c9112fc68f refs/tags/jdk-11.0.20.1-ga ++^fffaff3d5e823187acbf7783339ee3df77580a00 ++addd42bb5035d66703d7f31f1d1101f7ef298dd8 refs/tags/jdk-11.0.21+0 ++^1000b1c0074af4b954c5f210d1684b5623e9723b ++f1a51286c362e568e1c964cc9ecbcbbd81c2a6ff refs/tags/jdk-11.0.21+1 ++^adc74777b3790486adc2cd03fd0a154095e95cf4 ++377d596c50f202d30a5a42b21e05d12a29cde016 refs/tags/jdk-11.0.21+2 ++^d24c7dff21a2adfc4c3275362040d40f3aa0fc8a ++1580b085d10bfcc42f545c4b8fe6e7d4673ba7a6 refs/tags/jdk-11.0.21+3 ++^9eadce369ea69e9d15f66f4f16b1bddbedd0040f ++c0b801f132903af4a1de30feaec0ced01bff4944 refs/tags/jdk-11.0.21+4 ++^d0f6931ab7f9e3ad30365abfa862958820035ee3 ++330cfbb9ceaf646c2fc696c3e5e11817bc0b5d9f refs/tags/jdk-11.0.21+5 ++^749ecd50633cf0286307880e9f58c4cee906a7f1 ++31c14fbe6661507db73efb462b6847f32feb265d refs/tags/jdk-11.0.21+6 ++^d4e7c767444c3a8f26947dcdc4f899dcdadca447 ++875418d6d3dd949f54cf43f00d2ebb031fa4d5ef refs/tags/jdk-11.0.21+7 ++^d4254d5edf1695e17c1a47d9d81e99b61c2161aa ++6e3c2974b244b927691ba5c917c06e3f60f84082 refs/tags/jdk-11.0.21+8 ++^f356adbff93da2627fe2e3c197c24aa7a1f1dbea ++70dd3f2b3cb427acb73d0066c976fe035080960b refs/tags/jdk-11.0.21+9 ++^a046767fe01a2d02ec81dcba2bd0a43e435dc709 ++04991936508f460ca35db74b750e63509ef5dfe5 refs/tags/jdk-11.0.21-ga ++^a046767fe01a2d02ec81dcba2bd0a43e435dc709 ++04b30949a4fc5773b8dbcbae330457e1c6aff878 refs/tags/jdk-11.0.22+0 ++^749ecd50633cf0286307880e9f58c4cee906a7f1 ++50bfcff6c521034ddfd533afa29a59925af337d3 refs/tags/jdk-11.0.22+1 ++^32e63eb87f063e796e92cb0e1a8cbc0594800949 ++afb10257704e1a3e4bf14b3153defade145e8eaa refs/tags/jdk-11.0.22+2 ++^75daf18555e213b4f72e7ce98fea686a08ae1940 ++1471ed22381e4d0879d8623b633618f0fdb44bc9 refs/tags/jdk-11.0.22+3 ++^5a7b227193a4b71697675611031781156ae30f72 ++3db3018f636b388dbd453a00a25da324de039d4a refs/tags/jdk-11.0.22+4 ++^f2488a31e002af3e0a7a866c91cbdd28be2d9a1f ++211eece33af09aed2f77543915f60b9ad9b1da45 refs/tags/jdk-11.0.22+5 ++^be01e6e792dea3da59f3c6b5f14882f678dcc1ce ++da9cbb6a05bf9c4ebf619af063231aca493552b4 refs/tags/jdk-11.0.22+6 ++^09b402a6bcecce976ee17ce358b0a90ea127ab69 ++d0031141c1756415d648630315c422b4c4827b0d refs/tags/jdk-11.0.22+7 ++^6739881b2fa7e8e8c05198bc7d5d4834638bd7d1 ++b59127e0aa2c8daea5f9e26b11aa3179d9fa52fc refs/tags/jdk-11.0.22-ga ++^6739881b2fa7e8e8c05198bc7d5d4834638bd7d1 ++4e5441f73033360513daa9a6d754e2da3eacfdf5 refs/tags/jdk-11.0.23+0 ++^be01e6e792dea3da59f3c6b5f14882f678dcc1ce ++0d0d682f87ee4eecd6cda10cdd8a43dc00fcc4ce refs/tags/jdk-11.0.23+1 ++^4fe0b836be216eb6b8a1316cbbfaba2286165846 ++6aef66ba19590cef2bce6e8806d6d4e3eb81c02d refs/tags/jdk-11.0.23+2 ++^54d1857208c45128bec2f2450d442d0e04d24dca ++2330cfe6367f03ebd1edf1794b051873c47130c2 refs/tags/jdk-11.0.23+3 ++^a60fb5a71d82faae6e6d7e6364d421fb181f2077 ++a51c812808ba26127f5883980f5bd7695f093843 refs/tags/jdk-11.0.23+4 ++^de3ae6f26507f0ed8a7af00ad93fdf78da77dad2 ++81e343b525e3fcbad48ae7eef47307b3ac120dde refs/tags/jdk-11.0.23+5 ++^1bb3ed339b50b7cc60279bb51c36d8e449453d4e ++b33a2487ed9eaff6164611fe1c73414a7afab584 refs/tags/jdk-11.0.23+6 ++^5c5687d4abde9180556db67c8a21f865dbebf7e7 ++b56b8f82292191b64fe78feb09b455171267e79e refs/tags/jdk-11.0.23+7 ++^bd29eb6eec88a088703582318f790dff2432b7b7 ++9d0b91bfa975ef8f73aadfa31a66fa8ee540f8c1 refs/tags/jdk-11.0.23+8 ++^4597cc3525dfb7cbceb268c4263542aee4c75d0b ++eeb1035e6f33c8726950455dcd022a5bf93217ac refs/tags/jdk-11.0.23+9 ++^7a356988b167292b90af5a2b8586c06351519215 ++1be3440ab5ce42c637ad6e6ae2309acc345f634b refs/tags/jdk-11.0.23-ga ++^7a356988b167292b90af5a2b8586c06351519215 ++6349b7750a3ba3aed99dc6dd92488e8d9fdf9661 refs/tags/jdk-11.0.24+0 ++^1bb3ed339b50b7cc60279bb51c36d8e449453d4e ++7259cf99ea74951dc3d509a2fa323a4d4916d5b4 refs/tags/jdk-11.0.24+1 ++^cabaf7482681fb17cb7722377da6baab0ed2fed3 ++44fdd8e4324dd6f1a403f944a9666c46f68e3449 refs/tags/jdk-11.0.24+2 ++^c542dc913a765e9f7ab3ab47d51d5633f8716b9b ++a3a1bb944696cbeeeefd9db488fd98b24f162a74 refs/tags/jdk-11.0.24+3 ++^42f70422f10472aa67ca86bfbac25a5d5c314ec2 ++13604a7c42e865d2044b303486302e6a9fa1cb16 refs/tags/jdk-11.0.24+4 ++^1d6965fd4eba8c22589f1833e3a1639f05ada771 ++5c4cd08b0f0fe6448f4a4655178ed8dbe418cae0 refs/tags/jdk-11.0.24+5 ++^47fd86ca1c51280629b9f2b86b659c91ffeee22a ++bea029ee83447faf5b5b4193f9bed2041126cd43 refs/tags/jdk-11.0.24+6 ++^d3bd5ae28a200b0bb0fcebcd2d29c3c15d260de0 ++18efece47f692e87b42278fe7a2354fe5c4f549e refs/tags/jdk-11.0.24+7 ++^1e3e6877d5c2eb53f9dbb4fc9e045d83975c84b1 ++1d054705b0c83c2f55915f571c07eec1a58007c6 refs/tags/jdk-11.0.24+8 ++^ff537af466ee74e914c5cee1042de650bfe0da5f ++02e5fea2354c2ecbcf483d5da9ca3aee3fe7e605 refs/tags/jdk-11.0.24-ga ++^ff537af466ee74e914c5cee1042de650bfe0da5f ++381c3a780a3ddec24198977e82058654b738a5a6 refs/tags/jdk-11.0.25+0 ++^47fd86ca1c51280629b9f2b86b659c91ffeee22a ++b6dd0944deba8cac3bfee32184871e8913c70a7a refs/tags/jdk-11.0.25+1 ++^95c0b97bc2bfcb686dfabc6d74424772f0f866a1 ++194e0e6655db16cd1c705fab5c224c556ad0f158 refs/tags/jdk-11.0.25+2 ++^3acdebea8539c12a7a6c6503976e8f74859d2264 ++21383364ff8a935a23b66c5729fd759c0cd77210 refs/tags/jdk-11.0.25+3 ++^f7217d7595da114f197ed8d9c78fbba453f875bb ++e59742f342adf2754faf203d1c8031a7d2083e16 refs/tags/jdk-11.0.25+4 ++^cd9e6cb584bfeb232bcea7a642664cb6dd4424f3 ++9ca0aa9dccf7b474f498e4f90dbbf5acd582a7db refs/tags/jdk-11.0.25+5 ++^a83d9303d5d1f7f3415436e145ea414b2680f783 ++21b0ac8c1af9e672daac2cc9f0b7a5224ea63dd0 refs/tags/jdk-11.0.25+6 ++^90ad5b18de314faca19e322bb21a4c33cec54785 ++1cad49dc5ec627b770e4350f62a30328650f83cd refs/tags/jdk-11.0.25+7 ++^0358cbd0a1538937612e3a78ffbfb64d7f4c45a2 ++ee9d518ea1e01abdea3c9edaf78b171cfda8099f refs/tags/jdk-11.0.25+8 ++^82c330b46498e78c67c1905535106c97536e4914 ++b180b2aa4e29a4ed54af6180e345faa10f58c579 refs/tags/jdk-11.0.25+9 ++^cee8535a9d3de8558b4b5028d68e397e508bef71 ++8f3f4ff6800f0859364095bceeb4c0557202d429 refs/tags/jdk-11.0.25-ga ++^cee8535a9d3de8558b4b5028d68e397e508bef71 ++9bf252fa665603a6055b51a2092d3afa4631d31f refs/tags/jdk-11.0.26+0 ++^a83d9303d5d1f7f3415436e145ea414b2680f783 ++d2533bb51173c68527d2353c4f850790a63804e7 refs/tags/jdk-11.0.26+1 ++^827528c3228705496813887f92f964310b010464 ++13b0056ab9425c7677b538d8d9a780bd11863ef0 refs/tags/jdk-11.0.26+2 ++^c99638d35c8aea16eae244d26bc4ab8dcb080788 ++7040999d12612fa82e4838bb2d16ac44df56a443 refs/tags/jdk-11.0.26+3 ++^1c80800a26fee6b1760b63bcfae672e232c639f7 ++60d864d30957ee3b422a4ee4c79eb70186e57b6b refs/tags/jdk-11.0.26+4 ++^4adb4598c3c6c51a716889ebb3a1c97669a725ef ++d74d4d4819a2a02a26a54eed680a56f6103b1428 refs/tags/jdk-11.0.26-ga ++^4adb4598c3c6c51a716889ebb3a1c97669a725ef ++b2a7765c49423b34497de86211724a1043597959 refs/tags/jdk-11.0.27+0 ++^1c80800a26fee6b1760b63bcfae672e232c639f7 ++bbce2ddaddd0af0fac207b9aa337390e39b41ad2 refs/tags/jdk-11.0.27+1 ++^33d19c4b29fa43ab7bf7feca5f35ee5ddaf5b987 ++2c95c3d9825649b6a119a76f30e3af167bf67f5d refs/tags/jdk-11.0.27+2 ++^8322c66efa9da9210eca7d6081d2a8c2d65ba4e0 ++7f56f70249704b953ff76d02781fb265dfd611dc refs/tags/jdk-11.0.27+3 ++^86dddbcda62626382d97c596f2edf777757dbe98 ++4855371b2ed3ff9bed849e056ac975726f627d81 refs/tags/jdk-11.0.27+4 ++^659a4669208645420e151e78ab5fd3ac3808b310 ++50f47700fe069d211db57a668fed8d64c2ecc4f5 refs/tags/jdk-11.0.3+0 ++^7630a17a0e0d9c92becb534c660f59e74fbbf9fb ++c6ba4fa7e9c2969fa50518f62c726192c1ac4ed7 refs/tags/jdk-11.0.3+1 ++^fb7b3bd6096fb38c6688e6a9263755991aad0f00 ++6fcb3b2693c79ef4aefe79f1614b97a9d6483d09 refs/tags/jdk-11.0.3+2 ++^5783d96313319d196abdc0927ea7760bfce20605 ++9e93a58b7739249eecc2cc9b2039ad6088637fa8 refs/tags/jdk-11.0.3+3 ++^19a1861dc6a03083ec0880a91ee591e1095587db ++240dccb90b3e23a0371bbccb6d779c1faba4f1d0 refs/tags/jdk-11.0.3+4 ++^816ea1d566827c6054306ea542a49cadd40772d3 ++86cdba23d5b1b0f2b2afe2c3f7b9d2597a5e67b7 refs/tags/jdk-11.0.3+5 ++^cd90905c5225d7e11666426438d6d07aaf50e731 ++510801b93083bc3f3c9207f9fa4a0c8767fa7287 refs/tags/jdk-11.0.3+6 ++^e621883a9f6806ee5f4a61e08ceff13e58d9b484 ++9e8332a9ca094dc515536228b06cf1e0d2f991eb refs/tags/jdk-11.0.3+7 ++^77f86fc3a4cab6e8f5a6defe8dd28bc44ff14077 ++f22ea1dae8c3292539f48894719d78e3e93f1f78 refs/tags/jdk-11.0.3-ga ++^77f86fc3a4cab6e8f5a6defe8dd28bc44ff14077 ++94028e8e1abf0767990c9dd9f5a0827a5240a70d refs/tags/jdk-11.0.4+0 ++^fb7b3bd6096fb38c6688e6a9263755991aad0f00 ++36f3a847be5a3441b3df26c2fc304ea60c294b96 refs/tags/jdk-11.0.4+1 ++^17f235dc46929e1dd3a8ebe3b4a00c058f20dd76 ++90a586e783a5f5ee15f24b4ea8f45b6b6106db6a refs/tags/jdk-11.0.4+10 ++^a1a7d699f44a4ba7dc1f23752abff7168cbae11d ++592b640d7e0e8b1432d8eef850f297c7a8a46306 refs/tags/jdk-11.0.4+11 ++^1350471e73792a64144e6e48a4e091f0f4e0de5c ++72123ff4cf3d9d516cb6eb30ae8595657420a0dc refs/tags/jdk-11.0.4+2 ++^0d45b5ac487f887f68a52cdc986fea5c09f07b32 ++215f6550955ccc37c833aac5230d1cf8f670ec9b refs/tags/jdk-11.0.4+3 ++^d67c7591d2fdbfb8b6762335719c0e099d51aa3d ++6416fae4db811f4671557882b4e2a0961b1311aa refs/tags/jdk-11.0.4+4 ++^bcd825a03c1fc437f32b54786dc854978dc455c8 ++803e7bc5b6ce647bdb14475774d6dd6562eb562a refs/tags/jdk-11.0.4+5 ++^049699c2bb7c286108b5cad6ca84f025fa880953 ++35d2c8bfb3a96f0931f7374206aa8ad5449c76c4 refs/tags/jdk-11.0.4+6 ++^fbf6a72ee26d0255dcdec7ca7b334f8f56334d22 ++7491fda97a365caea2cb18394f7bb4925c9e6215 refs/tags/jdk-11.0.4+7 ++^eb894e22233a26111c096a7833f23fd7b1f7630f ++49b8b1027dd195554a584655e7f1aa39ef49ab6d refs/tags/jdk-11.0.4+8 ++^44e9108a26a67004aea6a2c978f8e7cdbf7455e7 ++093baaebd297e51be2b37861b2f56907bab3c094 refs/tags/jdk-11.0.4+9 ++^30a7af9f2153ef355b8a0c46e64f58bb811aab96 ++a5cfea11de38a19f3ba9e06c4c8d160efd0451e7 refs/tags/jdk-11.0.4-ga ++^1350471e73792a64144e6e48a4e091f0f4e0de5c ++638bc30720c64b3d6a4c709697a6715deef743aa refs/tags/jdk-11.0.5+0 ++^8248f03e14b8f65ce77cb192389dcad44f387796 ++544aa5d3e2e02009f61e64b073c3c6bed8276788 refs/tags/jdk-11.0.5+1 ++^78e47c6fffa26cda0ea6044342d98d423bd2a6ff ++90b82ba093d280979fff6e2be6b82b23a8c58bba refs/tags/jdk-11.0.5+10 ++^80853189eb68f13cc52ae6106871186c9fbdc384 ++aa43a8c0700a7c07dc03e22ae034f0387519fbdf refs/tags/jdk-11.0.5+2 ++^f08fce0ce27d9395720a57d7423f3b728aa53515 ++6aa631db401ec8a932ff79c81e357b10459bf1b9 refs/tags/jdk-11.0.5+3 ++^c0456d8982f1be7491d70549dda2ff9350b0c38b ++ab378ed5dab8605d33513f908b2f5b89bb83d4ad refs/tags/jdk-11.0.5+4 ++^95e5e3bd6a314286c665db74c9cdb2e05dc9f83c ++7ec4279bded404b003859e77e5ec719fe24551e3 refs/tags/jdk-11.0.5+5 ++^e0a13da4738cc23883ec85947d4f57cdaffd6c50 ++243d22019f8eed04ad8bf2749d537a9338bb503c refs/tags/jdk-11.0.5+6 ++^54486569a80fbb905cd7b4151152ae8bd729b655 ++76e874d0ec889349e4557ef0d06e6fcc4d8f0bc5 refs/tags/jdk-11.0.5+7 ++^61cf67c4825d5b6cac51041b7f032acac2024a93 ++bd398c58bdee42a9bb6f010633e4c791e04be68a refs/tags/jdk-11.0.5+8 ++^e59dc4fc99af10ba3d2d711f0854d374d2e02de1 ++c76c10830501eb8a033d3f3879917ee56a2d5bfd refs/tags/jdk-11.0.5+9 ++^46ca4f5ac7ad037a412ea5d859cb781c8573fcc4 ++bd59d308ac85667cf4a316f63dbf88b0b46f1bc0 refs/tags/jdk-11.0.5-ga ++^80853189eb68f13cc52ae6106871186c9fbdc384 ++b52c747eb06a3304bd4b7a074de4bf4284d3ec6d refs/tags/jdk-11.0.6+0 ++^fa719f44d0c9003315e7ce067f9f02e58b5f8dd2 ++bf461e222d9912f3aa073fed8ae29f31bc35dead refs/tags/jdk-11.0.6+1 ++^1434a2dc3244a78b7c6cdfc2085f8d51ae958b28 ++55623c9a77d801130f84668594b5950362ef8c86 refs/tags/jdk-11.0.6+10 ++^f957822b4172adf4f3d08431622bcfefecb864a3 ++6baad10e963b070bd3c78cce681fa1ab418381f5 refs/tags/jdk-11.0.6+2 ++^7522d270ed4f9e1bfb621ac83cc582b6fb9a7347 ++5e21b0253275d2fcbbb3ea6b19088e14c3f3d776 refs/tags/jdk-11.0.6+3 ++^be95351ac41a323bb46e1929d4127106af727b54 ++95fe98e9758a63a86c3681e37f1166d952bad2a8 refs/tags/jdk-11.0.6+4 ++^c700badecd650bc48c0b42f0184c9086cc06651a ++f5f9980b14d3e89fd2cc4259debd146091045f19 refs/tags/jdk-11.0.6+5 ++^ad979fb4c93addf54ae72df7bfe6d0c16c8fb490 ++04a3e17bde8a0f2fdfa9c05f4364671abfed0e28 refs/tags/jdk-11.0.6+6 ++^05ec1f91870a6e3040166cf25baa2fe1b3c80dd1 ++88009d55ad721f1b5be8b7c05072ae2094152ef0 refs/tags/jdk-11.0.6+7 ++^9209d841518f22db2420a4dfcb82be1bb04aaa0c ++b442eff6dadac5ec61be19bdf6858d70abfd7339 refs/tags/jdk-11.0.6+8 ++^b0763c13c97045fef272fd1a5fd3781356878b42 ++e9c7a92617745ae842116e8364daea3cf6788df3 refs/tags/jdk-11.0.6+9 ++^f99ab952b83cb522b1a6398802e61cae7c0f80e0 ++2353f2e6c8fa406a9c4386c20a564ec021043f28 refs/tags/jdk-11.0.6-ga ++^f957822b4172adf4f3d08431622bcfefecb864a3 ++e806fa8d9cfcfbe34ab38b67b1e64d45153dc5b0 refs/tags/jdk-11.0.7+0 ++^63d06c701972535d2cd0029f05e232b38d150269 ++9efb9f200ef921ada4198be2fd29f3ab3b962ec3 refs/tags/jdk-11.0.7+1 ++^6f4c9a6f552123ae41e9ec3cdf5c689f082cc580 ++ecbed753d97b7a065e74bddbfee47f4c806a3c0d refs/tags/jdk-11.0.7+10 ++^f5b96177df89e36a6c281dffebd08688cfeea02b ++1959070ba228ab49ed7a73117e2ac0658a77a052 refs/tags/jdk-11.0.7+2 ++^d9347d249898a3e98769938fc82cdf2aadbd6da2 ++d08082d59d17f290b8b7795c78266b89399bfdc8 refs/tags/jdk-11.0.7+3 ++^45c5153fd3df2f0c5b6fad14de1d3ceb339ce623 ++6fc0f167202d960d4673e745e515453864d51a45 refs/tags/jdk-11.0.7+4 ++^8c3d56cbdd190c32651feef0744673bc923d011b ++9a602ccd45be7e7151dc426bdccbd532debb86dc refs/tags/jdk-11.0.7+5 ++^ac1ff2bdc959e32c7a9e9aa9d17fc92d623ee758 ++688afae9cfa607ba6eead143a46b2fae3ec885c6 refs/tags/jdk-11.0.7+6 ++^9906f8b167aec8e1cfa3dba1b239191cea9dad96 ++4c1b1d0e258aa27b0c7a4430c0ededff4aca6eda refs/tags/jdk-11.0.7+7 ++^b478b9823896a3991f185c12d1a69929922213a9 ++6d64430f01bfaed29b8587e8a713fa166e61040b refs/tags/jdk-11.0.7+8 ++^11f10539f5b55b8d768b5cf8b703d3da3d0e268e ++4e0c72776ceefc81a48aace55015bade6b0208b1 refs/tags/jdk-11.0.7+9 ++^e566dca620c43d56798770b41cd0d25a63a71b82 ++2bf7b8eb7338e1497c11a0941ccce0530643faaa refs/tags/jdk-11.0.7-ga ++^f5b96177df89e36a6c281dffebd08688cfeea02b ++763517029f6c9fc62bdba11dd5960ed08e881a16 refs/tags/jdk-11.0.8+0 ++^563901c0a3642211b727e93ea72b1a12d625ccad ++80726fc07cafb892bbd3a4ef81fcdfa9341b8e72 refs/tags/jdk-11.0.8+1 ++^afd7b286d368a7fbad85a4f72352a0b7dfb1bd6a ++bf627d6544cd32f6fd41896086313df81324fe62 refs/tags/jdk-11.0.8+10 ++^871fe6e553f9b35f348240eaa5faab39b5de4c1b ++cfbc403e64de62af664b8df790da355f3fc0584a refs/tags/jdk-11.0.8+2 ++^455ee586bcefa8b77a1e7b9d203fa36a05e2fd29 ++3a09a8258f8ead55389afea47b64511d0a7e766b refs/tags/jdk-11.0.8+3 ++^5fd381700fb818cf55227987f302d7174e73e4f4 ++683a700110d8c77a9eea798785a3720d161a0196 refs/tags/jdk-11.0.8+4 ++^dfac805c9295f0b803ba2361af40ba7577412da9 ++22333acfad242f781053e5a30f485f0494c2fa17 refs/tags/jdk-11.0.8+5 ++^34ab95d52027a2d62442e6ee7a360e83e785cf03 ++844c7012f8a05d2038f5419a01dfb67d08516493 refs/tags/jdk-11.0.8+6 ++^5ed0a895b1a5da2735bbde194beb62048f383204 ++743ff7aa9967c0fb6cafff53a56f3e89b814b557 refs/tags/jdk-11.0.8+7 ++^6d36251c9550223ed7631ae84006dbed9d8d13a8 ++18f7e364df3763f553a1c5995ddb2cc9d2a0195c refs/tags/jdk-11.0.8+8 ++^9da659373018a5098417e30f90ddb0333e7d33e0 ++8c85d4b8ea24ec4d91e341d4fc4e920dbe4d97df refs/tags/jdk-11.0.8+9 ++^9c2500cdcffe7442da78ecee53037ae154dffaff ++c5f564392052eb8f5973c56a7db919e3fd33d1ed refs/tags/jdk-11.0.8-ga ++^871fe6e553f9b35f348240eaa5faab39b5de4c1b ++6d36a6c696a6b06fc9952ced5a20d18ebbc90b20 refs/tags/jdk-11.0.9+0 ++^e7da987e5ce74c5e2e643542898ebd06195ff735 ++076f6ce81df4c23a9ce5947c3bf69cbbb50234e9 refs/tags/jdk-11.0.9+1 ++^3977b0b374692f0e23fa026a7d9bd610f3fcfddd ++ffcb36fb814c519dcaa75daae9a236683dfab3fc refs/tags/jdk-11.0.9+10 ++^b28b1350395c6167ab9c6aca32834e7d7e3b8bb6 ++61e99f1a2080eb5b7449b6175e7e5e4f5d2d251c refs/tags/jdk-11.0.9+11 ++^5a14b40edfdb5c936bef94c1ff934d6e063e99ef ++0f1ecc8630871da6f4795f0d54270dbe90e687c3 refs/tags/jdk-11.0.9+2 ++^e2230dc5e6f5aafccb5b8962c168a3ff4b1421e1 ++2e932dfd0d9961aae139876c7df52f090ac150bc refs/tags/jdk-11.0.9+3 ++^5d872cf832589bbbd65eebc42d0465612d8aa86b ++d781a0d876fe58e6b0919f2939447ff2503fdcbf refs/tags/jdk-11.0.9+4 ++^453c86e63c0ff97ec17f5d5c4d71ff66bc8f91f7 ++0341a0510b20fb144f284e386b939bd34819d62f refs/tags/jdk-11.0.9+5 ++^2702e387845b4003ca51bcc5a277ef0bf3945508 ++b2baeadbb75916e4f8e5c6cc94ca65ef26a13923 refs/tags/jdk-11.0.9+6 ++^3819204b0e40041358861c49e65e6ecfe40245bb ++ec53d32baf8eec0df205ba42800642c1be0bc09e refs/tags/jdk-11.0.9+7 ++^bcd0a472544f94c579f3410d08a54376d3fe2e50 ++c143f766a189488c37c420d70e92dde250c13b1c refs/tags/jdk-11.0.9+8 ++^14a1204e4918411e9c4687f0e74f9e2bc7815c75 ++890fa2caae60db6bfed7817cc1bf79e7765a359b refs/tags/jdk-11.0.9+9 ++^2de2721c35940efd1dc848c2993a4ff0f57facd5 ++cd490020acfe6cba1da336c6b476745acf1033c9 refs/tags/jdk-11.0.9-ga ++^5a14b40edfdb5c936bef94c1ff934d6e063e99ef ++17ed0f33cf2ed1cffca2fbae0ca0787e4540f381 refs/tags/jdk-11.0.9.1+0 ++^b3a8b182fb86b6a9a72fc59ab295bf25f4eed114 ++e56eae1955d4e4f279aa79d3d1dc5daa882447b2 refs/tags/jdk-11.0.9.1+1 ++^5e85f038142479c09dc5ca62a1cf8bcb9b851410 ++af94a2167e6e14150bafefad8d376cab9018af6e refs/tags/jdk-11.0.9.1-ga ++^f6ed88f7868437f5a874e340447146fb67a618dc ++9b8db1756bfcff2633049e1f5dd8a8f7c2ed7c9d refs/tags/jdk-12+0 ++^446bbb0f40cdf32f1d979abcc03509898eb724c9 ++1582a7e598bb8b1823a5c386b801dc44a1d25249 refs/tags/jdk-9+100 ++^9fcb6958fa7c54d201a26bb9e8cf2036ecfcbdf9 ++69194310cf0464d81d37d8df03e38fc3d2710579 refs/tags/jdk-9+101 ++^180c59d14700b2b7de2da5814f63f9a3d68cec71 ++6615f036e258e739a2abb71b303790064c4734d3 refs/tags/jdk-9+102 ++^07b44796c2d07bafd552c0bd818752c10efddf5a ++3a3a073a2da66d9e18ed4c4d19b92d09240ab090 refs/tags/jdk-9+103 ++^8521982b8d1b55c0102bf7e28c842e69f485e157 ++4e88fb28c6b1edc8d20e445af39149e3e23d1996 refs/tags/jdk-9+104 ++^7f0667866d1af96322a23f5a73b48cb323384feb ++4ce5077f2b106588dc552715e66ad7023cf1eda8 refs/tags/jdk-9+105 ++^915de61609dccb4b7bda298c61ec7abe3bc26fe5 ++2df2831b8e08b4c1300db067fe80cf3af0ec40bc refs/tags/jdk-9+106 ++^ca3da12f5a90f938ee823db5b757c6f9ac582cc5 ++d0db872057fbf050ac8deaac7cb47a55712f7482 refs/tags/jdk-9+107 ++^886c5498792019d3e3c2024086b03e03acf5927e ++a11e025c63b93c65781f55c53b7313bbf7c92875 refs/tags/jdk-9+108 ++^b1bd20bdd05f116628fc1aca1797848250156997 ++dcc8b52a59746b20736d9105e8e0de09857155df refs/tags/jdk-9+109 ++^7f3c7fe56bac35bf5c78a26351d4c9f72f9115f4 ++8441913a0b27212e660ff451eda2370188ac38ff refs/tags/jdk-9+110 ++^8bf8993801b8a8638273ceaa33d4cb9d0d073ec4 ++88c5f7382d4ce0a11e92a61c4e3d587934ddb881 refs/tags/jdk-9+111 ++^a30c34b58c4dff8a6db6d87aab9392cc0258344d ++778fdbafa31121eb5f1bbcd78b49b9328dd2c7e3 refs/tags/jdk-9+112 ++^1627f81245e18d0c413a8786fdc07f2faa20c09a ++fdd70c9fbdcfc82f251b1160542922bf2cc83d39 refs/tags/jdk-9+113 ++^871832c718f9e5c91134f9b935360cae17075278 ++5937ed8624520c254f9399f2a65ad94094aedf73 refs/tags/jdk-9+114 ++^70dbeeb6df5f9f560e06d0c72084ef3cf4933e6b ++564d309f0d310c084ad2f98f3abf298c979a45af refs/tags/jdk-9+115 ++^4935f9d64d5e493fefbfb27281835b2405160fe6 ++d5b77b3bc0fb4bbc5fe7f30deb061279eb419e4b refs/tags/jdk-9+116 ++^0a3a2c3ebe58c7bd7435a10dcd93f4449d5381fc ++ae90286b9fd00ae17949088dc64f66db08cc98cb refs/tags/jdk-9+117 ++^2a6a1d7c8e8c39c487d6612380155c08d3658b58 ++a521614410de91f55400a6e246c9694fc148cfb3 refs/tags/jdk-9+118 ++^dd927b90d51ff791e3b33ab0970c4fdf718cca22 ++04ba9e69a4f6a09d5f74235ffdfb829d5cb5d998 refs/tags/jdk-9+119 ++^a3cdceaa83b0ef368e4f7063f25952c9fb29362b ++4168d03091702d5ebc553bfa0c8e14b0a54359dc refs/tags/jdk-9+120 ++^fea34ed6344c6298014a1aaeffb233fd23b860ac ++bea448789d1e3bf695d33094adf7e6b39fd5846e refs/tags/jdk-9+121 ++^efa657c1e9942df38db7a41b9bf9913e69d55165 ++0422b80ad16d16ddc1456742b0ae2fbb7cf0df45 refs/tags/jdk-9+122 ++^ef681fc8dc1591f73fd27508347af96b60ac2468 ++37f7bcd6d1f8324bb153163b5c754794d2526f5a refs/tags/jdk-9+123 ++^e620ceaad835e7fdeb96c0a28b74a59fa5ed2407 ++1e848753437d25fdd0590d3ed9b46328313d4a41 refs/tags/jdk-9+124 ++^491d8743c3c86ab46acaff5ead86e243fae478a1 ++53a00f16ec6652ea85d7dc381fd38897460f44b0 refs/tags/jdk-9+125 ++^396d6f62855090a7dd2d8e1240ed152722c97d9c ++747f6bedd64e86aada33da154dadf2e57db01902 refs/tags/jdk-9+126 ++^87b56a2dd136f5278164a49e3584216ace5bac0c ++a2c7e6a714ca7b2e5a50787035ff14b3b678d94e refs/tags/jdk-9+127 ++^d50a21bbb31e0a35edc1d2885a29253150fe2508 ++e83a1980e69679b58cbfb906cb48d538300375b5 refs/tags/jdk-9+128 ++^378ab9dd25a7f124150432f8b37663e1e749a1f9 ++67593f151245ee408b03c4f71525ebdc301a61e8 refs/tags/jdk-9+129 ++^85c169d7cb506541f8fdd6fabe5a06a19bbfc154 ++10a78c405152f49db1e8d25ca7b85bfc9d0f4490 refs/tags/jdk-9+130 ++^53adb9034de5170e341850541cb8d0c40d2cf054 ++ae5472b20f020ccc4cbb24c920f9e83a85a335d5 refs/tags/jdk-9+131 ++^bb1bd0254941ecaf95000ffdf0d7e21d7e3170f9 ++2806304c1728c7824844312872529797002e7a83 refs/tags/jdk-9+132 ++^1c1ec9a26e00ca1db8a78bc152434a93c188fc9c ++1ec5b887d12580ad7a8d48618bfc89e7961662cb refs/tags/jdk-9+133 ++^9f1c64a88b6b91afa168f03b0c67d1e7f9ed0955 ++4cc92828a5b6f8a837e70a9de3b294b5b629f249 refs/tags/jdk-9+134 ++^5b5a8a6cc6b5832e823f487940ed16c9687182eb ++64d8ae2a938a71579daf9a5c74e908a1d23784f1 refs/tags/jdk-9+135 ++^e1a6127998ce6318bd8f795d9a866e1c0846332a ++188443a1cf685af954f49129759ab15f1b280ca0 refs/tags/jdk-9+136 ++^7624e7608b2e525ffdd2ae5440aa01a91bdec618 ++babb175caba72b0275c134c4f5d20d6949fb3a4d refs/tags/jdk-9+137 ++^6b4039c28a41579c4a12c22e0e6cd209845c3355 ++111a602803c9ca87f916513bba13caf153c7a48f refs/tags/jdk-9+138 ++^80ec55b53a45310b8203a818f258d1293838eefc ++2c95bd4634f8637edf605b71e0a56d8c7fc7a698 refs/tags/jdk-9+139 ++^07476b2f7ddf533fa1aaf1099bc9b1f615858fdc ++912618bc20d708c9e101dcbc6bbfd5eac518306d refs/tags/jdk-9+140 ++^e91b43837dde750e71c20596b379d00523b33db8 ++413af7e621ce90e1cae041f84fc6d88c668c2757 refs/tags/jdk-9+141 ++^5f4ad59aeed79e280c63220cf703249191f07ee4 ++3af5051c95bc68fc3288379b2caab2d74d9f510d refs/tags/jdk-9+142 ++^7b77bd9dcfd79e99d3268b28e1f9c7899fa42bc9 ++18cd9deffb9334c6d4de4170d3466c7e171e4cc1 refs/tags/jdk-9+143 ++^0032be065804fcfe1b90344a7194ce743926220f ++0ca5855de1e081c5d05cdca36193d1ace0851f7d refs/tags/jdk-9+144 ++^12bd5afb7c112e9e49c07ceae65e0e28b2e36c7d ++fed65b0cb6e5152c7e6825f2b568db7756412ac9 refs/tags/jdk-9+145 ++^32f54b25b586fe52dbedbacf009986e927816165 ++4264d788f4f06589935c791af4d832285ead63fe refs/tags/jdk-9+146 ++^39abaf7f457e8f574127f3f453713bd01b0ffdde ++693f974b82632f0c8f8f7f53c336415c15e395a4 refs/tags/jdk-9+147 ++^d8f3239b538a11c57c586fb1223682bef4c4e4b6 ++bb94041006a84518c84fc4ab19a56af7a51fd4c1 refs/tags/jdk-9+148 ++^bd93de680820ec80120e7a6644001e5a2a8f61e7 ++9aa750b64d540d41c089c3aa5869d6ac46f06f1d refs/tags/jdk-9+149 ++^0870c6c734c2eea0f2f5aba92dc46dcbba94524c ++c041586d1ec6f3e1ca4a0cee726578ec1f7477cf refs/tags/jdk-9+150 ++^b5f2c3aaacc58c46de9a8f1006b8b3d0e4e4e11a ++0e1605d316a81f856fe74d8b15d41f2a767de401 refs/tags/jdk-9+151 ++^f8ccef19828841d55e476590e6c8510b83afecf1 ++7ac6cd64a404e4a06d2e14f8e6094f3ee6111957 refs/tags/jdk-9+152 ++^6182483d5339ab7aadaae8e1dc5d36a7427fab76 ++16eb94ef61f32bd96e5828526797fa5459823ead refs/tags/jdk-9+153 ++^18dda40b2b79bb1133d8b7c4b82e60d13d8a5347 ++b3015bc86a57a81627bc1cab6ffe6fffd483d071 refs/tags/jdk-9+154 ++^7eb3a2d4cb1fba528c85aa4ffd15f52cfc873e41 ++530f37b6fc04de413e3565757bb0f8e548c9b56e refs/tags/jdk-9+155 ++^b659f6d8f4dec3c2fa299b47c52a34ed1b1fb2e1 ++8bd9152968ef49b41449cd6c87cb89c5202f592b refs/tags/jdk-9+156 ++^a57ec3df7324e8b0fc5c9b4f92d215c4ab65da9a ++38701507135dab7863d04fad29623127ec5da86a refs/tags/jdk-9+157 ++^47ba458f7e831599461f6383b4067b8713d1b666 ++ffd4fd05b24e852a41a43b73a94fec69a51e0ee6 refs/tags/jdk-9+158 ++^034b02e7cc590a56147108fb33f58ed3285bcd4c ++737886208796fa017c65227afb2c813cb482f855 refs/tags/jdk-9+159 ++^7632a6cb432c0bb51771f4c38d428cccaddc6a12 ++85d94b54b00fece2270d6f3c1895b3c0b86a6183 refs/tags/jdk-9+160 ++^d9a76ca99ea60b4cd23dad97dc81dfaaa67f8510 ++a959851fb040363b5a9dcac447855e0faeec2d6f refs/tags/jdk-9+161 ++^75718cd3ca8c8840b575442029ac83292913bda3 ++90b7d6d9a9001be7fdc373418142dab2edad0e1d refs/tags/jdk-9+162 ++^5ea6cb3b797e2a46cc5812a1c861cfa360b452c3 ++0a91adbea47ca754983393773365fb54fee7f64b refs/tags/jdk-9+163 ++^f4eae10ee81d005f55269a3a9b9bf76437174cfc ++ba5c8c289bb8f61a8e2e54b02c3c2cd39e28a0f2 refs/tags/jdk-9+164 ++^4ffdaed29fb6a2b904351a92987b1dfbca3738fd ++c6b7ae611e14d1f128f21a786abf647b9ed0b031 refs/tags/jdk-9+165 ++^17fa368265c012249b5d6e8af758e52610a35beb ++816e9b4320a4a4960cda934bfd8e32419f3962d4 refs/tags/jdk-9+166 ++^6559850c817fefc617cd26e0a8db36596824eb23 ++77acf91b9276326379331f8c50656e7d9def7705 refs/tags/jdk-9+167 ++^47ea0d5a0fbe41be37cc4eb16c539232562edcf9 ++080713b05a306ba7d7ec0ed8c0bf4c019edd45a9 refs/tags/jdk-9+168 ++^a24d2b46ba0cfe5749c0e38f0a5754ab6cbc7a15 ++a6185f03faadf4b8a5c399009fa4eb198a230932 refs/tags/jdk-9+169 ++^5500fb31ab0cf748daec2171c7b8230518dcaa33 ++aae92d1b795fd5f29dd2702e44fb1a977282ac74 refs/tags/jdk-9+170 ++^8a15f0667e96839ded55dc2ccd0d62b97c9264e9 ++24d55cb33ed010cfc6ec77151f33cb90798c21fc refs/tags/jdk-9+171 ++^b71a161b2cb8ae9b6578e5ea1f9ed41d98c0d4d8 ++cb5d4c752c294b4a6079d01b055a811f4b833cc9 refs/tags/jdk-9+172 ++^902b559c9ae5269bd7d4f031bf5dccab4433630e ++4972c343422f0066c3b567944ec56c55ffa2ed24 refs/tags/jdk-9+173 ++^022478636a6b5f9cf312c3792d375d807b498385 ++0e9dd1bf210351e5b025cf5e7d2b4e31590cc9f6 refs/tags/jdk-9+174 ++^0d0f16460065e880fb5eafe688661cc787a17b40 ++492aa438be3c667954f868c9d285103da6cf359e refs/tags/jdk-9+175 ++^3c8e884fcdf7d5f12f2aed167fe7267ee40f1357 ++004c097c61970ff6ba07f5825a8c16a4fdccf286 refs/tags/jdk-9+176 ++^90fcca973f46c597fb5bc0d709fde4465d8ecbba ++f53ce208f9d5e1800d5a6a89544ce82f9b28983c refs/tags/jdk-9+177 ++^b227a46b5ef7f1ba0b49a16b77671aefc5d3cd8b ++04fee7d7e5ae95d6daa7f7ce68523cebd4ecfe71 refs/tags/jdk-9+178 ++^dc8f53651c5a81f06c82b5da6b65ad1967183a93 ++24f571942356bb5c165da89ba1fac94371705c36 refs/tags/jdk-9+179 ++^3d75a204e566738c449347c4b35581638d20c201 ++a51eb972b7ef381d66cc298df7fddd017ce58186 refs/tags/jdk-9+180 ++^ff269607d1d4db44f928a1e2906f6e82714ae716 ++7cf862ce18a1b56b8778f32efdf572b5042dc364 refs/tags/jdk-9+181 ++^801281100cbbec62d41c643ee4d79537a8e8992c ++7dc588ba19877cf6cea996f63a18b5275b99cb70 refs/tags/jdk-9+95 ++^78e63c03e2549e120ac1aa4e62a0f7a40dd2b8c8 ++2562628672da0bcd2849ae6cc3f9f6a6fcd5ea9d refs/tags/jdk-9+96 ++^0d0198d28d62da093cbe9c08d063f5fe65892cec ++ec684ad4426fcd8f5f63a6077d536a6d28e8df30 refs/tags/jdk-9+97 ++^7e3889ef430d60765dab390a49c81f3592dd2830 ++36cfa7f2cd8b3e46b3e81f181e0dcdc1e8526c29 refs/tags/jdk-9+98 ++^131d46ac9b546cac74e9fa21b3ab428792cb8709 ++ce43713cea0a0416abe43cf6c21cdc49fe61fef9 refs/tags/jdk-9+99 ++^fd85ac4b23211bdd622ff63b6afe3710ff42f49d ++efd610bdd1bfefb5fec3179e39f7b7abec934892 refs/tags/jdk7-b100 ++^adc046b4724af88528a82e304178dffc18959a98 ++41bb883dedc82d6e1382f6a00b7d6db89841e121 refs/tags/jdk7-b101 ++^38378b7ee032d70653b3f0d4205f2305cf4f1170 ++5ef2431d009c48e564c82758de5875e2bb6b2f76 refs/tags/jdk7-b102 ++^7c87c80e687af8a1569a5e6b615cc21afd12e84b ++8f36543686f0d4b3ce977c557e773dd1146391ff refs/tags/jdk7-b103 ++^0861a6d60d82bb436b0f392773d9d325ebe5e77d ++0a4f8c145553187bf1e6061e9ba1e031b9afab17 refs/tags/jdk7-b104 ++^df74e9546287abcac9c1d3995f67c9135be7cb7d ++f2f8b37292929dd4e7ad3f47ba76070f37de67ac refs/tags/jdk7-b105 ++^4862cbc68f15c0a0ab83f3871612aba1b0dcd46b ++8b5873409cdab86ccd1298050ea1aeec446ae8e9 refs/tags/jdk7-b106 ++^b2679e3dc4e7b0167394090b886f2df6d561a6f0 ++669abe597cc4103acddb4eddfa2bc992d9342977 refs/tags/jdk7-b107 ++^2d4322b265b2e3ddccba3d482fcc46b775343518 ++412778b6d52bce6eba3af580b676d69c23b54252 refs/tags/jdk7-b108 ++^ecec377dfb8f513c70d9f9678ea61e4c380c4543 ++ad86a3c1408ddeb26d91408b20cce2babb8b5259 refs/tags/jdk7-b109 ++^a4aa79ba87a370d6f435c643e5f58ef3c9dcc6a6 ++d845d52ae802349532334f5581ee1b5ea46017be refs/tags/jdk7-b110 ++^135c61b9feb66f754e0eb88270fcc045354db16c ++8f37fc875ee7ca2fe32cb50c6e27ae02b319ab32 refs/tags/jdk7-b111 ++^0bd0f10d2c5965369490624627f16a39d35c8734 ++2341024fd83e798d7dd5d597a41e0d65d7c12e97 refs/tags/jdk7-b112 ++^d6ba5ab1f738989994af4b8f3326d989cdd23c05 ++c3a189a0122a37130ca52a2fb9ce29b73841cc36 refs/tags/jdk7-b113 ++^fc0cd82e4607a70972ca6c0b217fe0089315e45e ++2467ae04daa34a624b247f4f47532956cba1d545 refs/tags/jdk7-b114 ++^df7769a808159a5ed011e7507d24d660ff21013a ++66e3caaf9dcb14cf80fc8fdaa0909a2884671539 refs/tags/jdk7-b115 ++^a487e981afa2f83953c84df21a32f68182320c7d ++463eb7cc13b3e154cdd0f869184567f8586db213 refs/tags/jdk7-b116 ++^af4b8efc5b0d192358839bf16365bdbb4ad649f6 ++b151ed6fc037873e33f30cf216674bb0467d29a5 refs/tags/jdk7-b117 ++^44a4e2bc87de4279b33c8101fe58ec60745dc95a ++d76e2efa929bd6c198b0ac2d9cb7ecd2ff4bb9b4 refs/tags/jdk7-b118 ++^8b3d68fe65240da6f4f47125b31246ca946afb6a ++807f8da2bb7dc7f610decf0d160da841ee7b2668 refs/tags/jdk7-b119 ++^e589dbf67e3481b7491baf9325c44a5c8b23901e ++56bdcc494ce423f9e2a706e66a797ec6a7f52a2e refs/tags/jdk7-b120 ++^4ae2fc83cfb5acd53b6bb6d4faa6012a9fe1cfb9 ++22158d77ae4f035958d2c8eac4a13bbaeffc6d24 refs/tags/jdk7-b121 ++^925752098ba63b25c1cb635f50a53684d4094f8b ++f4249f693e6dd25ab445032f8c2e830faecb9561 refs/tags/jdk7-b122 ++^85aab321556e557d298055496d9ed2794f6b6587 ++fd0ed100af641d7eb833aa81205675ad491ff03d refs/tags/jdk7-b123 ++^2632bbc0ac2919d3bff1d5a7455a0af46cf96b26 ++194fd2a8f8b325ef0f49309c707e7786b6775f25 refs/tags/jdk7-b124 ++^d25946a6a9bdd2c36f04677a890d9f3fff9f45c7 ++ace234ed336a79357b7f0616fce264c2a63e2563 refs/tags/jdk7-b125 ++^d4e654d0da7f20b1069abce84c0ffd0c6bcd0449 ++ba82c6acdb0e6d32bd7d53cdcae1246fe4b94302 refs/tags/jdk7-b126 ++^de85b246eb2b6442b6f2997cf82bbc4e3aa4c99d ++bdeb6df49744a1ca55f211fa68a1a60236987cb3 refs/tags/jdk7-b127 ++^3558ae2d03f831ec68ce25f7595d01d1b65086b0 ++956da41d8cffea06ad856dbb730a4704ba518890 refs/tags/jdk7-b128 ++^27982685d0a6cd7546334fe25e84f11013668522 ++51e631d0992715fa9a463e0ef3c9d943bdb534b2 refs/tags/jdk7-b129 ++^05cdc0aa7715bb9292f99860fbd28a0caecf09b7 ++3c9373d3df3a34bf1e692ef305986a8c5443aeff refs/tags/jdk7-b130 ++^fcde9ec75df70be2c42c523c6986ea3540e46df2 ++330b6ca2f9ee9e908318314fbb9c09c3f171ee6f refs/tags/jdk7-b131 ++^cfa6e0878b1aff48b521ee21d2598abe7f4964c2 ++5f19ac0afbb570584ad828d3d2fad5f61c714ab5 refs/tags/jdk7-b132 ++^8170cbb75c9936bcb2f58666a8b87cbd96856d5c ++74bed3ef0e1ed35b99aca9479cd2696479d1f740 refs/tags/jdk7-b133 ++^c6d7830dfc6dfb1b1ce76d8be24244d4b4e88fbe ++a34eebc5c315bc373494a76dc3019f7070fffbd2 refs/tags/jdk7-b134 ++^31a15b61ab6bb6352520042697058b42acfca1f2 ++64f78cd046a40e9a4af7d3af7a8d107246e0ae6b refs/tags/jdk7-b135 ++^f80ed5fdede64782ba572489c3b50357f4989b44 ++4ff9fd0e2348037bb2c8fbbd8fb2b7b1fd286ce5 refs/tags/jdk7-b136 ++^d538bce17282b7e8eed585bbf462bf80a7aacb9f ++70fac480bfa14df49075d241abb3216da117a7ce refs/tags/jdk7-b137 ++^730c7dd8eda0816deb84846952106b95d0440fde ++23001cded84e092e5f6aa2e76a3ba211f54fd901 refs/tags/jdk7-b138 ++^9369498f1a357cc355619062fa6541a1ced74d15 ++c6de0d41508a0b14dc0d7c99f8046399b754b6bd refs/tags/jdk7-b139 ++^cc3355f5379ffe61c12188737441c89d6a2c3d73 ++794bdee7df4c8dff9b0468c10293517ed759341b refs/tags/jdk7-b140 ++^269b07f5859a2a03c11e5e077957433a858e921c ++1e5e8975f01b04390fd8c6f64140bc20946bc019 refs/tags/jdk7-b141 ++^7ff3916e57ab852014885c3e7bdb95e5c1ed8c1e ++47826d25365174ddc966a6dcef521c58e4fdad74 refs/tags/jdk7-b142 ++^1424f2cc9e495594ee6eeb9223be9a356a24ef90 ++c89735d5cd4388bd4d410d5f571890d4eb71dad5 refs/tags/jdk7-b143 ++^7f5de78e6f0f23313686423dd18bc2c6038e1923 ++82ba8a6e01a628ed8711a22d732a821ac1740f8f refs/tags/jdk7-b144 ++^58fb76bbf033a7a396a6449abd1a98848aff1685 ++db5a9dcc9f9f29ecdf3e0df6736fbc9115cc0a2c refs/tags/jdk7-b145 ++^d62d57c36fff42f1ebec6f2705e667bb91ab74b5 ++951c3e1a01aaf26856a20b0c381b356ca8937455 refs/tags/jdk7-b146 ++^8380be1403799bef6d28efea01581cd6893ce6f3 ++4c18e8f3e93e35d77f2f51b1ca1708bac8bcb828 refs/tags/jdk7-b147 ++^7b2e99178f7cf41ecd86b2ccfba38ea653e815e7 ++9b175de44b8d94cc4eb1ffdd9141ebcfbef8837b refs/tags/jdk7-b24 ++^77c86a964655e3586a404d3e0803bd8cd6dbbc01 ++7bab50939039be5f645e155b9ac4d056abbf8532 refs/tags/jdk7-b25 ++^493ac9ee8f9c4fb66b687bd740b8e1fb5ee8b86a ++97c1c021cced669d8c19c33ebbe9b6c579a2e9e1 refs/tags/jdk7-b26 ++^f872a3a32f8e4cbd258e6dc5bacf72a3baa542d5 ++8ded10494122afda3c84738ed427779a66c1e0a2 refs/tags/jdk7-b27 ++^1ab5adaa6ce53bc22f2c8c9e0b115366e4b23f1f ++cd1004e47abcf6b6a09bdf5ca715e0285662f341 refs/tags/jdk7-b28 ++^3021d76b4529165ede29d8fb4454db28767a593d ++9e5d9d2db5d07a1481ecf61eeca943bfc972fc7d refs/tags/jdk7-b29 ++^d7c5094a893900321393d3205809672a61b2dda3 ++ac8631eac98888f58c5489564da769bff3928334 refs/tags/jdk7-b30 ++^744ae99f10082b2bd922e5b995b8787dcd6dfea5 ++c6ce4bf77c9ceeb0dbd0ec0ec9212cd4e5235040 refs/tags/jdk7-b31 ++^575988272e099ed835b41aa4d7f02795dcc55a4c ++884fabec050fa169349b7c7cb4aceec581dff9d3 refs/tags/jdk7-b32 ++^f42262c0392d1737c15a02b7b7a252faf4352907 ++5a415851a75c7608cbb4c58ec8b9474e91defbd8 refs/tags/jdk7-b33 ++^406f3420f4f4ced03917c21c2fe03a80cc71a87e ++d4f5d536ca4d68d53dc47a20067189c61f637954 refs/tags/jdk7-b34 ++^25183c156af4f2a98e847cab1b030a300803de7c ++96faf9559d724880c98940af7e8a671216d46df4 refs/tags/jdk7-b35 ++^2032a83d3f372d0b26dcd9023c1800e612211406 ++b87273f30446d181566f1896e58ea66b94080c9a refs/tags/jdk7-b36 ++^52c8ea5a97497bebed82d2cdfd70b86e459f4926 ++a489551ddee047297daa092d9ebdeb5802c15a39 refs/tags/jdk7-b37 ++^5585d3e79e65031a1ceacff0d228d56c0ecfc779 ++e46cffbcf32e8b09b461cfec2d02ede0487c483a refs/tags/jdk7-b38 ++^e40b297a75e99ad65b348e22a1331dc026f509b0 ++d3a70254ca03328b8e7c1ce7c2b81ec5407f576f refs/tags/jdk7-b39 ++^cfb63b2f47b4fc9e1e477e1affad98496dc9adb2 ++c0d75397102ace426666ac42f37072cb24e1e132 refs/tags/jdk7-b40 ++^6c04fd835e86522d2136ee663e19cfd5f71b9aa8 ++7bf378585a58588838ba6d143843a68907fd0fe3 refs/tags/jdk7-b41 ++^594c9ed01f4a3d911d73b65c3fbb3829435db6cb ++d4fea9f8a8fa7196c9d29857104baea4b0c4a602 refs/tags/jdk7-b42 ++^790cf17df4eb23f483585a2cbc025156c1966bb0 ++4af814f9a46508986dc1aa9cf99cb9d0432597fa refs/tags/jdk7-b43 ++^943b5566ce27943869f8bb7357dd82c532a25583 ++1a54172bae772c6f7e9c00abd84e1d1ff184baa4 refs/tags/jdk7-b44 ++^60a3f5bc64fd5855617bcc0231ff24f2d43c4bb8 ++422769e492d28335d11cebd18d72402382482cfc refs/tags/jdk7-b45 ++^0620440d1f92448c18cedb790913579beaff19d8 ++54e5a28cf11deb4786bdfe0a7a9dacc4511121e6 refs/tags/jdk7-b46 ++^e49da806ac4cbdd256339eb344cef5ce5c502a04 ++111b956456ab1346da9fd82271349be42669467c refs/tags/jdk7-b47 ++^b647e47be80c73593a37139f7e5a1640363ef05f ++8fd5e55c7b5997b52046b66bb29c92e19a4903af refs/tags/jdk7-b48 ++^c44a783b409e34c74c90a7a11776f3c56ed32b8e ++995ff7cb59be7c177d566362f0b3ca6ca7453b7b refs/tags/jdk7-b49 ++^b80a4e3e5b01e6c5c712e62b1e443ee7d3eccd19 ++c6399cce72f276780e2116f5980744531b0a6a50 refs/tags/jdk7-b50 ++^ff625db728de649bf94f806748818d9fbfabc8ab ++d9cd99caab6d675d5ee1a6e1b0f998d31764b9cf refs/tags/jdk7-b51 ++^38930ae468910fb1d763f18c1d9473beffa7f3cb ++fca93cf46e5749ff54f77dba67585ff3d8765a6a refs/tags/jdk7-b52 ++^8844da387d371a94ad40975d72113168f6d5c993 ++0af385d2f302647bb3888f42c23958fd6ad25b77 refs/tags/jdk7-b53 ++^9d14bdc3f86c288f3356e6baedd1871502521a7a ++b03b0c6a2154a4ca8ce0c99e1f7f51e07366d02c refs/tags/jdk7-b54 ++^6e1d4b9a47d7a164e183703af6dc196269487729 ++6e1a0005ed2844ecd5b2a4e24358540bfb520049 refs/tags/jdk7-b55 ++^423befc9a0123b2cf13041f8acbb2a0000ddccdc ++85137260ae007edd1ea14b9cdc6af1b893f17d7f refs/tags/jdk7-b56 ++^21694f8b3fb7bc5210e5c372df30967428468c8a ++f82f3a513bd16122db802d09dfa127dad430abe5 refs/tags/jdk7-b57 ++^30795df1f9490b597e19e6a98b078c93730d2bf9 ++53bee31d02d9aa3f381bf2d5d51dabe20d9eb1f5 refs/tags/jdk7-b58 ++^0cbcd44d1d22441acd1dfdb481a217bfa4636d85 ++31168f1b8b98396ec00b9220d5303811fce645eb refs/tags/jdk7-b59 ++^6d918271d525e0fcf10d2f582e15c2ac4c13998b ++41d9f358754b36548e6b2e5048fb50ae5b2b5d86 refs/tags/jdk7-b60 ++^c1ff9b2e3b5e31e5874ca7d7a38ea4fbd9bbdd5d ++c8035cbd3cb10f6f0b7f04de09fd3cd191d9681d refs/tags/jdk7-b61 ++^54ab66f63e1c374780ad1606d5700f762a92cb80 ++cd586208c77b4e22d85c49125568dbd515414c61 refs/tags/jdk7-b62 ++^30558fec61d54ef2e40fdebae348a70c9cdd6763 ++c4bcfc43f9c5338aaefe824de56947b792071ebc refs/tags/jdk7-b63 ++^2a60847f5b7f5988e84612366c9117ce2f55de53 ++f9aece23ac937f282c1ef1c2ee553b790b76887d refs/tags/jdk7-b64 ++^26adaaea4ed60e82eff9739594268850f910318f ++a1a63928026db0f57df81382085cc618ccacf6d7 refs/tags/jdk7-b65 ++^88b37fb2a8aecf2b0afa75904d212da11919aa98 ++e08b7e4ba15a36b63f501640efb004fe5837f98f refs/tags/jdk7-b66 ++^432d4059851a73a7609aff119cd0802446d44fab ++5a1940077cae9dba048813d509d2ef89bcfb96b1 refs/tags/jdk7-b67 ++^b4b746fb274cb65f8cbf4a884bb20749a8f35d2b ++4f03e7978ed7bb68f9aca77e293f795090c478c9 refs/tags/jdk7-b68 ++^9a9ea731542833248a434d7735e1fe2b635a5144 ++dc51d5c5c12324e7f56149d729aa82b38c88196f refs/tags/jdk7-b69 ++^2ec9bad2a7582607a6b0f60d0797cbbdda72f2e1 ++2a38ccab4919e2353ed6386fd854c25f7d6b303b refs/tags/jdk7-b70 ++^a23f487d2dd0dab4a5bdae5fc8c09dbf645fe533 ++a1b22ccf58e6d74ce8589164af78788ccab378e4 refs/tags/jdk7-b71 ++^2e480a6f2bcd1402cd640be33452c0256d11ac60 ++0a75ac9db88ec1dd9433d696cd605adb405c745c refs/tags/jdk7-b72 ++^e21ea57f72b20424ac38930bcf56513cd42642e5 ++0ace9968df934dbacabba0ee45847ffa3fced39f refs/tags/jdk7-b73 ++^ac3412974fda876f16226a8e1fb6bd6dc22404df ++60145fbfff6148414c835ef9ce262cf0f85d3d98 refs/tags/jdk7-b74 ++^4d263d042f254af2855109e3ba45bdaf3c81baa7 ++cae9ea4202fe0a0b84c3ba3a4286d3785c3f6ca9 refs/tags/jdk7-b75 ++^53c56beacc49396093bfb8638eef74c173f05ac4 ++375f127b0c34d42bef10a0ac44bf0b25516aed92 refs/tags/jdk7-b76 ++^d49120d46668eaaab9df465a9ee17b696cb4e37f ++06075f46db0f07ec9839e75d1c4f5f27a6084520 refs/tags/jdk7-b77 ++^b25112408f3377fe593bcab4d8c25450d999c69c ++499c94d48e4d3cf923aff10dd5dcf541637905d3 refs/tags/jdk7-b78 ++^9cb97e1c64e1cb3b9c9714459d5a8aade9394145 ++7a59943ff0dd152ee979e2af6589568390e35b57 refs/tags/jdk7-b79 ++^2ff37874ef49029c8151533ffc9d71a04386ce14 ++c3121b2c14d248ecd6e581af178a3da05e66c543 refs/tags/jdk7-b80 ++^13ad3ed8b99f8c872eebb5d0bb647d5bb44ea0b5 ++d806fa09e03b29786c1b1776d71e727855a6b7a8 refs/tags/jdk7-b81 ++^0b2e54aa23985dac467d654b8f076cbd0a530ee2 ++3594cf726c8b3f8f2a304467ce7c785cd7045156 refs/tags/jdk7-b82 ++^6a6913f7549510394a18591eb5482fdbfbe627d7 ++82b342952619d2787843e519097281c271b6acfc refs/tags/jdk7-b83 ++^b0a0e766a0137ae33b343dd0dd9b701f6c2e5a98 ++07e0be28ec548faac20b1ba2064da5a58fad7730 refs/tags/jdk7-b84 ++^b7ee18f90316ae3f74c6cef3762e4d74f9762151 ++d4f8aa6d92665bdab465017d25a750b4668c0875 refs/tags/jdk7-b85 ++^1408dbfdbe550dcdea4cb9a849fab6cb371ded18 ++e48bb556d7c2ac32d23e916f46b54e60bca477b9 refs/tags/jdk7-b86 ++^d9942bb3c67113bf9479c6d9174f6e381d558c43 ++0f9ae8dd28767d43f858cf18698787a21932e452 refs/tags/jdk7-b87 ++^bbbf57c1966fc8dea6ab5d35693a9fd88cf6ea45 ++efd4f93dafebaa32b09e7a27f8eb60d55d99ce33 refs/tags/jdk7-b88 ++^3eab8982825fdeaea8eff39242fda4175306474e ++f5a00618023720347d6e8bc2b3c675ae277a108f refs/tags/jdk7-b89 ++^b14ad6680729b40b2e7a19e7803b0f97eceed558 ++8d26dd5a9cd3c91d295c339ca3cc3d1cd43fb877 refs/tags/jdk7-b90 ++^a3a51c78856c360e5efc3aea1c0eda070b4638c5 ++01f5980edd1f78ca8a60e08a280f2fbf80b983da refs/tags/jdk7-b91 ++^7588f37667fd2a8c00d9a1a6e1afc605b75e0dc2 ++d69e7f1549739773cf5213374d4f419a9254ec48 refs/tags/jdk7-b92 ++^9329c4986eae210a66c03400eee8e5b9c5e0fef9 ++1b925484dccfa1a952a3c09ffcda2f1303f259c2 refs/tags/jdk7-b93 ++^f16e36c40b2d8f85b06c848ec2037fed0b0a8521 ++9aaa0184a32764175891f192e3d4c75b5a518484 refs/tags/jdk7-b94 ++^017d851c20f8f838376e5f035fa745f9ea114996 ++dedb4072824b7b60881f57f6de53a867d4741d55 refs/tags/jdk7-b95 ++^d08e6435e4026542e4d4bffdf12748e83ef0f9fb ++9039a8bc5cab82c1f9bec78d51acbb72949c5d3d refs/tags/jdk7-b96 ++^7ac3ff14ceb10e65ffc86b2f6d8e1b96c3434eaf ++9763c02d42fff23734cf599bca96dcc0e5f07366 refs/tags/jdk7-b97 ++^e514f9072fc6ea3d2ad4e9a81251bf1fc1ed1eb6 ++5b35f0daf2f9e94249779aead0ebad3465469eec refs/tags/jdk7-b98 ++^ecd9f7bd776e8d29c8425f922653f1d2db4f91c2 ++d0b45eea6f3e6f4c351fcc5a0bfd1763d9823b3a refs/tags/jdk7-b99 ++^ba79b2bcce1ceefdeb44bb7075bc5d2647a56834 ++33852ed5c01906475eba4839854a5b5a39f65309 refs/tags/jdk8-b01 ++^d2ac7a107e4af38df029fc19e37df25a4831514e ++a02db6e6acd9a8c2b2aad3d857de939352cf830f refs/tags/jdk8-b02 ++^425272b22550faa5443b408fe7f8b79b7e896dd0 ++fc7477630f94a58df74e1e0ea1a7edc137ef49cc refs/tags/jdk8-b03 ++^ce11b33ae7c46f9ff2c5a09ae21a1db818cd1c49 ++25af5e82f9f7f61ff66237834b9a21ff5cd60fa0 refs/tags/jdk8-b04 ++^f36d48190e9cbc338248369a4f5ae635f1b60611 ++4279c95658b930659279147f9569d4e252e92d65 refs/tags/jdk8-b05 ++^4208296685976a0c2ea36b40658dce8e455763e4 ++1fa8ae54f16314fc34855baa73d6de9da41f3ccf refs/tags/jdk8-b06 ++^356b331207d9a58788f4647cf351a9be437a793a ++51c703c885c8bae4ef59745cc1c6db9297e78ab5 refs/tags/jdk8-b07 ++^bb930ae01ef2a0e28e652f19f172894ba6201a65 ++32dcc60a0764dba8fca0b647b2ff3d50d4a41d10 refs/tags/jdk8-b08 ++^48ad07fd2cacdfcde606b33a369b1bf8df592088 ++51b33e55af6050a1cfb6297c0a53aaae4dc7ae9d refs/tags/jdk8-b09 ++^1cf5ba0b12bb8d4d128e1cc0ec40732f0cdcf746 ++fda73bc333c7f08de6312f89c620ec232d049131 refs/tags/jdk8-b10 ++^e482d16c432711d4f165cd46b6db93bf05234512 ++fdc37d42f8f00f8358e33fb39993fa807704ebef refs/tags/jdk8-b100 ++^c77a22380df2af9ce846a13cd5544687b363ae49 ++f0431b532429d56d2a39d0c6972be84b899217ce refs/tags/jdk8-b101 ++^6412341d454eee8a151cf89b51cabfb7b3d87140 ++e2861622725b5276b40d5891c9833cfb0d2a4fc3 refs/tags/jdk8-b102 ++^e9a2e84e45e1120aa306a01dfb087200f6a7f903 ++623d92f31d30968626802ffb3bbceec6b9644dd8 refs/tags/jdk8-b103 ++^41525a23dc036496ea16ec52346acaf473fa8601 ++91494f4f152359a82a335ba48266fe24b88b7c7b refs/tags/jdk8-b104 ++^1962df5a7e3659c50a9b6cdbcdf3ed08b0034851 ++f58827194988e5ccddda280ae0950390f6ca4b55 refs/tags/jdk8-b105 ++^a21b1cb0780505f68e489fad8ad20f5cccb956e7 ++beb501b49ae29f61be0072818710a9d3725c8c20 refs/tags/jdk8-b106 ++^6f3035d9eb1f70384b341a02c97814f6d36b83b8 ++68e6ddc62e0a13797ddea78883e4df970fc77bc9 refs/tags/jdk8-b107 ++^98bbb2a9fc6fbe34e96891e7f9a8663ebfdebc23 ++450932aa6d03a6ab488aee81961aa5e185138b57 refs/tags/jdk8-b108 ++^955960c3dd1aed6cfd071799cc0c472233611d27 ++0a018293a6c9e21745bc444af4b72e84eb2c8c65 refs/tags/jdk8-b109 ++^674c05c3546814df711d0f9384c63d56458aa9ba ++561c543a67d2d1b0fc4a9026d02f9893e8cba9e8 refs/tags/jdk8-b11 ++^7c18f827d7f096cbeb96b086a8516754f0c70221 ++9d2009d2bb5f2dc1ba023209c610a6ef8f47a0e2 refs/tags/jdk8-b110 ++^029001938827cb860dfed40390539cfdcdc39067 ++f5a5cba1f0b90138b295e07e2c11e6a74a4d8031 refs/tags/jdk8-b111 ++^27cab0e0c87f124277c7afeb5dd6a8750443804e ++f98a74d021bd2bb406a457672057d944666e9c4d refs/tags/jdk8-b112 ++^d38a1f186d640dede9fccb727ec98db3a413f9d8 ++b3141c3a22e3b4dc867e5c0f1ed8897e944ac745 refs/tags/jdk8-b113 ++^53fb16b381c50bf51d11b47f8781ec2fe3f8690f ++827dc623d0f8c7daff9b19914fd68e6e579f82f4 refs/tags/jdk8-b114 ++^31a141290be88273d6cd40d076a72fce1dbaed4c ++caddbf8b5820bd6d3d9362136b534a66d0d62570 refs/tags/jdk8-b115 ++^805a34ccbe791ac02ffed1594b519f4f23c61129 ++c0a37161b8fe781ef25ee871e3e4e940f4aec3b6 refs/tags/jdk8-b116 ++^29edd23be2fd0898193254347c750b38a5debd4b ++8dda2f153e7355c2600b4ca90b841616d7ca6b24 refs/tags/jdk8-b117 ++^6c6d4cb7859deb89811c88ab16c56e0360f4ce83 ++e0e24f9d0cf5ae728b3852caa88ca58655ff29a3 refs/tags/jdk8-b118 ++^63c7ac362b1857cc0a2ce6cc60fec2fe1025de28 ++b0b1706af992194fb69c0b8f83f8d3e6efd69eda refs/tags/jdk8-b119 ++^9d65d79487672ea753fe278ec93520de4201f4f2 ++9c4e14e02ee2fcacfce94a282cc2bef7286f372b refs/tags/jdk8-b12 ++^55168184d686e3a43111f91a7ff10af998ac3eb2 ++be9ff95d58f9bb8620a11a813e51fc88a4d54664 refs/tags/jdk8-b120 ++^9a9add8825a040565051a09010b29b099c2e7d49 ++2fb5e812337daeb99b03666ee758cd0e696290d9 refs/tags/jdk8-b13 ++^bf689f8a346b36cebf85c420281481f759d5891f ++b4b6499c23ffc5dd76b9ae5938626e81e6be9891 refs/tags/jdk8-b14 ++^561f5f44de853e0feb6597014d60ae3331c93a0f ++8900fe0fd894cb14af02de4cc63d8b791c45ede5 refs/tags/jdk8-b15 ++^469f89911f4fd593ef2d2cfa6175e79673ed2ce2 ++c1a0394aa6a7c1224e9b210f4396d0d6b66799a8 refs/tags/jdk8-b16 ++^b81c3f5efa016772ca4e8ea3b31a1856ca4ce83e ++058ee1c7d8965630161fa4b5b2e777f2cbed0968 refs/tags/jdk8-b17 ++^0f3b43e31b3021710ccc96b3e43d7e179bc591b9 ++e1de342f56e3c45b731f2b7a93113ac1330e73e7 refs/tags/jdk8-b18 ++^c6e510d7a09129e1b8e9a3854d1342927f170a28 ++b5b97b08fd8f84b9012c1417179f8fc86772fba9 refs/tags/jdk8-b19 ++^7afb6b5a4a2028edab7bb502a85ab2d3da2cde2d ++1590b85bb87b8ea2594a6055f0530376bd44cde3 refs/tags/jdk8-b20 ++^0d3829a2c5a70961ffc539865adc1442c1a30bb1 ++228e5e5fd11137188e3cf286934caf9d4236270f refs/tags/jdk8-b21 ++^4c1a2f6b6e07693159b56025c5113f913fa5f04f ++e54520becb3a80498ca8e08c5458bb22b0b04d60 refs/tags/jdk8-b22 ++^a077a5878cd54de5080853ed8de0c1341771e69a ++0cc6a9dda6fe05647947debc5821f67816c66bac refs/tags/jdk8-b23 ++^f48f666a63864031c1e7ca3c7a294e76e3ead0c7 ++83ca3edc0bd1bb85cefb3f4d54c1fff4e5928703 refs/tags/jdk8-b24 ++^6e913f4649da7ea174b9e049c0678148b3d51762 ++c9a34851b006da5e806b9e5fab993e566558e2ea refs/tags/jdk8-b25 ++^69efabad3d8a2ff47a62a4626c574a56edec1cfd ++a3db0e1600aba0268c2816380cd89c6ba43797c0 refs/tags/jdk8-b26 ++^6f539c5cf97c6b209a03518d3be87afc06530e22 ++c0d7f825f41e1ac2f31cdd1941d58b7e4c3e5a26 refs/tags/jdk8-b27 ++^2b7ba88d551d4f22b3f78345f222a667ac69a965 ++62b5d4df52d6bd43cac7ff1c54ab322980e5d9d3 refs/tags/jdk8-b28 ++^abf322bf84d267aa51a34841f56dd15804fbe2f7 ++817f23c52cf86510b41f5d212398365ffcf1edb0 refs/tags/jdk8-b29 ++^651770b5df8b16d14338b3b20a24ece2c5b839e3 ++3eeedc2818cfcfaab60a500737502935f997c501 refs/tags/jdk8-b30 ++^61bc4ca404d1bdc5c1e4536af73b720ac67a0e04 ++c3bf3142941b5fdb259e140d7becd8ca5915e4fa refs/tags/jdk8-b31 ++^ed6697aa20e3f9c17a496a544b10bfe3543de38f ++f6fdb895dee84338c9de2e8a9850b516611365dc refs/tags/jdk8-b32 ++^94ed22086fcd5f24630747a9c997e835bf47be64 ++0a5ecb4af210a6821e0b40c8b54895dee3957c70 refs/tags/jdk8-b33 ++^a1f493478abd41c2f2cd01148ed377ec47563c26 ++d262ee9294a3eb09db871f9630e0ef1e405b826a refs/tags/jdk8-b34 ++^d2f0792c3907f9d383af488cedc1d16c95c7c999 ++399f3e012999b2bda0a5ddf98440f3455670f886 refs/tags/jdk8-b35 ++^2e7611228e247899fd50576e311cb116ef6ea2bc ++e0c6075c80c84de7cdb64e11622ee84c15588318 refs/tags/jdk8-b36 ++^4840199698c84655569cee604d72a90c6ed1e0d0 ++076f99900dc9251b72cd599c7bc9abcf12ea7649 refs/tags/jdk8-b37 ++^e3f1a15d934fe315f99c53c267095a63216e1e5f ++13a921a59bba0dd7821f2e4c11573fc4cac96395 refs/tags/jdk8-b38 ++^3de2a40e44be109eb9d222d229273e632f065738 ++2c970e04d9cdb83774a3fc7c147b19709f237f8f refs/tags/jdk8-b39 ++^2de299b0862437c3b773446ed09efbf592421477 ++0da3d5c13df505ba47c661cebaa0728c8ce84cf7 refs/tags/jdk8-b40 ++^880e09412543af479bc335faeda6196489a2a045 ++703f7c42a2fecbeaef200315ed1c0f9425e0c8d3 refs/tags/jdk8-b41 ++^ffd7528dd6cb33c64bdc27d1aa4860962789ed1c ++5b30a7757eea0587041b3ca24f351455516c32eb refs/tags/jdk8-b42 ++^6687eed67752584ebeccd7afd7e00fa854031814 ++5cd8ae46b042552ae8b3f73771e92c20c011373c refs/tags/jdk8-b43 ++^c0ed0fe43338374f9962bff468d66c2cad4b70f6 ++77b1dd9260e9ef426b87f5d511e8a62fcff3637e refs/tags/jdk8-b44 ++^2e1841432e581cd40fc24683fedc630f040f81e3 ++2c8668b2097f10ba8c88187b2462f82a2eb330a0 refs/tags/jdk8-b45 ++^7517b9d19367e1f057e5450d7871135b5f878d02 ++f52e9db9cf9586d4a13e5b48f4e6f6a077f73870 refs/tags/jdk8-b46 ++^16a39a42d1342834b4683023c4ac8a7872d13bc0 ++cb201a6450a1dbbd62d3c2222a4750b556d39323 refs/tags/jdk8-b47 ++^b56b984193acf014484e8491631bfb48e1f4884d ++a42e922abfb42cd7a94212381eda86bd797b8105 refs/tags/jdk8-b48 ++^5d039154dec1bf7eea9fee4673edd508b8409668 ++b0e8e30b0add732280a547be984a3cf9a12df68f refs/tags/jdk8-b49 ++^5d98b14bef406ee5e857a29d6d4c549f1772b408 ++f390330de75f3edeb05add4333cf0ded4d0b1ca9 refs/tags/jdk8-b50 ++^6384444219962e0cfab62d215d08d4f4254d57e9 ++c7b70a66bce35e1bccaafa389c804b505a9e4cc1 refs/tags/jdk8-b51 ++^bd04d75035a888d5034c5f7e2e0508d1d28d14af ++c280fe5b6705e79c24f0dd0e93e690b7e5691796 refs/tags/jdk8-b52 ++^9e31be3e8dd02b143fa9997732e714b0886ebee0 ++fd59f3ea44435c85a06fb0845565c76824265a89 refs/tags/jdk8-b53 ++^b07a721f8e22f724831edf215ddaf8607103d904 ++c4c77c0beb27be157948a266de74f111277dacd9 refs/tags/jdk8-b54 ++^264a0511f0c4793a027ba8874d2c74c032e5b702 ++7de35fcb4e06005859683edbd4b04c9ebc637bb2 refs/tags/jdk8-b55 ++^b41431ec801f0b1defca2461b6d25cc6459c0c2d ++8886e35f0cdb0ecb76c23c7aa66e7f95ae865214 refs/tags/jdk8-b56 ++^6c1ac6f6bb7d4533d592da576275ac91e36f7c4f ++55f0abde6d1bd79364fc2130b2505856dade5132 refs/tags/jdk8-b57 ++^901ebe2983837dbce0ffec88d7e7285ba1967022 ++fa9c6eaeb4b60c0f2604d4e09763e9776b20b0e8 refs/tags/jdk8-b58 ++^5238f9a66e5ba8771c2fe22a79cceadcca9d9220 ++bd56a1486356d36b5f221cac91a11d46b4e3c8b2 refs/tags/jdk8-b59 ++^4e637a8f8088bd3987ae03113111064fdff905b9 ++3fd7db6d40dd794b2012b2a78bb83fdada8abed6 refs/tags/jdk8-b60 ++^34063e3656db6d0cadb9168f37024e6e66fc2372 ++43de065837a30359690f262e6a9c6386a3110a16 refs/tags/jdk8-b61 ++^1c78bebc35307677de0a379ccecf99725e7246d7 ++f0bcc45527caff96c77894f3e5ee69469819f00a refs/tags/jdk8-b62 ++^650aac0d5e472ff99afc1cccf900bdee2002286b ++1a94953a17e39b6f80370aa293116e326a18a477 refs/tags/jdk8-b63 ++^59b1cb08b10a159bb08f1103c8457954a8779564 ++f40577fdfae1064bc26309c56eb00e6d00a049c0 refs/tags/jdk8-b64 ++^86c5d4aaebd148650028ba0f10e37b3825d3f983 ++7b2e4a34c59908521085550fab7341b4df551e4f refs/tags/jdk8-b65 ++^e7d87b234c444e39369e8575284f785c56113324 ++ab2191e3ccb18cef302fb7c125488067dd9c11af refs/tags/jdk8-b66 ++^81ecd2932e0caee8ed01955fccc9e958c6a5cda3 ++a7ebc22bb6d0ef7ccb66077e784bd8c779271bfc refs/tags/jdk8-b67 ++^924beaaf2cb40541f53cd8e6949eb763be65d4f0 ++fb39e375097898fd71b5cc9cef873955b0c71338 refs/tags/jdk8-b68 ++^faaa074af726290f9da3d7f66dea5a1d73f83415 ++320e1e9a1c9db090e759888fc520c3865d94d517 refs/tags/jdk8-b69 ++^902594c3e652b268f088dd846466a9b3af57d8ef ++01fdada0af68f6b7a0839840f1db3b40bfbd3b40 refs/tags/jdk8-b70 ++^78bc845d664c705679de49c5f26ba6f129d116f3 ++25da6dfa22f1aa25a85e78926487cdd8ef760412 refs/tags/jdk8-b71 ++^e7187d14db3748428c4a312203549f7ee31d4471 ++d34718c67e882dd5b5048cc0f7c8ecbdf7e8852d refs/tags/jdk8-b72 ++^8261ee6da3c5843806c20808cc4206c73bb0efac ++81b4e5400b4b6ed8a755a2993dec6cfb7487c5a0 refs/tags/jdk8-b73 ++^1c11f83e9262d3bf07b9d095a7b1d3659f1f2a9e ++9df2fa988fbd3cd25a0bc3a016b93738f7cf501e refs/tags/jdk8-b74 ++^75c48b0d1b36d9361a412ee2db2f51b7d9b6ef1c ++9c8df92261d3a50ec11a7b743891f3adf08c7639 refs/tags/jdk8-b75 ++^5f0d1aff638a1ee9df3ae019b7896eba488fcfa3 ++f8fe95d85e22efd8d55945acc30b4ef5a7fba9d7 refs/tags/jdk8-b76 ++^9a87fa5db98892de60f932a9a380e185a28f2232 ++3fb074be9d7474410efd47b744fe51f04a2ed4f8 refs/tags/jdk8-b77 ++^7ba83041b1d65545833655293d0976dfd1ffdea8 ++3ead3a74348f1687e7e903ea4346d2f820d144fa refs/tags/jdk8-b78 ++^93a052bab37ae1946b8c2893ae0d48af756df25c ++76c445339712be147e15e117b3a75d03d827c7f5 refs/tags/jdk8-b79 ++^950ddf6143fe7f2cfaa1a9d5cf96ad631231cc8a ++e47c4ad33dc38b3829baea1114ed42a3afa6c44a refs/tags/jdk8-b80 ++^ef906c89cecf724206e54125e5b619a78a3f13de ++932d2c02021d5850582651e8d1bcda95c13cc0c7 refs/tags/jdk8-b81 ++^ac2b8241a3494e37f1624601c5a4eb3239137786 ++f1c64c13d3eef0308782af9591bfdf344ff40587 refs/tags/jdk8-b82 ++^61cac54a92db2ee17ca29e3c1b43da8e5887f415 ++a622c1980a9d917793f357b77ed4b27d75d04a9a refs/tags/jdk8-b83 ++^7c84115ffb3930d3f095225d9b32075f2246177e ++a532e44f19896cd738d76f436b88817e73279a7c refs/tags/jdk8-b84 ++^9e90d15aa7babe03b4128168d2688e93c6137e0b ++fe8a12dc5fb276ea1cda6d31c03dfe52c58ee3ac refs/tags/jdk8-b85 ++^7f1db5eedb16c4db61e0596cfeb7979b4269fa62 ++fee6f44b8b104c5af10eb150967d15b42d87f073 refs/tags/jdk8-b86 ++^686ff53731493b1d66ea63f9326624a82a567aaa ++b0cebaa4bf1dc1e2165c91878e3d7caa1578e4eb refs/tags/jdk8-b87 ++^662cdf07462ccc6330bdb3d8f56694eafc49d71f ++7550f3f8ac4966ce76d90dcb57e03fc77b070c50 refs/tags/jdk8-b88 ++^39b2afb3bb63eea44e55b61e5c77477d72089e1a ++8633970b1c505c37540b2821b01ce1f3d982f352 refs/tags/jdk8-b89 ++^2fa38a69d03d34f5df18704275ae419dfbd0d85d ++4dcb0cc7ae2c2bc8f6db1366d8e1877ad7fb8cc2 refs/tags/jdk8-b90 ++^aaf112686c283a7e6b6b1efa7d05617d07e550d6 ++f17647afbae44da697d846b6719dffc5da22a533 refs/tags/jdk8-b91 ++^82d185e64838992b019c90133d508d479d5ced0a ++1b3d50b7f19d59ab6e3e552cf00c30854227dbea refs/tags/jdk8-b92 ++^22e500e3a917594cd93baaf8b5c7d29360d250d1 ++da575ccd3f5e3f063a18bd89c7b9e49c9fb1ad47 refs/tags/jdk8-b93 ++^064e98a35c8967ae7c8284128bd565369af012ff ++5263ce65860555d8eed8a08096bc147170b32903 refs/tags/jdk8-b94 ++^3e0356fb8df690fc18a1cbf51b39b2675e39e430 ++b94b179fc604891a76d1befbb7f9933b6e21fad1 refs/tags/jdk8-b95 ++^7e5fa723b7f5ec98b0d3ff50c98e138c7f145cde ++20a81b3697e720b32c88839e4ca96e40d69d5814 refs/tags/jdk8-b96 ++^d9e5bebaa657e3e796913283ec7818f85925bd91 ++477e6634a0107fcd02afc47e096476326d6b0a8f refs/tags/jdk8-b97 ++^618a81477260932007d23768f37e7dea2c32dcac ++d405ff56451054b5b0ba3f780f9ffef100aa5fe3 refs/tags/jdk8-b98 ++^5b4e46bf5f6091d3001cb2f537b99dda36bffcc8 ++f2da184e305469a090e8e5cfa50018128558036a refs/tags/jdk8-b99 ++^b7f9acdbd397234ef219df5f6292f62a1cadfab8 ++8950e8e0a06913dfb2b6f78c839ce4a3255c3f8b refs/tags/jdk9-b00 ++^15c21206724668578fb0653f28aaf5647702643d ++a4781f7911e76e2908f7cbb6b0ed964a873e670f refs/tags/jdk9-b01 ++^343c8d34a8ca9f56c077632da2a74a45b59b036e ++3d9ab12cb9c60dcf1d97a63064de2917ae9a00e6 refs/tags/jdk9-b02 ++^e403295caebceb752e4f1f9727f838969875c8ff ++343fd661c7feefdc8d30eca439db2fb7ec919ef5 refs/tags/jdk9-b03 ++^8ac95cfe8037175566a2575dae00d839a57247b9 ++459a60a718165eacd7fc1aee2d05b43abc784bac refs/tags/jdk9-b04 ++^67810b5cb5d349066502883b4ef06cb133910edf ++d428be387385f9a12ecbad51eb69b78cf2d02610 refs/tags/jdk9-b05 ++^f980bf3f3fe5bf2b0de1e7640f1e531c5285d924 ++b0d75da07a72f8487088a1be84d813f506350c08 refs/tags/jdk9-b06 ++^436cd45cdc936f5c3b748ca18363351554a22dd3 ++87dde3df8dc888d82d2825468218805e3c7aeef9 refs/tags/jdk9-b07 ++^e482a971810a509b2a929a87af0f84d2d9a99f61 ++40acaee0742285fc04abd0e8150f955732638012 refs/tags/jdk9-b08 ++^87a0f4a044f6b0a2465f5c9b8539a3bd6bab6935 ++88777efb8d8d6d0ee87b5ebde6ad3f1a4fb379c1 refs/tags/jdk9-b09 ++^aee6fe61f761c828801643214706683132bc7f98 ++43f9318baadd9837cbb0441bc3bce82c917ebc90 refs/tags/jdk9-b10 ++^e39260eee243afa487df6fbf628af1c569144529 ++9ab1ae689b3fc59c26a86bc95f5de1b3e16ae15b refs/tags/jdk9-b11 ++^e5a91499f0f82057f3a5acf68b99091e4875ab5f ++ea0e4b594af5055ca2d451066b4796a0cd66d15c refs/tags/jdk9-b12 ++^3d61a661e2fff929cdfcf631acd9f306fac7568a ++881341bfa5507464e55dc06e344d0c24f8ccaed5 refs/tags/jdk9-b13 ++^599fcee2f291fd95c239079c44d1542310924b96 ++ef5ce609a342df30322f54231b60a514f2df8fd3 refs/tags/jdk9-b14 ++^b35ce163b6704d76019675fdc6d831653b4d9383 ++1f130c947959b4bcd506bfca3ff5aff69e903734 refs/tags/jdk9-b15 ++^714a7e877e42462a0ca81f89702cabd20cb08cd5 ++b9da1b90f4c9726e38d78de7774142691a26702f refs/tags/jdk9-b16 ++^490b1acb50798a64e784c2e529e0a3c8acd80693 ++a0e7be25ac56363623757b91f8833dfbad459c35 refs/tags/jdk9-b17 ++^bb1f242a9b4c318ee7cd68ebdb214f460c492c4f ++d2a3926ea2fd352595f57b14606d836c8db9429b refs/tags/jdk9-b18 ++^9813076ace0ab339046921725572e67b593afd58 ++91851ca5f942bee6983af82460aca57ec55d7dfd refs/tags/jdk9-b19 ++^80bb4ab1c8b4aee0547c8f3b920e46e9d3b69522 ++62e91dd964b6ec7c056775773c0ee8ed7fd24f83 refs/tags/jdk9-b20 ++^8117632422392511098fc62abece5f089e5674fc ++5d1aab89956a88f6dba057ce4c5a328f7c506230 refs/tags/jdk9-b21 ++^9fb0e574aae9362ed2baa777008a08ec2bf79e51 ++c57d1155a778fbd8373a9e70e62049b136ba5a67 refs/tags/jdk9-b22 ++^73f82e2dc6408b43ed57ecf4e4302cb27de3e192 ++3b91fad6fb807e901d429934055108421f21789b refs/tags/jdk9-b23 ++^47692bbf7edd2ff41a0e002210b46abeed151ea2 ++164cfacef29ce05d6681f38225a13c4476b4a8eb refs/tags/jdk9-b24 ++^18ddef8cefcc9ad71bc079646f59cb4e86a57082 ++b5b9ec94c2537567f926597f27a2823724a9810a refs/tags/jdk9-b25 ++^a60e87763d4f2e19cc3492439d5cc4aa4a7743ce ++2c2d21bae63b70f22885648f751e92ab9e360941 refs/tags/jdk9-b26 ++^6b0a761ca3a65fb86418beed3f06d81f4eef06c2 ++137faac2bcf39633b47f83cef83b4fa8bf86fd62 refs/tags/jdk9-b27 ++^a0fb53a7cf0af6e20bdabeaf7dfb424e8b0f753e ++8ac0c7efac15406e5d2777f9c9cc866dfbc25c09 refs/tags/jdk9-b28 ++^111e0d2600bc9968dae276be7a683ed2810dc8b9 ++a7adca59d69a5a384cacb06b7627c87b837f2973 refs/tags/jdk9-b29 ++^c66cab347927bb95736d8b286c68121837c96c6a ++346321263b744b01e4e710eeb25567f2077618f1 refs/tags/jdk9-b30 ++^5bad5939982ce68816b59f09f543e2a1fafae7f5 ++185a252bd6856073004d1f28772cc91db5265a24 refs/tags/jdk9-b31 ++^8c15cc3983ea15487cfd707dc6205c93b61b5388 ++c12fc70b13cbd7973340ecc6497f32a2bcec6e18 refs/tags/jdk9-b32 ++^1a2793f29e6a96b22edfc2c281cf4a27a6e1ee00 ++dcf28216b40575059b09a84c764af9c01dcd7d3c refs/tags/jdk9-b33 ++^50228a4342b8656e6045e87b72071c20fcd467fc ++4567670051979e1dd0f090acc36a758018ad1073 refs/tags/jdk9-b34 ++^1949d10887973c3d9441aa83e331d1ba3b0a38e9 ++360d68ad494adeedcd5262a14cd02286f200022e refs/tags/jdk9-b35 ++^5fed7c392c9ec02ae6d880bfdd21b0e09da4cac8 ++b3a6ef997beb041fe33ce468e803e66a1795a20b refs/tags/jdk9-b36 ++^839cec40e9e44270cccbeb4b47964150f994e781 ++77b4ef42ae30a6ca60b3c118134382d73a51f434 refs/tags/jdk9-b37 ++^0498575d5ea67bcbe25e6f02d2b2544445360e37 ++658e432550973b0e98e53e6fd99de2f840e56ec1 refs/tags/jdk9-b38 ++^ce7a159195751f597f24331cd477a85e590658ec ++f81d7b2ce025d3480d21854fb51c1795f20c82fb refs/tags/jdk9-b39 ++^e49b1e9aef94106e944151000e23c146b5b32c18 ++a135302d3ee8cf3cfcaa19c001f70290438a0f5e refs/tags/jdk9-b40 ++^99895e4249b13d2acfdedca1b73e56a96d7729b1 ++c292ae6d93a833247ee0ab24ba82d44145fcd14f refs/tags/jdk9-b41 ++^61ae72e93c9ee15485a8b1c7761dc765ca688228 ++79e60c3b730d46fd883558d4c25e41344170c1eb refs/tags/jdk9-b42 ++^bbce1abbce3032e8bb16519183e57b4fa3afe29b ++4b21498206371ac098e10249ef4a870a08e8e0b7 refs/tags/jdk9-b43 ++^f6c045bef0bbb3598e19ed9d70e5d679b74b8734 ++e7ba06728e111dbfe36a98c99e4cd64621df5497 refs/tags/jdk9-b44 ++^d85024b3210f546a7c0313eccbc3ac5f5227aa9f ++8d8affb886b0236f8a717987a24f06143aeed025 refs/tags/jdk9-b45 ++^d708838beed0de92df39b370c14dd463a1d0cb6c ++8b14cfeb0b2af65b0070c7539bb1a6a3cdf42a50 refs/tags/jdk9-b46 ++^7d89dd003982bf545a215229e2e2fcccb54f2741 ++d1aabfd0c22f0181c970167fd30cf14156e2592f refs/tags/jdk9-b47 ++^f022a99128d43344bee42f1e1a2cd90f1eefae8d ++da0347c03db51aa8eb3445a3a828d61a4f6b2c99 refs/tags/jdk9-b48 ++^4775e0767d4cff35fab90e301eeb02a85d45fb27 ++16babc62f41c2ffca3cb05ddfea6868deead03e9 refs/tags/jdk9-b49 ++^edc9d85e7b460f2303b0d4e9051708475861f2f4 ++b4c32db44013abd2533300539a78fdae1a7ada5b refs/tags/jdk9-b50 ++^b1d6b18b334862e5fe38b9ec10995c7b2554e5d5 ++1281b62285505c23101061654ba241edcdb28a56 refs/tags/jdk9-b51 ++^7081b471c4fe7e5cca67aec495edd422d8262548 ++595161194578e3e9a9ba57ba11029a1833c07d46 refs/tags/jdk9-b52 ++^f3a755b2ab03bfb3f76cd2d57f6169158bcb805b ++c0101fb71b37f7c0dcaaba13978e0e459ccec7fb refs/tags/jdk9-b53 ++^44cc65ae492f450ca2667ded13020a678823eed6 ++d2364a518d1031cb0c73e7f7cfcfd52eb1f18e94 refs/tags/jdk9-b54 ++^cd16fed9b8b0cd46021947ac5feccae50a5ce97d ++1c982cb7f85153ac0c210802d9a9e41460c7ba42 refs/tags/jdk9-b55 ++^63923c6c41a70ff3c29025b729410876ec497a30 ++c958aae26d5da5c188d589509687282f0b920c56 refs/tags/jdk9-b56 ++^3251eb721038b71a0154b49478cd2625d7957689 ++a9349830f86c61b5f7c770afd1eb51707325d430 refs/tags/jdk9-b57 ++^3e1c88b819ec336e8c9dafaef4c5eb0855337085 ++cf75fc532cbad160a44e934c6a69cb34fbffb0f7 refs/tags/jdk9-b58 ++^b2903fd32699d2410690b55e34caf484f8981e94 ++9956b524fa15e5f9057bddd356a3b45bbaab5e82 refs/tags/jdk9-b59 ++^67557506e3c3592209e4da2c8ce4fbbc18d12248 ++f2611cad78090c02826d806fdafd0977d4e68a61 refs/tags/jdk9-b60 ++^ec05163d91c493cec2d4d444a6d895ecdd7b6398 ++12de2c36de36821b9cb40f4a6c121d66f1b508c1 refs/tags/jdk9-b61 ++^7cbdcf978df72ad804031faac34121517a73f607 ++0c1c88d2fbdbcd23ea051f2abaf6c4a86db458dc refs/tags/jdk9-b62 ++^18bafb792cf7fc16b77533c013f6e54f3900f949 ++0e509299aac83a0a400d27b033854042ba449e1b refs/tags/jdk9-b63 ++^cbb7a567ca52a735fcfcbf5bfa383a6756a12964 ++72098746c7adfa5568a6c214414b66c85ee697af refs/tags/jdk9-b64 ++^bd394344b3c5f9724fff6ce8cf8a0910fb667390 ++c400eb68ba57ef03714043f93abb610bd5568734 refs/tags/jdk9-b65 ++^ef28a587f7d12daef26188d07a58407686142475 ++a9e4585e621191f5d637ea0ecf01a38809365436 refs/tags/jdk9-b66 ++^7a711fe858af20192294fd7c3beed93283b0ba45 ++b683e90fcd33347ddba800cb8bad1eb12bdd4180 refs/tags/jdk9-b67 ++^63dc40184ad5c4f620bf42188aaeaaaeb61dc627 ++c37853537a4b840b16e79a55c19f2c8ba1f2ff96 refs/tags/jdk9-b68 ++^d35b2d378b7f5ecce913f180e4572a0195fdc090 ++03f8585bd31e76ac22dde481aa7b72032c97ee21 refs/tags/jdk9-b69 ++^733c4e989fb73bfd22356d805fcea98f48f874ac ++5ba4552b04af30ad805a1b529abf88121008f031 refs/tags/jdk9-b70 ++^9ced0d90d5d3f7b5ee5a35b09ab3fcbdc93f735b ++efecadee5f0157acbb4eae9af3e34d240cd16849 refs/tags/jdk9-b71 ++^eb76b21f6d9e9d151fb9d88a66507e4973c5cfba ++9b32dc03c950d1cc6517b65f7183c7c4ba2abeca refs/tags/jdk9-b72 ++^52cdae26ef16356867aaefb98405568a75376cea ++e827738fe4b24e044a7cde30848467f0305f6312 refs/tags/jdk9-b73 ++^7c256783a5b2ccb7d69fda8f564d8ce009c4969c ++4348771a983ce0e0a3725ff8c3bc47819426ee0e refs/tags/jdk9-b74 ++^37836b1f3d659cf1e04bd86f0a3fb3b5d6be2ee6 ++5b65b01ac6be96421af884d6a83f9b2485e99685 refs/tags/jdk9-b75 ++^c590df00222e9e11bc4d2f30664fd1e1dee4ff00 ++4744cd8ac0c122eafb651acf2e4828da37bf3d98 refs/tags/jdk9-b76 ++^d2e2494f9e8ffb711b25714567f6040fe1266ad1 ++6cd0bc3967743b9e184103c2266fdac7d6d3fc9d refs/tags/jdk9-b77 ++^ae676b44c4c2ba43025987a8c827b25834ffaba7 ++dd19c8cf3981f3beb94f78cb6e0618852350ce6b refs/tags/jdk9-b78 ++^d9b43a9e2c68d291bacac0324efe7861e07a2989 ++e07d3f6a7f4cb3fdb617efee5ae8b86c0a4b4311 refs/tags/jdk9-b79 ++^11dee9e7fefe3d078c18fa81d6ce17915de39771 ++75282effeb0cbb7d137bd5c70a82d0ae369d4af3 refs/tags/jdk9-b80 ++^44c8b13d11bc4171c6a67eb0108c45012e48170a ++feae4e33a44b8ff054ce00e814263bf3241a5982 refs/tags/jdk9-b81 ++^33994176ee6b92653f43e50f081e2322ae1bf80b ++c87a9e00c41b1d876825865a3957d914f4566e17 refs/tags/jdk9-b82 ++^9969836a335847563ffe838d6189ff339f4fbf88 ++94c1374132b62651645a95dfd9c4912f68e8a579 refs/tags/jdk9-b83 ++^2a12715485a74d5abba50763f5a82f7c0eb4792d ++37c057e10b741299b236f0d31434fc5887a6cb70 refs/tags/jdk9-b84 ++^96f1486b0a2e51253c9f007d4fd4d9dcf4db717c ++3849cb9d2d542abfd7620dbbe54c1eb28d97f38e refs/tags/jdk9-b85 ++^d12b5c154b4027fd5c3ff58229052740240f96b4 ++e6cc6cb0f2c235edfed1f6fa5396c4768f600ed3 refs/tags/jdk9-b86 ++^119988f54a6b56edabff648b5c8a6ac68acc45c7 ++35f1b84b90d68737d90cc9674081c6fd24f727f8 refs/tags/jdk9-b87 ++^aa8e6904dc4484f0b7fccdef7699fac61f554b03 ++5bc4d39bd96dd6e273a4b34ed0f11e2dedffff85 refs/tags/jdk9-b88 ++^b2faf14a664a0edccf5f151ce06d1d76600a602f ++a060162fb5f65f4f2161bbcacde9a906e032a841 refs/tags/jdk9-b89 ++^1b3ee82ffc5c816840f8f43cb370132052ab61b1 ++e70bd431d9d9655f5ef8ffded19f760d55d1eecc refs/tags/jdk9-b90 ++^a7775aadf723b8e2766e97defbaea34f9e3ef6f0 ++03a6c2e9f01c69c246dbad6e1a93d2849df7dc07 refs/tags/jdk9-b91 ++^bc941d24181c55d0253c993110ca254af04c4ad1 ++748526bd1c42cc0454d6c042705eb28435b8afd2 refs/tags/jdk9-b92 ++^ce4153b48fe2eeb35a472064b3db85af17c4a170 ++b1a75f98bfae7a95dffbb74b0a5ee2ba88f43583 refs/tags/jdk9-b93 ++^d13176b6ba33b2af025a851b50e34fb3af7e0794 ++8cf535c977afe777927f081bdca2549152524104 refs/tags/jdk9-b94 ++^b6a729a79b2ca65ec3dc26af1ee8dcd1cd3afa41 ++3b673f1e788166288a3b8e28f0b94d82183810d3 refs/tags/swjdk-11+28 ++4c1c9815d67a5742185b6ca6e2c26d8229003bbe refs/tags/swjdk-11.0.10-ga ++a1486079314c4936445ad0e0bab2a87d2cb7f4a4 refs/tags/swjdk-11.0.11-ga ++7cc160ab3528b1613c08672908d5030d14e66d32 refs/tags/swjdk-11.0.12-ga ++59ca7e6404e00bd8f26148051549d0aaa8652312 refs/tags/swjdk-11.0.13-ga ++ab9ecd50be67e8f52997a323a3d0da54837e8836 refs/tags/swjdk-11.0.14-ga ++60e8ee3adf8969a2950d8a4d9e377157719af229 refs/tags/swjdk-11.0.14-ga.2209.SP3 ++e102c4dd8ea9491adcac41a6e813afabc1845e80 refs/tags/swjdk-11.0.15-ga ++a1bd33e27f6b63d146e5c24e6a3e40f5bc88aa74 refs/tags/swjdk-11.0.16 ++d6cf8c32903b0dc72b8c27d73f78341420874b55 refs/tags/swjdk-11.0.16-ga ++91d63cb90669dcc2cc54e1b0d7e6331a9543e198 refs/tags/swjdk-11.0.17-ga ++916c4ad2fb91581ba6a461dcd430181af3534c9a refs/tags/swjdk-11.0.21 ++4cc486bd98ff19e17a6181735bb5db9b4a3cca2b refs/tags/swjdk-11.0.26 ++fddd7c766058a56d4645602eaef3b4ae9b5f6731 refs/tags/swjdk-11.0.26-ga ++9736b3fa28e7e4f25017300aa7d4a7bd0313f1bc refs/tags/swjdk-11.0.7+5 ++10cbcce08fd85964904898b477f19956aabcaa5f refs/tags/swjdk-11.0.7-ga ++932bb744d4a349c4b01b0a14ed37cefef3b2ea2f refs/tags/swjdk-11.0.8+1 ++d3bb48639af5a30b5a8ba7f2c7ddc3505995ca13 refs/tags/swjdk-11.0.8+10 ++bfb68a117b3a8c72733863bd9f022cff92b7a0c3 refs/tags/swjdk-11.0.8+2 ++6ce34d7aff8f2fe8942f2c30982253428645d2b5 refs/tags/swjdk-11.0.8+3 ++15d409bfd10853feb1d2a2e81cd6fba1ec5ed9b5 refs/tags/swjdk-11.0.8+4 ++9b177d89c0ca1a34f36c4c378d35af2fa196a305 refs/tags/swjdk-11.0.8+5 ++5bb3dff540a19a66704f764cedad2dfca9531931 refs/tags/swjdk-11.0.8+9 ++d3bb48639af5a30b5a8ba7f2c7ddc3505995ca13 refs/tags/swjdk-11.0.8-ga ++93b4da472ea9e52d26d3fae87277f5fe5e283552 refs/tags/swjdk-11.0.9.1-ga ++29874ca14942e4442f7efe43225b9dd8a964bf4b refs/tags/swjdk11.0.15-sw1.0.0 ++d3482b5161df5d3d1eb37ad25c306904a06f1ace refs/tags/swjdk11.0.15-sw1.0.0-beta.1 ++0b026f3f4fc174e9aeae5f5ba57064f1b6ae98f3 refs/tags/swjdk11.0.15-sw1.0.0-beta.2 ++eae8862b8b4a4c00145859295e58b0a24249a226 refs/tags/swjdk11.0.15-sw1.0.1-SP.1-beta.1 ++39d5e1edaec022d5b1ae9fc5f44e35292b3d18e6 refs/tags/swjdk11.0.15-sw1.1.0 ++1af79d2f461d1ffd04e34777530332e7432c5ba1 refs/tags/swjdk11.0.15-sw1.1.0-beta.2 ++9c67981f299a0262354d69997d5235e68a5a9b0a refs/tags/swjdk11.0.15-sw1.2.0 ++6680635f0f5ab231888f7a64491cdb9a8b205907 refs/tags/swjdk11.0.15-sw1.2.0-beta.0 ++7fcfae396217f58bf69c6027a9265dfe17c25090 refs/tags/swjdk11.0.15-sw1.3.0 ++0df513871064819f239540d541fc821340c3f571 refs/tags/swjdk11.0.15-sw1.3.0-beta.0 ++f8012988c139f837a3717d7a6d485f72a8f66355 refs/tags/swjdk11.0.15-sw1.3.1 ++abcf1222f2b5941c3683d7ff3537b88655988727 refs/tags/swjdk11.0.15-sw1.3.1-beta.0 +diff -uNr openjdk/.git/refs/heads/sw-master afu11u/.git/refs/heads/sw-master +--- openjdk/.git/refs/heads/sw-master 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/refs/heads/sw-master 2025-05-09 10:05:55.424290519 +0800 +@@ -0,0 +1 @@ ++531a81f289670e918b667eb3b5e298773a9f7400 +diff -uNr openjdk/.git/refs/heads/tag-swjdk-11.0.17-ga afu11u/.git/refs/heads/tag-swjdk-11.0.17-ga +--- openjdk/.git/refs/heads/tag-swjdk-11.0.17-ga 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/refs/heads/tag-swjdk-11.0.17-ga 2025-05-09 10:06:54.812292525 +0800 +@@ -0,0 +1 @@ ++91d63cb90669dcc2cc54e1b0d7e6331a9543e198 +diff -uNr openjdk/.git/refs/remotes/origin/HEAD afu11u/.git/refs/remotes/origin/HEAD +--- openjdk/.git/refs/remotes/origin/HEAD 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.git/refs/remotes/origin/HEAD 2025-05-09 10:05:55.420290519 +0800 +@@ -0,0 +1 @@ ++ref: refs/remotes/origin/sw-master +diff -uNr openjdk/.gitattributes afu11u/.gitattributes +--- openjdk/.gitattributes 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.gitattributes 2025-05-09 10:05:55.520290522 +0800 +@@ -0,0 +1 @@ ++* -text +diff -uNr openjdk/.gitignore afu11u/.gitignore +--- openjdk/.gitignore 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/.gitignore 2025-05-09 10:05:55.520290522 +0800 +@@ -0,0 +1,15 @@ ++/build/ ++/dist/ ++/.idea/ ++nbproject/private/ ++/webrev ++/.src-rev ++/.jib/ ++.DS_Store ++.metadata/ ++.recommenders/ ++test/nashorn/script/external ++test/nashorn/lib ++NashornProfile.txt ++**/JTreport/** ++**/JTwork/** +diff -uNr openjdk/idegen.sh afu11u/idegen.sh +--- openjdk/idegen.sh 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/idegen.sh 2025-05-09 10:05:55.524290522 +0800 +@@ -0,0 +1,6 @@ ++#!/bin/bash ++rep=$(pwd) ++echo $rep ++sed -i "s!/home/yj/work/swjdk/afu11u-yj!$rep!g" compile_commands.json ++git update-index --assume-unchanged compile_commands.json ++ +diff -uNr openjdk/make/autoconf/build-aux/autoconf-config.guess afu11u/make/autoconf/build-aux/autoconf-config.guess +--- openjdk/make/autoconf/build-aux/autoconf-config.guess 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/autoconf/build-aux/autoconf-config.guess 2025-05-09 10:05:55.532290523 +0800 +@@ -907,6 +907,9 @@ + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; ++ sw_64:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ +diff -uNr openjdk/make/autoconf/build-performance.m4 afu11u/make/autoconf/build-performance.m4 +--- openjdk/make/autoconf/build-performance.m4 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/autoconf/build-performance.m4 2025-05-09 10:05:55.532290523 +0800 +@@ -32,6 +32,10 @@ + if test -f /proc/cpuinfo; then + # Looks like a Linux (or cygwin) system + NUM_CORES=`cat /proc/cpuinfo | grep -c processor` ++ if test "$NUM_CORES" -eq "0"; then ++ # ZHJ20170103 for SW64 ++ NUM_CORES=`cat /proc/cpuinfo | grep "cpus active" | awk '{ print [$]4 }'` ++ fi + FOUND_CORES=yes + elif test -x /usr/sbin/psrinfo; then + # Looks like a Solaris system +diff -uNr openjdk/make/autoconf/flags-cflags.m4 afu11u/make/autoconf/flags-cflags.m4 +--- openjdk/make/autoconf/flags-cflags.m4 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/autoconf/flags-cflags.m4 2025-05-09 10:06:54.164292503 +0800 +@@ -250,9 +250,9 @@ + C_O_FLAG_NORM="-xO2 -Wc,-Qrm-s -Wc,-Qiselect-T0" + fi + elif test "x$TOOLCHAIN_TYPE" = xgcc; then +- C_O_FLAG_HIGHEST_JVM="-O3" +- C_O_FLAG_HIGHEST="-O3" +- C_O_FLAG_HI="-O3" ++ C_O_FLAG_HIGHEST_JVM="-O2" ++ C_O_FLAG_HIGHEST="-O2" ++ C_O_FLAG_HI="-O2" + C_O_FLAG_NORM="-O2" + C_O_FLAG_SIZE="-Os" + C_O_FLAG_DEBUG="-O0" +diff -uNr openjdk/make/autoconf/hotspot.m4 afu11u/make/autoconf/hotspot.m4 +--- openjdk/make/autoconf/hotspot.m4 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/autoconf/hotspot.m4 2025-05-09 10:05:55.536290523 +0800 +@@ -421,6 +421,7 @@ + # Only enable jvmci on x86_64, sparcv9 and aarch64 + if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \ + test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \ ++ test "x$OPENJDK_TARGET_CPU" = "xsw64" || \ + test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then + AC_MSG_RESULT([yes]) + JVM_FEATURES_jvmci="jvmci" +diff -uNr openjdk/make/autoconf/platform.m4 afu11u/make/autoconf/platform.m4 +--- openjdk/make/autoconf/platform.m4 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/autoconf/platform.m4 2025-05-09 10:06:54.168292503 +0800 +@@ -162,6 +162,12 @@ + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=big + ;; ++ sw_64) ++ VAR_CPU=sw64 ++ VAR_CPU_ARCH=sw64 ++ VAR_CPU_BITS=64 ++ VAR_CPU_ENDIAN=little ++ ;; + *) + AC_MSG_ERROR([unsupported cpu $1]) + ;; +@@ -534,6 +540,8 @@ + HOTSPOT_$1_CPU=ppc_64 + elif test "x$OPENJDK_$1_CPU" = xppc64le; then + HOTSPOT_$1_CPU=ppc_64 ++ elif test "x$OPENJDK_$1_CPU" = xsw64; then ++ HOTSPOT_$1_CPU=sw_64 + fi + AC_SUBST(HOTSPOT_$1_CPU) + +@@ -554,6 +562,8 @@ + HOTSPOT_$1_CPU_DEFINE=PPC64 + elif test "x$OPENJDK_$1_CPU" = xppc64le; then + HOTSPOT_$1_CPU_DEFINE=PPC64 ++ elif test "x$OPENJDK_$1_CPU" = xsw64; then ++ HOTSPOT_$1_CPU_DEFINE=SW64 + + # The cpu defines below are for zero, we don't support them directly. + elif test "x$OPENJDK_$1_CPU" = xsparc; then +diff -uNr openjdk/make/CompileJavaModules.gmk afu11u/make/CompileJavaModules.gmk +--- openjdk/make/CompileJavaModules.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/CompileJavaModules.gmk 2025-05-09 10:05:55.528290522 +0800 +@@ -434,6 +434,7 @@ + + jdk.internal.vm.compiler_ADD_JAVAC_FLAGS += -parameters -XDstringConcat=inline \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.aarch64=jdk.internal.vm.compiler \ ++ --add-exports jdk.internal.vm.ci/jdk.vm.ci.sw64=jdk.internal.vm.compiler \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.amd64=jdk.internal.vm.compiler \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.code=jdk.internal.vm.compiler \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.code.site=jdk.internal.vm.compiler \ +@@ -441,6 +442,7 @@ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.common=jdk.internal.vm.compiler \ + --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.sw64=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 \ +@@ -460,6 +462,7 @@ + org.graalvm.compiler.api.directives.test \ + org.graalvm.compiler.api.test \ + org.graalvm.compiler.asm.aarch64.test \ ++ org.graalvm.compiler.asm.sw64.test \ + org.graalvm.compiler.asm.amd64.test \ + org.graalvm.compiler.asm.sparc.test \ + org.graalvm.compiler.asm.test \ +@@ -497,6 +500,7 @@ + + jdk.aot_ADD_JAVAC_FLAGS += -parameters -XDstringConcat=inline \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.aarch64=jdk.internal.vm.compiler,jdk.aot \ ++ --add-exports jdk.internal.vm.ci/jdk.vm.ci.sw64=jdk.internal.vm.compiler,jdk.aot \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.amd64=jdk.internal.vm.compiler,jdk.aot \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.code=jdk.internal.vm.compiler,jdk.aot \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.code.site=jdk.internal.vm.compiler,jdk.aot \ +@@ -504,6 +508,7 @@ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.common=jdk.internal.vm.compiler,jdk.aot \ + --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.sw64=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 \ +diff -uNr openjdk/make/conf/jib-profiles.js afu11u/make/conf/jib-profiles.js +--- openjdk/make/conf/jib-profiles.js 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/conf/jib-profiles.js 2025-05-09 10:06:54.168292503 +0800 +@@ -233,7 +233,7 @@ + common.main_profile_names = [ + "linux-x64", "linux-x86", "macosx-x64", "solaris-x64", + "solaris-sparcv9", "windows-x64", "windows-x86", +- "linux-aarch64", "linux-arm32", "linux-arm64", "linux-arm-vfp-hflt", ++ "linux-aarch64", "linux-sw64", "linux-arm32", "linux-arm64", "linux-arm-vfp-hflt", + "linux-arm-vfp-hflt-dyn" + ]; + +@@ -460,6 +460,17 @@ + ], + }, + ++ "linux-sw64": { ++ target_os: "linux", ++ target_cpu: "sw64", ++ build_cpu: "sw64", ++ dependencies: ["devkit", "build_devkit", "cups"], ++ configure_args: [ ++ "--openjdk-target=sw_64-linux-gnu", "--with-freetype=bundled", ++ "--disable-warnings-as-errors", "--with-cpu-port=sw64", ++ ], ++ }, ++ + "linux-arm64": { + target_os: "linux", + target_cpu: "aarch64", +diff -uNr openjdk/make/devkit/Tools.gmk afu11u/make/devkit/Tools.gmk +--- openjdk/make/devkit/Tools.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/devkit/Tools.gmk 2025-05-09 10:05:55.664290527 +0800 +@@ -286,6 +286,10 @@ + + PATHPRE = PATH=$(PATHEXT)$(PATH) + NUM_CORES := $(shell cat /proc/cpuinfo | grep -c processor) ++# ZHJ20170103 for SW64 ++if test "$NUM_CORES" -eq "0"; then ++ NUM_CORES=`cat /proc/cpuinfo | grep "cpus active" | awk '{print $4}'` ++fi + BUILDPAR = -j$(NUM_CORES) + + # Default commands to when making +diff -uNr openjdk/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk afu11u/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk +--- openjdk/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk 2025-05-09 10:05:55.668290527 +0800 +@@ -39,12 +39,14 @@ + org.graalvm.compiler.code \ + org.graalvm.compiler.core \ + org.graalvm.compiler.core.aarch64 \ ++ org.graalvm.compiler.core.sw64 \ + 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.sw64 \ + org.graalvm.compiler.hotspot.amd64 \ + org.graalvm.compiler.hotspot.sparc \ + org.graalvm.compiler.graph \ +@@ -56,6 +58,7 @@ + org.graalvm.compiler.nodes \ + org.graalvm.compiler.replacements \ + org.graalvm.compiler.replacements.aarch64 \ ++ org.graalvm.compiler.replacements.sw64 \ + org.graalvm.compiler.replacements.amd64 \ + org.graalvm.compiler.phases \ + org.graalvm.compiler.phases.common \ +@@ -82,6 +85,7 @@ + ADD_EXPORTS := \ + --add-modules jdk.internal.vm.ci \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.aarch64=jdk.internal.vm.compiler \ ++ --add-exports jdk.internal.vm.ci/jdk.vm.ci.sw64=jdk.internal.vm.compiler \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.amd64=jdk.internal.vm.compiler \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.code=jdk.internal.vm.compiler \ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.code.site=jdk.internal.vm.compiler \ +@@ -89,6 +93,7 @@ + --add-exports jdk.internal.vm.ci/jdk.vm.ci.common=jdk.internal.vm.compiler \ + --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.sw64=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 \ +diff -uNr openjdk/make/hotspot/ide/CreateVSProject.gmk afu11u/make/hotspot/ide/CreateVSProject.gmk +--- openjdk/make/hotspot/ide/CreateVSProject.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/hotspot/ide/CreateVSProject.gmk 2025-05-09 10:05:55.672290527 +0800 +@@ -69,6 +69,7 @@ + + IGNORED_PLATFORMS_ARGS := \ + -ignorePath aarch64 \ ++ -ignorePath sw64 \ + -ignorePath aix \ + -ignorePath arm \ + -ignorePath bsd \ +diff -uNr openjdk/make/hotspot/lib/JvmFeatures.gmk afu11u/make/hotspot/lib/JvmFeatures.gmk +--- openjdk/make/hotspot/lib/JvmFeatures.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/hotspot/lib/JvmFeatures.gmk 2025-05-09 10:05:55.672290527 +0800 +@@ -129,7 +129,7 @@ + ifneq ($(call check-jvm-feature, aot), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_AOT=0 + JVM_EXCLUDE_FILES += \ +- compiledIC_aot_x86_64.cpp compiledIC_aot_aarch64.cpp \ ++ compiledIC_aot_x86_64.cpp compiledIC_aot_aarch64.cpp compiledIC_aot_sw64.cpp \ + compilerRuntime.cpp aotCodeHeap.cpp aotCompiledMethod.cpp \ + aotLoader.cpp compiledIC_aot.cpp + endif +diff -uNr openjdk/make/launcher/Launcher-jdk.aot.gmk afu11u/make/launcher/Launcher-jdk.aot.gmk +--- openjdk/make/launcher/Launcher-jdk.aot.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/launcher/Launcher-jdk.aot.gmk 2025-05-09 10:05:55.700290528 +0800 +@@ -32,6 +32,7 @@ + MAIN_CLASS := jdk.tools.jaotc.Main, \ + EXTRA_JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \ + --add-exports=jdk.internal.vm.ci/jdk.vm.ci.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ ++ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.sw64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ + --add-exports=jdk.internal.vm.ci/jdk.vm.ci.amd64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ + --add-exports=jdk.internal.vm.ci/jdk.vm.ci.code=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ + --add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.site=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ +@@ -39,9 +40,10 @@ + --add-exports=jdk.internal.vm.ci/jdk.vm.ci.common=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ + --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ + , \ +- JAVA_ARGS := --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \ ++ JAVA_ARGS := \ + --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.sw64=$(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) \ +diff -uNr openjdk/make/lib/Lib-jdk.crypto.ec.gmk afu11u/make/lib/Lib-jdk.crypto.ec.gmk +--- openjdk/make/lib/Lib-jdk.crypto.ec.gmk 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/make/lib/Lib-jdk.crypto.ec.gmk 2025-05-09 10:05:55.704290528 +0800 +@@ -43,7 +43,7 @@ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ + OPTIMIZATION := LOW, \ + CFLAGS := $(BUILD_LIBSUNEC_CFLAGS_JDKLIB) \ +- -DMP_API_COMPATIBLE, \ ++ -DMP_API_COMPATIBLE -DNSS_ECC_MORE_THAN_SUITE_B, \ + CXXFLAGS := $(BUILD_LIBSUNEC_CXXFLAGS_JDKLIB), \ + DISABLED_WARNINGS_gcc := sign-compare implicit-fallthrough, \ + DISABLED_WARNINGS_microsoft := 4101 4244 4146 4018, \ +diff -uNr openjdk/make/RunTestsPrebuilt.gmk afu11u/make/RunTestsPrebuilt.gmk +--- openjdk/make/RunTestsPrebuilt.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/RunTestsPrebuilt.gmk 2025-05-09 10:05:55.532290523 +0800 +@@ -223,6 +223,10 @@ + # Check number of cores and memory in MB + ifeq ($(OPENJDK_TARGET_OS), linux) + NUM_CORES := $(shell $(CAT) /proc/cpuinfo | $(GREP) -c processor) ++ # ZHJ20170103 for SW64 ++ if test "$NUM_CORES" -eq "0"; then ++ NUM_CORES=`cat /proc/cpuinfo | grep "cpus active" | awk '{print $4}'` ++ fi + MEMORY_SIZE := $(shell \ + $(EXPR) `$(CAT) /proc/meminfo | $(GREP) MemTotal | $(AWK) '{print $$2}'` / 1024 \ + ) +diff -uNr openjdk/make/test/JtregGraalUnit.gmk afu11u/make/test/JtregGraalUnit.gmk +--- openjdk/make/test/JtregGraalUnit.gmk 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/make/test/JtregGraalUnit.gmk 2025-05-09 10:05:55.712290529 +0800 +@@ -62,6 +62,7 @@ + $(SRC_DIR)/org.graalvm.compiler.api.directives.test/src \ + $(SRC_DIR)/org.graalvm.compiler.api.test/src \ + $(SRC_DIR)/org.graalvm.compiler.asm.aarch64.test/src \ ++ $(SRC_DIR)/org.graalvm.compiler.asm.sw64.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 \ +diff -uNr openjdk/native_configure afu11u/native_configure +--- openjdk/native_configure 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/native_configure 2025-05-09 10:06:54.184292503 +0800 +@@ -0,0 +1,28 @@ ++#!/bin/bash ++level=${1?usage: $0 release/slowdebug} ++ # --with-jvm-variants JVM variants (separated by commas) to build ++ # (server,client,minimal,core,zero,custom) [server] ++ # --with-jvm-features "aot cds cmsgc compiler1 compiler2 epsilongc g1gc graal jfr \ ++ # jni-check jvmci jvmti management nmt parallelgc serialgc services vm-structs zgc" ++ # --enable-aot=no \ ++ # --enable-cds=no \ ++ # --disable-ccache \ ++ builddate=`date +%Y-%m-%d` ++ buildtag=sw1.3.0 ++ bash configure \ ++ --with-freetype=bundled \ ++ --with-zlib=bundled \ ++ --with-native-debug-symbols=internal \ ++ --with-debug-level=$level \ ++ --with-jvm-variants=custom \ ++ --with-jvm-features=serialgc,vm-structs,parallelgc,compiler2,management,nmt,g1gc,cmsgc,jvmti,services,jni-check,jfr \ ++ --with-version-date=$builddate \ ++ --with-version-opt=$buildtag \ ++ --with-version-pre=no \ ++ --enable-sjavac=no \ ++ --disable-javac-server \ ++ --disable-warnings-as-errors \ ++ --with-extra-cflags=" -mieee -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=type-limits -Wno-error=format-security -Wno-error=conversion-null -Wno-error=sign-compare -Wno-error=int-to-pointer-cast -mgprel-size=32" \ ++ --with-extra-cxxflags="-mieee -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=type-limits -Wno-error=format-security -Wno-error=conversion-null -Wno-error=sign-compare -Wno-error=int-to-pointer-cast -mgprel-size=32" \ ++ --with-extra-ldflags=" -mieee -Wl,-no-relax" ++ +diff -uNr openjdk/README afu11u/README +--- openjdk/README 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/README 2025-05-09 10:05:55.520290522 +0800 +@@ -0,0 +1,21 @@ ++Read READYJ.md for compilation guild! ++ ++Welcome to the JDK! ++=================== ++ ++For information about building the JDK, including how to retrieve all ++of the source code, please see either of these files: ++ ++ * doc/building.html (html version) ++ * doc/building.md (markdown version) ++ ++See http://openjdk.java.net/ for more information about the OpenJDK ++Community and the JDK. ++ ++=================== ++ ++如果你不能在6B服务器上顺利执行`bash native_configure release`命令,观察生成的config.log,如果出现 unrecongnized command line option '-mgprel-size=32',说明编译使用的gcc版本较低。 ++ ++解决办法: ++ ++修改native_configure文件,删除2处 "-mgprel-size=32",删除1处 "-Wl,-no-relax" +diff -uNr openjdk/READSW.md afu11u/READSW.md +--- openjdk/READSW.md 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/READSW.md 2025-05-09 10:05:55.520290522 +0800 +@@ -0,0 +1,12 @@ ++## build whole jdk ++copy a jdk to root dir, named like jdk-sw-c ++native compile: ++1.export PATH=./jdk-sw-c/bin:$PATH ++2.bash native_configure release ++3.make CONF=linux-sw64-normal-custom-release images ++ ++If the build environment no git, you must do "bash version_patch.sh" on the environment has git to get the git id, ++then copy the swjdk11u src to the target envirinment. ++ 1. bash native_configure release(slowdebug) ++ 2. make all ++ +diff -uNr openjdk/READYJ.md afu11u/READYJ.md +--- openjdk/READYJ.md 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/READYJ.md 2025-05-09 10:05:55.520290522 +0800 +@@ -0,0 +1,16 @@ ++## only build hotspot ++use cross compile: ++使用bash cross_configure slowdebug做配置 ++ ++copy a jdk to root dir, named like jdk-sw-c ++edit cross_compile to modify remote_ip, then ++使用bash cross_compile slowdebug jdk-sw-c 做编译 ++ ++## build whole jdk ++use native compile: ++copy a swjdk11 to the root of this repos and name it jdk-sw-c. ++>> export PATH=./jdk-sw-c/bin:$PATH ++>> bash native_configure release ++>> make CONF=linux-sw64-normal-custom-release images ++on x86: ++>> cp -r build/linux-sw64-normal-custom-release/images/jdk jdk-sw-c +diff -uNr openjdk/src/hotspot/cpu/sw64/abstractInterpreter_sw64.cpp afu11u/src/hotspot/cpu/sw64/abstractInterpreter_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/abstractInterpreter_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/abstractInterpreter_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,161 @@ ++/* ++ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "interpreter/interpreter.hpp" ++#include "oops/constMethod.hpp" ++#include "oops/method.hpp" ++#include "runtime/frame.inline.hpp" ++#include "utilities/align.hpp" ++#include "utilities/debug.hpp" ++#include "utilities/macros.hpp" ++ ++ ++// asm based interpreter deoptimization helpers ++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. ++ ++ // fixed size of an interpreter frame: ++ int overhead = frame::sender_sp_offset - ++ frame::interpreter_frame_initial_sp_offset; ++ // Our locals were accounted for by the caller (or last_frame_adjust ++ // on the transistion) Since the callee parameters already account ++ // for the callee's params we only need to account for the extra ++ // locals. ++ int size = overhead + ++ (callee_locals - callee_params)*Interpreter::stackElementWords + ++ monitors * frame::interpreter_frame_monitor_size() + ++ temps* Interpreter::stackElementWords + extra_args; ++ ++ return 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_locals, ++ frame* caller, ++ frame* interpreter_frame, ++ bool is_top_frame, ++ bool is_bottom_frame) { ++ // The frame interpreter_frame is guaranteed to be the right size, ++ // as determined by a previous call to the size_activation() method. ++ // It is also guaranteed to be walkable even though it is in a ++ // skeletal state ++ ++ int max_locals = method->max_locals() * Interpreter::stackElementWords; ++ int extra_locals = (method->max_locals() - method->size_of_parameters()) * ++ Interpreter::stackElementWords; ++ ++#ifdef ASSERT ++ assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable"); ++#endif ++ ++ interpreter_frame->interpreter_frame_set_method(method); ++ // NOTE the difference in using sender_sp and ++ // interpreter_frame_sender_sp interpreter_frame_sender_sp is ++ // the original sp of the caller (the unextended_sp) and ++ // sender_sp is fp+8/16 (32bit/64bit) XXX ++ intptr_t* locals = interpreter_frame->sender_sp() + max_locals - 1; ++ ++#ifdef ASSERT ++ if (caller->is_interpreted_frame()) { ++ assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement"); ++ } ++#endif ++ ++ interpreter_frame->interpreter_frame_set_locals(locals); ++ BasicObjectLock* montop = interpreter_frame->interpreter_frame_monitor_begin(); ++ BasicObjectLock* monbot = montop - moncount; ++ interpreter_frame->interpreter_frame_set_monitor_end(monbot); ++ ++ // Set last_sp ++ intptr_t* esp = (intptr_t*) monbot - ++ tempcount*Interpreter::stackElementWords - ++ popframe_extra_args; ++ interpreter_frame->interpreter_frame_set_last_sp(esp); ++ ++ // All frames but the initial (oldest) interpreter frame we fill in have ++ // a value for sender_sp that allows walking the stack but isn't ++ // truly correct. Correct the value here. ++ if (extra_locals != 0 && ++ interpreter_frame->sender_sp() == ++ interpreter_frame->interpreter_frame_sender_sp()) { ++ interpreter_frame->set_interpreter_frame_sender_sp(caller->sp() + ++ extra_locals); ++ } ++ *interpreter_frame->interpreter_frame_cache_addr() = ++ method->constants()->cache(); ++ *interpreter_frame->interpreter_frame_mirror_addr() = ++ method->method_holder()->java_mirror(); ++} ++ ++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; ++} ++ ++// How much stack a method activation needs in words. ++int AbstractInterpreter::size_top_interpreter_activation(Method* method) { ++ const int entry_size = frame::interpreter_frame_monitor_size(); ++ ++ // total overhead size: entry_size + (saved rbp thru expr stack ++ // bottom). be sure to change this if you add/subtract anything ++ // to/from the overhead area ++ const int overhead_size = ++ -(frame::interpreter_frame_initial_sp_offset) + entry_size; ++ ++ const int stub_code = frame::entry_frame_after_call_words; ++ ++ const int method_stack = (method->max_locals() + method->max_stack()) * ++ Interpreter::stackElementWords; ++ return (overhead_size + method_stack + stub_code); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/ad_encode.m4 afu11u/src/hotspot/cpu/sw64/ad_encode.m4 +--- openjdk/src/hotspot/cpu/sw64/ad_encode.m4 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/ad_encode.m4 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,98 @@ ++dnl Copyright (c) 2014, Red Hat Inc. All rights reserved. ++dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++dnl ++dnl This code is free software; you can redistribute it and/or modify it ++dnl under the terms of the GNU General Public License version 2 only, as ++dnl published by the Free Software Foundation. ++dnl ++dnl This code is distributed in the hope that it will be useful, but WITHOUT ++dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++dnl version 2 for more details (a copy is included in the LICENSE file that ++dnl accompanied this code). ++dnl ++dnl You should have received a copy of the GNU General Public License version ++dnl 2 along with this work; if not, write to the Free Software Foundation, ++dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++dnl ++dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++dnl or visit www.oracle.com if you need additional information or have any ++dnl questions. ++dnl ++dnl ++dnl Process this file with m4 ad_encode.m4 to generate the load/store ++dnl patterns used in sw64.ad. ++dnl ++define(choose, `loadStore($1, &MacroAssembler::$3, $2, $4, ++ $5, $6, $7, $8);dnl ++ ++ %}')dnl ++define(access, ` ++ $3Register $1_reg = as_$3Register($$1$$reg); ++ $4choose(MacroAssembler(&cbuf), $1_reg,$2,$mem->opcode(), ++ as_Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp)')dnl ++define(load,` ++ enc_class sw64_enc_$2($1 dst, memory mem) %{dnl ++access(dst,$2,$3)')dnl ++load(iRegI,ldrsbw) ++load(iRegI,ldrsb) ++load(iRegI,ldrb) ++load(iRegL,ldrb) ++load(iRegI,ldrshw) ++load(iRegI,ldrsh) ++load(iRegI,ldrh) ++load(iRegL,ldrh) ++load(iRegI,ldrw) ++load(iRegL,ldrw) ++load(iRegL,ldrsw) ++load(iRegL,ldr) ++load(vRegF,ldrs,Float) ++load(vRegD,ldrd,Float) ++define(STORE,` ++ enc_class sw64_enc_$2($1 src, memory mem) %{dnl ++access(src,$2,$3,$4)')dnl ++define(STORE0,` ++ enc_class sw64_enc_$2`'0(memory mem) %{ ++ MacroAssembler _masm(&cbuf); ++ choose(_masm,zr,$2,$mem->opcode(), ++ as_$3Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp)')dnl ++STORE(iRegI,strb) ++STORE0(iRegI,strb) ++STORE(iRegI,strh) ++STORE0(iRegI,strh) ++STORE(iRegI,strw) ++STORE0(iRegI,strw) ++STORE(iRegL,str,, ++`// we sometimes get asked to store the stack pointer into the ++ // current thread -- we cannot do that directly on Sw64 ++ if (src_reg == r31_sp) { ++ MacroAssembler _masm(&cbuf); ++ assert(as_Register($mem$$base) == rthread, "unexpected store for sp"); ++ __ mov(rscratch2, sp); ++ src_reg = rscratch2; ++ } ++ ') ++STORE0(iRegL,str) ++STORE(vRegF,strs,Float) ++STORE(vRegD,strd,Float) ++ ++ enc_class sw64_enc_strw_immn(immN src, memory mem) %{ ++ MacroAssembler _masm(&cbuf); ++ address con = (address)$src$$constant; ++ // need to do this the hard way until we can manage relocs ++ // for 32 bit constants ++ __ movoop(rscratch2, (jobject)con); ++ if (con) __ encode_heap_oop_not_null(rscratch2); ++ choose(_masm,rscratch2,strw,$mem->opcode(), ++ as_Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp) ++ ++ enc_class sw64_enc_strw_immnk(immN src, memory mem) %{ ++ MacroAssembler _masm(&cbuf); ++ address con = (address)$src$$constant; ++ // need to do this the hard way until we can manage relocs ++ // for 32 bit constants ++ __ movoop(rscratch2, (jobject)con); ++ __ encode_klass_not_null(rscratch2); ++ choose(_masm,rscratch2,strw,$mem->opcode(), ++ as_Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp) ++ +diff -uNr openjdk/src/hotspot/cpu/sw64/assembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/assembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/assembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/assembler_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,220 @@ ++/* ++ * 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 ++#include ++ ++#include "precompiled.hpp" ++#include "asm/assembler.hpp" ++#include "asm/assembler.inline.hpp" ++#include "interpreter/interpreter.hpp" ++ ++#ifndef PRODUCT ++const unsigned long Assembler::asm_bp = 0x00007fffee09ac88; ++#endif ++ ++#include "compiler/disassembler.hpp" ++#include "memory/resourceArea.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "assembler_sw64.hpp" ++//#include "immediate_sw64.hpp" ++ ++extern "C" void entry(CodeBuffer *cb); ++ ++#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 entry(CodeBuffer *cb) { ++ ++ // { ++ // for (int i = 0; i < 256; i+=16) ++ // { ++ // printf("\"%20.20g\", ", unpack(i)); ++ // printf("\"%20.20g\", ", unpack(i+1)); ++ // } ++ // printf("\n"); ++ // } ++ ++ Assembler _masm(cb); ++ address entry = __ pc(); ++ ++ // Smoke test for assembler ++ ++} ++ ++#undef __ ++ ++#define ADDRESSEMIT(RegType, is_xx)\ ++void Address::emit(RegType ra, Assembler* as, int opcode) {\ ++ if (_mode == base_index_scale_disp) {\ ++ guarantee(_tmp != noreg, "we need a tmp reg here");\ ++ if (_scale == times_8) {\ ++ as->s8addl(_index, _base, _tmp); \ ++ } else if (_scale == times_4) {\ ++ as->s4addl(_index, _base, _tmp); \ ++ } else if (_scale == times_2) {\ ++ if (_tmp != _index) {\ ++ as->addl(_base, _index, _tmp); \ ++ as->addl(_tmp, _index, _tmp); \ ++ } else {\ ++ as->addl(_index, _index, _index); \ ++ as->addl(_base, _index, _index); \ ++ }\ ++ } else {\ ++ as->addl(_base, _index, _tmp);\ ++ }\ ++ as->emit_sw2_long(opcode| as->is_xx(ra) | as->is_mdisp(_disp) | as->is_rb(_tmp));\ ++ } else if (_mode == base_plus_disp) {\ ++ as->emit_sw2_long(opcode| as->is_xx(ra) | as->is_mdisp(_disp) | as->is_rb(_base));\ ++ } else {\ ++ ShouldNotReachHere();\ ++ }\ ++} ++ADDRESSEMIT(Register, is_ra) ++ADDRESSEMIT(FloatRegister, is_fa) ++#undef ADDRESSEMIT ++ ++// Convert the raw encoding form into the form expected by the constructor for ++// Address. An index of 30 (rsp) corresponds to having no index, so convert ++// that to noreg for the Address constructor. ++Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) { ++ RelocationHolder rspec; ++ if (disp_reloc != relocInfo::none) { ++ rspec = Relocation::spec_simple(disp_reloc); ++ } ++ bool valid_index = index != sp->encoding(); ++ if (valid_index) { ++ Address madr(as_Register(base), as_Register(index), (Address::ScaleFactor)scale, in_ByteSize(disp)); ++ madr._mode = base_index_scale_disp; ++ madr._rspec = rspec; ++ return madr; ++ } else { ++ Address madr(as_Register(base), in_ByteSize(disp)); ++ madr._mode = base_plus_disp; ++ madr._rspec = rspec; ++ return madr; ++ } ++} ++ ++int AbstractAssembler::code_fill_byte() { ++ return 0x00; ++} ++ ++// n.b. this is implemented in subclass MacroAssembler ++void Assembler::bang_stack_with_offset(int offset) { Unimplemented(); } ++ ++ ++// and now the routines called by the assembler which encapsulate the ++// above encode and decode functions ++ ++//uint32_t ++//asm_util::encode_logical_immediate(bool is32, uint64_t imm) ++//{ ++// ShouldNotReachHere(); ++// return encoding_for_logical_immediate(imm); ++//} ++ ++//unsigned Assembler::pack(double value) { ++// ShouldNotReachHere(); ++// float val = (float)value; ++// unsigned result = encoding_for_fp_immediate(val); ++// guarantee(unpack(result) == value, ++// "Invalid floating-point immediate operand"); ++// return result; ++//} ++ ++// Packed operands for Floating-point Move (immediate) ++ ++//static float unpack(unsigned value) { ++// ShouldNotReachHere(); ++// return 0; ++//} ++ ++AddressLiteral::AddressLiteral(address target, relocInfo::relocType rtype) { ++ _is_lval = false; ++ _target = target; ++ switch (rtype) { ++ case relocInfo::oop_type: ++ case relocInfo::metadata_type: ++ // Oops are a special case. Normally they would be their own section ++ // but in cases like icBuffer they are literals in the code stream that ++ // we don't have a section for. We use none so that we get a literal address ++ // which is always patchable. ++ break; ++ case relocInfo::external_word_type: ++ _rspec = external_word_Relocation::spec(target); ++ break; ++ case relocInfo::internal_word_type: ++ _rspec = internal_word_Relocation::spec(target); ++ break; ++ case relocInfo::opt_virtual_call_type: ++ _rspec = opt_virtual_call_Relocation::spec(); ++ break; ++ case relocInfo::static_call_type: ++ _rspec = static_call_Relocation::spec(); ++ break; ++ case relocInfo::runtime_call_type: ++ _rspec = runtime_call_Relocation::spec(); ++ break; ++ case relocInfo::poll_type: ++ case relocInfo::poll_return_type: ++ _rspec = Relocation::spec_simple(rtype); ++ break; ++ case relocInfo::none: ++ break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++} ++ ++#ifdef ASSERT ++void Assembler::check_relocation(RelocationHolder const& rspec, int format) { ++ address inst = inst_mark(); ++ assert(inst != NULL && inst <= pc(), "must point to beginning of instruction"); ++// address opnd; ++ ++ Relocation* r = rspec.reloc(); ++ if (r->type() == relocInfo::none) { ++ return; ++ } else if (r->is_call() || format == call32_operand) { ++ // assert(format == imm32_operand, "cannot specify a nonzero format"); ++// opnd = locate_operand(inst, call32_operand);// yj todo ++ } else if (r->is_data()) { ++// assert(format == imm_operand || format == disp32_operand ++// LP64_ONLY(|| format == narrow_oop_operand), "format ok"); ++// opnd = locate_operand(inst, (WhichOperand)format);// yj todo ++ } else { ++// assert(format == imm_operand, "cannot specify a format"); ++ return; ++ } ++// assert(opnd == pc(), "must put operand where relocs can find it"); ++} ++#endif // ASSERT +\ 文件尾没有换行符 +diff -uNr openjdk/src/hotspot/cpu/sw64/assembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/assembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/assembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/assembler_sw64.hpp 2025-05-09 10:06:54.192292504 +0800 +@@ -0,0 +1,2005 @@ ++/* ++ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2019, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_ASSEMBLER_SW64_HPP ++#define CPU_SW64_VM_ASSEMBLER_SW64_HPP ++ ++#include "asm/register.hpp" ++#include "runtime/vm_version.hpp" ++ ++// Define some macros to help SW64 Instructions' implementation. ++#define OP(x) (((x) & 0x3F) << 26) ++#define PCD(oo) (OP(oo)) ++#define OPMEM(oo) (OP(oo)) ++#define BRA(oo) (OP(oo)) ++#define OFP(oo,ff) (OP(oo) | (((ff) & 0xFF) << 5)) ++#define FMA(oo,ff) (OP(oo) | (((ff) & 0x3F) << 10)) ++#define MFC(oo,ff) (OP(oo) | ((ff) & 0xFFFF)) ++#define OPR(oo,ff) (OP(oo) | (((ff) & 0xFF) << 5)) ++#define OPRL(oo,ff) (OP(oo) | (((ff) & 0xFF) << 5)) ++#define TOPR(oo,ff) (OP(oo) | (((ff) & 0x07) << 10)) ++#define TOPRL(oo,ff) (OP(oo) | (((ff) & 0x07) << 10)) ++ ++#define ATMEM(oo,h) (OP(oo) | (((h) & 0xF) << 12)) ++#define PRIRET(oo,h) (OP(oo) | (((h) & 0x1) << 20)) ++#define EV6HWMEM(oo,ff) (OP(oo) | (((ff) & 0xF) << 12)) ++#define CSR(oo,ff) (OP(oo) | (((ff) & 0xFF) << 8)) ++ ++#define LOGX(oo,ff) (OP(oo) | (((ff) & 0x3F) << 10)) ++#define PSE_LOGX(oo,ff) (OP(oo) | (((ff) & 0x3F) << 10) | (((ff) >> 0x6) << 26 ) | 0x3E0 ) ++ ++REGISTER_DECLARATION(Register, V0, i0); ++REGISTER_DECLARATION(Register, T0, i1); ++REGISTER_DECLARATION(Register, T1, i2); ++REGISTER_DECLARATION(Register, T2, i3); ++REGISTER_DECLARATION(Register, T3, i4); ++REGISTER_DECLARATION(Register, T4, i5); ++REGISTER_DECLARATION(Register, T5, i6); ++REGISTER_DECLARATION(Register, T6, i7); ++REGISTER_DECLARATION(Register, T7, i8); ++REGISTER_DECLARATION(Register, S0, i9); ++REGISTER_DECLARATION(Register, S1, i10); ++REGISTER_DECLARATION(Register, S2, i11); ++REGISTER_DECLARATION(Register, S3, i12); ++REGISTER_DECLARATION(Register, S4, i13); ++REGISTER_DECLARATION(Register, S5, i14); ++REGISTER_DECLARATION(Register, FP, i15); ++REGISTER_DECLARATION(Register, A0, i16); ++REGISTER_DECLARATION(Register, A1, i17); ++REGISTER_DECLARATION(Register, A2, i18); ++REGISTER_DECLARATION(Register, A3, i19); ++REGISTER_DECLARATION(Register, A4, i20); ++REGISTER_DECLARATION(Register, A5, i21); ++REGISTER_DECLARATION(Register, T8, i22); ++REGISTER_DECLARATION(Register, T9, i23); ++REGISTER_DECLARATION(Register, T10, i24); ++REGISTER_DECLARATION(Register, T11, i25); ++REGISTER_DECLARATION(Register, RA, i26); ++REGISTER_DECLARATION(Register, T12, i27); ++REGISTER_DECLARATION(Register, AT, i28); ++REGISTER_DECLARATION(Register, GP, i29); ++REGISTER_DECLARATION(Register, SP, i30); ++REGISTER_DECLARATION(Register, R0, i31); ++ ++REGISTER_DECLARATION(FloatRegister, F0, f0); ++REGISTER_DECLARATION(FloatRegister, F1, f1); ++REGISTER_DECLARATION(FloatRegister, F2, f2); ++REGISTER_DECLARATION(FloatRegister, F3, f3); ++REGISTER_DECLARATION(FloatRegister, F4, f4); ++REGISTER_DECLARATION(FloatRegister, F5, f5); ++REGISTER_DECLARATION(FloatRegister, F6, f6); ++REGISTER_DECLARATION(FloatRegister, F7, f7); ++REGISTER_DECLARATION(FloatRegister, F8, f8); ++REGISTER_DECLARATION(FloatRegister, F9, f9); ++REGISTER_DECLARATION(FloatRegister, F10, f10); ++REGISTER_DECLARATION(FloatRegister, F11, f11); ++REGISTER_DECLARATION(FloatRegister, F12, f12); ++REGISTER_DECLARATION(FloatRegister, F13, f13); ++REGISTER_DECLARATION(FloatRegister, F14, f14); ++REGISTER_DECLARATION(FloatRegister, F15, f15); ++REGISTER_DECLARATION(FloatRegister, F16, f16); ++REGISTER_DECLARATION(FloatRegister, F17, f17); ++REGISTER_DECLARATION(FloatRegister, F18, f18); ++REGISTER_DECLARATION(FloatRegister, F19, f19); ++REGISTER_DECLARATION(FloatRegister, F20, f20); ++REGISTER_DECLARATION(FloatRegister, F21, f21); ++REGISTER_DECLARATION(FloatRegister, F22, f22); ++REGISTER_DECLARATION(FloatRegister, F23, f23); ++REGISTER_DECLARATION(FloatRegister, F24, f24); ++REGISTER_DECLARATION(FloatRegister, F25, f25); ++REGISTER_DECLARATION(FloatRegister, F26, f26); ++REGISTER_DECLARATION(FloatRegister, F27, f27); ++REGISTER_DECLARATION(FloatRegister, F28, f28); ++REGISTER_DECLARATION(FloatRegister, F29, f29); ++REGISTER_DECLARATION(FloatRegister, F30, f30); ++REGISTER_DECLARATION(FloatRegister, F31, f31); ++ ++////REGISTER_DECLARATION(Register, c_rarg0, i0); ++REGISTER_DECLARATION(Register, c_rarg0, A0); ++REGISTER_DECLARATION(Register, c_rarg1, A1); ++REGISTER_DECLARATION(Register, c_rarg2, A2); ++REGISTER_DECLARATION(Register, c_rarg3, A3); ++REGISTER_DECLARATION(Register, c_rarg4, A4); ++REGISTER_DECLARATION(Register, c_rarg5, A5); ++ ++REGISTER_DECLARATION(FloatRegister, c_farg0, F16); ++REGISTER_DECLARATION(FloatRegister, c_farg1, F17); ++REGISTER_DECLARATION(FloatRegister, c_farg2, F18); ++REGISTER_DECLARATION(FloatRegister, c_farg3, F19); ++REGISTER_DECLARATION(FloatRegister, c_farg4, F20); ++REGISTER_DECLARATION(FloatRegister, c_farg5, F21); ++ ++// Symbolically name the register arguments used by the Java calling convention. ++// We have control over the convention for java so we can do what we please. ++// What pleases us is to offset the java calling convention so that when ++// we call a suitable jni method the arguments are lined up and we don't ++// have to do much shuffling. A suitable jni method is non-static and a ++// small number of arguments ++// ++// |--------------------------------------------------------------------| ++// | c_rarg0 c_rarg1 c_rarg2 c_rarg3 c_rarg4 c_rarg5 c_rarg6 c_rarg7 | ++// |--------------------------------------------------------------------| ++// | r0 r1 r2 r3 r4 r5 r6 r7 | ++// |--------------------------------------------------------------------| ++// | j_rarg7 j_rarg0 j_rarg1 j_rarg2 j_rarg3 j_rarg4 j_rarg5 j_rarg6 | ++// |--------------------------------------------------------------------| ++ ++ ++REGISTER_DECLARATION(Register, j_rarg0, c_rarg1); ++REGISTER_DECLARATION(Register, j_rarg1, c_rarg2); ++REGISTER_DECLARATION(Register, j_rarg2, c_rarg3); ++REGISTER_DECLARATION(Register, j_rarg3, c_rarg4); ++REGISTER_DECLARATION(Register, j_rarg4, c_rarg5); ++REGISTER_DECLARATION(Register, j_rarg5, c_rarg0); ++ ++// Java floating args are passed as per C ++ ++REGISTER_DECLARATION(FloatRegister, j_farg0, F16); ++REGISTER_DECLARATION(FloatRegister, j_farg1, F17); ++REGISTER_DECLARATION(FloatRegister, j_farg2, F18); ++REGISTER_DECLARATION(FloatRegister, j_farg3, F19); ++REGISTER_DECLARATION(FloatRegister, j_farg4, F20); ++REGISTER_DECLARATION(FloatRegister, j_farg5, F21); ++ ++// registers used to hold VM data either temporarily within a method ++// or across method calls ++ ++// volatile (caller-save) registers ++ ++// r8 is used for indirect result location return ++// we use it and r9 as scratch registers ++REGISTER_DECLARATION(Register, rscratch1, T5); ++REGISTER_DECLARATION(Register, rscratch2, T6); ++REGISTER_DECLARATION(Register, rscratch3, T11); ++REGISTER_DECLARATION(Register, rscratch4, AT); ++//TODO:need delete, we should not use rscratch1_GP & rscratch2_AT, we should use rcc or rscratch4 to replace jzy ++REGISTER_DECLARATION(Register, rscratch1_GP, GP); ++REGISTER_DECLARATION(Register, rscratch2_AT, AT); ++ ++ ++// non-volatile (callee-save) registers are r16-29 ++// of which the following are dedicated global state ++ ++// link register ++REGISTER_DECLARATION(Register, lr, RA); ++// frame pointer ++REGISTER_DECLARATION(Register, rfp, FP); ++ ++REGISTER_DECLARATION(Register, rbcp, S0); ++REGISTER_DECLARATION(Register, rlocals, S1); ++REGISTER_DECLARATION(Register, rthread, S2); ++REGISTER_DECLARATION(Register, rmethod, S3); ++REGISTER_DECLARATION(Register, rsender, S4); ++REGISTER_DECLARATION(Register, r12_heapbase, S5); ++ ++REGISTER_DECLARATION(Register, rdispatch, T8); ++REGISTER_DECLARATION(Register, rnext, T10); ++REGISTER_DECLARATION(Register, rmonitors, T11); ++//REGISTER_DECLARATION(Register, rcpool, T12); //??? ++REGISTER_DECLARATION(Register, pv, T12); // as target procedure, maybe be used as temp register ++ ++REGISTER_DECLARATION(Register, esp, SP); ++REGISTER_DECLARATION(Register, rcc, GP); ++ ++REGISTER_DECLARATION(Register, FSR, V0); ++REGISTER_DECLARATION(Register, SSR, T4); ++REGISTER_DECLARATION(FloatRegister, FSF, f0); ++REGISTER_DECLARATION(FloatRegister, SSF, f1); ++REGISTER_DECLARATION(FloatRegister, FTF, f14); ++REGISTER_DECLARATION(FloatRegister, FcmpRES, f29); //TODO:need delete jzy ++REGISTER_DECLARATION(FloatRegister, fcc, f29); ++REGISTER_DECLARATION(FloatRegister, fscratch1, f28); ++REGISTER_DECLARATION(FloatRegister, fzero, f31); ++ ++// x86 GPR simulation ++REGISTER_DECLARATION(Register, rax, V0); ++REGISTER_DECLARATION(Register, rdi, A0); ++REGISTER_DECLARATION(Register, rsi, A1); ++REGISTER_DECLARATION(Register, rdx, A2); ++REGISTER_DECLARATION(Register, rcx, A3); ++REGISTER_DECLARATION(Register, r8, A4); ++REGISTER_DECLARATION(Register, r9, A5); ++REGISTER_DECLARATION(Register, rbx, S3); ++REGISTER_DECLARATION(Register, rbp, FP); ++REGISTER_DECLARATION(Register, r12, S5); ++REGISTER_DECLARATION(Register, r13, S0); ++REGISTER_DECLARATION(Register, r14, S1); ++REGISTER_DECLARATION(Register, r15, S2); ++REGISTER_DECLARATION(Register, r10, T5); ++REGISTER_DECLARATION(Register, r11, T6); ++REGISTER_DECLARATION(Register, rsp, SP); ++#define OPT_SAFEPOINT 1 ++ ++#define assert_cond(ARG1) assert(ARG1, #ARG1) ++ ++class Assembler; ++ ++class ArrayAddress; ++ ++// Addressing modes ++class Address { ++public: ++ enum ScaleFactor { ++ no_scale = -1, ++ times_1 = 0, ++ times_2 = 1, ++ times_4 = 2, ++ times_8 = 3, ++ times_ptr = times_8 ++ }; ++ ++ static ScaleFactor times(int size) { ++ assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size"); ++ if (size == 8) return times_8; ++ if (size == 4) return times_4; ++ if (size == 2) return times_2; ++ return times_1; ++ } ++ ++ static int scale_size(ScaleFactor scale) { ++ assert(scale != no_scale, ""); ++ assert(((1 << (int)times_1) == 1 && ++ (1 << (int)times_2) == 2 && ++ (1 << (int)times_4) == 4 && ++ (1 << (int)times_8) == 8), ""); ++ return (1 << (int)scale); ++ } ++ ++ enum mode { base_plus_disp, base_index_scale_disp }; ++ ++ private: ++ Register _base; ++ Register _index; ++ Register _tmp; ++ ScaleFactor _scale; ++ long _offset; ++ int _disp;//why int not long? jzy ++ enum mode _mode; ++ ++ RelocationHolder _rspec; ++ ++ // Typically we use AddressLiterals we want to use their rval ++ // However in some situations we want the lval (effect address) of ++ // the item. We provide a special factory for making those lvals. ++ bool _is_lval; ++ ++ // If the target is far we'll need to load the ea of this to a ++ // register to reach it. Otherwise if near we can do PC-relative ++ // addressing. ++ address _target; ++ ++ public: ++ Address() ++ : _base(noreg), ++ _disp(0) { ++ } ++ ++ Address(Register base, Register index, ScaleFactor scale, int disp = 0) ++ : _base (base), ++ _index(index), ++ _scale(scale), ++ _disp (disp), ++ _mode (base_index_scale_disp), ++ _tmp (noreg) { ++ assert(!index->is_valid() == (scale == Address::no_scale), ++ "inconsistent address"); ++ } ++ ++ Address(Register base, RegisterOrConstant index, ScaleFactor scale = times_1, int disp = 0) ++ : _base (base), ++ _index(index.register_or_noreg()), ++ _scale(scale), ++ _disp (disp + (index.constant_or_zero() * scale_size(scale))), ++ _mode (index.is_constant() ? base_plus_disp : base_index_scale_disp), ++ _tmp (noreg){ ++ if (!index.is_register()) scale = Address::no_scale; ++ assert(!_index->is_valid() == (scale == Address::no_scale), ++ "inconsistent address"); ++ } ++ ++ Address(Register base, int disp = 0) ++ : _base(base), ++ _index(noreg), ++ _scale(no_scale), ++ _disp(disp), ++ _tmp(noreg), ++ _mode(base_plus_disp){ ++ } ++ ++ void emit(Register ra, Assembler* as, int opcode); ++ void emit(FloatRegister ra, Assembler* as, int opcode); ++ ++#ifdef ASSERT ++ Address(Register base, ByteSize disp) ++ : _base(base), ++ _index(noreg), ++ _scale(no_scale), ++ _disp(in_bytes(disp)), ++ _tmp(noreg), ++ _mode(base_plus_disp){ ++ } ++ ++ Address(Register base, Register index, ScaleFactor scale, ByteSize disp) ++ : _base(base), ++ _index(index), ++ _scale(scale), ++ _disp(in_bytes(disp)), ++ _mode(base_index_scale_disp), ++ _tmp(noreg){ ++ assert(!index->is_valid() == (scale == Address::no_scale), ++ "inconsistent address"); ++ } ++ ++ Address(Register base, RegisterOrConstant index, ScaleFactor scale, ByteSize disp) ++ : _base (base), ++ _index(index.register_or_noreg()), ++ _scale(scale), ++ _disp (in_bytes(disp) + (index.constant_or_zero() * scale_size(scale))), ++ _mode (base_index_scale_disp), ++ _tmp (noreg) { ++ if (!index.is_register()) scale = Address::no_scale; ++ assert(!_index->is_valid() == (scale == Address::no_scale), ++ "inconsistent address"); ++ } ++#endif // ASSERT ++ ++ // accessors ++ bool uses(Register reg) const { return _base == reg || _index == reg; } ++ Register base() const { return _base; } ++ int disp() const { return _disp; } ++ Register index() const { return _index; } ++ ScaleFactor scale() const { return _scale; } ++ void setTmp(Register reg) { ++ _tmp = reg; ++ } ++ long offset() const { ++ return _offset; ++ } ++ mode getMode() const { ++ return _mode; ++ } ++ address target() const { return _target; } ++ const RelocationHolder& rspec() const { return _rspec; } ++ static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc); ++ ++ private: ++ ++ 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::poll_type: ++ case relocInfo::poll_return_type: ++ return Relocation::spec_simple(rtype); ++ case relocInfo::none: ++ case relocInfo::oop_type: ++ // Oops are a special case. Normally they would be their own section ++ // but in cases like icBuffer they are literals in the code stream that ++ // we don't have a section for. We use none so that we get a literal address ++ // which is always patchable. ++ return RelocationHolder(); ++ default: ++ ShouldNotReachHere(); ++ return RelocationHolder(); ++ } ++ } ++ ++public: ++ ++ friend class Assembler; ++ friend class MacroAssembler; ++ friend class LIR_Assembler; // base/index/scale/disp ++}; ++ ++class Argument { ++ private: ++ int _number; ++ public: ++ enum { ++ n_register_parameters = 6, // 6 integer registers used to pass parameters ++ n_float_register_parameters = 6, // 6 float registers used to pass parameters ++ ++ n_int_register_parameters_c = 6, // r0, r1, ... r7 (c_rarg0, c_rarg1, ...) ++ n_float_register_parameters_c = 6, // v0, v1, ... v7 (c_farg0, c_farg1, ... ) ++ n_int_register_parameters_j = 6, // r1, ... r7, r0 (rj_rarg0, j_rarg1, ... ++ n_float_register_parameters_j = 6 // v0, v1, ... v7 (j_farg0, j_farg1, .. ++ }; ++ ++ Argument(int number):_number(number){ } ++ ++ int number()const {return _number;} ++ bool is_Register()const {return _number < n_register_parameters;} ++ bool is_FloatRegister()const {return _number < n_float_register_parameters;} ++ ++ Register as_Register()const { ++ assert(is_Register(), "must be a register argument"); ++ return ::as_Register(A0->encoding() + _number); ++ } ++ FloatRegister as_FloatRegister()const { ++ assert(is_FloatRegister(), "must be a float register argument"); ++ return ::as_FloatRegister(F16->encoding() + _number); ++ } ++ ++ Address as_caller_address()const {return Address(esp, (number() - n_register_parameters) * wordSize);} ++}; ++ ++class AddressLiteral { ++ friend class ArrayAddress; ++ RelocationHolder _rspec; ++ // Typically we use AddressLiterals we want to use their rval ++ // However in some situations we want the lval (effect address) of the item. ++ // We provide a special factory for making those lvals. ++ bool _is_lval; ++ ++ // If the target is far we'll need to load the ea of this to ++ // a register to reach it. Otherwise if near we can do rip ++ // relative addressing. ++ ++ address _target; ++ ++ protected: ++ // creation ++ AddressLiteral() ++ : _is_lval(false), ++ _target(NULL) ++ {} ++ ++ public: ++ ++ ++ AddressLiteral(address target, relocInfo::relocType rtype); ++ ++ AddressLiteral(address target, RelocationHolder const& rspec) ++ : _rspec(rspec), ++ _is_lval(false), ++ _target(target) ++ {} ++ ++ AddressLiteral addr() { ++ AddressLiteral ret = *this; ++ ret._is_lval = true; ++ return ret; ++ } ++ ++ ++ private: ++ ++ address target() { return _target; } ++ bool is_lval() { return _is_lval; } ++ ++ relocInfo::relocType reloc() const { return _rspec.type(); } ++ const RelocationHolder& rspec() const { return _rspec; } ++ ++ friend class Assembler; ++ friend class MacroAssembler; ++ friend class Address; ++ friend class LIR_Assembler; ++}; ++ ++// Convience classes ++class RuntimeAddress: public AddressLiteral { ++ ++ public: ++ ++ RuntimeAddress(address target) : AddressLiteral(target, relocInfo::runtime_call_type) {} ++ ++}; ++ ++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)) {} ++ ++}; ++ ++class InternalAddress: public AddressLiteral { ++ ++ public: ++ ++ InternalAddress(address target) : AddressLiteral(target, relocInfo::internal_word_type) {} ++}; ++ ++// x86 can do array addressing as a single operation since disp can be an absolute ++// address amd64 can't. We create a class that expresses the concept but does extra ++// magic on amd64 to get the final result ++ ++class ArrayAddress { ++ private: ++ ++ AddressLiteral _base; ++ Address _index; ++ ++ public: ++ ++ ArrayAddress() {}; ++ ArrayAddress(AddressLiteral base, Address index): _base(base), _index(index) {}; ++ AddressLiteral base() { return _base; } ++ Address index() { return _index; } ++ ++}; ++ ++class Assembler : public AbstractAssembler { ++ friend class AbstractAssembler; // for the non-virtual hack ++ ++#ifndef PRODUCT ++ static const unsigned long asm_bp; ++ ++ void emit_long(jint x) { ++ if ((unsigned long)pc() == asm_bp) ++ asm volatile ("nop"); ++ AbstractAssembler::emit_int32(x); ++ } ++#else ++ void emit_long(jint x) { ++ AbstractAssembler::emit_int32(x); ++ } ++#endif ++ ++public: ++ enum Condition { ++ zero = 0x4, ++ notZero = 0x5, ++ equal = 0x4, ++ notEqual = 0x5, ++ less = 0xc, ++ lessEqual = 0xe, ++ greater = 0xf, ++ greaterEqual = 0xd, ++ below = 0x2, ++ belowEqual = 0x6, ++ above = 0x7, ++ aboveEqual = 0x3, ++ overflow = 0x0, ++ noOverflow = 0x1, ++ carrySet = 0x2, ++ carryClear = 0x3, ++ positive = 0x9, ++ negative = 0x8, ++ notNegative = 0x10, ++ success = 0xa, ++ failed = 0xb, ++// // Conditional branch (immediate) ++// EQ, NE, HS, CS=HS, LO, CC=LO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV ++ }; ++ enum ConditionLength { ++ bitl = 64, ++ bitw = 32, ++ bith = 16, ++ bitb = 8 ++ }; ++ ++ enum WhichOperand { ++ imm_operand = 0, // embedded 32-bit|64-bit immediate operand ++ disp32_operand = 1, // embedded 32-bit displacement or address ++ call32_operand = 2, // embedded 32-bit self-relative displacement ++ narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop ++ _WhichOperand_limit = 4 ++ }; ++ enum { instruction_size = 4 }; ++ ++ // The maximum range of a branch is fixed for the Sw64 ++ // architecture. In debug mode we shrink it in order to test ++ // trampolines, but not so small that branches in the interpreter ++ // are out of range. ++ static const unsigned long branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); ++ ++ static bool reachable_from_branch_at(address branch, address target) { ++ return uabs(target - branch) < branch_range; ++ } ++ ++ // Floating-point Move (immediate) ++private: ++ unsigned pack(double value); ++ ++public: ++ ++ Assembler(CodeBuffer* code) : AbstractAssembler(code) { ++#ifdef CHECK_DELAY ++ delay_state = no_delay; ++#endif ++ } ++ ++ virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, ++ Register tmp, ++ int offset) { ++ ShouldNotCallThis(); ++ return RegisterOrConstant(); ++ } ++ ++ // Stack overflow checking ++ virtual void bang_stack_with_offset(int offset); ++ ++ static bool operand_valid_for_logical_immediate(bool is32, uint64_t imm); ++ static bool operand_valid_for_add_sub_immediate(long imm); ++ static bool operand_valid_for_float_immediate(double imm); ++ ++ void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); ++ void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); ++ ++public: ++ enum ops_mem { ++ op_call = OPMEM(0x01), ++ op_ret = OPMEM(0x02), ++ op_jmp = OPMEM(0x03), ++ op_ldwe = OPMEM(0x09), op_fillcs = op_ldwe, ++ op_ldse = OPMEM(0x0A), op_e_fillcs = op_ldse, ++ op_ldde = OPMEM(0x0B), op_fillcs_e = op_ldde, ++ op_vlds = OPMEM(0x0C), op_e_fillde = op_vlds, ++ op_vldd = OPMEM(0x0D), ++ op_vsts = OPMEM(0x0E), ++ op_vstd = OPMEM(0x0F), ++ op_ldbu = OPMEM(0x20), op_flushd = op_ldbu, ++ op_ldhu = OPMEM(0x21), op_evictdg = op_ldhu, ++ op_ldw = OPMEM(0x22), op_s_fillcs = op_ldw, ++ op_ldl = OPMEM(0x23), op_s_fillde = op_ldl, ++ op_ldl_u = OPMEM(0x24), op_evictdl = op_ldl_u, ++ op_flds = OPMEM(0x26), op_fillde = op_flds, ++ op_fldd = OPMEM(0x27), op_fillde_e = op_fldd, ++ op_stb = OPMEM(0x28), ++ op_sth = OPMEM(0x29), ++ op_stw = OPMEM(0x2A), ++ op_stl = OPMEM(0x2B), ++ op_stl_u = OPMEM(0x2C), ++ op_fsts = OPMEM(0x2E), ++ op_fstd = OPMEM(0x2F), ++ op_ldi = OPMEM(0x3E), ++ op_ldih = OPMEM(0x3F) ++ }; ++ ++ enum ops_atmem { ++ op_lldw = ATMEM(0x08, 0x0), ++ op_lldl = ATMEM(0x08, 0x1), ++ op_ldw_inc = ATMEM(0x08, 0x2), //SW2F ++ op_ldl_inc = ATMEM(0x08, 0x3), //SW2F ++ op_ldw_dec = ATMEM(0x08, 0x4), //SW2F ++ op_ldl_dec = ATMEM(0x08, 0x5), //SW2F ++ op_ldw_set = ATMEM(0x08, 0x6), //SW2F ++ op_ldl_set = ATMEM(0x08, 0x7), //SW2F ++ op_lstw = ATMEM(0x08, 0x8), ++ op_lstl = ATMEM(0x08, 0x9), ++ op_ldw_nc = ATMEM(0x08, 0xA), ++ op_ldl_nc = ATMEM(0x08, 0xB), ++ op_ldd_nc = ATMEM(0x08, 0xC), ++ op_stw_nc = ATMEM(0x08, 0xD), ++ op_stl_nc = ATMEM(0x08, 0xE), ++ op_std_nc = ATMEM(0x08, 0xF), ++ op_vldw_u = ATMEM(0x1C, 0x0), ++ op_vstw_u = ATMEM(0x1C, 0x1), ++ op_vlds_u = ATMEM(0x1C, 0x2), ++ op_vsts_u = ATMEM(0x1C, 0x3), ++ op_vldd_u = ATMEM(0x1C, 0x4), ++ op_vstd_u = ATMEM(0x1C, 0x5), ++ op_vstw_ul = ATMEM(0x1C, 0x8), ++ op_vstw_uh = ATMEM(0x1C, 0x9), ++ op_vsts_ul = ATMEM(0x1C, 0xA), ++ op_vsts_uh = ATMEM(0x1C, 0xB), ++ op_vstd_ul = ATMEM(0x1C, 0xC), ++ op_vstd_uh = ATMEM(0x1C, 0xD), ++ op_vldd_nc = ATMEM(0x1C, 0xE), ++ op_vstd_nc = ATMEM(0x1C, 0xF), ++ op_ldbu_a = ATMEM(0x1E, 0x0), //SW8A ++ op_ldhu_a = ATMEM(0x1E, 0x1), //SW8A ++ op_ldw_a = ATMEM(0x1E, 0x2), //SW8A ++ op_ldl_a = ATMEM(0x1E, 0x3), //SW8A ++ op_flds_a = ATMEM(0x1E, 0x4), //SW8A ++ op_fldd_a = ATMEM(0x1E, 0x5), //SW8A ++ op_stb_a = ATMEM(0x1E, 0x6), //SW8A ++ op_sth_a = ATMEM(0x1E, 0x7), //SW8A ++ op_stw_a = ATMEM(0x1E, 0x8), //SW8A ++ op_stl_a = ATMEM(0x1E, 0x9), //SW8A ++ op_fsts_a = ATMEM(0x1E, 0xA), //SW8A ++ op_fstd_a = ATMEM(0x1E, 0xB) //SW8A ++ }; ++ ++ enum ops_ev6hwmem { ++ op_pri_ld = EV6HWMEM(0x25, 0x0), ++ op_pri_st = EV6HWMEM(0x2D, 0x0), ++ }; ++ ++ enum ops_opr { ++ op_addw = OPR(0x10, 0x00), ++ op_subw = OPR(0x10, 0x01), ++ op_s4addw = OPR(0x10, 0x02), ++ op_s4subw = OPR(0x10, 0x03), ++ op_s8addw = OPR(0x10, 0x04), ++ op_s8subw = OPR(0x10, 0x05), ++ op_addl = OPR(0x10, 0x08), ++ op_subl = OPR(0x10, 0x09), ++ op_s4addl = OPR(0x10, 0x0A), ++ op_s4subl = OPR(0x10, 0x0B), ++ op_s8addl = OPR(0x10, 0x0C), ++ op_s8subl = OPR(0x10, 0x0D), ++ op_mulw = OPR(0x10, 0x10), ++ op_divw = OPR(0x10, 0x11), //SW8A ++ op_udivw = OPR(0x10, 0x12), //SW8A ++ op_remw = OPR(0x10, 0x13), //SW8A ++ op_uremw = OPR(0x10, 0x14), //SW8A ++ op_mull = OPR(0x10, 0x18), ++ op_umulh = OPR(0x10, 0x19), ++ op_divl = OPR(0x10, 0x1A), //SW8A ++ op_udivl = OPR(0x10, 0x1B), //SW8A ++ op_reml = OPR(0x10, 0x1C), //SW8A ++ op_ureml = OPR(0x10, 0x1D), //SW8A ++ op_addpi = OPR(0x10, 0x1E), //SW8A ++ op_addpis = OPR(0x10, 0x1F), //SW8A ++ op_cmpeq = OPR(0x10, 0x28), ++ op_cmplt = OPR(0x10, 0x29), ++ op_cmple = OPR(0x10, 0x2A), ++ op_cmpult = OPR(0x10, 0x2B), ++ op_cmpule = OPR(0x10, 0x2C), ++ op_sbt = OPR(0x10, 0x2D), //SW8A ++ op_cbt = OPR(0x10, 0x2E), //SW8A ++ op_and = OPR(0x10, 0x38), ++ op_bic = OPR(0x10, 0x39), ++ op_bis = OPR(0x10, 0x3A), ++ op_ornot = OPR(0x10, 0x3B), ++ op_xor = OPR(0x10, 0x3C), ++ op_eqv = OPR(0x10, 0x3D), ++ op_inslb = OPR(0x10, 0x40), //0x10.40~0x10.47 ++ op_inslh = OPR(0x10, 0x41), ++ op_inslw = OPR(0x10, 0x42), ++ op_insll = OPR(0x10, 0x43), ++ op_inshb = OPR(0x10, 0x44), ++ op_inshh = OPR(0x10, 0x45), ++ op_inshw = OPR(0x10, 0x46), ++ op_inshl = OPR(0x10, 0x47), ++ op_slll = OPR(0x10, 0x48), ++ op_srll = OPR(0x10, 0x49), ++ op_sral = OPR(0x10, 0x4A), ++ op_roll = OPR(0x10, 0x4B), //SW8A ++ op_sllw = OPR(0x10, 0x4C), //SW8A ++ op_srlw = OPR(0x10, 0x4D), //SW8A ++ op_sraw = OPR(0x10, 0x4E), //SW8A ++ op_rolw = OPR(0x10, 0x4F), //SW8A ++ op_extlb = OPR(0x10, 0x50), //0x10.50~0x10.57 ++ op_extlh = OPR(0x10, 0x51), ++ op_extlw = OPR(0x10, 0x52), ++ op_extll = OPR(0x10, 0x53), ++ op_exthb = OPR(0x10, 0x54), ++ op_exthh = OPR(0x10, 0x55), ++ op_exthw = OPR(0x10, 0x56), ++ op_exthl = OPR(0x10, 0x57), ++ op_ctpop = OPR(0x10, 0x58), ++ op_ctlz = OPR(0x10, 0x59), ++ op_cttz = OPR(0x10, 0x5A), ++ op_revbh = OPR(0x10, 0x5B), //SW8A ++ op_revbw = OPR(0x10, 0x5C), //SW8A ++ op_revbl = OPR(0x10, 0x5D), //SW8A ++ op_casw = OPR(0x10, 0x5E), //SW8A ++ op_casl = OPR(0x10, 0x5F), //SW8A ++ op_masklb = OPR(0x10, 0x60), //0x10.60~0x10.67 ++ op_masklh = OPR(0x10, 0x61), ++ op_masklw = OPR(0x10, 0x62), ++ op_maskll = OPR(0x10, 0x63), ++ op_maskhb = OPR(0x10, 0x64), ++ op_maskhh = OPR(0x10, 0x65), ++ op_maskhw = OPR(0x10, 0x66), ++ op_maskhl = OPR(0x10, 0x67), ++ op_zap = OPR(0x10, 0x68), ++ op_zapnot = OPR(0x10, 0x69), ++ op_sextb = OPR(0x10, 0x6A), ++ op_sexth = OPR(0x10, 0x6B), ++ op_cmpgeb = OPR(0x10, 0x6C), //0x10.6C ++ op_fimovs = OPR(0x10, 0x70), ++ op_fimovd = OPR(0x10, 0x78), ++ op_cmovdl = OFP(0x10, 0x72), ++ op_cmovdl_g = OFP(0x10, 0x74), ++ op_cmovdl_p = OFP(0x10, 0x7A), ++ op_cmovdl_z = OFP(0x10, 0x7C), ++ op_cmovdl_n = OFP(0x10, 0x80), ++ op_cmovdlu = OFP(0x10, 0x81), ++ op_cmovdlu_g= OFP(0x10, 0x82), ++ op_cmovdlu_p= OFP(0x10, 0x83), ++ op_cmovdlu_z= OFP(0x10, 0x84), ++ op_cmovdlu_n= OFP(0x10, 0x85), ++ op_cmovdw = OFP(0x10, 0x8B), ++ op_cmovdw_g = OFP(0x10, 0x8C), ++ op_cmovdw_p = OFP(0x10, 0x8D), ++ op_cmovdw_z = OFP(0x10, 0x8E), ++ op_cmovdw_n = OFP(0x10, 0x8F), ++ op_cmovdwu = OFP(0x10, 0x86), ++ op_cmovdwu_g= OFP(0x10, 0x87), ++ op_cmovdwu_p= OFP(0x10, 0x88), ++ op_cmovdwu_z= OFP(0x10, 0x89), ++ op_cmovdwu_n= OFP(0x10, 0x8A), ++ op_seleq = TOPR(0x11, 0x0), ++ op_selge = TOPR(0x11, 0x1), ++ op_selgt = TOPR(0x11, 0x2), ++ op_selle = TOPR(0x11, 0x3), ++ op_sellt = TOPR(0x11, 0x4), ++ op_selne = TOPR(0x11, 0x5), ++ op_sellbc = TOPR(0x11, 0x6), ++ op_sellbs = TOPR(0x11, 0x7) ++ }; ++ ++ enum ops_oprl{ ++ op_addw_l = OPRL(0x12, 0x00), ++ op_subw_l = OPRL(0x12, 0x01), ++ op_s4addw_l = OPRL(0x12, 0x02), ++ op_s4subw_l = OPRL(0x12, 0x03), ++ op_s8addw_l = OPRL(0x12, 0x04), ++ op_s8subw_l = OPRL(0x12, 0x05), ++ op_addl_l = OPRL(0x12, 0x08), ++ op_subl_l = OPRL(0x12, 0x09), ++ op_s4addl_l = OPRL(0x12, 0x0A), ++ op_s4subl_l = OPRL(0x12, 0x0B), ++ op_s8addl_l = OPRL(0x12, 0x0C), ++ op_s8subl_l = OPRL(0x12, 0x0D), ++ op_mulw_l = OPRL(0x12, 0x10), ++ op_mull_l = OPRL(0x12, 0x18), ++ op_umulh_l = OPRL(0x12, 0x19), ++ op_cmpeq_l = OPRL(0x12, 0x28), ++ op_cmplt_l = OPRL(0x12, 0x29), ++ op_cmple_l = OPRL(0x12, 0x2A), ++ op_cmpult_l = OPRL(0x12, 0x2B), ++ op_cmpule_l = OPRL(0x12, 0x2C), ++ op_sbt_l = OPRL(0x12, 0x2D), //SW8A ++ op_cbt_l = OPRL(0x12, 0x2E), //SW8A ++ op_and_l = OPRL(0x12, 0x38), ++ op_bic_l = OPRL(0x12, 0x39), ++ op_bis_l = OPRL(0x12, 0x3A), ++ op_ornot_l = OPRL(0x12, 0x3B), ++ op_xor_l = OPRL(0x12, 0x3C), ++ op_eqv_l = OPRL(0x12, 0x3D), ++ op_inslb_l = OPRL(0x12, 0x40), //0x12.40~0x12.47 ++ op_inslh_l = OPRL(0x12, 0x41), ++ op_inslw_l = OPRL(0x12, 0x42), ++ op_insll_l = OPRL(0x12, 0x43), ++ op_inshb_l = OPRL(0x12, 0x44), ++ op_inshh_l = OPRL(0x12, 0x45), ++ op_inshw_l = OPRL(0x12, 0x46), ++ op_inshl_l = OPRL(0x12, 0x47), ++ op_slll_l = OPRL(0x12, 0x48), ++ op_srll_l = OPRL(0x12, 0x49), ++ op_sral_l = OPRL(0x12, 0x4A), ++ op_roll_l = OPRL(0x12, 0x4B), //SW8A ++ op_sllw_l = OPRL(0x12, 0x4C), //SW8A ++ op_srlw_l = OPRL(0x12, 0x4D), //SW8A ++ op_sraw_l = OPRL(0x12, 0x4E), //SW8A ++ op_rolw_l = OPRL(0x12, 0x4F), //SW8A ++ op_extlb_l = OPRL(0x12, 0x50), //0x12.50~0x12.57 ++ op_extlh_l = OPRL(0x12, 0x51), ++ op_extlw_l = OPRL(0x12, 0x52), ++ op_extll_l = OPRL(0x12, 0x53), ++ op_exthb_l = OPRL(0x12, 0x54), ++ op_exthh_l = OPRL(0x12, 0x55), ++ op_exthw_l = OPRL(0x12, 0x56), ++ op_exthl_l = OPRL(0x12, 0x57), ++ op_masklb_l = OPRL(0x12, 0x60), //0x12.60~0x12.67 ++ op_masklh_l = OPRL(0x12, 0x61), ++ op_masklw_l = OPRL(0x12, 0x62), ++ op_maskll_l = OPRL(0x12, 0x63), ++ op_maskhb_l = OPRL(0x12, 0x64), ++ op_maskhh_l = OPRL(0x12, 0x65), ++ op_maskhw_l = OPRL(0x12, 0x66), ++ op_maskhl_l = OPRL(0x12, 0x67), ++ op_zap_l = OPRL(0x12, 0x68), ++ op_zapnot_l = OPRL(0x12, 0x69), ++ op_sextb_l = OPRL(0x12, 0x6A), ++ op_sexth_l = OPRL(0x12, 0x6B), ++ op_cmpgeb_l = OPRL(0x12, 0x6C), //0x12.6C ++ op_seleq_l = TOPRL(0x13, 0x0), ++ op_selge_l = TOPRL(0x13, 0x1), ++ op_selgt_l = TOPRL(0x13, 0x2), ++ op_selle_l = TOPRL(0x13, 0x3), ++ op_sellt_l = TOPRL(0x13, 0x4), ++ op_selne_l = TOPRL(0x13, 0x5), ++ op_sellbc_l = TOPRL(0x13, 0x6), ++ op_sellbs_l = TOPRL(0x13, 0x7) ++ }; ++ ++ enum ops_bra { ++ op_br = BRA(0x04), ++ op_bsr = BRA(0x05), ++ op_beq = BRA(0x30), ++ op_bne = BRA(0x31), ++ op_blt = BRA(0x32), ++ op_ble = BRA(0x33), ++ op_bgt = BRA(0x34), ++ op_bge = BRA(0x35), ++ op_blbc = BRA(0x36), ++ op_blbs = BRA(0x37), ++ op_fbeq = BRA(0x38), ++ op_fbne = BRA(0x39), ++ op_fblt = BRA(0x3A), ++ op_fble = BRA(0x3B), ++ op_fbgt = BRA(0x3C), ++ op_fbge = BRA(0x3D), ++ op_lbr = BRA(0x1D), //SW8A ++ }; ++ ++ enum ops_fp { ++ op_fadds = OFP(0x18, 0x00), ++ op_faddd = OFP(0x18, 0x01), ++ op_fsubs = OFP(0x18, 0x02), ++ op_fsubd = OFP(0x18, 0x03), ++ op_fmuls = OFP(0x18, 0x04), ++ op_fmuld = OFP(0x18, 0x05), ++ op_fdivs = OFP(0x18, 0x06), ++ op_fdivd = OFP(0x18, 0x07), ++ op_fsqrts = OFP(0x18, 0x08), ++ op_fsqrtd = OFP(0x18, 0x09), ++ op_fcmpeq = OFP(0x18, 0x10), ++ op_fcmple = OFP(0x18, 0x11), ++ op_fcmplt = OFP(0x18, 0x12), ++ op_fcmpun = OFP(0x18, 0x13), ++ op_fcvtsd = OFP(0x18, 0x20), ++ op_fcvtds = OFP(0x18, 0x21), ++ op_fcvtdl_g = OFP(0x18, 0x22), //lx_fcvtdl ++ op_fcvtdl_p = OFP(0x18, 0x23), ++ op_fcvtdl_z = OFP(0x18, 0x24), ++ op_fcvtdl_n = OFP(0x18, 0x25), //lx_fcvtdl ++ op_fcvtdl = OFP(0x18, 0x27), ++ op_fcvtwl = OFP(0x18, 0x28), ++ op_fcvtlw = OFP(0x18, 0x29), ++ op_fcvtls = OFP(0x18, 0x2D), ++ op_fcvtld = OFP(0x18, 0x2F), ++ op_fcpys = OFP(0x18, 0x30), ++ op_fcpyse = OFP(0x18, 0x31), ++ op_fcpysn = OFP(0x18, 0x32), ++ op_ifmovs = OFP(0x18, 0x40), ++ op_ifmovd = OFP(0x18, 0x41), ++ op_cmovls = OFP(0x18, 0x48), ++ op_cmovld = OFP(0x18, 0x4A), ++ op_cmovuls = OFP(0x18, 0x4C), ++ op_cmovuld = OFP(0x18, 0x4E), ++ op_cmovws = OFP(0x18, 0x49), ++ op_cmovwd = OFP(0x18, 0x4B), ++ op_cmovuws = OFP(0x18, 0x4D), ++ op_cmovuwd = OFP(0x18, 0x4F), ++ op_rfpcr = OFP(0x18, 0x50), ++ op_wfpcr = OFP(0x18, 0x51), ++ op_setfpec0 = OFP(0x18, 0x54), ++ op_setfpec1 = OFP(0x18, 0x55), ++ op_setfpec2 = OFP(0x18, 0x56), ++ op_setfpec3 = OFP(0x18, 0x57), ++ op_frecs = OFP(0x18, 0x58), //SW8A ++ op_frecd = OFP(0x18, 0x59), //SW8A ++ op_fris = OFP(0x18, 0x5A), //SW8A ++ op_fris_g = OFP(0x18, 0x5B), //SW8A ++ op_fris_p = OFP(0x18, 0x5C), //SW8A ++ op_fris_z = OFP(0x18, 0x5D), //SW8A ++ op_fris_n = OFP(0x18, 0x5F), //SW8A ++ op_frid = OFP(0x18, 0x60), //SW8A ++ op_frid_g = OFP(0x18, 0x61), //SW8A ++ op_frid_p = OFP(0x18, 0x62), //SW8A ++ op_frid_z = OFP(0x18, 0x63), //SW8A ++ op_frid_n = OFP(0x18, 0x64), //SW8A ++ op_vaddw = OFP(0x1A, 0x00), ++ op_vsubw = OFP(0x1A, 0x01), ++ op_vcmpgew = OFP(0x1A, 0x02), ++ op_vcmpeqw = OFP(0x1A, 0x03), ++ op_vcmplew = OFP(0x1A, 0x04), ++ op_vcmpltw = OFP(0x1A, 0x05), ++ op_vcmpulew = OFP(0x1A, 0x06), ++ op_vcmpultw = OFP(0x1A, 0x07), ++ op_vsllw = OFP(0x1A, 0x08), ++ op_vsrlw = OFP(0x1A, 0x09), ++ op_vsraw = OFP(0x1A, 0x0A), ++ op_vrolw = OFP(0x1A, 0x0B), ++ op_sllow = OFP(0x1A, 0x0C), ++ op_srlow = OFP(0x1A, 0x0D), ++ op_vaddl = OFP(0x1A, 0x0E), ++ op_vsubl = OFP(0x1A, 0x0F), ++ op_vsllb = OFP(0x1A, 0x10), //SW8A ++ op_vsrlb = OFP(0x1A, 0x11), //SW8A ++ op_vsrab = OFP(0x1A, 0x12), //SW8A ++ op_vrolb = OFP(0x1A, 0x13), //SW8A ++ op_vsllh = OFP(0x1A, 0x14), //SW8A ++ op_vsrlh = OFP(0x1A, 0x15), //SW8A ++ op_vsrah = OFP(0x1A, 0x16), //SW8A ++ op_vrolh = OFP(0x1A, 0x17), //SW8A ++ op_ctpopow = OFP(0x1A, 0x18), ++ op_ctlzow = OFP(0x1A, 0x19), ++ op_vslll = OFP(0x1A, 0x1A), //SW8A ++ op_vsrll = OFP(0x1A, 0x1B), //SW8A ++ op_vsral = OFP(0x1A, 0x1C), //SW8A ++ op_vroll = OFP(0x1A, 0x1D), //SW8A ++ op_vmaxb = OFP(0x1A, 0x1E), //SW8A ++ op_vminb = OFP(0x1A, 0x1F), //SW8A ++ op_vucaddw = OFP(0x1A, 0x40), ++ op_vucsubw = OFP(0x1A, 0x41), ++ op_vucaddh = OFP(0x1A, 0x42), ++ op_vucsubh = OFP(0x1A, 0x43), ++ op_vucaddb = OFP(0x1A, 0x44), ++ op_vucsubb = OFP(0x1A, 0x45), ++ op_sraow = OFP(0x1A, 0x46), //SW8A ++ op_vsumw = OFP(0x1A, 0x47), //SW8A ++ op_vsuml = OFP(0x1A, 0x48), //SW8A ++ op_vsm4r = OFP(0x1A, 0x49), //SW8A, ENCRYPT ++ op_vbinvw = OFP(0x1A, 0x4A), //SW8A, ENCRYPT ++ op_vcmpueqb = OFP(0x1A, 0x4B), //SW8A ++ op_vcmpugtb = OFP(0x1A, 0x4C), //SW8A ++ op_vsm3msw = OFP(0x1A, 0x4D), //SW8A, ENCRYPT ++ op_vmaxh = OFP(0x1A, 0x50), //SW8A ++ op_vminh = OFP(0x1A, 0x51), //SW8A ++ op_vmaxw = OFP(0x1A, 0x52), //SW8A ++ op_vminw = OFP(0x1A, 0x53), //SW8A ++ op_vmaxl = OFP(0x1A, 0x54), //SW8A ++ op_vminl = OFP(0x1A, 0x55), //SW8A ++ op_vumaxb = OFP(0x1A, 0x56), //SW8A ++ op_vuminb = OFP(0x1A, 0x57), //SW8A ++ op_vumaxh = OFP(0x1A, 0x58), //SW8A ++ op_vuminh = OFP(0x1A, 0x59), //SW8A ++ op_vumaxw = OFP(0x1A, 0x5A), //SW8A ++ op_vuminw = OFP(0x1A, 0x5B), //SW8A ++ op_vumaxl = OFP(0x1A, 0x5C), //SW8A ++ op_vuminl = OFP(0x1A, 0x5D), //SW8A ++ op_vadds = OFP(0x1A, 0x80), ++ op_vaddd = OFP(0x1A, 0x81), ++ op_vsubs = OFP(0x1A, 0x82), ++ op_vsubd = OFP(0x1A, 0x83), ++ op_vmuls = OFP(0x1A, 0x84), ++ op_vmuld = OFP(0x1A, 0x85), ++ op_vdivs = OFP(0x1A, 0x86), ++ op_vdivd = OFP(0x1A, 0x87), ++ op_vsqrts = OFP(0x1A, 0x88), ++ op_vsqrtd = OFP(0x1A, 0x89), ++ op_vfcmpeq = OFP(0x1A, 0x8C), ++ op_vfcmple = OFP(0x1A, 0x8D), ++ op_vfcmplt = OFP(0x1A, 0x8E), ++ op_vfcmpun = OFP(0x1A, 0x8F), ++ op_vcpys = OFP(0x1A, 0x90), ++ op_vcpyse = OFP(0x1A, 0x91), ++ op_vcpysn = OFP(0x1A, 0x92), ++ op_vsums = OFP(0x1A, 0x93), //SW8A ++ op_vsumd = OFP(0x1A, 0x94), //SW8A ++ op_vfcvtsd = OFP(0x1A, 0x95), //SW8A ++ op_vfcvtds = OFP(0x1A, 0x96), //SW8A ++ op_vfcvtls = OFP(0x1A, 0x99), //SW8A ++ op_vfcvtld = OFP(0x1A, 0x9A), //SW8A ++ op_vfcvtdl = OFP(0x1A, 0x9B), //SW8A ++ op_vfcvtdl_g = OFP(0x1A, 0x9C), //SW8A ++ op_vfcvtdl_p = OFP(0x1A, 0x9D), //SW8A ++ op_vfcvtdl_z = OFP(0x1A, 0x9E), //SW8A ++ op_vfcvtdl_n = OFP(0x1A, 0x9F), //SW8A ++ op_vfris = OFP(0x1A, 0xA0), //SW8A ++ op_vfris_g = OFP(0x1A, 0xA1), //SW8A ++ op_vfris_p = OFP(0x1A, 0xA2), //SW8A ++ op_vfris_z = OFP(0x1A, 0xA3), //SW8A ++ op_vfris_n = OFP(0x1A, 0xA4), //SW8A ++ op_vfrid = OFP(0x1A, 0xA5), //SW8A ++ op_vfrid_g = OFP(0x1A, 0xA6), //SW8A ++ op_vfrid_p = OFP(0x1A, 0xA7), //SW8A ++ op_vfrid_z = OFP(0x1A, 0xA8), //SW8A ++ op_vfrid_n = OFP(0x1A, 0xA9), //SW8A ++ op_vfrecs = OFP(0x1A, 0xAA), //SW8A ++ op_vfrecd = OFP(0x1A, 0xAB), //SW8A ++ op_vmaxs = OFP(0x1A, 0xAC), //SW8A ++ op_vmins = OFP(0x1A, 0xAD), //SW8A ++ op_vmaxd = OFP(0x1A, 0xAE), //SW8A ++ op_vmind = OFP(0x1A, 0xAF), //SW8A ++ }; ++ ++ enum ops_fpl { ++ op_vaddw_l = OFP(0x1A, 0x20), ++ op_vsubw_l = OFP(0x1A, 0x21), ++ op_vcmpgew_l = OFP(0x1A, 0x22), ++ op_vcmpeqw_l = OFP(0x1A, 0x23), ++ op_vcmplew_l = OFP(0x1A, 0x24), ++ op_vcmpltw_l = OFP(0x1A, 0x25), ++ op_vcmpulew_l = OFP(0x1A, 0x26), ++ op_vcmpultw_l = OFP(0x1A, 0x27), ++ op_vsllw_l = OFP(0x1A, 0x28), ++ op_vsrlw_l = OFP(0x1A, 0x29), ++ op_vsraw_l = OFP(0x1A, 0x2A), ++ op_vrolw_l = OFP(0x1A, 0x2B), ++ op_sllow_l = OFP(0x1A, 0x2C), ++ op_srlow_l = OFP(0x1A, 0x2D), ++ op_vaddl_l = OFP(0x1A, 0x2E), ++ op_vsubl_l = OFP(0x1A, 0x2F), ++ op_vsllb_l = OFP(0x1A, 0x30), //SW8A ++ op_vsrlb_l = OFP(0x1A, 0x31), //SW8A ++ op_vsrab_l = OFP(0x1A, 0x32), //SW8A ++ op_vrolb_l = OFP(0x1A, 0x33), //SW8A ++ op_vsllh_l = OFP(0x1A, 0x34), //SW8A ++ op_vsrlh_l = OFP(0x1A, 0x35), //SW8A ++ op_vsrah_l = OFP(0x1A, 0x36), //SW8A ++ op_vrolh_l = OFP(0x1A, 0x37), //SW8A ++ op_vslll_l = OFP(0x1A, 0x3A), //SW8A ++ op_vsrll_l = OFP(0x1A, 0x3B), //SW8A ++ op_vsral_l = OFP(0x1A, 0x3C), //SW8A ++ op_vroll_l = OFP(0x1A, 0x3D), //SW8A ++ op_vucaddw_l = OFP(0x1A, 0x60), ++ op_vucsubw_l = OFP(0x1A, 0x61), ++ op_vucaddh_l = OFP(0x1A, 0x62), ++ op_vucsubh_l = OFP(0x1A, 0x63), ++ op_vucaddb_l = OFP(0x1A, 0x64), ++ op_vucsubb_l = OFP(0x1A, 0x65), ++ op_sraow_l = OFP(0x1A, 0x66), //SW8A ++ op_vsm4key_l = OFP(0x1A, 0x68), //SW8A, ENCRYPT ++ op_vcmpueqb_l = OFP(0x1A, 0x6B), //SW8A ++ op_vcmpugtb_l = OFP(0x1A, 0x6C), //SW8A ++ op_vfcvtsh_l = OFP(0x1B, 0x35), //SW8A ++ op_vfcvths_l = OFP(0x1B, 0x36) //SW8A ++ }; ++ ++ enum ops_fma { ++ op_fmas = FMA(0x19, 0x00), ++ op_fmad = FMA(0x19, 0x01), ++ op_fmss = FMA(0x19, 0x02), ++ op_fmsd = FMA(0x19, 0x03), ++ op_fnmas = FMA(0x19, 0x04), ++ op_fnmad = FMA(0x19, 0x05), ++ op_fnmss = FMA(0x19, 0x06), ++ op_fnmsd = FMA(0x19, 0x07), ++ op_fseleq = FMA(0x19, 0x10), ++ op_fselne = FMA(0x19, 0x11), ++ op_fsellt = FMA(0x19, 0x12), ++ op_fselle = FMA(0x19, 0x13), ++ op_fselgt = FMA(0x19, 0x14), ++ op_fselge = FMA(0x19, 0x15), ++ op_vmas = FMA(0x1B, 0x00), ++ op_vmad = FMA(0x1B, 0x01), ++ op_vmss = FMA(0x1B, 0x02), ++ op_vmsd = FMA(0x1B, 0x03), ++ op_vnmas = FMA(0x1B, 0x04), ++ op_vnmad = FMA(0x1B, 0x05), ++ op_vnmss = FMA(0x1B, 0x06), ++ op_vnmsd = FMA(0x1B, 0x07), ++ op_vfseleq = FMA(0x1B, 0x10), ++ op_vfsellt = FMA(0x1B, 0x12), ++ op_vfselle = FMA(0x1B, 0x13), ++ op_vseleqw = FMA(0x1B, 0x18), ++ op_vsellbcw = FMA(0x1B, 0x19), ++ op_vselltw = FMA(0x1B, 0x1A), ++ op_vsellew = FMA(0x1B, 0x1B), ++ op_vcpyw = FMA(0x1B, 0x24), ++ op_vcpyf = FMA(0x1B, 0x25), ++ op_vconw = FMA(0x1B, 0x26), ++ op_vshfw = FMA(0x1B, 0x27), ++ op_vcons = FMA(0x1B, 0x28), ++ op_vcond = FMA(0x1B, 0x29), ++ op_vinsectlh = FMA(0x1B, 0x2C), //SW8A ++ op_vinsectlw = FMA(0x1B, 0x2D), //SW8A ++ op_vinsectll = FMA(0x1B, 0x2E), //SW8A ++ op_vinsectlb = FMA(0x1B, 0x2F), //SW8A ++ op_vshfqb = FMA(0x1B, 0x31), //SW8A ++ op_vcpyb = FMA(0x1B, 0x32), //SW8A ++ op_vcpyh = FMA(0x1B, 0x33) //SW8A ++ }; ++ ++ enum ops_fmal { ++ op_vinsw_l = FMA(0x1B, 0x20), ++ op_vinsf_l = FMA(0x1B, 0x21), ++ op_vextw_l = FMA(0x1B, 0x22), ++ op_vextf_l = FMA(0x1B, 0x23), ++ op_vinsb_l = FMA(0x1B, 0x2A), //SW8A ++ op_vinsh_l = FMA(0x1B, 0x2B), //SW8A ++ op_vshfq_l = FMA(0x1B, 0x30), //SW8A ++ op_vsm3r_l = FMA(0x1B, 0x34), //SW8A, ENCRYPT ++ op_vseleqw_l = FMA(0x1B, 0x38), ++ op_vsellbcw_l = FMA(0x1B, 0x39), ++ op_vselltw_l = FMA(0x1B, 0x3A), ++ op_vsellew_l = FMA(0x1B, 0x3B) ++ }; ++ ++ enum ops_extra { ++ op_sys_call = PCD(0x00), ++ op_memb = MFC(0x06, 0x0000), ++ op_imemb = MFC(0x06, 0x0001), //SW8A ++ op_wmemb = MFC(0x06, 0x0002), //SW8A ++ op_rtc = MFC(0x06, 0x0020), ++ op_rcid = MFC(0x06, 0x0040), ++ op_halt = MFC(0x06, 0x0080), ++ op_rd_f = MFC(0x06, 0x1000), //SW2F ++ op_wr_f = MFC(0x06, 0x1020), //SW2F ++ op_rtid = MFC(0x06, 0x1040), ++ op_csrws = CSR(0x06, 0xFC), //SW8A ++ op_csrwc = CSR(0x06, 0xFD), //SW8A ++ op_csrr = CSR(0x06, 0xFE), ++ op_csrw = CSR(0x06, 0xFF), ++ op_pri_ret = PRIRET(0x07, 0x0), ++ op_vlog = LOGX(0x14, 0x00), ++ op_vbisw = PSE_LOGX(0x14, 0x30), ++ op_vxorw = PSE_LOGX(0x14, 0x3c), ++ op_vandw = PSE_LOGX(0x14, 0xc0), ++ op_veqvw = PSE_LOGX(0x14, 0xc3), ++ op_vornotw = PSE_LOGX(0x14, 0xf3), ++ op_vbicw = PSE_LOGX(0x14, 0xfc), ++ op_dpfhr = ATMEM(0x1E, 0xE), //SW6B ++ op_dpfhw = ATMEM(0x1E, 0xF), //SW6B ++ }; ++ ++ // compute inverse of simm ++ static int inv_simm(int x, int nbits) { ++ return (int)(x << (32 - nbits)) >> (32 - nbits); ++ } ++ ++ static int inv_simm16( int x ) { return inv_simm(x, 16); } //ZHJ20110307 modified ++ ++ // 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); ++ } ++ ++ static int sw2_op(int inst) {return (int)(inst & OP(-1)); } ++ static int sw2_arith_op(int inst) {return (int)(inst & OPR(-1, -1)); } ++ static int sw2_mfc_op(int inst) {return (int)(inst & MFC(-1, -1)); } ++ ++ static Register sw2_ra( int x ) { return as_Register(inv_u_field(x, 25, 21)); } ++ static Register sw2_rb( int x ) { return as_Register(inv_u_field(x, 20, 16)); } ++ static Register sw2_rc( int x ) { return as_Register(inv_u_field(x, 4, 0)); } ++ static int sw2_mdisp( int x ) { return inv_simm16(x); } ++ ++ static int fmask(uint32_t hi_bit, uint32_t lo_bit) { ++ assert( hi_bit >= lo_bit && hi_bit < 32, "bad bits"); ++ return (1 << ( hi_bit-lo_bit + 1 )) - 1; ++ } ++ ++#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 opcode(int insn) { return (insn>>26)&0x3f; } ++ static int rs(int insn) { return (insn>>21)&0x1f; } ++ static int rt(int insn) { return (insn>>16)&0x1f; } ++ static int imm_off(int insn) { return (short)bitfield(insn, 0, 16); } ++ ++ // the plain int register fields. ++ static int is_ra (Register ra) { return u_field ( ra->encoding(), 25, 21 ); }; ++ static int is_rb (Register rb) { return u_field ( rb->encoding(), 20, 16 ); }; ++ static int is_rc (Register rc) { return u_field ( rc->encoding(), 4, 0 ); }; ++ /* for the third operand of ternary operands integer insn. */ ++ static int is_r3 (Register r3) { return u_field ( r3->encoding(), 9, 5 ); }; ++ /* th th fields for dpfhr and dpfhw instructions */ ++ static int is_th (int th) { return u_field ( th, 25, 21 ); }; ++ ++ //the plain fp register fields. ++ static int is_fa (FloatRegister fa) { return u_field ( fa->encoding(), 25, 21 ); }; ++ static int is_fb (FloatRegister fb) { return u_field ( fb->encoding(), 20, 16 ); }; ++ static int is_fc (FloatRegister fc) { return u_field ( fc->encoding(), 4, 0 ); }; ++ /* the plain fp register fields */ ++ static int is_f3 (FloatRegister f3) { return u_field ( f3->encoding(), 9, 5 ); }; ++ ++ 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"); ++ } ++ ++ // signed immediate, in low bits, nbits long ++ static int simm(int x, int nbits) { ++ assert_signed_range(x, nbits); ++ return x & (( 1 << nbits ) - 1); ++ } ++ static int simm2(int64_t val, int msb, int lsb) { ++ int nbits = msb - lsb + 1; ++ int64_t chk = val >> (nbits - 1); ++ guarantee (chk == -1 || chk == 0, "Field too big for insn"); ++ unsigned uval = val; ++ unsigned mask = checked_cast(right_n_bits(nbits)); ++ uval &= mask; ++ uval <<= lsb; ++ return uval; ++ } ++ inline void check_delay() { ++# ifdef CHECK_DELAY ++ guarantee(delay_state != at_delay_slot, "must say delayed() when filling delay slot"); ++ delay_state = no_delay; ++# endif ++ } ++ ++ void emit_sw2_long(int); // shadows AbstractAssembler::emit_long ++ ++ void nop(int i = 1) { assert(i > 0, "count > 0"); for (; i > 0 ; i--) emit_sw2_long( op_ldi | is_ra(R0) ); } ++ ++ /* the unsigned 8-bit literal of operate format insns. */ ++ static int is_lit (int lit) { return u_field ( lit ,20, 13 ); }; ++ ++ /* the signed 13-bit literal of operate format insns. */ ++ static int is_apint (int apint) { return simm2 ( apint, 25, 13 ); }; ++ ++ /* the signed 16-bit displacement of memory format insns. from here ++ we can't tell what relocation should be used, so don't use a default. */ ++ static int is_mdisp (int mdisp) { return simm ( mdisp ,16 ); }; ++ ++ /* the signed "23-bit" aligned displacement of branch format insns. */ ++ static int is_bdisp (int bdisp) { return simm ( bdisp ,21 ); }; ++ ++ /* the 26-bit palcode function */ ++ static int is_palfn (int palfn) { return simm ( palfn, 26 ); }; ++ /* the optional signed "16-bit" aligned displacement of the jmp/jsr hint */ ++ static int is_jmphint (int jmphint) { return simm ( jmphint, 16); }; ++ ++ /* the optional hint to ret/jsr_coroutine */ ++ static int is_rethint (int rethint) { return simm ( rethint, 16); }; ++ /* the 12-bit displacement for the ev[46] hw_{ return u_field (ld,st} (pal1b/pal1f) insns. */ ++ static int is_ev6hwdisp (int ev6hwdisp) { return simm ( ev6hwdisp, 12 ); }; ++ ++ /* sw2 simd settle instruction lit */ ++ static int is_fmalit (int fmalit) { return u_field ( fmalit ,9 ,5 ); };//v1.1 ++ ++ static int is_rpiindex (int rpiindex) { return u_field ( rpiindex ,7, 0 ); }; ++ ++ static int is_atmdisp ( int atmdisp ) { return u_field ( atmdisp, 10, 0 ); }; ++ ++ static int is_vlog_h ( int vlog ) { return u_field ( (vlog & 0xff) >>6 , 27, 26 ); }; ++ static int is_vlog_l ( int vlog ) { return u_field ( vlog & 0x3f , 15, 10 ); }; ++ ++ void flush() { ++#ifdef CHECK_DELAY ++ guarantee( delay_state == no_delay, "ending code with a delay slot"); ++#endif ++ AbstractAssembler::flush(); ++ } ++ ++ void assert_not_delayed() { ++#ifdef CHECK_DELAY ++ assert_not_delayed("next instruction should not be a delay slot"); ++#endif ++ } ++ ++ void assert_not_delayed(const char* msg) { ++#ifdef CHECK_DELAY ++ if(delay_state != no_delay){ ++ tty->print_cr("%s:%d, pc: %lx", __func__, __LINE__, pc()); ++ } ++ assert(delay_state == no_delay, msg); ++#endif ++ } ++ ++protected: ++#ifdef ASSERT ++ void check_relocation(RelocationHolder const& rspec, int format); ++#endif ++ ++ // instruction only in sw2, including sw2f, sw4a, sw6a ++ static void sw2_only() { assert( VM_Version::sw2only(), "This instruction only works on sw2f, sw4a or sw6a"); } ++ // instruction only in sw3, including sw6b ++ static void sw3_only() { assert( VM_Version::sw3only(), "This instruction only works on sw6b"); } ++ static void sw4_only() { assert( VM_Version::sw4only(), "This instruction only works on sw6b"); } ++ ++public: ++ // SW64 common helper functions ++ static bool operand_valid_for_simple_type_instruction_immediate(int imm) { return is_lit(imm); } ++ static bool operand_valid_for_storage_type_instruction_immediate(int imm) { return is_simm16(imm); } ++ ++ // SW64 Generic instructions ++ void sys_call_b( int palfn ); ++ void sys_call ( int palfn ); ++ void call ( Register ra, Register rb, int jmphint ); ++ void ret ( Register ra, Register rb, int rethint ); ++ void jmp ( Register ra, Register rb, int jmphint ); ++ void br ( Register ra, int bdisp ); ++ void bsr ( Register ra, int bdisp ); ++ void memb ( void ); ++ void imemb ( void ); ++ void wmemb ( void ); ++ void rtc ( Register ra, Register rb ); ++ void rcid ( Register ra); ++ void halt ( void); ++ void rd_f ( Register ra ); //SW2F ++ void wr_f ( Register ra ); //SW2F ++ void rtid ( Register ra); ++ void csrws ( Register ra, int rpiindex ); ++ void csrwc ( Register ra, int rpiindex ); ++ void csrr ( Register ra, int rpiindex ); ++ void csrw ( Register ra, int rpiindex ); ++ void pri_ret ( Register ra ); ++ void lldw ( Register ra, int atmdisp, Register rb ); ++ void lldl ( Register ra, int atmdisp, Register rb ); ++ void ldw_inc ( Register ra, int atmdisp, Register rb ); //SW2F ++ void ldl_inc ( Register ra, int atmdisp, Register rb ); //SW2F ++ void ldw_dec ( Register ra, int atmdisp, Register rb ); //SW2F ++ void ldl_dec ( Register ra, int atmdisp, Register rb ); //SW2F ++ void ldw_set ( Register ra, int atmdisp, Register rb ); //SW2F ++ void ldl_set ( Register ra, int atmdisp, Register rb ); //SW2F ++ void lstw ( Register ra, int atmdisp, Register rb ); ++ void lstl ( Register ra, int atmdisp, Register rb ); ++ void ldw_nc ( Register ra, int atmdisp, Register rb ); ++ void ldl_nc ( Register ra, int atmdisp, Register rb ); ++ void ldd_nc ( Register ra, int atmdisp, Register rb ); ++ void stw_nc ( Register ra, int atmdisp, Register rb ); ++ void stl_nc ( Register ra, int atmdisp, Register rb ); ++ void std_nc ( Register ra, int atmdisp, Register rb ); ++ void ldwe ( FloatRegister fa, int mdisp, Register rb ); ++ void ldse ( FloatRegister fa, int mdisp, Register rb ); ++ void ldde ( FloatRegister fa, int mdisp, Register rb ); ++ void vlds ( FloatRegister fa, int mdisp, Register rb ); ++ void vldd ( FloatRegister fa, int mdisp, Register rb ); ++ void vsts ( FloatRegister fa, int mdisp, Register rb ); ++ void vstd ( FloatRegister fa, int mdisp, Register rb ); ++ ++ void addw ( Register ra, Register rb, Register rc ); ++ void addw ( Register ra, int lit, Register rc ); ++ void subw ( Register ra, Register rb, Register rc ); ++ void subw ( Register ra, int lit, Register rc ); ++ void s4addw ( Register ra, Register rb, Register rc ); ++ void s4addw ( Register ra, int lit, Register rc ); ++ void s4subw ( Register ra, Register rb, Register rc ); ++ void s4subw ( Register ra, int lit, Register rc ); ++ void s8addw ( Register ra, Register rb, Register rc ); ++ void s8addw ( Register ra, int lit, Register rc ); ++ void s8subw ( Register ra, Register rb, Register rc ); ++ void s8subw ( Register ra, int lit, Register rc ); ++ void addl ( Register ra, Register rb, Register rc ); ++ void addl ( Register ra, int lit, Register rc ); ++ void subl ( Register ra, Register rb, Register rc ); ++ void subl ( Register ra, int lit, Register rc ); ++ void s4addl ( Register ra, Register rb, Register rc ); ++ void s4addl ( Register ra, int lit, Register rc ); ++ void s4subl ( Register ra, Register rb, Register rc ); ++ void s4subl ( Register ra, int lit, Register rc ); ++ void s8addl ( Register ra, Register rb, Register rc ); ++ void s8addl ( Register ra, int lit, Register rc ); ++ void s8subl ( Register ra, Register rb, Register rc ); ++ void s8subl ( Register ra, int lit, Register rc ); ++ void mulw ( Register ra, Register rb, Register rc ); ++ void mulw ( Register ra, int lit, Register rc ); ++ void divw ( Register ra, Register rb, Register rc ); //SW6B ++ void udivw ( Register ra, Register rb, Register rc ); //SW6B ++ void remw ( Register ra, Register rb, Register rc ); //SW6B ++ void uremw ( Register ra, Register rb, Register rc ); //SW6B ++ void mull ( Register ra, Register rb, Register rc ); ++ void mull ( Register ra, int lit, Register rc ); ++ void umulh ( Register ra, Register rb, Register rc ); ++ void umulh ( Register ra, int lit, Register rc ); ++ void divl ( Register ra, Register rb, Register rc ); //SW6B ++ void udivl ( Register ra, Register rb, Register rc ); //SW6B ++ void reml ( Register ra, Register rb, Register rc ); //SW6B ++ void ureml ( Register ra, Register rb, Register rc ); //SW6B ++ void addpi ( int apint, Register rc ); //SW6B ++ void addpis ( int apint, Register rc ); //SW6B ++ ++ void cmpeq ( Register ra, Register rb, Register rc ); ++ void cmpeq ( Register ra, int lit, Register rc ); ++ void cmplt ( Register ra, Register rb, Register rc ); ++ void cmplt ( Register ra, int lit, Register rc ); ++ void cmple ( Register ra, Register rb, Register rc ); ++ void cmple ( Register ra, int lit, Register rc ); ++ void cmpult ( Register ra, Register rb, Register rc ); ++ void cmpult ( Register ra, int lit, Register rc ); ++ void cmpule ( Register ra, Register rb, Register rc ); ++ void cmpule ( Register ra, int lit, Register rc ); ++ void sbt ( Register ra, Register rb, Register rc ); ++ void sbt ( Register ra, int lit, Register rc ); ++ void cbt ( Register ra, Register rb, Register rc ); ++ void cbt ( Register ra, int lit, Register rc ); ++ void and_ins ( Register ra, Register rb, Register rc ); ++ void and_ins ( Register ra, int lit, Register rc ); ++ void bic ( Register ra, Register rb, Register rc ); ++ void bic ( Register ra, int lit, Register rc ); ++ void bis ( Register ra, Register rb, Register rc ); ++ void bis ( Register ra, int lit, Register rc ); ++ void ornot ( Register ra, Register rb, Register rc ); ++ void ornot ( Register ra, int lit, Register rc ); ++ void xor_ins ( Register ra, Register rb, Register rc ); ++ void xor_ins ( Register ra, int lit, Register rc ); ++ void eqv ( Register ra, Register rb, Register rc ); ++ void eqv ( Register ra, int lit, Register rc ); ++ void inslb ( Register ra, Register rb, Register rc ); ++ void inslb ( Register ra, int lit, Register rc ); ++ void inslh ( Register ra, Register rb, Register rc ); ++ void inslh ( Register ra, int lit, Register rc ); ++ void inslw ( Register ra, Register rb, Register rc ); ++ void inslw ( Register ra, int lit, Register rc ); ++ void insll ( Register ra, Register rb, Register rc ); ++ void insll ( Register ra, int lit, Register rc ); ++ void inshb ( Register ra, Register rb, Register rc ); ++ void inshb ( Register ra, int lit, Register rc ); ++ void inshh ( Register ra, Register rb, Register rc ); ++ void inshh ( Register ra, int lit, Register rc ); ++ void inshw ( Register ra, Register rb, Register rc ); ++ void inshw ( Register ra, int lit, Register rc ); ++ void inshl ( Register ra, Register rb, Register rc ); ++ void inshl ( Register ra, int lit, Register rc ); ++ void slll ( Register ra, Register rb, Register rc ); ++ void slll ( Register ra, int lit, Register rc ); ++ void srll ( Register ra, Register rb, Register rc ); ++ void srll ( Register ra, int lit, Register rc ); ++ void sral ( Register ra, Register rb, Register rc ); ++ void sral ( Register ra, int lit, Register rc ); ++ void roll ( Register ra, Register rb, Register rc ); ++ void roll ( Register ra, int lit, Register rc ); ++ void sllw ( Register ra, Register rb, Register rc ); ++ void sllw ( Register ra, int lit, Register rc ); ++ void srlw ( Register ra, Register rb, Register rc ); ++ void srlw ( Register ra, int lit, Register rc ); ++ void sraw ( Register ra, Register rb, Register rc ); ++ void sraw ( Register ra, int lit, Register rc ); ++ void rolw ( Register ra, Register rb, Register rc ); ++ void rolw ( Register ra, int lit, Register rc ); ++ void extlb ( Register ra, Register rb, Register rc ); ++ void extlb ( Register ra, int lit, Register rc ); ++ void extlh ( Register ra, Register rb, Register rc ); ++ void extlh ( Register ra, int lit, Register rc ); ++ void extlw ( Register ra, Register rb, Register rc ); ++ void extlw ( Register ra, int lit, Register rc ); ++ void extll ( Register ra, Register rb, Register rc ); ++ void extll ( Register ra, int lit, Register rc ); ++ void exthb ( Register ra, Register rb, Register rc ); ++ void exthb ( Register ra, int lit, Register rc ); ++ void exthh ( Register ra, Register rb, Register rc ); ++ void exthh ( Register ra, int lit, Register rc ); ++ void exthw ( Register ra, Register rb, Register rc ); ++ void exthw ( Register ra, int lit, Register rc ); ++ void exthl ( Register ra, Register rb, Register rc ); ++ void exthl ( Register ra, int lit, Register rc ); ++ void ctpop ( Register rb, Register rc ); ++ void ctlz ( Register rb, Register rc ); ++ void cttz ( Register rb, Register rc ); ++ void revbh ( Register rb, Register rc ); ++ void revbw ( Register rb, Register rc ); ++ void revbl ( Register rb, Register rc ); ++ void casw ( Register ra, Register rb, Register rc ); ++ void casl ( Register ra, Register rb, Register rc ); ++ void masklb ( Register ra, Register rb, Register rc ); ++ void masklb ( Register ra, int lit, Register rc ); ++ void masklh ( Register ra, Register rb, Register rc ); ++ void masklh ( Register ra, int lit, Register rc ); ++ void masklw ( Register ra, Register rb, Register rc ); ++ void masklw ( Register ra, int lit, Register rc ); ++ void maskll ( Register ra, Register rb, Register rc ); ++ void maskll ( Register ra, int lit, Register rc ); ++ void maskhb ( Register ra, Register rb, Register rc ); ++ void maskhb ( Register ra, int lit, Register rc ); ++ void maskhh ( Register ra, Register rb, Register rc ); ++ void maskhh ( Register ra, int lit, Register rc ); ++ void maskhw ( Register ra, Register rb, Register rc ); ++ void maskhw ( Register ra, int lit, Register rc ); ++ void maskhl ( Register ra, Register rb, Register rc ); ++ void maskhl ( Register ra, int lit, Register rc ); ++ void zap ( Register ra, Register rb, Register rc ); ++ void zap ( Register ra, int lit, Register rc ); ++ void zapnot ( Register ra, Register rb, Register rc ); ++ void zapnot ( Register ra, int lit, Register rc ); ++ void sextb ( Register rb, Register rc); ++ void sextb ( int lit, Register rc ); ++ void sexth ( Register rb, Register rc ); ++ void sexth ( int lit, Register rc ); ++ void cmpgeb ( Register ra, Register rb, Register rc ); ++ void cmpgeb ( Register ra, int lit, Register rc ); ++ void fimovs ( FloatRegister fa, Register rc ); // For sw4a SQData ++ void fimovd ( FloatRegister fa, Register rc ); // For sw4a SQData ++ void seleq ( Register ra, Register rb,Register r3, Register rc ); ++ void seleq ( Register ra, int lit, Register r3,Register rc ); ++ void selge ( Register ra, Register rb,Register r3, Register rc ); ++ void selge ( Register ra, int lit, Register r3,Register rc ); ++ void selgt ( Register ra, Register rb,Register r3, Register rc ); ++ void selgt ( Register ra, int lit, Register r3,Register rc ); ++ void selle ( Register ra, Register rb,Register r3, Register rc ); ++ void selle ( Register ra, int lit, Register r3,Register rc ); ++ void sellt ( Register ra, Register rb,Register r3, Register rc ); ++ void sellt ( Register ra, int lit, Register r3,Register rc ); ++ void selne ( Register ra, Register rb,Register r3, Register rc ); ++ void selne ( Register ra, int lit, Register r3,Register rc ); ++ void sellbc ( Register ra, Register rb,Register r3, Register rc ); ++ void sellbc ( Register ra, int lit, Register r3,Register rc ); ++ void sellbs ( Register ra, Register rb,Register r3, Register rc ); ++ void sellbs ( Register ra, int lit, Register r3,Register rc ); ++ ++ void vlog ( int vlog, FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ); ++ void vbisw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vxorw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vandw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void veqvw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vornotw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vbicw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ ++ void fadds ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void faddd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fsubs ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fsubd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fmuls ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fmuld ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fdivs ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fdivd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fsqrts ( FloatRegister fb, FloatRegister fc ); ++ void fsqrtd ( FloatRegister fb, FloatRegister fc ); ++ void fcmpeq ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fcmple ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fcmplt ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fcmpun ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fcvtsd ( FloatRegister fb, FloatRegister fc ); ++ void fcvtds ( FloatRegister fb, FloatRegister fc ); ++ void fcvtdl_g ( FloatRegister fb, FloatRegister fc ); //lx_fcvtdl ++ void fcvtdl_p ( FloatRegister fb, FloatRegister fc ); ++ void fcvtdl_z ( FloatRegister fb, FloatRegister fc ); ++ void fcvtdl_n ( FloatRegister fb, FloatRegister fc ); //lx_fcvtdl ++ void fcvtdl ( FloatRegister fb, FloatRegister fc ); ++ void fcvtwl ( FloatRegister fb, FloatRegister fc ); ++ void fcvtlw ( FloatRegister fb, FloatRegister fc ); ++ void fcvtls ( FloatRegister fb, FloatRegister fc ); ++ void fcvtld ( FloatRegister fb, FloatRegister fc ); ++ void fcpys ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fcpyse ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void fcpysn ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void ifmovs ( Register ra, FloatRegister fc ); // For sw4a SQData ++ void ifmovd ( Register ra, FloatRegister fc ); // For sw4a SQData ++ //cmov ++ void cmovdl ( Register rc, FloatRegister fb ); ++ void cmovdl_g ( Register rc, FloatRegister fb ); ++ void cmovdl_p ( Register rc, FloatRegister fb ); ++ void cmovdl_z ( Register rc, FloatRegister fb ); ++ void cmovdl_n ( Register rc, FloatRegister fb ); ++ ++ void cmovdlu ( Register rc, FloatRegister fb ); ++ void cmovdlu_g ( Register rc, FloatRegister fb ); ++ void cmovdlu_p ( Register rc, FloatRegister fb ); ++ void cmovdlu_z ( Register rc, FloatRegister fb ); ++ void cmovdlu_n ( Register rc, FloatRegister fb ); ++ ++ void cmovdw ( Register rc, FloatRegister fb ); ++ void cmovdw_g ( Register rc, FloatRegister fb ); ++ void cmovdw_p ( Register rc, FloatRegister fb ); ++ void cmovdw_z ( Register rc, FloatRegister fb ); ++ void cmovdw_n ( Register rc, FloatRegister fb ); ++ ++ void cmovdwu ( Register rc, FloatRegister fb ); ++ void cmovdwu_g ( Register rc, FloatRegister fb ); ++ void cmovdwu_p ( Register rc, FloatRegister fb ); ++ void cmovdwu_z ( Register rc, FloatRegister fb ); ++ void cmovdwu_n ( Register rc, FloatRegister fb ); ++ ++ void cmovls ( FloatRegister fc, Register rb ); ++ void cmovld ( FloatRegister fc, Register rb ); ++ void cmovuls ( FloatRegister fc, Register rb ); ++ void cmovuld ( FloatRegister fc, Register rb ); ++ void cmovws ( FloatRegister fc, Register rb ); ++ void cmovwd ( FloatRegister fc, Register rb ); ++ void cmovuws ( FloatRegister fc, Register rb ); ++ void cmovuwd ( FloatRegister fc, Register rb ); ++ ++ void rfpcr ( FloatRegister fa); ++ void wfpcr ( FloatRegister fa); ++ void setfpec0 (); ++ void setfpec1 (); ++ void setfpec2 (); ++ void setfpec3 (); ++ void frecs ( FloatRegister fa, FloatRegister fc ); ++ void frecd ( FloatRegister fa, FloatRegister fc ); ++ void fris ( FloatRegister fb, FloatRegister fc ); ++ void fris_g ( FloatRegister fb, FloatRegister fc ); ++ void fris_p ( FloatRegister fb, FloatRegister fc ); ++ void fris_z ( FloatRegister fb, FloatRegister fc ); ++ void fris_n ( FloatRegister fb, FloatRegister fc ); ++ void frid ( FloatRegister fb, FloatRegister fc ); ++ void frid_g ( FloatRegister fb, FloatRegister fc ); ++ void frid_p ( FloatRegister fb, FloatRegister fc ); ++ void frid_z ( FloatRegister fb, FloatRegister fc ); ++ void frid_n ( FloatRegister fb, FloatRegister fc ); ++ void fmas ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fmad ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fmss ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fmsd ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fnmas ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fnmad ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fnmss ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fnmsd ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fseleq ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fselne ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fsellt ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fselle ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fselgt ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void fselge ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ ++ void vaddw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vaddw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsubw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsubw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmpgew ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpgew ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmpeqw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpeqw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmplew ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmplew ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmpltw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpltw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmpulew ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpulew ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmpultw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpultw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsllw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsllw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsrlw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsrlw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsraw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsraw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vrolw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vrolw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void sllow ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void sllow ( FloatRegister fa, int lit, FloatRegister fc ); ++ void srlow ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void srlow ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vaddl ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vaddl ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsubl ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsubl ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsllb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsllb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsrlb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsrlb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsrab ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsrab ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vrolb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vrolb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsllh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsllh ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsrlh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsrlh ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsrah ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsrah ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vrolh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vrolh ( FloatRegister fa, int lit, FloatRegister fc ); ++ void ctpopow ( FloatRegister fa, FloatRegister fc ); ++ void ctlzow ( FloatRegister fa, FloatRegister fc ); ++ void vslll ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vslll ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsrll ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsrll ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsral ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsral ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vroll ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vroll ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vmaxb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vminb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ ++ void vucaddw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vucaddw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vucsubw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vucsubw ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vucaddh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vucaddh ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vucsubh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vucsubh ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vucaddb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vucaddb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vucsubb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vucsubb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void sraow ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void sraow ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsumw ( FloatRegister fa, FloatRegister fc ); ++ void vsuml ( FloatRegister fa, FloatRegister fc ); ++ void vcmpueqb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpueqb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vcmpugtb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcmpugtb ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vmaxh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vminh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmaxw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vminw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmaxl ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vminl ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vumaxb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vuminb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vumaxh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vuminh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vumaxw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vuminw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vumaxl ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vuminl ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ ++ void vsm3msw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsm4key ( FloatRegister fa, int lit, FloatRegister fc ); ++ void vsm4r ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vbinvw ( FloatRegister fb, FloatRegister fc ); ++ ++ void vadds ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vaddd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsubs ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsubd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmuls ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmuld ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vdivs ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vdivd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsqrts ( FloatRegister fb, FloatRegister fc ); ++ void vsqrtd ( FloatRegister fb, FloatRegister fc ); ++ void vfcmpeq ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vfcmple ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vfcmplt ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vfcmpun ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcpys ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vfmov ( FloatRegister fa, FloatRegister fc ); ++ void vcpyse ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcpysn ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vsums ( FloatRegister fa, FloatRegister fc ); ++ void vsumd ( FloatRegister fa, FloatRegister fc ); ++ void vfrecs ( FloatRegister fa, FloatRegister fc ); ++ void vfrecd ( FloatRegister fa, FloatRegister fc ); ++ void vfcvtsd ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtds ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtls ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtld ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtdl ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtdl_g ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtdl_p ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtdl_z ( FloatRegister fb, FloatRegister fc ); ++ void vfcvtdl_n ( FloatRegister fb, FloatRegister fc ); ++ void vfris ( FloatRegister fb, FloatRegister fc ); ++ void vfris_g ( FloatRegister fb, FloatRegister fc ); ++ void vfris_p ( FloatRegister fb, FloatRegister fc ); ++ void vfris_z ( FloatRegister fb, FloatRegister fc ); ++ void vfris_n ( FloatRegister fb, FloatRegister fc ); ++ void vfrid ( FloatRegister fb, FloatRegister fc ); ++ void vfrid_g ( FloatRegister fb, FloatRegister fc ); ++ void vfrid_p ( FloatRegister fb, FloatRegister fc ); ++ void vfrid_z ( FloatRegister fb, FloatRegister fc ); ++ void vfrid_n ( FloatRegister fb, FloatRegister fc ); ++ void vmaxs ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmins ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmaxd ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vmind ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ ++ void vmas ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vmad ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vmss ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vmsd ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vnmas ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vnmad ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vnmss ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vnmsd ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vfseleq ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vfsellt ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vfselle ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vseleqw ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vseleqw ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vsellbcw ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vsellbcw ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vselltw ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vselltw ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vsellew ( FloatRegister fa, FloatRegister fb, FloatRegister f3, FloatRegister fc ); ++ void vsellew ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vinsw ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vinsf ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vextw ( FloatRegister fa, int fmalit, FloatRegister fc); ++ void vextf ( FloatRegister fa, int fmalit, FloatRegister fc); ++ void vcpyw ( FloatRegister fa, FloatRegister fc); ++ void vcpyf ( FloatRegister fa, FloatRegister fc); ++ void vconw ( FloatRegister va, FloatRegister vb, FloatRegister fc, FloatRegister vd ); ++ void vshfw ( FloatRegister va, FloatRegister vb, FloatRegister fc, FloatRegister vd ); ++ void vcons ( FloatRegister va, FloatRegister vb, FloatRegister fc, FloatRegister vd ); ++ void vcond ( FloatRegister va, FloatRegister vb, FloatRegister fc, FloatRegister vd ); ++ void vinsb ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vinsh ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vinsectlh ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vinsectlw ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vinsectll ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vinsectlb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vshfq ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vshfqb ( FloatRegister fa, FloatRegister fb, FloatRegister fc ); ++ void vcpyb ( FloatRegister fa, FloatRegister fc ); ++ void vcpyh ( FloatRegister fa, FloatRegister fc ); ++ void vsm3r ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vfcvtsh ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ void vfcvths ( FloatRegister fa, FloatRegister fb, int fmalit, FloatRegister fc ); ++ ++ void vldw_u ( FloatRegister fa, int atmdisp, Register rb ); ++ void vstw_u ( FloatRegister fa, int atmdisp, Register rb ); ++ void vlds_u ( FloatRegister fa, int atmdisp, Register rb ); ++ void vsts_u ( FloatRegister fa, int atmdisp, Register rb ); ++ void vldd_u ( FloatRegister fa, int atmdisp, Register rb ); ++ void vstd_u ( FloatRegister fa, int atmdisp, Register rb ); ++ void vstw_ul ( FloatRegister fa, int atmdisp, Register rb ); ++ void vstw_uh ( FloatRegister fa, int atmdisp, Register rb ); ++ void vsts_ul ( FloatRegister fa, int atmdisp, Register rb ); ++ void vsts_uh ( FloatRegister fa, int atmdisp, Register rb ); ++ void vstd_ul ( FloatRegister fa, int atmdisp, Register rb ); ++ void vstd_uh ( FloatRegister fa, int atmdisp, Register rb ); ++ void lbr ( int palfn ); ++ void ldbu_a ( Register ra, int atmdisp, Register rb ); ++ void ldhu_a ( Register ra, int atmdisp, Register rb ); ++ void ldw_a ( Register ra, int atmdisp, Register rb ); ++ void ldl_a ( Register ra, int atmdisp, Register rb ); ++ void stb_a ( Register ra, int atmdisp, Register rb ); ++ void sth_a ( Register ra, int atmdisp, Register rb ); ++ void stw_a ( Register ra, int atmdisp, Register rb ); ++ void stl_a ( Register ra, int atmdisp, Register rb ); ++ void flds_a ( FloatRegister fa, int atmdisp, Register rb ); ++ void fldd_a ( FloatRegister fa, int atmdisp, Register rb ); ++ void fsts_a ( FloatRegister fa, int atmdisp, Register rb ); ++ void fstd_a ( FloatRegister fa, int atmdisp, Register rb ); ++ void dpfhr ( int th, int atmdisp, Register rb ); ++ void dpfhw ( int th, int atmdisp, Register rb ); ++ void ldbu ( Register ra, int mdisp, Register rb ); ++ void ldhu ( Register ra, int mdisp, Register rb ); ++ void ldw ( Register ra, int mdisp, Register rb ); ++ void ldl ( Register ra, int mdisp, Register rb ); ++ void ldl_u ( Register ra, int mdisp, Register rb ); ++ void pri_ld ( Register ra, int ev6hwdisp, Register rb ); ++ void flds ( FloatRegister fa, int mdisp, Register rb ); ++ void fldd ( FloatRegister fa, int mdisp, Register rb ); ++ void stb ( Register ra, int mdisp, Register rb ); ++ void sth ( Register ra, int mdisp, Register rb ); ++ void stw ( Register ra, int mdisp, Register rb ); ++ void stl ( Register ra, int mdisp, Register rb ); ++ void stl_u ( Register ra, int mdisp, Register rb ); ++ void pri_st ( Register ra, int ev6hwdisp, Register rb ); ++ void fsts ( FloatRegister fa, int mdisp, Register rb ); ++ void fstd ( FloatRegister fa, int mdisp, Register rb ); ++ void beq ( Register ra, int bdisp ); ++ void bne ( Register ra, int bdisp ); ++ void blt ( Register ra, int bdisp ); ++ void ble ( Register ra, int bdisp ); ++ void bgt ( Register ra, int bdisp ); ++ void bge ( Register ra, int bdisp ); ++ void blbc ( Register ra, int bdisp ); ++ void blbs ( Register ra, int bdisp ); ++ void fbeq ( FloatRegister fa, int bdisp ); ++ void fbne ( FloatRegister fa, int bdisp ); ++ void fblt ( FloatRegister fa, int bdisp ); ++ void fble ( FloatRegister fa, int bdisp ); ++ void fbgt ( FloatRegister fa, int bdisp ); ++ void fbge ( FloatRegister fa, int bdisp ); ++ void ldi ( Register ra, int mdisp, Register rb ); ++ void ldih ( Register ra, int mdisp, Register rb ); ++ ++ // cache control instruction ++ void s_fillcs ( int mdisp, Register rb ); ++ void s_fillde ( int mdisp, Register rb ); ++ void fillde ( int mdisp, Register rb ); ++ void fillde_e ( int mdisp, Register rb ); ++ void fillcs ( int mdisp, Register rb ); ++ void fillcs_e ( int mdisp, Register rb ); ++ void e_fillcs ( int mdisp, Register rb ); ++ void e_fillde ( int mdisp, Register rb ); ++ void flushd ( int mdisp, Register rb ); ++ void evictdl ( int mdisp, Register rb ); ++ void evictdg ( int mdisp, Register rb ); ++ ++ //jzy just for compiling, maybe delete in future ++ static address locate_operand(address inst, WhichOperand which) { assert(false, "unimplement locate_operand:jzy"); return inst;} ++ static address locate_next_instruction(address inst) { assert(false, "unimplement locate_next_instruction:jzy"); return inst;} ++ static bool is_polling_page_far() { assert(false, "unimplement is_polling_page_far:jzy");; return false; } ++ void clflush(Address addr) { assert(false, "unimplement clflush:jzy"); } ++}; ++ ++// Invert a condition ++inline const Assembler::Condition operator~(const Assembler::Condition cond) { ++ return Assembler::Condition(int(cond) ^ 1); ++} ++ ++class BiasedLockingCounters; ++ ++extern "C" void das(uint64_t start, int len); ++ ++#endif // CPU_SW64_VM_ASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/assembler_sw64.inline.hpp afu11u/src/hotspot/cpu/sw64/assembler_sw64.inline.hpp +--- openjdk/src/hotspot/cpu/sw64/assembler_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/assembler_sw64.inline.hpp 2025-05-09 10:06:54.192292504 +0800 +@@ -0,0 +1,1227 @@ ++/* ++ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_ASSEMBLER_SW64_INLINE_HPP ++#define CPU_SW64_VM_ASSEMBLER_SW64_INLINE_HPP ++ ++#include "asm/assembler.inline.hpp" ++#include "asm/codeBuffer.hpp" ++#include "code/codeCache.hpp" ++ ++inline void Assembler::emit_sw2_long(int x) { ++ AbstractAssembler::emit_int32(x); ++} ++ ++inline void Assembler::sys_call_b( int palfn ) ++ { emit_sw2_long( op_sys_call | is_palfn(palfn) ); } ++inline void Assembler::sys_call( int palfn ) ++ { sys_call_b(palfn); /* emit_sw2_long( op_sys_call | ( 0x1 << 25 ) | is_palfn(palfn) );*/ } ++ ++inline void Assembler::call( Register ra, Register rb, int jmphint ) ++ { emit_sw2_long( op_call | is_ra(ra) | is_rb(rb) | is_jmphint(jmphint) ); } ++inline void Assembler::ret( Register ra, Register rb, int rethint ) ++ { emit_sw2_long( op_ret | is_ra(ra) | is_rb(rb) | is_rethint(rethint) ); } ++inline void Assembler::jmp( Register ra, Register rb, int jmphint ) ++ { emit_sw2_long( op_jmp | is_ra(ra) | is_rb(rb) | is_jmphint(jmphint) ); } ++inline void Assembler::br( Register ra, int bdisp ) ++ { emit_sw2_long( op_br | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::bsr( Register ra, int bdisp ) ++ { emit_sw2_long( op_bsr | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::memb( void ) ++ { emit_sw2_long( op_memb); } ++inline void Assembler::imemb( void ) ++ { sw3_only(); emit_sw2_long( op_imemb); } ++inline void Assembler::wmemb( void ) ++ { sw4_only(); emit_sw2_long( op_wmemb); } ++inline void Assembler::rtc( Register ra, Register rb ) ++ { emit_sw2_long( op_rtc | is_ra(ra) | is_rb(rb) ); } ++inline void Assembler::rcid( Register ra ) ++ { emit_sw2_long( op_rcid | is_ra(ra) ); } ++inline void Assembler::halt( void ) ++ { emit_sw2_long( op_halt ); } ++inline void Assembler::rd_f( Register ra ) ++ { sw2_only(); emit_sw2_long( op_rd_f | is_ra(ra) | is_rb(R0) ); } ++inline void Assembler::wr_f( Register ra ) ++ { sw2_only(); emit_sw2_long( op_wr_f | is_ra(ra) | is_rb(R0) ); } ++inline void Assembler::rtid( Register ra ) ++ { emit_sw2_long( op_rtid | is_ra(ra) ); } ++inline void Assembler::csrws( Register ra, int rpiindex ) ++{ sw4_only(); emit_sw2_long( op_csrws | is_ra(ra) | is_rpiindex(rpiindex) ); } ++inline void Assembler::csrwc( Register ra, int rpiindex ) ++{ sw4_only(); emit_sw2_long( op_csrwc | is_ra(ra) | is_rpiindex(rpiindex) ); } ++inline void Assembler::csrr( Register ra, int rpiindex ) ++ { emit_sw2_long( op_csrr | is_ra(ra) | is_rpiindex(rpiindex) ); } ++inline void Assembler::csrw( Register ra, int rpiindex ) ++ { emit_sw2_long( op_csrw | is_ra(ra) | is_rpiindex(rpiindex) ); } ++inline void Assembler::pri_ret( Register ra ) ++ { emit_sw2_long( op_pri_ret | is_ra(ra) ); } ++ ++inline void Assembler::lldw( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_lldw | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::lldl( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_lldl | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++ ++inline void Assembler::ldw_inc( Register ra, int atmdisp, Register rb ) ++ { sw2_only(); emit_sw2_long( op_ldw_inc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldl_inc( Register ra, int atmdisp, Register rb ) ++ { sw2_only(); emit_sw2_long( op_ldl_inc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldw_dec( Register ra, int atmdisp, Register rb ) ++ { sw2_only(); emit_sw2_long( op_ldw_dec | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldl_dec( Register ra, int atmdisp, Register rb ) ++ { sw2_only(); emit_sw2_long( op_ldl_dec | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldw_set( Register ra, int atmdisp, Register rb ) ++ { sw2_only(); emit_sw2_long( op_ldw_set | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldl_set( Register ra, int atmdisp, Register rb ) ++ { sw2_only(); emit_sw2_long( op_ldl_set | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++ ++inline void Assembler::lstw( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_lstw | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::lstl( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_lstl | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldw_nc( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_ldw_nc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldl_nc( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_ldl_nc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldd_nc( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_ldd_nc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::stw_nc( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_stw_nc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::stl_nc( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_stl_nc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::std_nc( Register ra, int atmdisp, Register rb ) ++ { emit_sw2_long( op_std_nc | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++ ++inline void Assembler::ldwe( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldwe | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldse( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldse | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldde( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldde | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::vlds( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_vlds | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::vldd( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_vldd | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::vsts( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_vsts | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::vstd( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_vstd | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++ ++inline void Assembler::addw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_addw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::addw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_addw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::subw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_subw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::subw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_subw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s4addw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s4addw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s4addw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s4addw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s4subw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s4subw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s4subw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s4subw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s8addw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s8addw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s8addw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s8addw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s8subw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s8subw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s8subw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s8subw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::addl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_addl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::addl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_addl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::subl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_subl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::subl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_subl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s4addl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s4addl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s4addl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s4addl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s4subl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s4subl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s4subl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s4subl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s8addl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s8addl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s8addl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s8addl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::s8subl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_s8subl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::s8subl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_s8subl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::mulw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_mulw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::mulw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_mulw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::divw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_divw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::udivw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_udivw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::remw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_remw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::uremw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_uremw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++ ++inline void Assembler::mull( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_mull | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::mull( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_mull_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::umulh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_umulh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::umulh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_umulh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::divl( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_divl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::udivl( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_udivl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::reml( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_reml | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::ureml( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_ureml | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++ ++inline void Assembler::addpi( int apint, Register rc ) ++ { sw4_only(); emit_sw2_long( op_addpi | is_apint(apint) | is_rc(rc) ); } ++inline void Assembler::addpis( int apint, Register rc ) ++ { sw4_only(); emit_sw2_long( op_addpis | is_apint(apint) | is_rc(rc) ); } ++ ++inline void Assembler::cmpeq( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_cmpeq | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cmpeq( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_cmpeq_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::cmplt( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_cmplt | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cmplt( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_cmplt_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::cmple( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_cmple | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cmple( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_cmple_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::cmpult( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_cmpult | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cmpult( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_cmpult_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::cmpule( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_cmpule | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cmpule( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_cmpule_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::sbt( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_sbt | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::sbt( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_sbt_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::cbt( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_cbt | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cbt( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_cbt_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::and_ins( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_and | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::and_ins( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_and_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::bic( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_bic | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::bic( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_bic_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::bis( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_bis | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::bis( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_bis_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::ornot( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_ornot | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::ornot( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_ornot_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::xor_ins( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_xor | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::xor_ins( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_xor_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::eqv( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_eqv | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::eqv( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_eqv_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::inslb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inslb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inslb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inslb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::inslh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inslh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inslh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inslh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::inslw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inslw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inslw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inslw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::insll( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_insll | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::insll( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_insll_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::inshb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inshb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inshb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inshb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::inshh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inshh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inshh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inshh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::inshw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inshw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inshw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inshw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::inshl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_inshl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::inshl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_inshl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::slll( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_slll | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::slll( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_slll_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::srll( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_srll | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::srll( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_srll_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::sral( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_sral | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::sral( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_sral_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::roll( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_roll | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::roll( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_roll_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::sllw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_sllw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::sllw( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_sllw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::srlw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_srlw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::srlw( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_srlw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::sraw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_sraw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::sraw( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_sraw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::rolw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_rolw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::rolw( Register ra, int lit, Register rc ) ++ { sw4_only(); emit_sw2_long( op_rolw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::extlb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_extlb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::extlb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_extlb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::extlh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_extlh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::extlh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_extlh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::extlw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_extlw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::extlw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_extlw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::extll( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_extll | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::extll( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_extll_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::exthb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_exthb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::exthb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_exthb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::exthh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_exthh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::exthh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_exthh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::exthw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_exthw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::exthw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_exthw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::exthl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_exthl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::exthl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_exthl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::ctpop( Register rb, Register rc ) ++ { emit_sw2_long( op_ctpop | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::ctlz( Register rb, Register rc ) ++ { emit_sw2_long( op_ctlz | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cttz( Register rb, Register rc ) ++ { emit_sw2_long( op_cttz | is_rb(rb) | is_rc(rc) ); } ++ ++inline void Assembler::revbh( Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_revbh | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::revbw( Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_revbw | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::revbl( Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_revbl | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::casw( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_casw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::casl( Register ra, Register rb, Register rc ) ++ { sw4_only(); emit_sw2_long( op_casl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++ ++inline void Assembler::masklb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_masklb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::masklb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_masklb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::masklh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_masklh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::masklh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_masklh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::masklw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_masklw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::masklw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_masklw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::maskll( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_maskll | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::maskll( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_maskll_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::maskhb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_maskhb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::maskhb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_maskhb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::maskhh( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_maskhh | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::maskhh( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_maskhh_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::maskhw( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_maskhw | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::maskhw( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_maskhw_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::maskhl( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_maskhl | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::maskhl( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_maskhl_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++ ++inline void Assembler::zap( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_zap | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::zap( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_zap_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::zapnot( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_zapnot | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::zapnot( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_zapnot_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::sextb( Register rb, Register rc) ++ { emit_sw2_long( op_sextb | is_ra(R0) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::sextb( int lit, Register rc ) ++ { emit_sw2_long( op_sextb_l | is_ra(R0) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::sexth( Register rb, Register rc ) ++ { emit_sw2_long( op_sexth | is_ra(R0) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::sexth( int lit, Register rc ) ++ { emit_sw2_long( op_sexth_l | is_ra(R0) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::cmpgeb( Register ra, Register rb, Register rc ) ++ { emit_sw2_long( op_cmpgeb | is_ra(ra) | is_rb(rb) | is_rc(rc) ); } ++inline void Assembler::cmpgeb( Register ra, int lit, Register rc ) ++ { emit_sw2_long( op_cmpgeb_l | is_ra(ra) | is_lit(lit) | is_rc(rc) ); } ++inline void Assembler::fimovs( FloatRegister fa, Register rc ) // For sw4a SQData ++ { emit_sw2_long( op_fimovs | is_fa(fa) | is_rc(rc) ); } ++inline void Assembler::fimovd( FloatRegister fa, Register rc ) // For sw4a SQData ++ { emit_sw2_long( op_fimovd | is_fa(fa) | is_rc(rc) ); } ++ ++inline void Assembler::seleq( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_seleq | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::seleq( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_seleq_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selge( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_selge | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selge( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_selge_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selgt( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_selgt | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selgt( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_selgt_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selle( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_selle | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selle( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_selle_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::sellt( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_sellt | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::sellt( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_sellt_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selne( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_selne | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::selne( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_selne_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::sellbc( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_sellbc | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::sellbc( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_sellbc_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::sellbs( Register ra, Register rb,Register r3, Register rc ) ++ { emit_sw2_long( op_sellbs | is_ra(ra) | is_rb(rb) | is_r3(r3) | is_rc(rc) ); } ++inline void Assembler::sellbs( Register ra, int lit, Register r3,Register rc ) ++ { emit_sw2_long( op_sellbs_l | is_ra(ra) | is_lit(lit) | is_r3(r3) | is_rc(rc) ); } ++ ++inline void Assembler::vlog( int vlog ,FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vlog | is_vlog_h(vlog) | is_vlog_l(vlog) | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vbisw( FloatRegister fa , FloatRegister fb , FloatRegister fc ) ++ { emit_sw2_long( op_vbisw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vxorw( FloatRegister fa , FloatRegister fb , FloatRegister fc ) ++ { emit_sw2_long( op_vxorw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vandw( FloatRegister fa , FloatRegister fb , FloatRegister fc ) ++ { emit_sw2_long( op_vandw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::veqvw( FloatRegister fa , FloatRegister fb , FloatRegister fc ) ++ { emit_sw2_long( op_veqvw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vornotw( FloatRegister fa , FloatRegister fb , FloatRegister fc ) ++ { emit_sw2_long( op_vornotw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vbicw( FloatRegister fa , FloatRegister fb , FloatRegister fc ) ++ { emit_sw2_long( op_vbicw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::fadds( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fadds | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::faddd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_faddd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fsubs( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fsubs | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fsubd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fsubd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fmuls( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fmuls | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fmuld( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fmuld | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fdivs( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fdivs | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fdivd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fdivd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fsqrts( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fsqrts | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fsqrtd( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fsqrtd | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::fcmpeq( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcmpeq | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcmple( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcmple | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcmplt( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcmplt | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcmpun( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcmpun | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::fcvtsd( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtsd | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtds( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtds | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtdl_g( FloatRegister fb, FloatRegister fc ) //lx_fcvtdl ++ { emit_sw2_long( op_fcvtdl_g | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtdl_p( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtdl_p | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtdl_z( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtdl_z | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtdl_n( FloatRegister fb, FloatRegister fc ) //lx_fcvtdl ++ { emit_sw2_long( op_fcvtdl_n | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtdl( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtdl | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtwl( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtwl | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtlw( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtlw | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtls( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtls | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcvtld( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcvtld | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::fcpys( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcpys | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcpyse( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcpyse | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fcpysn( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_fcpysn | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::ifmovs( Register ra, FloatRegister fc ) ++ { emit_sw2_long( op_ifmovs | is_ra(ra) | is_fc(fc) ); } ++inline void Assembler::ifmovd( Register ra, FloatRegister fc ) ++ { emit_sw2_long( op_ifmovd | is_ra(ra) | is_fc(fc) ); } ++ //cmov ++inline void Assembler::cmovdl( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdl | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdl_g( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdl_g | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdl_p( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdl_p | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdl_z( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdl_z | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdl_n( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdl_n | is_fb(fb) | is_rc(rc) ); } ++ ++inline void Assembler::cmovdlu( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdlu | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdlu_g( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdlu_g | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdlu_p( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdlu_p | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdlu_z( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdlu_z | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdlu_n( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdlu_n | is_fb(fb) | is_rc(rc) ); } ++ ++inline void Assembler::cmovdw( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdw | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdw_g( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdw_g | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdw_p( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdw_p | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdw_z( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdw_z | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdw_n( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdw_n | is_fb(fb) | is_rc(rc) ); } ++ ++inline void Assembler::cmovdwu( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdwu | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdwu_g( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdwu_g | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdwu_p( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdwu_p | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdwu_z( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdwu_z | is_fb(fb) | is_rc(rc) ); } ++inline void Assembler::cmovdwu_n( Register rc, FloatRegister fb ) ++{ sw4_only(); emit_sw2_long( op_cmovdwu_n | is_fb(fb) | is_rc(rc) ); } ++ ++inline void Assembler::cmovls( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovls | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovld( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovld | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovuls( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovuls | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovuld( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovuld | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovws( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovws | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovwd( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovwd | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovuws( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovuws | is_rb(rb) | is_fc(fc) ); } ++inline void Assembler::cmovuwd( FloatRegister fc, Register rb ) ++{ sw4_only(); emit_sw2_long( op_cmovuwd | is_rb(rb) | is_fc(fc) ); } ++ ++inline void Assembler::rfpcr( FloatRegister fa) ++ { emit_sw2_long( op_rfpcr | is_fa(fa) ); } ++inline void Assembler::wfpcr( FloatRegister fa) ++ { emit_sw2_long( op_wfpcr | is_fa(fa) ); } ++ ++inline void Assembler::setfpec0() { emit_sw2_long( op_setfpec0 ); } ++inline void Assembler::setfpec1() { emit_sw2_long( op_setfpec1 ); } ++inline void Assembler::setfpec2() { emit_sw2_long( op_setfpec2 ); } ++inline void Assembler::setfpec3() { emit_sw2_long( op_setfpec3 ); } ++ ++inline void Assembler::frecs( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frecs | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::frecd( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frecd | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::fris( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_fris | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fris_g( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_fris_g | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fris_p( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_fris_p | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fris_z( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_fris_z | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::fris_n( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_fris_n | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::frid( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frid | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::frid_g( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frid_g | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::frid_p( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frid_p | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::frid_z( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frid_z | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::frid_n( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_frid_n | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::fmas( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fmas | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fmad( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fmad | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fmss( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fmss | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fmsd( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fmsd | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fnmas( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fnmas | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fnmad( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fnmad | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fnmss( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fnmss | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fnmsd( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fnmsd | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++ ++inline void Assembler::fseleq( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fseleq | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fselne( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fselne | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fsellt( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fsellt | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fselle( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fselle | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fselgt( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fselgt | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::fselge( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_fselge | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++ ++inline void Assembler::vaddw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vaddw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vaddw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vaddw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsubw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsubw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsubw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vsubw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++ ++inline void Assembler::vcmpgew( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpgew | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpgew( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpgew_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vcmpeqw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpeqw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpeqw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpeqw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vcmplew( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcmplew | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmplew( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vcmplew_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vcmpltw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpltw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpltw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpltw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vcmpulew( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpulew | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpulew( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpulew_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vcmpultw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpultw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpultw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vcmpultw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++ ++inline void Assembler::vsllw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsllw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsllw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vsllw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsrlw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsrlw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsrlw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vsrlw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsraw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsraw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsraw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vsraw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vrolw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vrolw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vrolw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vrolw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::sllow( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_sllow | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::sllow( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_sllow_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::srlow( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_srlow | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::srlow( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_srlow_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++ ++inline void Assembler::vaddl( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vaddl | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vaddl( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vaddl_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsubl( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsubl | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsubl( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vsubl_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++ ++inline void Assembler::vsllb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsllb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsllb( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsllb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsrlb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrlb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsrlb( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrlb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsrab( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrab | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsrab( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrab_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vrolb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vrolb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vrolb( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vrolb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsllh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsllh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsllh( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsllh_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsrlh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrlh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsrlh( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrlh_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsrah( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrah | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsrah( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrah_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vrolh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vrolh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vrolh( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vrolh_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++ ++inline void Assembler::ctpopow( FloatRegister fa, FloatRegister fc ) ++ { emit_sw2_long( op_ctpopow | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::ctlzow( FloatRegister fa, FloatRegister fc ) ++ { emit_sw2_long( op_ctlzow | is_fa(fa) | is_fc(fc) ); } ++ ++inline void Assembler::vslll( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vslll | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vslll( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vslll_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsrll( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrll | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsrll( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsrll_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsral( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsral | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsral( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsral_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vroll( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vroll | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vroll( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vroll_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vmaxb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmaxb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vminb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vminb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vucaddw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vucaddw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vucaddw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vucaddw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vucsubw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vucsubw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vucsubw( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vucsubw_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vucaddh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vucaddh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vucaddh( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vucaddh_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vucsubh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vucsubh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vucsubh( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vucsubh_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vucaddb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vucaddb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vucaddb( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vucaddb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vucsubb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vucsubb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vucsubb( FloatRegister fa, int lit, FloatRegister fc ) ++ { emit_sw2_long( op_vucsubb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++ ++inline void Assembler::sraow( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_sraow | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::sraow( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long(op_sraow_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsumw( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsumw | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vsuml( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsuml | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vcmpueqb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vcmpueqb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpueqb( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vcmpueqb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vcmpugtb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vcmpugtb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcmpugtb( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vcmpugtb_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vmaxh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmaxh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vminh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vminh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmaxw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmaxw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vminw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vminw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmaxl( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmaxl | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vminl( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vminl | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vumaxb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vumaxb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vuminb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vuminb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vumaxh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vumaxh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vuminh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vuminh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vumaxw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vumaxw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vuminw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vuminw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vumaxl( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vumaxl | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vuminl( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vuminl | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vsm3msw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsm3msw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsm4key( FloatRegister fa, int lit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsm4key_l | is_fa(fa) | is_lit(lit) | is_fc(fc) ); } ++inline void Assembler::vsm4r( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsm4r | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vbinvw( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vbinvw | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vadds( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vadds | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vaddd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vaddd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsubs( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsubs | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsubd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsubd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmuls( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vmuls | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmuld( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vmuld | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vdivs( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vdivs | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vdivd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vdivd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsqrts( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsqrts | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vsqrtd( FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vsqrtd | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vfcmpeq( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vfcmpeq | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcmple( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vfcmple | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcmplt( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vfcmplt | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcmpun( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vfcmpun | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcpys( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcpys | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfmov( FloatRegister fa, FloatRegister fc ) ++ { emit_sw2_long( op_vcpys | is_fa(fa) | is_fb(fa) | is_fc(fc) ); } ++inline void Assembler::vcpyse( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcpyse | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcpysn( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { emit_sw2_long( op_vcpysn | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vsums( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsums | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vsumd( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsumd | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vfcvtsd( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtsd | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtds( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtds | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtls( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtls | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtld( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtld | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtdl( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtdl | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtdl_g( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtdl_g | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtdl_p( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtdl_p | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtdl_z( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtdl_z | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfcvtdl_n( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtdl_n | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vfris( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfris | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfris_g( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfris_g | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfris_p( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfris_p | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfris_z( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfris_z | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfris_n( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfris_n | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfrid( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrid | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfrid_g( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrid_g | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfrid_p( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrid_p | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfrid_z( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrid_z | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfrid_n( FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrid_n | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vfrecs( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrecs | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vfrecd( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfrecd | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vmaxs( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmaxs | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmins( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmins | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmaxd( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmaxd | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vmind( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vmind | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++ ++inline void Assembler::vmas( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vmas | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vmad( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vmad | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vmss( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vmss | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vmsd( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vmsd | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vnmas( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vnmas | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vnmad( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vnmad | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vnmss( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vnmss | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vnmsd( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vnmsd | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++ ++inline void Assembler::vfseleq( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vfseleq | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vfsellt( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vfsellt | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vfselle( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vfselle | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vseleqw( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vseleqw | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vseleqw( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { emit_sw2_long( op_vseleqw_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vsellbcw( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vsellbcw | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vsellbcw( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { emit_sw2_long( op_vsellbcw_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vselltw( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vselltw | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vselltw( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { emit_sw2_long( op_vselltw_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vsellew( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vsellew | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vsellew( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { emit_sw2_long( op_vsellew_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++ ++inline void Assembler::vinsw( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { emit_sw2_long( op_vinsw_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vinsf( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { emit_sw2_long( op_vinsf_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vextw( FloatRegister fa, int fmalit, FloatRegister fc) ++ { emit_sw2_long( op_vextw_l | is_fa(fa) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vextf( FloatRegister fa, int fmalit, FloatRegister fc) ++ { emit_sw2_long( op_vextf_l | is_fa(fa) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vcpyw( FloatRegister fa, FloatRegister fc) ++ { emit_sw2_long( op_vcpyw | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vcpyf( FloatRegister fa, FloatRegister fc) ++ { emit_sw2_long( op_vcpyf | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vconw( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vconw | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vshfw( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vshfw | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vcons( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vcons | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++inline void Assembler::vcond( FloatRegister fa,FloatRegister fb,FloatRegister f3, FloatRegister fc ) ++ { emit_sw2_long( op_vcond | is_fa(fa) | is_fb(fb) | is_f3(f3) | is_fc(fc) ); } ++ ++inline void Assembler::vinsb( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vinsb_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vinsh( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vinsh_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vinsectlh( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vinsectlh | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vinsectlw( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vinsectlw | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vinsectll( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vinsectll | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vinsectlb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vinsectlb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vshfq( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vshfq_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vshfqb( FloatRegister fa, FloatRegister fb, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vshfqb | is_fa(fa) | is_fb(fb) | is_fc(fc) ); } ++inline void Assembler::vcpyb( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vcpyb | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vcpyh( FloatRegister fa, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vcpyh | is_fa(fa) | is_fc(fc) ); } ++inline void Assembler::vsm3r( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vsm3r_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vfcvtsh( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvtsh_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++inline void Assembler::vfcvths( FloatRegister fa,FloatRegister fb, int fmalit, FloatRegister fc ) ++ { sw4_only(); emit_sw2_long( op_vfcvths_l | is_fa(fa) | is_fb(fb) | is_fmalit(fmalit) | is_fc(fc) ); } ++ ++inline void Assembler::vldw_u( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vldw_u | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vstw_u( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vstw_u | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vlds_u( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vsts_u | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vsts_u( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vsts_u | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vldd_u( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vldd_u | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vstd_u( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vstd_u | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vstw_ul( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vstw_ul | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vstw_uh( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vstw_uh | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vsts_ul( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vsts_ul | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vsts_uh( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vsts_uh | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vstd_ul( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vstd_ul | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::vstd_uh( FloatRegister fa, int atmdisp, Register rb ) ++ { emit_sw2_long( op_vstd_uh | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++ ++inline void Assembler::lbr( int palfn ) ++ { sw4_only(); emit_sw2_long( op_lbr | is_palfn(palfn) ); } ++ ++inline void Assembler::ldbu_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_ldbu_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldhu_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_ldhu_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldw_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_ldw_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::ldl_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_ldl_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::stb_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_stb_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::sth_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_sth_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::stw_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_stw_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::stl_a( Register ra, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_stl_a | is_ra(ra) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::flds_a( FloatRegister fa, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_flds_a | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::fldd_a( FloatRegister fa, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_fldd_a | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::fsts_a( FloatRegister fa, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_fsts_a | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::fstd_a( FloatRegister fa, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_fstd_a | is_fa(fa) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++ ++inline void Assembler::dpfhr( int th, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_dpfhr | is_th(th) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++inline void Assembler::dpfhw( int th, int atmdisp, Register rb ) ++ { sw4_only(); emit_sw2_long( op_dpfhw | is_th(th) | is_atmdisp(atmdisp) | is_rb(rb) ); } ++ ++inline void Assembler::ldbu( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldbu | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldhu( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldhu | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldw( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldw | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldl( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldl | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldl_u( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldl_u | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++ ++inline void Assembler::pri_ld( Register ra, int ev6hwdisp, Register rb ) ++ { emit_sw2_long( op_pri_ld | is_ra(ra) | is_ev6hwdisp(ev6hwdisp) | is_rb(rb) ); } ++ ++inline void Assembler::flds( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_flds | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::fldd( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_fldd | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::stb( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_stb | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::sth( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_sth | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::stw( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_stw | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::stl( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_stl | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::stl_u( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_stl_u | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++ ++inline void Assembler::pri_st( Register ra, int ev6hwdisp, Register rb ) ++ { emit_sw2_long( op_pri_st | is_ra(ra) | is_ev6hwdisp(ev6hwdisp) | is_rb(rb) ); } ++ ++inline void Assembler::fsts( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_fsts | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::fstd( FloatRegister fa, int mdisp, Register rb ) ++ { emit_sw2_long( op_fstd | is_fa(fa) | is_mdisp(mdisp) | is_rb(rb) ); } ++ ++inline void Assembler::beq( Register ra, int bdisp ) ++ { emit_sw2_long( op_beq | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::bne( Register ra, int bdisp ) ++ { emit_sw2_long( op_bne | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::blt( Register ra, int bdisp ) ++ { emit_sw2_long( op_blt | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::ble( Register ra, int bdisp ) ++ { emit_sw2_long( op_ble | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::bgt( Register ra, int bdisp ) ++ { emit_sw2_long( op_bgt | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::bge( Register ra, int bdisp ) ++ { emit_sw2_long( op_bge | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::blbc( Register ra, int bdisp ) ++ { emit_sw2_long( op_blbc | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::blbs( Register ra, int bdisp ) ++ { emit_sw2_long( op_blbs | is_ra(ra) | is_bdisp(bdisp) ); } ++inline void Assembler::fbeq( FloatRegister fa, int bdisp ) ++ { emit_sw2_long( op_fbeq | is_fa(fa) | is_bdisp(bdisp) ); } ++inline void Assembler::fbne( FloatRegister fa, int bdisp ) ++ { emit_sw2_long( op_fbne | is_fa(fa) | is_bdisp(bdisp) ); } ++inline void Assembler::fblt( FloatRegister fa, int bdisp ) ++ { emit_sw2_long( op_fblt | is_fa(fa) | is_bdisp(bdisp) ); } ++inline void Assembler::fble( FloatRegister fa, int bdisp ) ++ { emit_sw2_long( op_fble | is_fa(fa) | is_bdisp(bdisp) ); } ++inline void Assembler::fbgt( FloatRegister fa, int bdisp ) ++ { emit_sw2_long( op_fbgt | is_fa(fa) | is_bdisp(bdisp) ); } ++inline void Assembler::fbge( FloatRegister fa, int bdisp ) ++ { emit_sw2_long( op_fbge | is_fa(fa) | is_bdisp(bdisp) ); } ++ ++inline void Assembler::ldi( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldi | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++inline void Assembler::ldih( Register ra, int mdisp, Register rb ) ++ { emit_sw2_long( op_ldih | is_ra(ra) | is_mdisp(mdisp) | is_rb(rb) ); } ++ ++// cache control instruction ++inline void Assembler::s_fillcs( int mdisp, Register rb ) ++ { ldw( R0, mdisp, rb); } ++inline void Assembler::s_fillde( int mdisp, Register rb ) ++ { ldl( R0, mdisp, rb); } ++inline void Assembler::fillde( int mdisp, Register rb ) ++ { flds( f31, mdisp, rb); } ++inline void Assembler::fillde_e( int mdisp, Register rb ) ++ { fldd( f31, mdisp, rb); } ++inline void Assembler::fillcs( int mdisp, Register rb ) ++ { ldwe( f31, mdisp, rb); } ++inline void Assembler::fillcs_e( int mdisp, Register rb ) ++ { ldde( f31, mdisp, rb); } ++inline void Assembler::e_fillcs( int mdisp, Register rb ) ++ { ldse( f31, mdisp, rb); } ++inline void Assembler::e_fillde( int mdisp, Register rb ) ++ { vlds( f31/*V31*/, mdisp, rb); } ++inline void Assembler::flushd( int mdisp, Register rb ) ++ { ldbu( R0, mdisp, rb); } ++inline void Assembler::evictdl( int mdisp, Register rb ) ++ { ldl_u( R0, mdisp, rb); } ++inline void Assembler::evictdg( int mdisp, Register rb ) ++ { ldhu( R0, mdisp, rb); } ++ ++#endif // CPU_SW64_VM_ASSEMBLER_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/bytes_sw64.hpp afu11u/src/hotspot/cpu/sw64/bytes_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/bytes_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/bytes_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_BYTES_SW64_HPP ++#define CPU_SW64_VM_BYTES_SW64_HPP ++ ++#include "memory/allocation.hpp" ++ ++class Bytes: AllStatic { ++public: ++ // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering ++ // (no special code is needed since x86 CPUs can access unaligned data) ++ static inline u2 get_native_u2(address p) { ++ if ((intptr_t)p & 0x1) { ++ return ((u2)p[1] << 8) | (u2)p[0]; ++ } else { ++ return *(u2*)p; ++ } ++ } ++ ++ static inline u4 get_native_u4(address p) { ++ return *(u4*)p; ++ } ++ ++ static inline u8 get_native_u8(address p) { ++ return *(u8*)p; ++ } ++ ++ //use mips unaligned load instructions ++ static inline void put_native_u2(address p, u2 x) { ++ if((intptr_t)p & 0x1) { ++ p[0] = (u_char)(x); ++ p[1] = (u_char)(x>>8); ++ } else { ++ *(u2*)p = x; ++ } ++ } ++ ++ static inline void put_native_u4(address p, u4 x) { ++ // refer to sparc implementation. ++ // Note that sparc is big-endian, while mips is little-endian ++ switch ( intptr_t(p) & 3 ) { ++ case 0: *(u4*)p = x; ++ break; ++ ++ case 2: ((u2*)p)[1] = x >> 16; ++ ((u2*)p)[0] = x; ++ break; ++ ++ default: ((u1*)p)[3] = x >> 24; ++ ((u1*)p)[2] = x >> 16; ++ ((u1*)p)[1] = x >> 8; ++ ((u1*)p)[0] = x; ++ break; ++ } ++ } ++ ++ static inline void put_native_u8(address p, u8 x) { ++ // refer to sparc implementation. ++ // Note that sparc is big-endian, while sw64 is little-endian ++ switch ( intptr_t(p) & 7 ) { ++ case 0: *(u8*)p = x; ++ break; ++ ++ case 4: ((u4*)p)[1] = x >> 32; ++ ((u4*)p)[0] = x; ++ break; ++ ++ case 2: ((u2*)p)[3] = x >> 48; ++ ((u2*)p)[2] = x >> 32; ++ ((u2*)p)[1] = x >> 16; ++ ((u2*)p)[0] = x; ++ break; ++ ++ default: ((u1*)p)[7] = x >> 56; ++ ((u1*)p)[6] = x >> 48; ++ ((u1*)p)[5] = x >> 40; ++ ((u1*)p)[4] = x >> 32; ++ ((u1*)p)[3] = x >> 24; ++ ((u1*)p)[2] = x >> 16; ++ ((u1*)p)[1] = x >> 8; ++ ((u1*)p)[0] = x; ++ } ++ } ++ ++ ++ // Efficient reading and writing of unaligned unsigned data in Java ++ // byte ordering (i.e. big-endian ordering). Byte-order reversal is ++ // needed since SW64 CPUs use little-endian format. ++ static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); } ++ static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); } ++ static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); } ++ ++ static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); } ++ static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); } ++ static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); } ++ ++ ++ // Efficient swapping of byte ordering ++ static inline u2 swap_u2(u2 x); // compiler-dependent implementation ++ static inline u4 swap_u4(u4 x); // compiler-dependent implementation ++ static inline u8 swap_u8(u8 x); ++}; ++ ++ ++// The following header contains the implementations of swap_u2, swap_u4, and swap_u8[_base] ++#include OS_CPU_HEADER_INLINE(bytes) ++ ++#endif // CPU_SW64_VM_BYTES_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_CodeStubs_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_CodeStubs_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_CodeStubs_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_CodeStubs_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,365 @@ ++/* ++ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.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_sw64.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "vmreg_sw64.inline.hpp" ++ ++ ++#define __ ce->masm()-> ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++void CounterOverflowStub::emit_code(LIR_Assembler* ce) { ++ __ BIND(_entry); ++ Metadata *m = _method->as_constant_ptr()->as_metadata(); ++ __ mov_metadata(rscratch1, m); ++ ce->store_parameter(rscratch1, 1); ++ ce->store_parameter(_bci, 0); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id))); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ __ b(_continuation); ++} ++ ++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); ++ __ far_call(RuntimeAddress(a)); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ debug_only(__ should_not_reach_here()); ++ return; ++ } ++ ++ if (_index->is_cpu_register()) { ++ __ mov(rscratch1, _index->as_register()); ++ } else { ++ __ mov(rscratch1, _index->as_jint()); ++ } ++ Runtime1::StubID stub_id; ++ if (_throw_index_out_of_bounds_exception) { ++ stub_id = Runtime1::throw_index_exception_id; ++ } else { ++ assert(_array != NULL, "sanity"); ++ __ mov(rscratch2, _array->as_pointer_register()); ++ stub_id = Runtime1::throw_range_check_failed_id; ++ } ++ __ lea(lr, RuntimeAddress(Runtime1::entry_for(stub_id))); ++ __ blr(lr); ++ 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); ++ __ far_call(RuntimeAddress(a)); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ debug_only(__ should_not_reach_here()); ++} ++ ++void DivByZeroStub::emit_code(LIR_Assembler* ce) { ++ if (_offset != -1) { ++ ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); ++ } ++ __ BIND(_entry); ++ __ far_call(Address(Runtime1::entry_for(Runtime1::throw_div0_exception_id), relocInfo::runtime_call_type)); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_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) { ++ assert(__ rsp_offset() == 0, "frame size should be fixed"); ++ __ BIND(_entry); ++ __ mov(i3, _klass_reg->as_register()); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(_stub_id))); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ assert(_result->as_register() == i0, "result must in i0,"); ++ __ b(_continuation); ++} ++ ++ ++// Implementation of NewTypeArrayStub ++ ++// 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) { ++ assert(__ rsp_offset() == 0, "frame size should be fixed"); ++ __ BIND(_entry); ++ assert(_length->as_register() == i19, "length must in i19,"); ++ assert(_klass_reg->as_register() == i3, "klass_reg must in i3"); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id))); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ assert(_result->as_register() == i0, "result must in i0"); ++ __ b(_continuation); ++} ++ ++ ++// Implementation of NewObjectArrayStub ++ ++NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { ++ _klass_reg = klass_reg; ++ _result = result; ++ _length = length; ++ _info = new CodeEmitInfo(info); ++} ++ ++ ++void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { ++ assert(__ rsp_offset() == 0, "frame size should be fixed"); ++ __ BIND(_entry); ++ assert(_length->as_register() == i19, "length must in i19,"); ++ assert(_klass_reg->as_register() == i3, "klass_reg must in i3"); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id))); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ assert(_result->as_register() == i0, "result must in i0"); ++ __ b(_continuation); ++} ++// 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) { ++ assert(__ rsp_offset() == 0, "frame size should be fixed"); ++ __ BIND(_entry); ++ ce->store_parameter(_obj_reg->as_register(), 1); ++ ce->store_parameter(_lock_reg->as_register(), 0); ++ Runtime1::StubID enter_id; ++ if (ce->compilation()->has_fpu_code()) { ++ enter_id = Runtime1::monitorenter_id; ++ } else { ++ enter_id = Runtime1::monitorenter_nofpu_id; ++ } ++ __ far_call(RuntimeAddress(Runtime1::entry_for(enter_id))); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ __ b(_continuation); ++} ++ ++ ++void MonitorExitStub::emit_code(LIR_Assembler* ce) { ++ __ BIND(_entry); ++ if (_compute_lock) { ++ // lock_reg was destroyed by fast unlocking attempt => recompute it ++ ce->monitor_address(_monitor_ix, _lock_reg); ++ } ++ ce->store_parameter(_lock_reg->as_register(), 0); ++ // note: non-blocking leaf routine => no call info needed ++ Runtime1::StubID exit_id; ++ if (ce->compilation()->has_fpu_code()) { ++ exit_id = Runtime1::monitorexit_id; ++ } else { ++ exit_id = Runtime1::monitorexit_nofpu_id; ++ } ++ __ adr(lr, _continuation); ++ __ far_jump(RuntimeAddress(Runtime1::entry_for(exit_id))); ++} ++ ++ ++// 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 (rspecially 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* masm) { ++} ++ ++void PatchingStub::emit_code(LIR_Assembler* ce) { ++ assert(false, "Sw64 should not use C1 runtime patching"); ++} ++ ++ ++void DeoptimizeStub::emit_code(LIR_Assembler* ce) { ++ __ BIND(_entry); ++ ce->store_parameter(_trap_request, 0); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id))); ++ ce->add_call_info_here(_info); ++ DEBUG_ONLY(__ should_not_reach_here()); ++} ++ ++ ++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); ++ __ far_call(RuntimeAddress(a)); ++ ce->add_call_info_here(_info); ++ ce->verify_oop_map(_info); ++ debug_only(__ should_not_reach_here()); ++} ++ ++ ++void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { ++ assert(__ rsp_offset() == 0, "frame size should be fixed"); ++ ++ __ BIND(_entry); ++ // pass the object in a scratch register because all other registers ++ // must be preserved ++ if (_obj->is_cpu_register()) { ++ __ mov(rscratch1, _obj->as_register()); ++ } ++ __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), NULL, rscratch2); ++ 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); ++ // Figure out where the args should go ++ // This should really convert the IntrinsicID to the Method* and signature ++ // but I don't know how to do that. ++ // ++ VMRegPair args[5]; ++ BasicType signature[5] = { T_OBJECT, T_INT, T_OBJECT, T_INT, T_INT}; ++ SharedRuntime::java_calling_convention(signature, args, 5, true); ++ ++ // push parameters ++ // (src, src_pos, dest, destPos, length) ++ Register r[5]; ++ r[0] = src()->as_register(); ++ r[1] = src_pos()->as_register(); ++ r[2] = dst()->as_register(); ++ r[3] = dst_pos()->as_register(); ++ r[4] = length()->as_register(); ++ ++ // next registers will get stored on the stack ++ for (int i = 0; i < 5 ; i++ ) { ++ VMReg r_1 = args[i].first(); ++ if (r_1->is_stack()) { ++ int st_off = r_1->reg2stack() * wordSize; ++ __ str (r[i], Address(sp, st_off)); ++ } else { ++ assert(r[i] == args[i].first()->as_Register(), "Wrong register for arg "); ++ } ++ } ++ ++ ce->align_call(lir_static_call); ++ ++ ce->emit_static_call_stub(); ++ if (ce->compilation()->bailed_out()) { ++ return; // CodeCache is full ++ } ++ Address resolve(SharedRuntime::get_resolve_static_call_stub(), ++ relocInfo::static_call_type); ++ address call = __ trampoline_call(resolve); ++ if (call == NULL) { ++ ce->bailout("trampoline stub overflow"); ++ return; ++ } ++ ce->add_call_info_here(info()); ++ ++#ifndef PRODUCT ++ __ lea(rscratch2, ExternalAddress((address)&Runtime1::_arraycopy_slowcase_cnt)); ++ __ incrementw(Address(rscratch2)); ++#endif ++ ++ __ b(_continuation); ++} ++ ++#undef __ +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_Defs_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_Defs_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_Defs_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_Defs_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C1_DEFS_SW64_HPP ++#define CPU_SW64_VM_C1_DEFS_SW64_HPP ++ ++// native word offsets from memory address (little endian) ++enum { ++ pd_lo_word_offset_in_bytes = 0, ++ pd_hi_word_offset_in_bytes = BytesPerWord ++}; ++ ++// explicit rounding operations are required to implement the strictFP mode ++enum { ++ pd_strict_fp_requires_explicit_rounding = false ++}; ++ ++// FIXME: There are no callee-saved ++ ++// registers ++enum { ++ pd_nof_cpu_regs_frame_map = RegisterImpl::number_of_registers, // number of registers used during code emission ++ pd_nof_fpu_regs_frame_map = FloatRegisterImpl::number_of_registers, // number of registers used during code emission ++ ++ pd_nof_caller_save_cpu_regs_frame_map = 19 - 2, // number of registers killed by calls ++ pd_nof_caller_save_fpu_regs_frame_map = 32, // number of registers killed by calls ++ ++ pd_first_callee_saved_reg = 19 - 2, ++ pd_last_callee_saved_reg = 26 - 2, ++ ++ pd_last_allocatable_cpu_reg = 16, ++ ++ pd_nof_cpu_regs_reg_alloc ++ = pd_last_allocatable_cpu_reg + 1, // number of registers that are visible to register allocator ++ pd_nof_fpu_regs_reg_alloc = 8, // number of registers that are visible to register allocator ++ ++ pd_nof_cpu_regs_linearscan = 32, // number of registers visible to linear scan ++ pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // number of registers visible to linear scan ++ pd_nof_xmm_regs_linearscan = 0, // like sparc we don't have any of these ++ pd_first_cpu_reg = 0, ++ pd_last_cpu_reg = 16, ++ pd_first_byte_reg = 0, ++ pd_last_byte_reg = 16, ++ pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, ++ pd_last_fpu_reg = pd_first_fpu_reg + 31, ++ ++ pd_first_callee_saved_fpu_reg = 8 + pd_first_fpu_reg, ++ pd_last_callee_saved_fpu_reg = 15 + pd_first_fpu_reg, ++}; ++ ++ ++// Encoding of float value in debug info. This is true on x86 where ++// floats are extended to doubles when stored in the stack, false for ++// Sw64 where floats and doubles are stored in their native form. ++enum { ++ pd_float_saved_as_double = false ++}; ++ ++#endif // CPU_SW64_VM_C1_DEFS_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++//-------------------------------------------------------- ++// FpuStackSim ++//-------------------------------------------------------- ++ ++// No FPU stack on SW64 +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_FpuStackSim_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C1_FPUSTACKSIM_HPP ++#define CPU_SW64_VM_C1_FPUSTACKSIM_HPP ++ ++// No FPU stack on SW64 ++class FpuStackSim; ++ ++#endif // CPU_SW64_VM_C1_FPUSTACKSIM_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_FrameMap_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_FrameMap_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_FrameMap_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_FrameMap_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,357 @@ ++/* ++ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "c1/c1_FrameMap.hpp" ++#include "c1/c1_LIR.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "vmreg_sw64.inline.hpp" ++ ++LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) { ++ 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, type)); ++ } else if (r_1->is_Register()) { ++ Register reg = r_1->as_Register(); ++ if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { ++ Register reg2 = r_2->as_Register(); ++ assert(reg2 == reg, "must be same register"); ++ opr = as_long_opr(reg); ++ } else if (type == T_OBJECT || type == T_ARRAY) { ++ 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"); ++ int num = r_1->as_FloatRegister()->encoding(); ++ if (type == T_FLOAT) { ++ opr = LIR_OprFact::single_fpu(num); ++ } else { ++ opr = LIR_OprFact::double_fpu(num); ++ } ++ } else { ++ ShouldNotReachHere(); ++ } ++ return opr; ++} ++ ++LIR_Opr FrameMap::r0_opr; ++LIR_Opr FrameMap::r1_opr; ++LIR_Opr FrameMap::r2_opr; ++LIR_Opr FrameMap::r3_opr; ++LIR_Opr FrameMap::r4_opr; ++LIR_Opr FrameMap::r5_opr; ++LIR_Opr FrameMap::r6_opr; ++LIR_Opr FrameMap::r7_opr; ++LIR_Opr FrameMap::r8_opr; ++LIR_Opr FrameMap::r9_opr; ++LIR_Opr FrameMap::r10_opr; ++LIR_Opr FrameMap::r11_opr; ++LIR_Opr FrameMap::r12_opr; ++LIR_Opr FrameMap::r13_opr; ++LIR_Opr FrameMap::r14_opr; ++LIR_Opr FrameMap::r15_opr; ++LIR_Opr FrameMap::r16_opr; ++LIR_Opr FrameMap::r17_opr; ++LIR_Opr FrameMap::r18_opr; ++LIR_Opr FrameMap::r19_opr; ++LIR_Opr FrameMap::r20_opr; ++LIR_Opr FrameMap::r21_opr; ++LIR_Opr FrameMap::r22_opr; ++LIR_Opr FrameMap::r23_opr; ++LIR_Opr FrameMap::r24_opr; ++LIR_Opr FrameMap::r25_opr; ++LIR_Opr FrameMap::r26_opr; ++LIR_Opr FrameMap::r27_opr; ++LIR_Opr FrameMap::r28_opr; ++LIR_Opr FrameMap::r29_opr; ++LIR_Opr FrameMap::r30_opr; ++ ++LIR_Opr FrameMap::rfp_opr; ++LIR_Opr FrameMap::sp_opr; ++ ++LIR_Opr FrameMap::receiver_opr; ++ ++LIR_Opr FrameMap::r0_oop_opr; ++LIR_Opr FrameMap::r1_oop_opr; ++LIR_Opr FrameMap::r2_oop_opr; ++LIR_Opr FrameMap::r3_oop_opr; ++LIR_Opr FrameMap::r4_oop_opr; ++LIR_Opr FrameMap::r5_oop_opr; ++LIR_Opr FrameMap::r6_oop_opr; ++LIR_Opr FrameMap::r7_oop_opr; ++LIR_Opr FrameMap::r8_oop_opr; ++LIR_Opr FrameMap::r9_oop_opr; ++LIR_Opr FrameMap::r10_oop_opr; ++LIR_Opr FrameMap::r11_oop_opr; ++LIR_Opr FrameMap::r12_oop_opr; ++LIR_Opr FrameMap::r13_oop_opr; ++LIR_Opr FrameMap::r14_oop_opr; ++LIR_Opr FrameMap::r15_oop_opr; ++LIR_Opr FrameMap::r16_oop_opr; ++LIR_Opr FrameMap::r17_oop_opr; ++LIR_Opr FrameMap::r18_oop_opr; ++LIR_Opr FrameMap::r19_oop_opr; ++LIR_Opr FrameMap::r20_oop_opr; ++LIR_Opr FrameMap::r21_oop_opr; ++LIR_Opr FrameMap::r22_oop_opr; ++LIR_Opr FrameMap::r23_oop_opr; ++LIR_Opr FrameMap::r24_oop_opr; ++LIR_Opr FrameMap::r25_oop_opr; ++LIR_Opr FrameMap::r26_oop_opr; ++LIR_Opr FrameMap::r27_oop_opr; ++LIR_Opr FrameMap::r28_oop_opr; ++LIR_Opr FrameMap::r29_oop_opr; ++LIR_Opr FrameMap::r30_oop_opr; ++ ++LIR_Opr FrameMap::rscratch1_opr; ++LIR_Opr FrameMap::rscratch2_opr; ++LIR_Opr FrameMap::rscratch1_long_opr; ++LIR_Opr FrameMap::rscratch2_long_opr; ++ ++LIR_Opr FrameMap::r0_metadata_opr; ++LIR_Opr FrameMap::r1_metadata_opr; ++LIR_Opr FrameMap::r2_metadata_opr; ++LIR_Opr FrameMap::r3_metadata_opr; ++LIR_Opr FrameMap::r4_metadata_opr; ++LIR_Opr FrameMap::r5_metadata_opr; ++ ++LIR_Opr FrameMap::long0_opr; ++LIR_Opr FrameMap::long1_opr; ++LIR_Opr FrameMap::fpu0_float_opr; ++LIR_Opr FrameMap::fpu0_double_opr; ++ ++LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, }; ++LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, }; ++ ++//-------------------------------------------------------- ++// FrameMap ++//-------------------------------------------------------- ++ ++void FrameMap::initialize() { ++ assert(!_init_done, "once"); ++ ++ int i=0; ++ map_register(i, i0); r0_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i1); r1_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i2); r2_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i3); r3_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i4); r4_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i5); r5_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i6); r6_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i7); r7_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i10); r10_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i11); r11_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i12); r12_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i13); r13_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i14); r14_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i15); r15_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i16); r16_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i17); r17_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i18); r18_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i19); r19_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i20); r20_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i21); r21_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i22); r22_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i23); r23_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i24); r24_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i25); r25_opr = LIR_OprFact::single_cpu(i); i++; ++ map_register(i, i26); r26_opr = LIR_OprFact::single_cpu(i); i++; ++ ++ map_register(i, i27); r27_opr = LIR_OprFact::single_cpu(i); i++; // rheapbase ++ map_register(i, i28); r28_opr = LIR_OprFact::single_cpu(i); i++; // rthread ++ map_register(i, i29); r29_opr = LIR_OprFact::single_cpu(i); i++; // rfp ++ map_register(i, i30); r30_opr = LIR_OprFact::single_cpu(i); i++; // lr ++// map_register(i, r31_sp); sp_opr = LIR_OprFact::single_cpu(i); i++; // sp ++ map_register(i, i8); r8_opr = LIR_OprFact::single_cpu(i); i++; // rscratch1 ++ map_register(i, i9); r9_opr = LIR_OprFact::single_cpu(i); i++; // rscratch2 ++ ++ rscratch1_opr = r8_opr; ++ rscratch2_opr = r9_opr; ++ rscratch1_long_opr = LIR_OprFact::double_cpu(r8_opr->cpu_regnr(), r8_opr->cpu_regnr()); ++ rscratch2_long_opr = LIR_OprFact::double_cpu(r9_opr->cpu_regnr(), r9_opr->cpu_regnr()); ++ ++ long0_opr = LIR_OprFact::double_cpu(0, 0); ++ long1_opr = LIR_OprFact::double_cpu(1, 1); ++ ++ fpu0_float_opr = LIR_OprFact::single_fpu(0); ++ fpu0_double_opr = LIR_OprFact::double_fpu(0); ++ ++ _caller_save_cpu_regs[0] = r0_opr; ++ _caller_save_cpu_regs[1] = r1_opr; ++ _caller_save_cpu_regs[2] = r2_opr; ++ _caller_save_cpu_regs[3] = r3_opr; ++ _caller_save_cpu_regs[4] = r4_opr; ++ _caller_save_cpu_regs[5] = r5_opr; ++ _caller_save_cpu_regs[6] = r6_opr; ++ _caller_save_cpu_regs[7] = r7_opr; ++ // rscratch1, rscratch 2 not included ++ _caller_save_cpu_regs[8] = r10_opr; ++ _caller_save_cpu_regs[9] = r11_opr; ++ _caller_save_cpu_regs[10] = r12_opr; ++ _caller_save_cpu_regs[11] = r13_opr; ++ _caller_save_cpu_regs[12] = r14_opr; ++ _caller_save_cpu_regs[13] = r15_opr; ++ _caller_save_cpu_regs[14] = r16_opr; ++ _caller_save_cpu_regs[15] = r17_opr; ++ _caller_save_cpu_regs[16] = r18_opr; ++ ++ for (int i = 0; i < 8; i++) { ++ _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i); ++ } ++ ++ _init_done = true; ++ ++ r0_oop_opr = as_oop_opr(i0); ++ r1_oop_opr = as_oop_opr(i1); ++ r2_oop_opr = as_oop_opr(i2); ++ r3_oop_opr = as_oop_opr(i3); ++ r4_oop_opr = as_oop_opr(i4); ++ r5_oop_opr = as_oop_opr(i5); ++ r6_oop_opr = as_oop_opr(i6); ++ r7_oop_opr = as_oop_opr(i7); ++ r8_oop_opr = as_oop_opr(i8); ++ r9_oop_opr = as_oop_opr(i9); ++ r10_oop_opr = as_oop_opr(i10); ++ r11_oop_opr = as_oop_opr(i11); ++ r12_oop_opr = as_oop_opr(i12); ++ r13_oop_opr = as_oop_opr(i13); ++ r14_oop_opr = as_oop_opr(i14); ++ r15_oop_opr = as_oop_opr(i15); ++ r16_oop_opr = as_oop_opr(i16); ++ r17_oop_opr = as_oop_opr(i17); ++ r18_oop_opr = as_oop_opr(i18); ++ r19_oop_opr = as_oop_opr(i19); ++ r20_oop_opr = as_oop_opr(i20); ++ r21_oop_opr = as_oop_opr(i21); ++ r22_oop_opr = as_oop_opr(i22); ++ r23_oop_opr = as_oop_opr(i23); ++ r24_oop_opr = as_oop_opr(i24); ++ r25_oop_opr = as_oop_opr(i25); ++ r26_oop_opr = as_oop_opr(i26); ++ r27_oop_opr = as_oop_opr(i27); ++ r28_oop_opr = as_oop_opr(i28); ++ r29_oop_opr = as_oop_opr(i29); ++ r30_oop_opr = as_oop_opr(i30); ++ ++ r0_metadata_opr = as_metadata_opr(i0); ++ r1_metadata_opr = as_metadata_opr(i1); ++ r2_metadata_opr = as_metadata_opr(i2); ++ r3_metadata_opr = as_metadata_opr(i3); ++ r4_metadata_opr = as_metadata_opr(i4); ++ r5_metadata_opr = as_metadata_opr(i5); ++ ++// sp_opr = as_pointer_opr(r31_sp); ++ rfp_opr = as_pointer_opr(rfp); ++ ++ VMRegPair regs; ++ BasicType sig_bt = T_OBJECT; ++ SharedRuntime::java_calling_convention(&sig_bt, ®s, 1, true); ++ receiver_opr = as_oop_opr(regs.first()->as_Register()); ++ ++ 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 { ++ // for rbp, based address use this: ++ // return Address(rbp, in_bytes(sp_offset) - (framesize() - 2) * 4); ++ return Address(sp, in_bytes(sp_offset)); ++} ++ ++ ++// ----------------mapping----------------------- ++// all mapping is based on rfp addressing, except for simple leaf methods where we access ++// the locals sp based (and no frame is built) ++ ++ ++// Frame for simple leaf methods (quick entries) ++// ++// +----------+ ++// | ret addr | <- TOS ++// +----------+ ++// | args | ++// | ...... | ++ ++// Frame for standard methods ++// ++// | .........| <- TOS ++// | locals | ++// +----------+ ++// | old fp, | <- RFP ++// +----------+ ++// | ret addr | ++// +----------+ ++// | args | ++// | .........| ++ ++ ++// For OopMaps, map a local variable or spill index to an VMRegImpl name. ++// This is the offset from sp() in the frame of the slot for the index, ++// skewed by VMRegImpl::stack0 to indicate a stack location (vs.a register.) ++// ++// framesize + ++// stack0 stack0 0 <- VMReg ++// | | | ++// ...........|..............|.............| ++// 0 1 2 3 x x 4 5 6 ... | <- local indices ++// ^ ^ sp() ( x x indicate link ++// | | and return addr) ++// arguments non-argument locals ++ ++ ++VMReg FrameMap::fpu_regname (int n) { ++ // Return the OptoReg name for the fpu stack slot "n" ++ // A spilled fpu stack slot comprises to two single-word OptoReg's. ++ return as_FloatRegister(n)->as_VMReg(); ++} ++ ++LIR_Opr FrameMap::stack_pointer() { ++ return FrameMap::sp_opr; ++} ++ ++ ++// JSR 292 ++LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { ++ return LIR_OprFact::illegalOpr; // Not needed on sw64 ++} ++ ++ ++bool FrameMap::validate_frame() { ++ return true; ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_FrameMap_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_FrameMap_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_FrameMap_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_FrameMap_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C1_FRAMEMAP_SW64_HPP ++#define CPU_SW64_VM_C1_FRAMEMAP_SW64_HPP ++ ++// On Sw64 the frame looks as follows: ++// ++// +-----------------------------+---------+----------------------------------------+----------------+----------- ++// | size_arguments-nof_reg_args | 2 words | size_locals-size_arguments+numreg_args | _size_monitors | spilling . ++// +-----------------------------+---------+----------------------------------------+----------------+----------- ++ ++ public: ++ static const int pd_c_runtime_reserved_arg_size; ++ ++ enum { ++ first_available_sp_in_frame = 0, ++ frame_pad_in_bytes = 16, ++ nof_reg_args = 8 ++ }; ++ ++ public: ++ static LIR_Opr receiver_opr; ++ ++ static LIR_Opr r0_opr; ++ static LIR_Opr r1_opr; ++ static LIR_Opr r2_opr; ++ static LIR_Opr r3_opr; ++ static LIR_Opr r4_opr; ++ static LIR_Opr r5_opr; ++ static LIR_Opr r6_opr; ++ static LIR_Opr r7_opr; ++ static LIR_Opr r8_opr; ++ static LIR_Opr r9_opr; ++ static LIR_Opr r10_opr; ++ static LIR_Opr r11_opr; ++ static LIR_Opr r12_opr; ++ static LIR_Opr r13_opr; ++ static LIR_Opr r14_opr; ++ static LIR_Opr r15_opr; ++ static LIR_Opr r16_opr; ++ static LIR_Opr r17_opr; ++ static LIR_Opr r18_opr; ++ static LIR_Opr r19_opr; ++ static LIR_Opr r20_opr; ++ static LIR_Opr r21_opr; ++ static LIR_Opr r22_opr; ++ static LIR_Opr r23_opr; ++ static LIR_Opr r24_opr; ++ static LIR_Opr r25_opr; ++ static LIR_Opr r26_opr; ++ static LIR_Opr r27_opr; ++ static LIR_Opr r28_opr; ++ static LIR_Opr r29_opr; ++ static LIR_Opr r30_opr; ++ static LIR_Opr rfp_opr; ++ static LIR_Opr sp_opr; ++ ++ static LIR_Opr r0_oop_opr; ++ static LIR_Opr r1_oop_opr; ++ static LIR_Opr r2_oop_opr; ++ static LIR_Opr r3_oop_opr; ++ static LIR_Opr r4_oop_opr; ++ static LIR_Opr r5_oop_opr; ++ static LIR_Opr r6_oop_opr; ++ static LIR_Opr r7_oop_opr; ++ static LIR_Opr r8_oop_opr; ++ static LIR_Opr r9_oop_opr; ++ static LIR_Opr r10_oop_opr; ++ static LIR_Opr r11_oop_opr; ++ static LIR_Opr r12_oop_opr; ++ static LIR_Opr r13_oop_opr; ++ static LIR_Opr r14_oop_opr; ++ static LIR_Opr r15_oop_opr; ++ static LIR_Opr r16_oop_opr; ++ static LIR_Opr r17_oop_opr; ++ static LIR_Opr r18_oop_opr; ++ static LIR_Opr r19_oop_opr; ++ static LIR_Opr r20_oop_opr; ++ static LIR_Opr r21_oop_opr; ++ static LIR_Opr r22_oop_opr; ++ static LIR_Opr r23_oop_opr; ++ static LIR_Opr r24_oop_opr; ++ static LIR_Opr r25_oop_opr; ++ static LIR_Opr r26_oop_opr; ++ static LIR_Opr r27_oop_opr; ++ static LIR_Opr r28_oop_opr; ++ static LIR_Opr r29_oop_opr; ++ static LIR_Opr r30_oop_opr; ++ ++ static LIR_Opr rscratch1_opr; ++ static LIR_Opr rscratch2_opr; ++ static LIR_Opr rscratch1_long_opr; ++ static LIR_Opr rscratch2_long_opr; ++ ++ static LIR_Opr r0_metadata_opr; ++ static LIR_Opr r1_metadata_opr; ++ static LIR_Opr r2_metadata_opr; ++ static LIR_Opr r3_metadata_opr; ++ static LIR_Opr r4_metadata_opr; ++ static LIR_Opr r5_metadata_opr; ++ ++ static LIR_Opr long0_opr; ++ static LIR_Opr long1_opr; ++ static LIR_Opr fpu0_float_opr; ++ static LIR_Opr fpu0_double_opr; ++ ++ static LIR_Opr as_long_opr(Register r) { ++ return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); ++ } ++ static LIR_Opr as_pointer_opr(Register r) { ++ return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); ++ } ++ ++ // VMReg name for spilled physical FPU stack slot n ++ static VMReg fpu_regname (int n); ++ ++ static bool is_caller_save_register (LIR_Opr opr) { return true; } ++ static bool is_caller_save_register (Register r) { return true; } ++ ++ 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; } ++ static int last_byte_reg() { return pd_last_byte_reg; } ++ ++#endif // CPU_SW64_VM_C1_FRAMEMAP_SW64_HPP ++ +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_globals_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_globals_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_globals_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_globals_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C1_GLOBALS_SW64_HPP ++#define CPU_SW64_VM_C1_GLOBALS_SW64_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, UseTLAB, true ); ++define_pd_global(bool, ResizeTLAB, 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, 1500 ); ++ ++define_pd_global(intx, OnStackReplacePercentage, 933 ); ++define_pd_global(intx, FreqInlineSize, 325 ); ++define_pd_global(intx, NewSizeThreadIncrease, 4*K ); ++define_pd_global(intx, InitialCodeCacheSize, 160*K); ++define_pd_global(intx, ReservedCodeCacheSize, 32*M ); ++define_pd_global(intx, NonProfiledCodeHeapSize, 13*M ); ++define_pd_global(intx, ProfiledCodeHeapSize, 14*M ); ++define_pd_global(intx, NonNMethodCodeHeapSize, 5*M ); ++define_pd_global(bool, ProfileInterpreter, false); ++define_pd_global(intx, CodeCacheExpansionSize, 32*K ); ++define_pd_global(uintx, CodeCacheMinBlockLength, 1); ++define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); ++define_pd_global(uintx, MetaspaceSize, 12*M ); ++define_pd_global(bool, NeverActAsServerClassMachine, true ); ++define_pd_global(uint64_t,MaxRAM, 1ULL*G); ++define_pd_global(bool, CICompileOSR, true ); ++#endif // !TIERED ++define_pd_global(bool, UseTypeProfile, false); ++define_pd_global(bool, RoundFPResults, true ); ++ ++define_pd_global(bool, LIRFillDelaySlots, false); ++define_pd_global(bool, OptimizeSinglePrecision, true ); ++define_pd_global(bool, CSEArrayLength, false); ++define_pd_global(bool, TwoOperandLIRForm, false ); ++ ++#endif // CPU_SW64_VM_C1_GLOBALS_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_LinearScan_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_LinearScan_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_LinearScan_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_LinearScan_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. All rights reserved. ++ * 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 Sw64 ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_LinearScan_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_LinearScan_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_LinearScan_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_LinearScan_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C1_LINEARSCAN_HPP ++#define CPU_SW64_VM_C1_LINEARSCAN_HPP ++ ++inline bool LinearScan::is_processed_reg_num(int reg_num) { ++ return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map; ++} ++ ++inline int LinearScan::num_physical_regs(BasicType type) { ++ return 1; ++} ++ ++ ++inline bool LinearScan::requires_adjacent_regs(BasicType type) { ++ return false; ++} ++ ++inline bool LinearScan::is_caller_save(int assigned_reg) { ++ assert(assigned_reg >= 0 && assigned_reg < nof_regs, "should call this only for registers"); ++ if (assigned_reg < pd_first_callee_saved_reg) ++ return true; ++ if (assigned_reg > pd_last_callee_saved_reg && assigned_reg < pd_first_callee_saved_fpu_reg) ++ return true; ++ if (assigned_reg > pd_last_callee_saved_fpu_reg && assigned_reg < pd_last_fpu_reg) ++ return true; ++ return false; ++} ++ ++ ++inline void LinearScan::pd_add_temps(LIR_Op* op) { ++ // FIXME ?? ++} ++ ++ ++// Implementation of LinearScanWalker ++ ++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_SW64_VM_C1_LINEARSCAN_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,3135 @@ ++/* ++ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "asm/assembler.hpp" ++#include "c1/c1_CodeStubs.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 "code/compiledIC.hpp" ++#include "gc/shared/barrierSet.hpp" ++#include "gc/shared/cardTableBarrierSet.hpp" ++#include "gc/shared/collectedHeap.hpp" ++#include "nativeInst_sw64.hpp" ++#include "oops/objArrayKlass.hpp" ++#include "runtime/frame.inline.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "vmreg_sw64.inline.hpp" ++ ++ ++ ++#ifndef PRODUCT ++#define COMMENT(x) do { __ block_comment(x); } while (0) ++#else ++#define COMMENT(x) ++#endif ++#define BIND(label) bind(label); COMMENT(#label ":") ++NEEDS_CLEANUP // remove this definitions ? ++const Register IC_Klass = rscratch2; // where the IC klass is cached ++const Register SYNC_header = i0; // synchronization header ++const Register SHIFT_count = i0; // where count for shift operations must be ++ ++#define __ _masm-> ++ ++ ++static void select_different_registers(Register preserve, ++ Register extra, ++ Register &tmp1, ++ Register &tmp2) { ++ if (tmp1 == preserve) { ++ assert_different_registers(tmp1, tmp2, extra); ++ tmp1 = extra; ++ } else if (tmp2 == preserve) { ++ assert_different_registers(tmp1, tmp2, extra); ++ tmp2 = extra; ++ } ++ assert_different_registers(preserve, tmp1, tmp2); ++} ++ ++ ++ ++static void select_different_registers(Register preserve, ++ Register extra, ++ Register &tmp1, ++ Register &tmp2, ++ Register &tmp3) { ++ if (tmp1 == preserve) { ++ assert_different_registers(tmp1, tmp2, tmp3, extra); ++ tmp1 = extra; ++ } else if (tmp2 == preserve) { ++ assert_different_registers(tmp1, tmp2, tmp3, extra); ++ tmp2 = extra; ++ } else if (tmp3 == preserve) { ++ assert_different_registers(tmp1, tmp2, tmp3, extra); ++ tmp3 = extra; ++ } ++ assert_different_registers(preserve, tmp1, tmp2, tmp3); ++} ++ ++ ++bool LIR_Assembler::is_small_constant(LIR_Opr opr) { Unimplemented(); return false; } ++ ++ ++LIR_Opr LIR_Assembler::receiverOpr() { ++ return FrameMap::receiver_opr; ++} ++ ++LIR_Opr LIR_Assembler::osrBufferPointer() { ++ return FrameMap::as_pointer_opr(receiverOpr()->as_register()); ++} ++ ++//--------------fpu register translations----------------------- ++ ++ ++address LIR_Assembler::float_constant(float f) { ++ address const_addr = __ float_constant(f); ++ if (const_addr == NULL) { ++ bailout("const section overflow"); ++ return __ code()->consts()->start(); ++ } else { ++ return const_addr; ++ } ++} ++ ++ ++address LIR_Assembler::double_constant(double d) { ++ address const_addr = __ double_constant(d); ++ if (const_addr == NULL) { ++ bailout("const section overflow"); ++ return __ code()->consts()->start(); ++ } else { ++ return const_addr; ++ } ++} ++ ++address LIR_Assembler::int_constant(jlong n) { ++ address const_addr = __ long_constant(n); ++ if (const_addr == NULL) { ++ bailout("const section overflow"); ++ return __ code()->consts()->start(); ++ } else { ++ return const_addr; ++ } ++} ++ ++void LIR_Assembler::set_24bit_FPU() { Unimplemented(); } ++ ++void LIR_Assembler::reset_FPU() { Unimplemented(); } ++ ++void LIR_Assembler::fpop() { Unimplemented(); } ++ ++void LIR_Assembler::fxch(int i) { Unimplemented(); } ++ ++void LIR_Assembler::fld(int i) { Unimplemented(); } ++ ++void LIR_Assembler::ffree(int i) { Unimplemented(); } ++ ++void LIR_Assembler::breakpoint() { Unimplemented(); } ++ ++void LIR_Assembler::push(LIR_Opr opr) { Unimplemented(); } ++ ++void LIR_Assembler::pop(LIR_Opr opr) { Unimplemented(); } ++ ++bool LIR_Assembler::is_literal_address(LIR_Address* addr) { Unimplemented(); return false; } ++//------------------------------------------- ++ ++static Register as_reg(LIR_Opr op) { ++ return op->is_double_cpu() ? op->as_register_lo() : op->as_register(); ++} ++ ++static jlong as_long(LIR_Opr data) { ++ jlong result; ++ switch (data->type()) { ++ case T_INT: ++ result = (data->as_jint()); ++ break; ++ case T_LONG: ++ result = (data->as_jlong()); ++ break; ++ default: ++ ShouldNotReachHere(); ++ result = 0; // unreachable ++ } ++ return result; ++} ++ ++Address LIR_Assembler::as_Address(LIR_Address* addr, Register tmp) { ++ Register base = addr->base()->as_pointer_register(); ++ LIR_Opr opr = addr->index(); ++ if (opr->is_cpu_register()) { ++ Register index; ++ if (opr->is_single_cpu()) ++ index = opr->as_register(); ++ else ++ index = opr->as_register_lo(); ++ assert(addr->disp() == 0, "must be"); ++ switch(opr->type()) { ++ case T_INT: ++ return Address(base, index, Address::sxtw(addr->scale())); ++ case T_LONG: ++ return Address(base, index, Address::lsl(addr->scale())); ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { ++ intptr_t addr_offset = intptr_t(addr->disp()); ++ if (Address::offset_ok_for_immed(addr_offset, addr->scale())) ++ return Address(base, addr_offset, Address::lsl(addr->scale())); ++ else { ++ __ mov(tmp, addr_offset); ++ return Address(base, tmp, Address::lsl(addr->scale())); ++ } ++ } ++ return Address(); ++} ++ ++Address LIR_Assembler::as_Address_hi(LIR_Address* addr) { ++ ShouldNotReachHere(); ++ return Address(); ++} ++ ++Address LIR_Assembler::as_Address(LIR_Address* addr) { ++ return as_Address(addr, rscratch1); ++} ++ ++Address LIR_Assembler::as_Address_lo(LIR_Address* addr) { ++ return as_Address(addr, rscratch1); // Ouch ++ // FIXME: This needs to be much more clever. See x86. ++} ++ ++ ++void LIR_Assembler::osr_entry() { ++ offsets()->set_value(CodeOffsets::OSR_Entry, code_offset()); ++ BlockBegin* osr_entry = compilation()->hir()->osr_entry(); ++ ValueStack* entry_state = osr_entry->state(); ++ int number_of_locks = entry_state->locks_size(); ++ ++ // we jump here if osr happens with the interpreter ++ // state set up to continue at the beginning of the ++ // loop that triggered osr - in particular, we have ++ // the following registers setup: ++ // ++ // r2: osr buffer ++ // ++ ++ // build frame ++ ciMethod* m = compilation()->method(); ++ __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); ++ ++ // OSR buffer is ++ // ++ // locals[nlocals-1..0] ++ // monitors[0..number_of_locks] ++ // ++ // 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. ++ // r2: 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_pointer_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; ++ __ ldr(rscratch1, Address(OSR_buf, slot_offset + 1*BytesPerWord)); ++ __ cbnz(rscratch1, L); ++ __ stop("locked object is NULL"); ++ __ BIND(L); ++ } ++#endif ++ __ ldr(i19, Address(OSR_buf, slot_offset + 0)); ++ __ str(i19, frame_map()->address_for_monitor_lock(i)); ++ __ ldr(i19, Address(OSR_buf, slot_offset + 1*BytesPerWord)); ++ __ str(i19, frame_map()->address_for_monitor_object(i)); ++ } ++ } ++} ++ ++ ++// inline cache check; done before the frame is built. ++int LIR_Assembler::check_icache() { ++ Register receiver = FrameMap::receiver_opr->as_register(); ++ Register ic_klass = IC_Klass; ++ int start_offset = __ offset(); ++ __ inline_cache_check(receiver, ic_klass); ++ ++ // if icache check fails, then jump to runtime routine ++ // Note: RECEIVER must still contain the receiver! ++ Label dont; ++ __ br(Assembler::EQ, dont); ++ __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); ++ ++ // We align the verified entry point unless the method body ++ // (including its inline cache check) will fit in a single 64-byte ++ // icache line. ++ if (! method()->is_accessor() || __ offset() - start_offset > 4 * 4) { ++ // force alignment after the cache check. ++ __ align(CodeEntryAlignment); ++ } ++ ++ __ BIND(dont); ++ return start_offset; ++} ++ ++ ++void LIR_Assembler::jobject2reg(jobject o, Register reg) { ++ if (o == NULL) { ++ __ mov(reg, zr); ++ } else { ++ __ movoop(reg, o, /*immediate*/true); ++ } ++} ++ ++void LIR_Assembler::deoptimize_trap(CodeEmitInfo *info) { ++ address target = NULL; ++ relocInfo::relocType reloc_type = relocInfo::none; ++ ++ switch (patching_id(info)) { ++ case PatchingStub::access_field_id: ++ target = Runtime1::entry_for(Runtime1::access_field_patching_id); ++ reloc_type = relocInfo::section_word_type; ++ break; ++ case PatchingStub::load_klass_id: ++ target = Runtime1::entry_for(Runtime1::load_klass_patching_id); ++ reloc_type = relocInfo::metadata_type; ++ break; ++ case PatchingStub::load_mirror_id: ++ target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); ++ reloc_type = relocInfo::oop_type; ++ break; ++ case PatchingStub::load_appendix_id: ++ target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); ++ reloc_type = relocInfo::oop_type; ++ break; ++ default: ShouldNotReachHere(); ++ } ++ ++ __ far_call(RuntimeAddress(target)); ++ add_call_info_here(info); ++} ++ ++void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) { ++ deoptimize_trap(info); ++} ++ ++ ++// This specifies the rsp decrement needed to build the frame ++int LIR_Assembler::initial_frame_size_in_bytes() const { ++ // if rounding, must let FrameMap know! ++ ++ // The frame_map records size in slots (32bit word) ++ ++ // subtract two words to account for return address and link ++ return (frame_map()->framesize() - (2*VMRegImpl::slots_per_word)) * VMRegImpl::stack_slot_size; ++} ++ ++ ++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 ++ 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(); ++ ++ // the exception oop and pc are in i0, and i3 ++ // no other registers need to be preserved, so invalidate them ++ __ invalidate_registers(false, true, true, false, true, true); ++ ++ // check that there is really an exception ++ __ verify_not_null_oop(i0); ++ ++ // search an exception handler (i0: exception oop, i3: throwing pc) ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id))); __ 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 ++ __ ldr(i0, Address(rthread, JavaThread::exception_oop_offset())); ++ __ str(zr, Address(rthread, JavaThread::exception_oop_offset())); ++ __ str(zr, Address(rthread, JavaThread::exception_pc_offset())); ++ ++ __ BIND(_unwind_handler_entry); ++ __ verify_not_null_oop(i0); ++ if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { ++ __ mov(i19, i0); // Preserve the exception ++ } ++ ++ // Preform needed unlocking ++ MonitorExitStub* stub = NULL; ++ if (method()->is_synchronized()) { ++ monitor_address(0, FrameMap::r0_opr); ++ stub = new MonitorExitStub(FrameMap::r0_opr, true, 0); ++ __ unlock_object(i5, i4, i0, *stub->entry()); ++ __ BIND(*stub->continuation()); ++ } ++ ++ if (compilation()->env()->dtrace_method_probes()) { ++ __ call_Unimplemented(); ++#if 0 ++ __ movptr(Address(rsp, 0), rax); ++ __ mov_metadata(Address(rsp, sizeof(void*)), method()->constant_encoding()); ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit))); ++#endif ++ } ++ ++ if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { ++ __ mov(i0, i19); // Restore the exception ++ } ++ ++ // remove the activation and dispatch to the unwind handler ++ __ block_comment("remove_frame and dispatch to the unwind handler"); ++ __ remove_frame(initial_frame_size_in_bytes()); ++ __ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id))); ++ ++ // 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 exception handler ++ 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(); ++ ++ __ adr(lr, pc()); ++ __ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); ++ guarantee(code_offset() - offset <= deopt_handler_size(), "overflow"); ++ __ end_a_stub(); ++ ++ return offset; ++} ++ ++void LIR_Assembler::add_debug_info_for_branch(address adr, CodeEmitInfo* info) { ++ _masm->code_section()->relocate(adr, relocInfo::poll_type); ++ int pc_offset = code_offset(); ++ flush_debug_info(pc_offset); ++ info->record_debug_info(compilation()->debug_info_recorder(), pc_offset); ++ if (info->exception_handlers() != NULL) { ++ compilation()->add_exception_handlers_for_pco(pc_offset, info->exception_handlers()); ++ } ++} ++ ++void LIR_Assembler::return_op(LIR_Opr result) { ++ assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == i0, "word returns are in i0,"); ++ ++ // Pop the stack before the safepoint code ++ __ remove_frame(initial_frame_size_in_bytes()); ++ ++ if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { ++ __ reserved_stack_check(); ++ } ++ ++ address polling_page(os::get_polling_page()); ++ __ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type); ++ __ ret(lr); ++} ++ ++int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { ++ address polling_page(os::get_polling_page()); ++ guarantee(info != NULL, "Shouldn't be NULL"); ++ assert(os::is_poll_address(polling_page), "should be"); ++ __ get_polling_page(rscratch1, polling_page, relocInfo::poll_type); ++ add_debug_info_for_branch(info); // This isn't just debug info: ++ // it's the oop map ++ __ read_polling_page(rscratch1, relocInfo::poll_type); ++ return __ offset(); ++} ++ ++ ++void LIR_Assembler::move_regs(Register from_reg, Register to_reg) { ++// if (from_reg == r31_sp) ++// from_reg = sp; ++// if (to_reg == r31_sp) ++// to_reg = sp; ++// __ mov(to_reg, from_reg); ++} ++ ++void LIR_Assembler::swap_reg(Register a, Register b) { Unimplemented(); } ++ ++ ++void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { ++ assert(src->is_constant(), "should not call otherwise"); ++ assert(dest->is_register(), "should not call otherwise"); ++ LIR_Const* c = src->as_constant_ptr(); ++ ++ switch (c->type()) { ++ case T_INT: { ++ assert(patch_code == lir_patch_none, "no patching handled here"); ++ __ movw(dest->as_register(), c->as_jint()); ++ break; ++ } ++ ++ case T_ADDRESS: { ++ assert(patch_code == lir_patch_none, "no patching handled here"); ++ __ mov(dest->as_register(), c->as_jint()); ++ break; ++ } ++ ++ case T_LONG: { ++ assert(patch_code == lir_patch_none, "no patching handled here"); ++ __ mov(dest->as_register_lo(), (intptr_t)c->as_jlong()); ++ break; ++ } ++ ++ case T_OBJECT: { ++ if (patch_code == lir_patch_none) { ++ jobject2reg(c->as_jobject(), dest->as_register()); ++ } else { ++ jobject2reg_with_patching(dest->as_register(), info); ++ } ++ break; ++ } ++ ++ case T_METADATA: { ++ if (patch_code != lir_patch_none) { ++ klass2reg_with_patching(dest->as_register(), info); ++ } else { ++ __ mov_metadata(dest->as_register(), c->as_metadata()); ++ } ++ break; ++ } ++ ++ case T_FLOAT: { ++ if (__ operand_valid_for_float_immediate(c->as_jfloat())) { ++ __ fmovs(dest->as_float_reg(), (c->as_jfloat())); ++ } else { ++ __ adr(rscratch1, InternalAddress(float_constant(c->as_jfloat()))); ++ __ ldrs(dest->as_float_reg(), Address(rscratch1)); ++ } ++ break; ++ } ++ ++ case T_DOUBLE: { ++ if (__ operand_valid_for_float_immediate(c->as_jdouble())) { ++ __ fmovd(dest->as_double_reg(), (c->as_jdouble())); ++ } else { ++ __ adr(rscratch1, InternalAddress(double_constant(c->as_jdouble()))); ++ __ ldrd(dest->as_double_reg(), Address(rscratch1)); ++ } ++ break; ++ } ++ ++ default: ++ ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { ++ LIR_Const* c = src->as_constant_ptr(); ++ switch (c->type()) { ++ case T_OBJECT: ++ { ++ if (! c->as_jobject()) ++ __ str(zr, frame_map()->address_for_slot(dest->single_stack_ix())); ++ else { ++ const2reg(src, FrameMap::rscratch1_opr, lir_patch_none, NULL); ++ reg2stack(FrameMap::rscratch1_opr, dest, c->type(), false); ++ } ++ } ++ break; ++ case T_ADDRESS: ++ { ++ const2reg(src, FrameMap::rscratch1_opr, lir_patch_none, NULL); ++ reg2stack(FrameMap::rscratch1_opr, dest, c->type(), false); ++ } ++ case T_INT: ++ case T_FLOAT: ++ { ++ Register reg = zr; ++ if (c->as_jint_bits() == 0) ++ __ strw(zr, frame_map()->address_for_slot(dest->single_stack_ix())); ++ else { ++ __ movw(rscratch1, c->as_jint_bits()); ++ __ strw(rscratch1, frame_map()->address_for_slot(dest->single_stack_ix())); ++ } ++ } ++ break; ++ case T_LONG: ++ case T_DOUBLE: ++ { ++ Register reg = zr; ++ if (c->as_jlong_bits() == 0) ++ __ str(zr, frame_map()->address_for_slot(dest->double_stack_ix(), ++ lo_word_offset_in_bytes)); ++ else { ++ __ mov(rscratch1, (intptr_t)c->as_jlong_bits()); ++ __ str(rscratch1, frame_map()->address_for_slot(dest->double_stack_ix(), ++ lo_word_offset_in_bytes)); ++ } ++ } ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { ++ assert(src->is_constant(), "should not call otherwise"); ++ LIR_Const* c = src->as_constant_ptr(); ++ LIR_Address* to_addr = dest->as_address_ptr(); ++ ++ void (Assembler::* insn)(Register Rt, const Address &adr); ++ ++ switch (type) { ++ case T_ADDRESS: ++ assert(c->as_jint() == 0, "should be"); ++ insn = &Assembler::str; ++ break; ++ case T_LONG: ++ assert(c->as_jlong() == 0, "should be"); ++ insn = &Assembler::str; ++ break; ++ case T_INT: ++ assert(c->as_jint() == 0, "should be"); ++ insn = &Assembler::strw; ++ break; ++ case T_OBJECT: ++ case T_ARRAY: ++ assert(c->as_jobject() == 0, "should be"); ++ if (UseCompressedOops && !wide) { ++ insn = &Assembler::strw; ++ } else { ++ insn = &Assembler::str; ++ } ++ break; ++ case T_CHAR: ++ case T_SHORT: ++ assert(c->as_jint() == 0, "should be"); ++ insn = &Assembler::strh; ++ break; ++ case T_BOOLEAN: ++ case T_BYTE: ++ assert(c->as_jint() == 0, "should be"); ++ insn = &Assembler::strb; ++ break; ++ default: ++ ShouldNotReachHere(); ++ insn = &Assembler::str; // unreachable ++ } ++ ++ if (info) add_debug_info_for_null_check_here(info); ++ (_masm->*insn)(zr, as_Address(to_addr, rscratch1)); ++} ++ ++void LIR_Assembler::reg2reg(LIR_Opr src, LIR_Opr dest) { ++ assert(src->is_register(), "should not call otherwise"); ++ assert(dest->is_register(), "should not call otherwise"); ++ ++ // move between cpu-registers ++ if (dest->is_single_cpu()) { ++ if (src->type() == T_LONG) { ++ // Can do LONG -> OBJECT ++ move_regs(src->as_register_lo(), dest->as_register()); ++ return; ++ } ++ assert(src->is_single_cpu(), "must match"); ++ if (src->type() == T_OBJECT) { ++ __ verify_oop(src->as_register()); ++ } ++ move_regs(src->as_register(), dest->as_register()); ++ ++ } else if (dest->is_double_cpu()) { ++ if (src->type() == T_OBJECT || src->type() == T_ARRAY) { ++ // Surprising to me but we can see move of a long to t_object ++ __ verify_oop(src->as_register()); ++ move_regs(src->as_register(), dest->as_register_lo()); ++ return; ++ } ++ assert(src->is_double_cpu(), "must match"); ++ Register f_lo = src->as_register_lo(); ++ Register f_hi = src->as_register_hi(); ++ Register t_lo = dest->as_register_lo(); ++ Register t_hi = dest->as_register_hi(); ++ assert(f_hi == f_lo, "must be same"); ++ assert(t_hi == t_lo, "must be same"); ++ move_regs(f_lo, t_lo); ++ ++ } else if (dest->is_single_fpu()) { ++ __ fmovs(dest->as_float_reg(), src->as_float_reg()); ++ ++ } else if (dest->is_double_fpu()) { ++ __ fmovd(dest->as_double_reg(), src->as_double_reg()); ++ ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::reg2stack(LIR_Opr src, LIR_Opr dest, BasicType type, bool pop_fpu_stack) { ++ if (src->is_single_cpu()) { ++ if (type == T_ARRAY || type == T_OBJECT) { ++ __ str(src->as_register(), frame_map()->address_for_slot(dest->single_stack_ix())); ++ __ verify_oop(src->as_register()); ++ } else if (type == T_METADATA || type == T_DOUBLE || type == T_ADDRESS) { ++ __ str(src->as_register(), frame_map()->address_for_slot(dest->single_stack_ix())); ++ } else { ++ __ strw(src->as_register(), frame_map()->address_for_slot(dest->single_stack_ix())); ++ } ++ ++ } else if (src->is_double_cpu()) { ++ Address dest_addr_LO = frame_map()->address_for_slot(dest->double_stack_ix(), lo_word_offset_in_bytes); ++ __ str(src->as_register_lo(), dest_addr_LO); ++ ++ } else if (src->is_single_fpu()) { ++ Address dest_addr = frame_map()->address_for_slot(dest->single_stack_ix()); ++ __ strs(src->as_float_reg(), dest_addr); ++ ++ } else if (src->is_double_fpu()) { ++ Address dest_addr = frame_map()->address_for_slot(dest->double_stack_ix()); ++ __ strd(src->as_double_reg(), dest_addr); ++ ++ } else { ++ ShouldNotReachHere(); ++ } ++ ++} ++ ++ ++void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, bool wide, bool /* unaligned */) { ++ LIR_Address* to_addr = dest->as_address_ptr(); ++ PatchingStub* patch = NULL; ++ Register compressed_src = rscratch1; ++ ++ if (patch_code != lir_patch_none) { ++ deoptimize_trap(info); ++ return; ++ } ++ ++ if (type == T_ARRAY || type == T_OBJECT) { ++ __ verify_oop(src->as_register()); ++ ++ if (UseCompressedOops && !wide) { ++ __ encode_heap_oop(compressed_src, src->as_register()); ++ } else { ++ compressed_src = src->as_register(); ++ } ++ } ++ ++ int null_check_here = code_offset(); ++ switch (type) { ++ case T_FLOAT: { ++ __ strs(src->as_float_reg(), as_Address(to_addr)); ++ break; ++ } ++ ++ case T_DOUBLE: { ++ __ strd(src->as_double_reg(), as_Address(to_addr)); ++ break; ++ } ++ ++ case T_ARRAY: // fall through ++ case T_OBJECT: // fall through ++ if (UseCompressedOops && !wide) { ++ __ strw(compressed_src, as_Address(to_addr, rscratch2)); ++ } else { ++ __ str(compressed_src, as_Address(to_addr)); ++ } ++ break; ++ case T_METADATA: ++ // We get here to store a method pointer to the stack to pass to ++ // a dtrace runtime call. This can't work on 64 bit with ++ // compressed klass ptrs: T_METADATA can be a compressed klass ++ // ptr or a 64 bit method pointer. ++ ShouldNotReachHere(); ++ __ str(src->as_register(), as_Address(to_addr)); ++ break; ++ case T_ADDRESS: ++ __ str(src->as_register(), as_Address(to_addr)); ++ break; ++ case T_INT: ++ __ strw(src->as_register(), as_Address(to_addr)); ++ break; ++ ++ case T_LONG: { ++ __ str(src->as_register_lo(), as_Address_lo(to_addr)); ++ break; ++ } ++ ++ case T_BYTE: // fall through ++ case T_BOOLEAN: { ++ __ strb(src->as_register(), as_Address(to_addr)); ++ break; ++ } ++ ++ case T_CHAR: // fall through ++ case T_SHORT: ++ __ strh(src->as_register(), as_Address(to_addr)); ++ break; ++ ++ default: ++ ShouldNotReachHere(); ++ } ++ if (info != NULL) { ++ add_debug_info_for_null_check(null_check_here, info); ++ } ++} ++ ++ ++void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { ++ assert(src->is_stack(), "should not call otherwise"); ++ assert(dest->is_register(), "should not call otherwise"); ++ ++ if (dest->is_single_cpu()) { ++ if (type == T_ARRAY || type == T_OBJECT) { ++ __ ldr(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix())); ++ __ verify_oop(dest->as_register()); ++ } else if (type == T_METADATA || type == T_ADDRESS) { ++ __ ldr(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix())); ++ } else { ++ __ ldrw(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix())); ++ } ++ ++ } else if (dest->is_double_cpu()) { ++ Address src_addr_LO = frame_map()->address_for_slot(src->double_stack_ix(), lo_word_offset_in_bytes); ++ __ ldr(dest->as_register_lo(), src_addr_LO); ++ ++ } else if (dest->is_single_fpu()) { ++ Address src_addr = frame_map()->address_for_slot(src->single_stack_ix()); ++ __ ldrs(dest->as_float_reg(), src_addr); ++ ++ } else if (dest->is_double_fpu()) { ++ Address src_addr = frame_map()->address_for_slot(src->double_stack_ix()); ++ __ ldrd(dest->as_double_reg(), src_addr); ++ ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++ ++void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo* info) { ++ address target = NULL; ++ relocInfo::relocType reloc_type = relocInfo::none; ++ ++ switch (patching_id(info)) { ++ case PatchingStub::access_field_id: ++ target = Runtime1::entry_for(Runtime1::access_field_patching_id); ++ reloc_type = relocInfo::section_word_type; ++ break; ++ case PatchingStub::load_klass_id: ++ target = Runtime1::entry_for(Runtime1::load_klass_patching_id); ++ reloc_type = relocInfo::metadata_type; ++ break; ++ case PatchingStub::load_mirror_id: ++ target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); ++ reloc_type = relocInfo::oop_type; ++ break; ++ case PatchingStub::load_appendix_id: ++ target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); ++ reloc_type = relocInfo::oop_type; ++ break; ++ default: ShouldNotReachHere(); ++ } ++ ++ __ far_call(RuntimeAddress(target)); ++ add_call_info_here(info); ++} ++ ++void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { ++ ++ LIR_Opr temp; ++ if (type == T_LONG || type == T_DOUBLE) ++ temp = FrameMap::rscratch1_long_opr; ++ else ++ temp = FrameMap::rscratch1_opr; ++ ++ stack2reg(src, temp, src->type()); ++ reg2stack(temp, dest, dest->type(), false); ++} ++ ++ ++void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide, bool /* unaligned */) { ++ LIR_Address* addr = src->as_address_ptr(); ++ LIR_Address* from_addr = src->as_address_ptr(); ++ ++ if (addr->base()->type() == T_OBJECT) { ++ __ verify_oop(addr->base()->as_pointer_register()); ++ } ++ ++ if (patch_code != lir_patch_none) { ++ deoptimize_trap(info); ++ return; ++ } ++ ++ if (info != NULL) { ++ add_debug_info_for_null_check_here(info); ++ } ++ int null_check_here = code_offset(); ++ switch (type) { ++ case T_FLOAT: { ++ __ ldrs(dest->as_float_reg(), as_Address(from_addr)); ++ break; ++ } ++ ++ case T_DOUBLE: { ++ __ ldrd(dest->as_double_reg(), as_Address(from_addr)); ++ break; ++ } ++ ++ case T_ARRAY: // fall through ++ case T_OBJECT: // fall through ++ if (UseCompressedOops && !wide) { ++ __ ldrw(dest->as_register(), as_Address(from_addr)); ++ } else { ++ __ ldr(dest->as_register(), as_Address(from_addr)); ++ } ++ break; ++ case T_METADATA: ++ // We get here to store a method pointer to the stack to pass to ++ // a dtrace runtime call. This can't work on 64 bit with ++ // compressed klass ptrs: T_METADATA can be a compressed klass ++ // ptr or a 64 bit method pointer. ++ ShouldNotReachHere(); ++ __ ldr(dest->as_register(), as_Address(from_addr)); ++ break; ++ case T_ADDRESS: ++ // FIXME: OMG this is a horrible kludge. Any offset from an ++ // address that matches klass_offset_in_bytes() will be loaded ++ // as a word, not a long. ++ if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { ++ __ ldrw(dest->as_register(), as_Address(from_addr)); ++ } else { ++ __ ldr(dest->as_register(), as_Address(from_addr)); ++ } ++ break; ++ case T_INT: ++ __ ldrw(dest->as_register(), as_Address(from_addr)); ++ break; ++ ++ case T_LONG: { ++ __ ldr(dest->as_register_lo(), as_Address_lo(from_addr)); ++ break; ++ } ++ ++ case T_BYTE: ++ __ ldrsb(dest->as_register(), as_Address(from_addr)); ++ break; ++ case T_BOOLEAN: { ++ __ ldrb(dest->as_register(), as_Address(from_addr)); ++ break; ++ } ++ ++ case T_CHAR: ++ __ ldrh(dest->as_register(), as_Address(from_addr)); ++ break; ++ case T_SHORT: ++ __ ldrsh(dest->as_register(), as_Address(from_addr)); ++ break; ++ ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ if (type == T_ARRAY || type == T_OBJECT) { ++ if (UseCompressedOops && !wide) { ++ __ decode_heap_oop(dest->as_register()); ++ } ++ __ verify_oop(dest->as_register()); ++ } else if (type == T_ADDRESS && addr->disp() == oopDesc::klass_offset_in_bytes()) { ++ if (UseCompressedClassPointers) { ++ __ decode_klass_not_null(dest->as_register()); ++ } ++ } ++} ++ ++ ++int LIR_Assembler::array_element_size(BasicType type) const { ++ int elem_size = type2aelembytes(type); ++ return exact_log2(elem_size); ++} ++ ++void LIR_Assembler::arithmetic_idiv(LIR_Op3* op, bool is_irem) { ++ Register Rdividend = op->in_opr1()->as_register(); ++ Register Rdivisor = op->in_opr2()->as_register(); ++ Register Rscratch = op->in_opr3()->as_register(); ++ Register Rresult = op->result_opr()->as_register(); ++ int divisor = -1; ++ ++ /* ++ TODO: For some reason, using the Rscratch that gets passed in is ++ not possible because the register allocator does not see the tmp reg ++ as used, and assignes it the same register as Rdividend. We use rscratch1 ++ instead. ++ ++ assert(Rdividend != Rscratch, ""); ++ assert(Rdivisor != Rscratch, ""); ++ */ ++ ++ if (Rdivisor == noreg && is_power_of_2(divisor)) { ++ // convert division by a power of two into some shifts and logical operations ++ } ++ ++ __ corrected_idivl(Rresult, Rdividend, Rdivisor, is_irem, rscratch1); ++} ++ ++void LIR_Assembler::emit_op3(LIR_Op3* op) { ++ switch (op->code()) { ++ case lir_idiv: ++ arithmetic_idiv(op, false); ++ break; ++ case lir_irem: ++ arithmetic_idiv(op, true); ++ break; ++ case lir_fmad: ++ __ fmaddd(op->result_opr()->as_double_reg(), ++ op->in_opr1()->as_double_reg(), ++ op->in_opr2()->as_double_reg(), ++ op->in_opr3()->as_double_reg()); ++ break; ++ case lir_fmaf: ++ __ fmadds(op->result_opr()->as_float_reg(), ++ op->in_opr1()->as_float_reg(), ++ op->in_opr2()->as_float_reg(), ++ op->in_opr3()->as_float_reg()); ++ break; ++ default: ShouldNotReachHere(); break; ++ } ++} ++ ++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 ++ ++ if (op->cond() == lir_cond_always) { ++ if (op->info() != NULL) add_debug_info_for_branch(op->info()); ++ __ b(*(op->label())); ++ } else { ++ Assembler::Condition acond; ++ if (op->code() == lir_cond_float_branch) { ++ bool is_unordered = (op->ublock() == op->block()); ++ // Assembler::EQ does not permit unordered branches, so we add ++ // another branch here. Likewise, Assembler::NE does not permit ++ // ordered branches. ++ if ((is_unordered && op->cond() == lir_cond_equal) ++ || (!is_unordered && op->cond() == lir_cond_notEqual)) ++ __ br(Assembler::VS, *(op->ublock()->label())); ++ switch(op->cond()) { ++ case lir_cond_equal: acond = Assembler::EQ; break; ++ case lir_cond_notEqual: acond = Assembler::NE; break; ++ case lir_cond_less: acond = (is_unordered ? Assembler::LT : Assembler::LO); break; ++ case lir_cond_lessEqual: acond = (is_unordered ? Assembler::LE : Assembler::LS); break; ++ case lir_cond_greaterEqual: acond = (is_unordered ? Assembler::HS : Assembler::GE); break; ++ case lir_cond_greater: acond = (is_unordered ? Assembler::HI : Assembler::GT); break; ++ default: ShouldNotReachHere(); ++ acond = Assembler::EQ; // unreachable ++ } ++ } else { ++ switch (op->cond()) { ++ case lir_cond_equal: acond = Assembler::EQ; break; ++ case lir_cond_notEqual: acond = Assembler::NE; break; ++ case lir_cond_less: acond = Assembler::LT; break; ++ case lir_cond_lessEqual: acond = Assembler::LE; break; ++ case lir_cond_greaterEqual: acond = Assembler::GE; break; ++ case lir_cond_greater: acond = Assembler::GT; break; ++ case lir_cond_belowEqual: acond = Assembler::LS; break; ++ case lir_cond_aboveEqual: acond = Assembler::HS; break; ++ default: ShouldNotReachHere(); ++ acond = Assembler::EQ; // unreachable ++ } ++ } ++ __ br(acond,*(op->label())); ++ } ++} ++ ++ ++ ++void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { ++ LIR_Opr src = op->in_opr(); ++ LIR_Opr dest = op->result_opr(); ++ ++ switch (op->bytecode()) { ++ case Bytecodes::_i2f: ++ { ++ __ scvtfws(dest->as_float_reg(), src->as_register()); ++ break; ++ } ++ case Bytecodes::_i2d: ++ { ++ __ scvtfwd(dest->as_double_reg(), src->as_register()); ++ break; ++ } ++ case Bytecodes::_l2d: ++ { ++ __ scvtfd(dest->as_double_reg(), src->as_register_lo()); ++ break; ++ } ++ case Bytecodes::_l2f: ++ { ++ __ scvtfs(dest->as_float_reg(), src->as_register_lo()); ++ break; ++ } ++ case Bytecodes::_f2d: ++ { ++ __ fcvts(dest->as_double_reg(), src->as_float_reg()); ++ break; ++ } ++ case Bytecodes::_d2f: ++ { ++ __ fcvtd(dest->as_float_reg(), src->as_double_reg()); ++ break; ++ } ++ case Bytecodes::_i2c: ++ { ++ __ ubfx(dest->as_register(), src->as_register(), 0, 16); ++ break; ++ } ++ case Bytecodes::_i2l: ++ { ++ __ sxtw(dest->as_register_lo(), src->as_register()); ++ break; ++ } ++ case Bytecodes::_i2s: ++ { ++ __ sxth(dest->as_register(), src->as_register()); ++ break; ++ } ++ case Bytecodes::_i2b: ++ { ++ __ sxtb(dest->as_register(), src->as_register()); ++ break; ++ } ++ case Bytecodes::_l2i: ++ { ++ _masm->block_comment("FIXME: This could be a no-op"); ++ __ uxtw(dest->as_register(), src->as_register_lo()); ++ break; ++ } ++ case Bytecodes::_d2l: ++ { ++ __ fcvtzd(dest->as_register_lo(), src->as_double_reg()); ++ break; ++ } ++ case Bytecodes::_f2i: ++ { ++ __ fcvtzsw(dest->as_register(), src->as_float_reg()); ++ break; ++ } ++ case Bytecodes::_f2l: ++ { ++ __ fcvtzs(dest->as_register_lo(), src->as_float_reg()); ++ break; ++ } ++ case Bytecodes::_d2i: ++ { ++ __ fcvtzdw(dest->as_register(), src->as_double_reg()); ++ break; ++ } ++ default: ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { ++ if (op->init_check()) { ++ __ ldrb(rscratch1, Address(op->klass()->as_register(), ++ InstanceKlass::init_state_offset())); ++ __ cmpw(rscratch1, InstanceKlass::fully_initialized); ++ add_debug_info_for_null_check_here(op->stub()->info()); ++ __ br(Assembler::NE, *op->stub()->entry()); ++ } ++ __ allocate_object(op->obj()->as_register(), ++ op->tmp1()->as_register(), ++ op->tmp2()->as_register(), ++ op->header_size(), ++ op->object_size(), ++ op->klass()->as_register(), ++ *op->stub()->entry()); ++ __ BIND(*op->stub()->continuation()); ++} ++ ++void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { ++ Register len = op->len()->as_register(); ++ __ uxtw(len, len); ++ ++ if (UseSlowPath || ++ (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) || ++ (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) { ++ __ b(*op->stub()->entry()); ++ } else { ++ Register tmp1 = op->tmp1()->as_register(); ++ Register tmp2 = op->tmp2()->as_register(); ++ Register tmp3 = op->tmp3()->as_register(); ++ if (len == tmp1) { ++ tmp1 = tmp3; ++ } else if (len == tmp2) { ++ tmp2 = tmp3; ++ } else if (len == tmp3) { ++ // everything is ok ++ } else { ++ __ mov(tmp3, len); ++ } ++ __ allocate_array(op->obj()->as_register(), ++ len, ++ tmp1, ++ tmp2, ++ arrayOopDesc::header_size(op->type()), ++ array_element_size(op->type()), ++ op->klass()->as_register(), ++ *op->stub()->entry()); ++ } ++ __ BIND(*op->stub()->continuation()); ++} ++ ++void LIR_Assembler::type_profile_helper(Register mdo, ++ ciMethodData *md, ciProfileData *data, ++ Register recv, Label* update_done) { ++ for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { ++ Label next_test; ++ // See if the receiver is receiver[n]. ++ __ lea(rscratch2, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)))); ++ __ ldr(rscratch1, Address(rscratch2)); ++ __ cmp(recv, rscratch1); ++ __ br(Assembler::NE, next_test); ++ Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))); ++ __ addptr(data_addr, DataLayout::counter_increment); ++ __ b(*update_done); ++ __ BIND(next_test); ++ } ++ ++ // Didn't find receiver; find next empty slot and fill it in ++ for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { ++ Label next_test; ++ __ lea(rscratch2, ++ Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)))); ++ Address recv_addr(rscratch2); ++ __ ldr(rscratch1, recv_addr); ++ __ cbnz(rscratch1, next_test); ++ __ str(recv, recv_addr); ++ __ mov(rscratch1, DataLayout::counter_increment); ++ __ lea(rscratch2, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)))); ++ __ str(rscratch1, Address(rscratch2)); ++ __ b(*update_done); ++ __ BIND(next_test); ++ } ++} ++ ++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(); ++ ciKlass* k = op->klass(); ++ Register Rtmp1 = noreg; ++ ++ // check if it needs to be profiled ++ ciMethodData* md; ++ ciProfileData* data; ++ ++ const bool should_profile = op->should_profile(); ++ ++ if (should_profile) { ++ ciMethod* method = op->profiled_method(); ++ assert(method != NULL, "Should have method"); ++ int bci = op->profiled_bci(); ++ md = method->method_data_or_null(); ++ assert(md != NULL, "Sanity"); ++ data = md->bci_to_data(bci); ++ assert(data != NULL, "need data for type check"); ++ assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); ++ } ++ Label profile_cast_success, profile_cast_failure; ++ Label *success_target = should_profile ? &profile_cast_success : success; ++ Label *failure_target = should_profile ? &profile_cast_failure : failure; ++ ++ if (obj == k_RInfo) { ++ k_RInfo = dst; ++ } else if (obj == klass_RInfo) { ++ klass_RInfo = dst; ++ } ++ if (k->is_loaded() && !UseCompressedClassPointers) { ++ select_different_registers(obj, dst, k_RInfo, klass_RInfo); ++ } else { ++ Rtmp1 = op->tmp3()->as_register(); ++ select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); ++ } ++ ++ assert_different_registers(obj, k_RInfo, klass_RInfo); ++ ++ if (should_profile) { ++ Label not_null; ++ __ cbnz(obj, not_null); ++ // Object is null; update MDO and exit ++ Register mdo = klass_RInfo; ++ __ mov_metadata(mdo, md->constant_encoding()); ++ Address data_addr ++ = __ form_address(rscratch2, mdo, ++ md->byte_offset_of_slot(data, DataLayout::flags_offset()), ++ 0); ++ __ ldrb(rscratch1, data_addr); ++ __ orr(rscratch1, rscratch1, BitData::null_seen_byte_constant()); ++ __ strb(rscratch1, data_addr); ++ __ b(*obj_is_null); ++ __ BIND(not_null); ++ } else { ++ __ cbz(obj, *obj_is_null); ++ } ++ ++ if (!k->is_loaded()) { ++ klass2reg_with_patching(k_RInfo, op->info_for_patch()); ++ } else { ++ __ mov_metadata(k_RInfo, k->constant_encoding()); ++ } ++ __ verify_oop(obj); ++ ++ if (op->fast_check()) { ++ // get object class ++ // not a safepoint as obj null check happens earlier ++ __ load_klass(rscratch1, obj); ++ __ cmp( rscratch1, k_RInfo); ++ ++ __ br(Assembler::NE, *failure_target); ++ // successful cast, fall through to profile or jump ++ } else { ++ // get object class ++ // not a safepoint as obj null check happens earlier ++ __ load_klass(klass_RInfo, obj); ++ if (k->is_loaded()) { ++ // See if we get an immediate positive hit ++ __ ldr(rscratch1, Address(klass_RInfo, long(k->super_check_offset()))); ++ __ cmp(k_RInfo, rscratch1); ++ if ((juint)in_bytes(Klass::secondary_super_cache_offset()) != k->super_check_offset()) { ++ __ br(Assembler::NE, *failure_target); ++ // successful cast, fall through to profile or jump ++ } else { ++ // See if we get an immediate positive hit ++ __ br(Assembler::EQ, *success_target); ++ // check for self ++ __ cmp(klass_RInfo, k_RInfo); ++ __ br(Assembler::EQ, *success_target); ++ ++ __ stp(klass_RInfo, k_RInfo, Address(__ pre(sp, -2 * wordSize))); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); ++ __ ldr(klass_RInfo, Address(__ post(sp, 2 * wordSize))); ++ // result is a boolean ++ __ cbzw(klass_RInfo, *failure_target); ++ // successful cast, fall through to profile or jump ++ } ++ } else { ++ // perform the fast part of the checking logic ++ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); ++ // call out-of-line instance of __ check_klass_subtype_slow_path(...): ++ __ stp(klass_RInfo, k_RInfo, Address(__ pre(sp, -2 * wordSize))); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); ++ __ ldp(k_RInfo, klass_RInfo, Address(__ post(sp, 2 * wordSize))); ++ // result is a boolean ++ __ cbz(k_RInfo, *failure_target); ++ // successful cast, fall through to profile or jump ++ } ++ } ++ if (should_profile) { ++ Register mdo = klass_RInfo, recv = k_RInfo; ++ __ BIND(profile_cast_success); ++ __ mov_metadata(mdo, md->constant_encoding()); ++ __ load_klass(recv, obj); ++ Label update_done; ++ type_profile_helper(mdo, md, data, recv, success); ++ __ b(*success); ++ ++ __ BIND(profile_cast_failure); ++ __ mov_metadata(mdo, md->constant_encoding()); ++ Address counter_addr ++ = __ form_address(rscratch2, mdo, ++ md->byte_offset_of_slot(data, CounterData::count_offset()), ++ 0); ++ __ ldr(rscratch1, counter_addr); ++ __ sub(rscratch1, rscratch1, DataLayout::counter_increment); ++ __ str(rscratch1, counter_addr); ++ __ b(*failure); ++ } ++ __ b(*success); ++} ++ ++ ++void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { ++ const bool should_profile = op->should_profile(); ++ ++ 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(); ++ ++ CodeStub* stub = op->stub(); ++ ++ // check if it needs to be profiled ++ ciMethodData* md; ++ ciProfileData* data; ++ ++ if (should_profile) { ++ ciMethod* method = op->profiled_method(); ++ assert(method != NULL, "Should have method"); ++ int bci = op->profiled_bci(); ++ md = method->method_data_or_null(); ++ assert(md != NULL, "Sanity"); ++ data = md->bci_to_data(bci); ++ assert(data != NULL, "need data for type check"); ++ assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); ++ } ++ Label profile_cast_success, profile_cast_failure, done; ++ Label *success_target = should_profile ? &profile_cast_success : &done; ++ Label *failure_target = should_profile ? &profile_cast_failure : stub->entry(); ++ ++ if (should_profile) { ++ Label not_null; ++ __ cbnz(value, not_null); ++ // Object is null; update MDO and exit ++ Register mdo = klass_RInfo; ++ __ mov_metadata(mdo, md->constant_encoding()); ++ Address data_addr ++ = __ form_address(rscratch2, mdo, ++ md->byte_offset_of_slot(data, DataLayout::flags_offset()), ++ 0); ++ __ ldrb(rscratch1, data_addr); ++ __ orr(rscratch1, rscratch1, BitData::null_seen_byte_constant()); ++ __ strb(rscratch1, data_addr); ++ __ b(done); ++ __ BIND(not_null); ++ } else { ++ __ cbz(value, done); ++ } ++ ++ add_debug_info_for_null_check_here(op->info_for_exception()); ++ __ load_klass(k_RInfo, array); ++ __ load_klass(klass_RInfo, value); ++ ++ // get instance klass (it's already uncompressed) ++ __ ldr(k_RInfo, Address(k_RInfo, ObjArrayKlass::element_klass_offset())); ++ // perform the fast part of the checking logic ++ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); ++ // call out-of-line instance of __ check_klass_subtype_slow_path(...): ++ __ stp(klass_RInfo, k_RInfo, Address(__ pre(sp, -2 * wordSize))); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); ++ __ ldp(k_RInfo, klass_RInfo, Address(__ post(sp, 2 * wordSize))); ++ // result is a boolean ++ __ cbzw(k_RInfo, *failure_target); ++ // fall through to the success case ++ ++ if (should_profile) { ++ Register mdo = klass_RInfo, recv = k_RInfo; ++ __ BIND(profile_cast_success); ++ __ mov_metadata(mdo, md->constant_encoding()); ++ __ load_klass(recv, value); ++ Label update_done; ++ type_profile_helper(mdo, md, data, recv, &done); ++ __ b(done); ++ ++ __ BIND(profile_cast_failure); ++ __ mov_metadata(mdo, md->constant_encoding()); ++ Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); ++ __ lea(rscratch2, counter_addr); ++ __ ldr(rscratch1, Address(rscratch2)); ++ __ sub(rscratch1, rscratch1, DataLayout::counter_increment); ++ __ str(rscratch1, Address(rscratch2)); ++ __ b(*stub->entry()); ++ } ++ ++ __ 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); ++ if (dst != obj) { ++ __ mov(dst, obj); ++ } ++ } 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); ++ __ mov(dst, zr); ++ __ b(done); ++ __ BIND(success); ++ __ mov(dst, 1); ++ __ BIND(done); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::casw(Register addr, Register newval, Register cmpval) { ++ __ cmpxchg(addr, cmpval, newval, Assembler::word, /* acquire*/ true, /* release*/ true, /* weak*/ false, rscratch1); ++ __ cset(rscratch1, Assembler::NE); ++ __ membar(__ AnyAny); ++} ++ ++void LIR_Assembler::casl(Register addr, Register newval, Register cmpval) { ++ __ cmpxchg(addr, cmpval, newval, Assembler::xword, /* acquire*/ true, /* release*/ true, /* weak*/ false, rscratch1); ++ __ cset(rscratch1, Assembler::NE); ++ __ membar(__ AnyAny); ++} ++ ++ ++void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { ++ assert(VM_Version::supports_cx8(), "wrong machine"); ++ Register addr; ++ if (op->addr()->is_register()) { ++ addr = as_reg(op->addr()); ++ } else { ++ assert(op->addr()->is_address(), "what else?"); ++ LIR_Address* addr_ptr = op->addr()->as_address_ptr(); ++ assert(addr_ptr->disp() == 0, "need 0 disp"); ++ assert(addr_ptr->index() == LIR_OprDesc::illegalOpr(), "need 0 index"); ++ addr = as_reg(addr_ptr->base()); ++ } ++ Register newval = as_reg(op->new_value()); ++ Register cmpval = as_reg(op->cmp_value()); ++ Label succeed, fail, around; ++ ++ if (op->code() == lir_cas_obj) { ++ if (UseCompressedOops) { ++ Register t1 = op->tmp1()->as_register(); ++ assert(op->tmp1()->is_valid(), "must be"); ++ __ encode_heap_oop(t1, cmpval); ++ cmpval = t1; ++ __ encode_heap_oop(rscratch2, newval); ++ newval = rscratch2; ++ casw(addr, newval, cmpval); ++ } else { ++ casl(addr, newval, cmpval); ++ } ++ } else if (op->code() == lir_cas_int) { ++ casw(addr, newval, cmpval); ++ } else { ++ casl(addr, newval, cmpval); ++ } ++} ++ ++ ++void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { ++ ++ Assembler::Condition acond, ncond; ++ switch (condition) { ++ case lir_cond_equal: acond = Assembler::EQ; ncond = Assembler::NE; break; ++ case lir_cond_notEqual: acond = Assembler::NE; ncond = Assembler::EQ; break; ++ case lir_cond_less: acond = Assembler::LT; ncond = Assembler::GE; break; ++ case lir_cond_lessEqual: acond = Assembler::LE; ncond = Assembler::GT; break; ++ case lir_cond_greaterEqual: acond = Assembler::GE; ncond = Assembler::LT; break; ++ case lir_cond_greater: acond = Assembler::GT; ncond = Assembler::LE; break; ++ case lir_cond_belowEqual: ++ case lir_cond_aboveEqual: ++ default: ShouldNotReachHere(); ++ acond = Assembler::EQ; ncond = Assembler::NE; // unreachable ++ } ++ ++ assert(result->is_single_cpu() || result->is_double_cpu(), ++ "expect single register for result"); ++ if (opr1->is_constant() && opr2->is_constant() ++ && opr1->type() == T_INT && opr2->type() == T_INT) { ++ jint val1 = opr1->as_jint(); ++ jint val2 = opr2->as_jint(); ++ if (val1 == 0 && val2 == 1) { ++ __ cset(result->as_register(), ncond); ++ return; ++ } else if (val1 == 1 && val2 == 0) { ++ __ cset(result->as_register(), acond); ++ return; ++ } ++ } ++ ++ if (opr1->is_constant() && opr2->is_constant() ++ && opr1->type() == T_LONG && opr2->type() == T_LONG) { ++ jlong val1 = opr1->as_jlong(); ++ jlong val2 = opr2->as_jlong(); ++ if (val1 == 0 && val2 == 1) { ++ __ cset(result->as_register_lo(), ncond); ++ return; ++ } else if (val1 == 1 && val2 == 0) { ++ __ cset(result->as_register_lo(), acond); ++ return; ++ } ++ } ++ ++ if (opr1->is_stack()) { ++ stack2reg(opr1, FrameMap::rscratch1_opr, result->type()); ++ opr1 = FrameMap::rscratch1_opr; ++ } else if (opr1->is_constant()) { ++ LIR_Opr tmp ++ = opr1->type() == T_LONG ? FrameMap::rscratch1_long_opr : FrameMap::rscratch1_opr; ++ const2reg(opr1, tmp, lir_patch_none, NULL); ++ opr1 = tmp; ++ } ++ ++ if (opr2->is_stack()) { ++ stack2reg(opr2, FrameMap::rscratch2_opr, result->type()); ++ opr2 = FrameMap::rscratch2_opr; ++ } else if (opr2->is_constant()) { ++ LIR_Opr tmp ++ = opr2->type() == T_LONG ? FrameMap::rscratch2_long_opr : FrameMap::rscratch2_opr; ++ const2reg(opr2, tmp, lir_patch_none, NULL); ++ opr2 = tmp; ++ } ++ ++ if (result->type() == T_LONG) ++ __ csel(result->as_register_lo(), opr1->as_register_lo(), opr2->as_register_lo(), acond); ++ else ++ __ csel(result->as_register(), opr1->as_register(), opr2->as_register(), acond); ++} ++ ++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, "should never be used, idiv/irem and ldiv/lrem not handled by this method"); ++ ++ if (left->is_single_cpu()) { ++ Register lreg = left->as_register(); ++ Register dreg = as_reg(dest); ++ ++ if (right->is_single_cpu()) { ++ // cpu register - cpu register ++ ++ assert(left->type() == T_INT && right->type() == T_INT && dest->type() == T_INT, ++ "should be"); ++ Register rreg = right->as_register(); ++ switch (code) { ++ case lir_add: __ addw (dest->as_register(), lreg, rreg); break; ++ case lir_sub: __ subw (dest->as_register(), lreg, rreg); break; ++ case lir_mul: __ mulw (dest->as_register(), lreg, rreg); break; ++ default: ShouldNotReachHere(); ++ } ++ ++ } else if (right->is_double_cpu()) { ++ Register rreg = right->as_register_lo(); ++ // single_cpu + double_cpu: can happen with obj+long ++ assert(code == lir_add || code == lir_sub, "mismatched arithmetic op"); ++ switch (code) { ++ case lir_add: __ add(dreg, lreg, rreg); break; ++ case lir_sub: __ sub(dreg, lreg, rreg); break; ++ default: ShouldNotReachHere(); ++ } ++ } else if (right->is_constant()) { ++ // cpu register - constant ++ jlong c; ++ ++ // FIXME. This is fugly: we really need to factor all this logic. ++ switch(right->type()) { ++ case T_LONG: ++ c = right->as_constant_ptr()->as_jlong(); ++ break; ++ case T_INT: ++ case T_ADDRESS: ++ c = right->as_constant_ptr()->as_jint(); ++ break; ++ default: ++ ShouldNotReachHere(); ++ c = 0; // unreachable ++ break; ++ } ++ ++ assert(code == lir_add || code == lir_sub, "mismatched arithmetic op"); ++ if (c == 0 && dreg == lreg) { ++ COMMENT("effective nop elided"); ++ return; ++ } ++ switch(left->type()) { ++ case T_INT: ++ switch (code) { ++ case lir_add: __ addw(dreg, c, lreg); break; ++ case lir_sub: __ subw(dreg, c, lreg); break; ++ default: ShouldNotReachHere(); ++ } ++ break; ++ case T_OBJECT: ++ case T_ADDRESS: ++ switch (code) { ++ case lir_add: __ add(dreg, lreg, c); break; ++ case lir_sub: __ sub(dreg, lreg, c); break; ++ default: ShouldNotReachHere(); ++ } ++ break; ++ ShouldNotReachHere(); ++ } ++ } else { ++ ShouldNotReachHere(); ++ } ++ ++ } else if (left->is_double_cpu()) { ++ Register lreg_lo = left->as_register_lo(); ++ ++ if (right->is_double_cpu()) { ++ // cpu register - cpu register ++ Register rreg_lo = right->as_register_lo(); ++ switch (code) { ++ case lir_add: __ add (dest->as_register_lo(), lreg_lo, rreg_lo); break; ++ case lir_sub: __ sub (dest->as_register_lo(), lreg_lo, rreg_lo); break; ++ case lir_mul: __ mul (dest->as_register_lo(), lreg_lo, rreg_lo); break; ++ case lir_div: __ corrected_idivq(dest->as_register_lo(), lreg_lo, rreg_lo, false, rscratch1); break; ++ case lir_rem: __ corrected_idivq(dest->as_register_lo(), lreg_lo, rreg_lo, true, rscratch1); break; ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ } else if (right->is_constant()) { ++ jlong c = right->as_constant_ptr()->as_jlong_bits(); ++ Register dreg = as_reg(dest); ++ assert(code == lir_add || code == lir_sub, "mismatched arithmetic op"); ++ if (c == 0 && dreg == lreg_lo) { ++ COMMENT("effective nop elided"); ++ return; ++ } ++ switch (code) { ++ case lir_add: __ add(dreg, lreg_lo, c); break; ++ case lir_sub: __ sub(dreg, lreg_lo, c); break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { ++ ShouldNotReachHere(); ++ } ++ } else if (left->is_single_fpu()) { ++ assert(right->is_single_fpu(), "right hand side of float arithmetics needs to be float register"); ++ switch (code) { ++ case lir_add: __ fadds (dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; ++ case lir_sub: __ fsubs (dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; ++ case lir_mul_strictfp: // fall through ++ case lir_mul: __ fmuls (dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; ++ case lir_div_strictfp: // fall through ++ case lir_div: __ fdivs (dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } else if (left->is_double_fpu()) { ++ if (right->is_double_fpu()) { ++ // fpu register - fpu register ++ switch (code) { ++ case lir_add: __ faddd (dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; ++ case lir_sub: __ fsubd (dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; ++ case lir_mul_strictfp: // fall through ++ case lir_mul: __ fmuld (dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; ++ case lir_div_strictfp: // fall through ++ case lir_div: __ fdivd (dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { ++ if (right->is_constant()) { ++ ShouldNotReachHere(); ++ } ++ ShouldNotReachHere(); ++ } ++ } else if (left->is_single_stack() || left->is_address()) { ++ assert(left == dest, "left and dest must be equal"); ++ ShouldNotReachHere(); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::arith_fpu_implementation(LIR_Code code, int left_index, int right_index, int dest_index, bool pop_fpu_stack) { Unimplemented(); } ++ ++ ++void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, LIR_Opr dest, LIR_Op* op) { ++ switch(code) { ++ case lir_abs : __ fabsd(dest->as_double_reg(), value->as_double_reg()); break; ++ case lir_sqrt: __ fsqrtd(dest->as_double_reg(), value->as_double_reg()); break; ++ default : ShouldNotReachHere(); ++ } ++} ++ ++void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst) { ++ ++ assert(left->is_single_cpu() || left->is_double_cpu(), "expect single or double register"); ++ Register Rleft = left->is_single_cpu() ? left->as_register() : ++ left->as_register_lo(); ++ if (dst->is_single_cpu()) { ++ Register Rdst = dst->as_register(); ++ if (right->is_constant()) { ++ switch (code) { ++ case lir_logic_and: __ andw (Rdst, Rleft, right->as_jint()); break; ++ case lir_logic_or: __ orrw (Rdst, Rleft, right->as_jint()); break; ++ case lir_logic_xor: __ eorw (Rdst, Rleft, right->as_jint()); break; ++ default: ShouldNotReachHere(); break; ++ } ++ } else { ++ Register Rright = right->is_single_cpu() ? right->as_register() : ++ right->as_register_lo(); ++ switch (code) { ++ case lir_logic_and: __ andw (Rdst, Rleft, Rright); break; ++ case lir_logic_or: __ orrw (Rdst, Rleft, Rright); break; ++ case lir_logic_xor: __ eorw (Rdst, Rleft, Rright); break; ++ default: ShouldNotReachHere(); break; ++ } ++ } ++ } else { ++ Register Rdst = dst->as_register_lo(); ++ if (right->is_constant()) { ++ switch (code) { ++ case lir_logic_and: __ andr (Rdst, Rleft, right->as_jlong()); break; ++ case lir_logic_or: __ orr (Rdst, Rleft, right->as_jlong()); break; ++ case lir_logic_xor: __ eor (Rdst, Rleft, right->as_jlong()); break; ++ default: ShouldNotReachHere(); break; ++ } ++ } else { ++ Register Rright = right->is_single_cpu() ? right->as_register() : ++ right->as_register_lo(); ++ switch (code) { ++ case lir_logic_and: __ andr (Rdst, Rleft, Rright); break; ++ case lir_logic_or: __ orr (Rdst, Rleft, Rright); break; ++ case lir_logic_xor: __ eor (Rdst, Rleft, Rright); break; ++ default: ShouldNotReachHere(); break; ++ } ++ } ++ } ++} ++ ++ ++ ++void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info) { Unimplemented(); } ++ ++ ++void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) { ++ if (opr1->is_constant() && opr2->is_single_cpu()) { ++ // tableswitch ++ Register reg = as_reg(opr2); ++ struct tableswitch &table = switches[opr1->as_constant_ptr()->as_jint()]; ++ __ tableswitch(reg, table._first_key, table._last_key, table._branches, table._after); ++ } else if (opr1->is_single_cpu() || opr1->is_double_cpu()) { ++ Register reg1 = as_reg(opr1); ++ if (opr2->is_single_cpu()) { ++ // cpu register - cpu register ++ Register reg2 = opr2->as_register(); ++ if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { ++ __ cmpoop(reg1, reg2); ++ } else { ++ assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY, "cmp int, oop?"); ++ __ cmpw(reg1, reg2); ++ } ++ return; ++ } ++ if (opr2->is_double_cpu()) { ++ // cpu register - cpu register ++ Register reg2 = opr2->as_register_lo(); ++ __ cmp(reg1, reg2); ++ return; ++ } ++ ++ if (opr2->is_constant()) { ++ bool is_32bit = false; // width of register operand ++ jlong imm; ++ ++ switch(opr2->type()) { ++ case T_INT: ++ imm = opr2->as_constant_ptr()->as_jint(); ++ is_32bit = true; ++ break; ++ case T_LONG: ++ imm = opr2->as_constant_ptr()->as_jlong(); ++ break; ++ case T_ADDRESS: ++ imm = opr2->as_constant_ptr()->as_jint(); ++ break; ++ case T_METADATA: ++ imm = (intptr_t)(opr2->as_constant_ptr()->as_metadata()); ++ break; ++ case T_OBJECT: ++ case T_ARRAY: ++ jobject2reg(opr2->as_constant_ptr()->as_jobject(), rscratch1); ++ __ cmpoop(reg1, rscratch1); ++ return; ++ default: ++ ShouldNotReachHere(); ++ imm = 0; // unreachable ++ break; ++ } ++ ++ if (Assembler::operand_valid_for_add_sub_immediate(imm)) { ++ if (is_32bit) ++ __ cmpw(reg1, imm); ++ else ++ __ cmp(reg1, imm); ++ return; ++ } else { ++ __ mov(rscratch1, imm); ++ if (is_32bit) ++ __ cmpw(reg1, rscratch1); ++ else ++ __ cmp(reg1, rscratch1); ++ return; ++ } ++ } else ++ ShouldNotReachHere(); ++ } else if (opr1->is_single_fpu()) { ++ FloatRegister reg1 = opr1->as_float_reg(); ++ assert(opr2->is_single_fpu(), "expect single float register"); ++ FloatRegister reg2 = opr2->as_float_reg(); ++ __ fcmps(reg1, reg2); ++ } else if (opr1->is_double_fpu()) { ++ FloatRegister reg1 = opr1->as_double_reg(); ++ assert(opr2->is_double_fpu(), "expect double float register"); ++ FloatRegister reg2 = opr2->as_double_reg(); ++ __ fcmpd(reg1, reg2); ++ } 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) { ++ Label done; ++ __ cmp(left->as_register_lo(), right->as_register_lo()); ++ __ mov(dst->as_register(), (u_int64_t)-1L); ++ __ br(Assembler::LT, done); ++ __ csinc(dst->as_register(), zr, zr, Assembler::EQ); ++ __ BIND(done); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++ ++void LIR_Assembler::align_call(LIR_Code code) { } ++ ++ ++void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { ++ address call = __ trampoline_call(Address(op->addr(), rtype)); ++ if (call == NULL) { ++ bailout("trampoline stub overflow"); ++ return; ++ } ++ add_call_info(code_offset(), op->info()); ++} ++ ++ ++void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { ++ address call = __ ic_call(op->addr()); ++ if (call == NULL) { ++ bailout("trampoline stub overflow"); ++ return; ++ } ++ add_call_info(code_offset(), op->info()); ++} ++ ++ ++/* Currently, vtable-dispatch is only enabled for sparc platforms */ ++void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { ++ ShouldNotReachHere(); ++} ++ ++ ++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)); ++ __ emit_static_call_stub(); ++ ++ assert(__ offset() - start + CompiledStaticCall::to_trampoline_stub_size() ++ <= call_stub_size(), "stub too big"); ++ __ end_a_stub(); ++} ++ ++ ++void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { ++ assert(exceptionOop->as_register() == i0, "must match"); ++ assert(exceptionPC->as_register() == i3, "must match"); ++ ++ // exception object is not added to oop map by LinearScan ++ // (LinearScan assumes that no oops are in fixed registers) ++ info->add_register_oop(exceptionOop); ++ Runtime1::StubID unwind_id; ++ ++ // get current pc information ++ // pc is only needed if the method has an exception handler, the unwind code does not need it. ++ int pc_for_athrow_offset = __ offset(); ++ InternalAddress pc_for_athrow(__ pc()); ++ __ adr(exceptionPC->as_register(), pc_for_athrow); ++ add_call_info(pc_for_athrow_offset, info); // for exception handler ++ ++ __ verify_not_null_oop(i0); ++ // search an exception handler (i0: exception oop, r3: throwing pc) ++ if (compilation()->has_fpu_code()) { ++ unwind_id = Runtime1::handle_exception_id; ++ } else { ++ unwind_id = Runtime1::handle_exception_nofpu_id; ++ } ++ __ far_call(RuntimeAddress(Runtime1::entry_for(unwind_id))); ++ ++ // FIXME: enough room for two byte trap ???? ++ __ nop(); ++} ++ ++ ++void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { ++ assert(exceptionOop->as_register() == i0, "must match"); ++ ++ __ b(_unwind_handler_entry); ++} ++ ++ ++void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) { ++ Register lreg = left->is_single_cpu() ? left->as_register() : left->as_register_lo(); ++ Register dreg = dest->is_single_cpu() ? dest->as_register() : dest->as_register_lo(); ++ ++ switch (left->type()) { ++ case T_INT: { ++ switch (code) { ++ case lir_shl: __ lslvw (dreg, lreg, count->as_register()); break; ++ case lir_shr: __ asrvw (dreg, lreg, count->as_register()); break; ++ case lir_ushr: __ lsrvw (dreg, lreg, count->as_register()); break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ break; ++ case T_LONG: ++ case T_ADDRESS: ++ case T_OBJECT: ++ switch (code) { ++ case lir_shl: __ lslv (dreg, lreg, count->as_register()); break; ++ case lir_shr: __ asrv (dreg, lreg, count->as_register()); break; ++ case lir_ushr: __ lsrv (dreg, lreg, count->as_register()); break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ } ++} ++ ++ ++void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) { ++ Register dreg = dest->is_single_cpu() ? dest->as_register() : dest->as_register_lo(); ++ Register lreg = left->is_single_cpu() ? left->as_register() : left->as_register_lo(); ++ ++ switch (left->type()) { ++ case T_INT: { ++ switch (code) { ++ case lir_shl: __ lslw (dreg, lreg, count); break; ++ case lir_shr: __ asrw (dreg, lreg, count); break; ++ case lir_ushr: __ lsrw (dreg, lreg, count); break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ break; ++ case T_LONG: ++ case T_ADDRESS: ++ case T_OBJECT: ++ switch (code) { ++ case lir_shl: __ lsl (dreg, lreg, count); break; ++ case lir_shr: __ asr (dreg, lreg, count); break; ++ case lir_ushr: __ lsr (dreg, lreg, count); break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ } ++} ++ ++ ++void LIR_Assembler::store_parameter(Register r, int offset_from_rsp_in_words) { ++ assert(offset_from_rsp_in_words >= 0, "invalid offset from rsp"); ++ int offset_from_rsp_in_bytes = offset_from_rsp_in_words * BytesPerWord; ++ assert(offset_from_rsp_in_bytes < frame_map()->reserved_argument_area_size(), "invalid offset"); ++ __ str (r, Address(sp, offset_from_rsp_in_bytes)); ++} ++ ++ ++void LIR_Assembler::store_parameter(jint c, int offset_from_rsp_in_words) { ++ assert(offset_from_rsp_in_words >= 0, "invalid offset from rsp"); ++ int offset_from_rsp_in_bytes = offset_from_rsp_in_words * BytesPerWord; ++ assert(offset_from_rsp_in_bytes < frame_map()->reserved_argument_area_size(), "invalid offset"); ++ __ mov (rscratch1, c); ++ __ str (rscratch1, Address(sp, offset_from_rsp_in_bytes)); ++} ++ ++ ++void LIR_Assembler::store_parameter(jobject o, int offset_from_rsp_in_words) { ++ ShouldNotReachHere(); ++ assert(offset_from_rsp_in_words >= 0, "invalid offset from rsp"); ++ int offset_from_rsp_in_bytes = offset_from_rsp_in_words * BytesPerWord; ++ assert(offset_from_rsp_in_bytes < frame_map()->reserved_argument_area_size(), "invalid offset"); ++ __ lea(rscratch1, __ constant_oop_address(o)); ++ __ str(rscratch1, Address(sp, offset_from_rsp_in_bytes)); ++} ++ ++ ++// This code replaces a call to arraycopy; no exception may ++// be thrown in this code, they must be thrown in the System.arraycopy ++// activation frame; we could save some checks if this would not be the case ++void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { ++ ciArrayKlass* default_type = op->expected_type(); ++ 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(); ++ ++ CodeStub* stub = op->stub(); ++ int flags = op->flags(); ++ BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; ++ if (basic_type == T_ARRAY) basic_type = T_OBJECT; ++ ++ // if we don't know anything, just go through the generic arraycopy ++ if (default_type == NULL // || basic_type == T_OBJECT ++ ) { ++ Label done; ++ assert(src == i1 && src_pos == i2, "mismatch in calling convention"); ++ ++ // Save the arguments in case the generic arraycopy fails and we ++ // have to fall back to the JNI stub ++ __ stp(dst, dst_pos, Address(sp, 0*BytesPerWord)); ++ __ stp(length, src_pos, Address(sp, 2*BytesPerWord)); ++ __ str(src, Address(sp, 4*BytesPerWord)); ++ ++ address copyfunc_addr = StubRoutines::generic_arraycopy(); ++ assert(copyfunc_addr != NULL, "generic arraycopy stub required"); ++ ++ // The arguments are in java calling convention so we shift them ++ // to C convention ++ assert_different_registers(c_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4); ++ __ mov(c_rarg0, j_rarg0); ++ assert_different_registers(c_rarg1, j_rarg2, j_rarg3, j_rarg4); ++ __ mov(c_rarg1, j_rarg1); ++ assert_different_registers(c_rarg2, j_rarg3, j_rarg4); ++ __ mov(c_rarg2, j_rarg2); ++ assert_different_registers(c_rarg3, j_rarg4); ++ __ mov(c_rarg3, j_rarg3); ++ __ mov(c_rarg4, j_rarg4); ++#ifndef PRODUCT ++ if (PrintC1Statistics) { ++ __ incrementw(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt)); ++ } ++#endif ++ __ far_call(RuntimeAddress(copyfunc_addr)); ++ ++ __ cbz(i0, *stub->continuation()); ++ ++ // Reload values from the stack so they are where the stub ++ // expects them. ++ __ ldp(dst, dst_pos, Address(sp, 0*BytesPerWord)); ++ __ ldp(length, src_pos, Address(sp, 2*BytesPerWord)); ++ __ ldr(src, Address(sp, 4*BytesPerWord)); ++ ++ // i0 is -1^K where K == partial copied count ++ __ eonw(rscratch1, i0, zr); ++ // adjust length down and src/end pos up by partial copied count ++ __ subw(length, length, rscratch1); ++ __ addw(src_pos, src_pos, rscratch1); ++ __ addw(dst_pos, dst_pos, rscratch1); ++ __ b(*stub->entry()); ++ ++ __ BIND(*stub->continuation()); ++ return; ++ } ++ ++ assert(default_type != NULL && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point"); ++ ++ int elem_size = type2aelembytes(basic_type); ++ int shift_amount; ++ int scale = exact_log2(elem_size); ++ ++ Address src_length_addr = Address(src, arrayOopDesc::length_offset_in_bytes()); ++ Address dst_length_addr = Address(dst, arrayOopDesc::length_offset_in_bytes()); ++ Address src_klass_addr = Address(src, oopDesc::klass_offset_in_bytes()); ++ Address dst_klass_addr = Address(dst, oopDesc::klass_offset_in_bytes()); ++ ++ // test for NULL ++ if (flags & LIR_OpArrayCopy::src_null_check) { ++ __ cbz(src, *stub->entry()); ++ } ++ if (flags & LIR_OpArrayCopy::dst_null_check) { ++ __ cbz(dst, *stub->entry()); ++ } ++ ++ // 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(tmp, dst); ++ __ ldrw(rscratch1, Address(tmp, in_bytes(Klass::layout_helper_offset()))); ++ __ cmpw(rscratch1, Klass::_lh_neutral_value); ++ __ br(Assembler::GE, *stub->entry()); ++ } ++ ++ if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) { ++ __ load_klass(tmp, src); ++ __ ldrw(rscratch1, Address(tmp, in_bytes(Klass::layout_helper_offset()))); ++ __ cmpw(rscratch1, Klass::_lh_neutral_value); ++ __ br(Assembler::GE, *stub->entry()); ++ } ++ } ++ ++ // check if negative ++ if (flags & LIR_OpArrayCopy::src_pos_positive_check) { ++ __ cmpw(src_pos, 0); ++ __ br(Assembler::LT, *stub->entry()); ++ } ++ if (flags & LIR_OpArrayCopy::dst_pos_positive_check) { ++ __ cmpw(dst_pos, 0); ++ __ br(Assembler::LT, *stub->entry()); ++ } ++ ++ if (flags & LIR_OpArrayCopy::length_positive_check) { ++ __ cmpw(length, 0); ++ __ br(Assembler::LT, *stub->entry()); ++ } ++ ++ if (flags & LIR_OpArrayCopy::src_range_check) { ++ __ addw(tmp, src_pos, length); ++ __ ldrw(rscratch1, src_length_addr); ++ __ cmpw(tmp, rscratch1); ++ __ br(Assembler::HI, *stub->entry()); ++ } ++ if (flags & LIR_OpArrayCopy::dst_range_check) { ++ __ addw(tmp, dst_pos, length); ++ __ ldrw(rscratch1, dst_length_addr); ++ __ cmpw(tmp, rscratch1); ++ __ br(Assembler::HI, *stub->entry()); ++ } ++ ++ 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) { ++ __ ldrw(tmp, src_klass_addr); ++ __ ldrw(rscratch1, dst_klass_addr); ++ __ cmpw(tmp, rscratch1); ++ } else { ++ __ ldr(tmp, src_klass_addr); ++ __ ldr(rscratch1, dst_klass_addr); ++ __ cmp(tmp, rscratch1); ++ } ++ __ br(Assembler::NE, *stub->entry()); ++ } else { ++ // For object arrays, if src is a sub class of dst then we can ++ // safely do the copy. ++ Label cont, slow; ++ ++#define PUSH(i1, i2) \ ++ stp(i1, i2, __ pre(sp, -2 * wordSize)); ++ ++#define POP(i1, i2) \ ++ ldp(i1, i2, __ post(sp, 2 * wordSize)); ++ ++ __ PUSH(src, dst); ++ ++ __ load_klass(src, src); ++ __ load_klass(dst, dst); ++ ++ __ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, NULL); ++ ++ __ PUSH(src, dst); ++ __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); ++ __ POP(src, dst); ++ ++ __ cbnz(src, cont); ++ ++ __ BIND(slow); ++ __ POP(src, dst); ++ ++ address copyfunc_addr = StubRoutines::checkcast_arraycopy(); ++ 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. ++ ++ 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(tmp, src); ++ } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { ++ __ load_klass(tmp, dst); ++ } ++ int lh_offset = in_bytes(Klass::layout_helper_offset()); ++ Address klass_lh_addr(tmp, lh_offset); ++ jint objArray_lh = Klass::array_layout_helper(T_OBJECT); ++ __ ldrw(rscratch1, klass_lh_addr); ++ __ mov(rscratch2, objArray_lh); ++ __ eorw(rscratch1, rscratch1, rscratch2); ++ __ cbnzw(rscratch1, *stub->entry()); ++ } ++ ++ // Spill because stubs can use any register they like and it's ++ // easier to restore just those that we care about. ++ __ stp(dst, dst_pos, Address(sp, 0*BytesPerWord)); ++ __ stp(length, src_pos, Address(sp, 2*BytesPerWord)); ++ __ str(src, Address(sp, 4*BytesPerWord)); ++ ++ __ lea(c_rarg0, Address(src, src_pos, Address::uxtw(scale))); ++ __ add(c_rarg0, c_rarg0, arrayOopDesc::base_offset_in_bytes(basic_type)); ++ assert_different_registers(c_rarg0, dst, dst_pos, length); ++ __ lea(c_rarg1, Address(dst, dst_pos, Address::uxtw(scale))); ++ __ add(c_rarg1, c_rarg1, arrayOopDesc::base_offset_in_bytes(basic_type)); ++ assert_different_registers(c_rarg1, dst, length); ++ __ uxtw(c_rarg2, length); ++ assert_different_registers(c_rarg2, dst); ++ ++ __ load_klass(c_rarg4, dst); ++ __ ldr(c_rarg4, Address(c_rarg4, ObjArrayKlass::element_klass_offset())); ++ __ ldrw(c_rarg3, Address(c_rarg4, Klass::super_check_offset_offset())); ++ __ far_call(RuntimeAddress(copyfunc_addr)); ++ ++#ifndef PRODUCT ++ if (PrintC1Statistics) { ++ Label failed; ++ __ cbnz(i0, failed); ++ __ incrementw(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_cnt)); ++ __ BIND(failed); ++ } ++#endif ++ ++ __ cbz(i0, *stub->continuation()); ++ ++#ifndef PRODUCT ++ if (PrintC1Statistics) { ++ __ incrementw(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_attempt_cnt)); ++ } ++#endif ++ assert_different_registers(dst, dst_pos, length, src_pos, src, i0, rscratch1); ++ ++ // Restore previously spilled arguments ++ __ ldp(dst, dst_pos, Address(sp, 0*BytesPerWord)); ++ __ ldp(length, src_pos, Address(sp, 2*BytesPerWord)); ++ __ ldr(src, Address(sp, 4*BytesPerWord)); ++ ++ // return value is -1^K where K is partial copied count ++ __ eonw(rscratch1, i0, zr); ++ // adjust length down and src/end pos up by partial copied count ++ __ subw(length, length, rscratch1); ++ __ addw(src_pos, src_pos, rscratch1); ++ __ addw(dst_pos, dst_pos, rscratch1); ++ } ++ ++ __ b(*stub->entry()); ++ ++ __ BIND(cont); ++ __ POP(src, dst); ++ } ++ } ++ ++#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; ++ __ mov_metadata(tmp, default_type->constant_encoding()); ++ if (UseCompressedClassPointers) { ++ __ encode_klass_not_null(tmp); ++ } ++ ++ if (basic_type != T_OBJECT) { ++ ++ if (UseCompressedClassPointers) { ++ __ ldrw(rscratch1, dst_klass_addr); ++ __ cmpw(tmp, rscratch1); ++ } else { ++ __ ldr(rscratch1, dst_klass_addr); ++ __ cmp(tmp, rscratch1); ++ } ++ __ br(Assembler::NE, halt); ++ if (UseCompressedClassPointers) { ++ __ ldrw(rscratch1, src_klass_addr); ++ __ cmpw(tmp, rscratch1); ++ } else { ++ __ ldr(rscratch1, src_klass_addr); ++ __ cmp(tmp, rscratch1); ++ } ++ __ br(Assembler::EQ, known_ok); ++ } else { ++ if (UseCompressedClassPointers) { ++ __ ldrw(rscratch1, dst_klass_addr); ++ __ cmpw(tmp, rscratch1); ++ } else { ++ __ ldr(rscratch1, dst_klass_addr); ++ __ cmp(tmp, rscratch1); ++ } ++ __ br(Assembler::EQ, known_ok); ++ __ cmp(src, dst); ++ __ br(Assembler::EQ, known_ok); ++ } ++ __ BIND(halt); ++ __ stop("incorrect type information in arraycopy"); ++ __ BIND(known_ok); ++ } ++#endif ++ ++#ifndef PRODUCT ++ if (PrintC1Statistics) { ++ __ incrementw(ExternalAddress(Runtime1::arraycopy_count_address(basic_type))); ++ } ++#endif ++ ++ __ lea(c_rarg0, Address(src, src_pos, Address::uxtw(scale))); ++ __ add(c_rarg0, c_rarg0, arrayOopDesc::base_offset_in_bytes(basic_type)); ++ assert_different_registers(c_rarg0, dst, dst_pos, length); ++ __ lea(c_rarg1, Address(dst, dst_pos, Address::uxtw(scale))); ++ __ add(c_rarg1, c_rarg1, arrayOopDesc::base_offset_in_bytes(basic_type)); ++ assert_different_registers(c_rarg1, dst, length); ++ __ uxtw(c_rarg2, length); ++ assert_different_registers(c_rarg2, dst); ++ ++ 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); ++ ++ CodeBlob *cb = CodeCache::find_blob(entry); ++ if (cb) { ++ __ far_call(RuntimeAddress(entry)); ++ } else { ++ __ call_VM_leaf(entry, 3); ++ } ++ ++ __ BIND(*stub->continuation()); ++} ++ ++ ++ ++ ++void LIR_Assembler::emit_lock(LIR_OpLock* op) { ++ Register obj = op->obj_opr()->as_register(); // may not be an oop ++ Register hdr = op->hdr_opr()->as_register(); ++ Register lock = op->lock_opr()->as_register(); ++ if (!UseFastLocking) { ++ __ b(*op->stub()->entry()); ++ } else if (op->code() == lir_lock) { ++ Register scratch = noreg; ++ if (UseBiasedLocking) { ++ scratch = op->scratch_opr()->as_register(); ++ } ++ assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); ++ // add debug info for NullPointerException only if one is possible ++ int null_check_offset = __ lock_object(hdr, obj, lock, scratch, *op->stub()->entry()); ++ if (op->info() != NULL) { ++ add_debug_info_for_null_check(null_check_offset, op->info()); ++ } ++ // done ++ } else if (op->code() == lir_unlock) { ++ assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); ++ __ unlock_object(hdr, obj, lock, *op->stub()->entry()); ++ } else { ++ Unimplemented(); ++ } ++ __ 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(); ++ __ mov_metadata(mdo, md->constant_encoding()); ++ Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); ++ // 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, 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))); ++ __ addptr(data_addr, DataLayout::counter_increment); ++ 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))); ++ __ mov_metadata(rscratch1, known_klass->constant_encoding()); ++ __ lea(rscratch2, recv_addr); ++ __ str(rscratch1, Address(rscratch2)); ++ Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); ++ __ addptr(data_addr, DataLayout::counter_increment); ++ return; ++ } ++ } ++ } else { ++ __ load_klass(recv, recv); ++ Label update_done; ++ type_profile_helper(mdo, md, data, recv, &update_done); ++ // Receiver did not match any saved receiver and there is no empty row for it. ++ // Increment total counter to indicate polymorphic case. ++ __ addptr(counter_addr, DataLayout::counter_increment); ++ ++ __ BIND(update_done); ++ } ++ } else { ++ // Static call ++ __ addptr(counter_addr, DataLayout::counter_increment); ++ } ++} ++ ++ ++void LIR_Assembler::emit_delay(LIR_OpDelay*) { ++ Unimplemented(); ++} ++ ++ ++void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { ++ __ lea(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); ++} ++ ++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 res = op->result_opr()->as_register(); ++ ++ assert_different_registers(val, crc, res); ++ unsigned long offset; ++ __ adrp(res, ExternalAddress(StubRoutines::crc_table_addr()), offset); ++ if (offset) __ add(res, res, offset); ++ ++ __ mvnw(crc, crc); // ~crc ++ __ update_byte_crc32(crc, val, res); ++ __ mvnw(res, crc); // ~crc ++} ++ ++void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { ++ COMMENT("emit_profile_type {"); ++ Register obj = op->obj()->as_register(); ++ Register tmp = op->tmp()->as_pointer_register(); ++ 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?"); ++ assert(mdo_addr.base() != rscratch1, "wrong register"); ++ ++ __ verify_oop(obj); ++ ++ if (tmp != obj) { ++ __ mov(tmp, obj); ++ } ++ if (do_null) { ++ __ cbnz(tmp, update); ++ if (!TypeEntries::was_null_seen(current_klass)) { ++ __ ldr(rscratch2, mdo_addr); ++ __ orr(rscratch2, rscratch2, TypeEntries::null_seen); ++ __ str(rscratch2, mdo_addr); ++ } ++ if (do_update) { ++#ifndef ASSERT ++ __ b(next); ++ } ++#else ++ __ b(next); ++ } ++ } else { ++ __ cbnz(tmp, update); ++ __ stop("unexpected null obj"); ++#endif ++ } ++ ++ __ BIND(update); ++ ++ if (do_update) { ++#ifdef ASSERT ++ if (exact_klass != NULL) { ++ Label ok; ++ __ load_klass(tmp, tmp); ++ __ mov_metadata(rscratch1, exact_klass->constant_encoding()); ++ __ eor(rscratch1, tmp, rscratch1); ++ __ cbz(rscratch1, ok); ++ __ stop("exact klass and actual klass differ"); ++ __ BIND(ok); ++ } ++#endif ++ if (!no_conflict) { ++ if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { ++ if (exact_klass != NULL) { ++ __ mov_metadata(tmp, exact_klass->constant_encoding()); ++ } else { ++ __ load_klass(tmp, tmp); ++ } ++ ++ __ ldr(rscratch2, mdo_addr); ++ __ eor(tmp, tmp, rscratch2); ++ __ andr(rscratch1, tmp, TypeEntries::type_klass_mask); ++ // klass seen before, nothing to do. The unknown bit may have been ++ // set already but no need to check. ++ __ cbz(rscratch1, next); ++ ++ __ tbnz(tmp, exact_log2(TypeEntries::type_unknown), next); // already unknown. Nothing to do anymore. ++ ++ if (TypeEntries::is_type_none(current_klass)) { ++ __ cbz(rscratch2, none); ++ __ cmp(rscratch2, TypeEntries::null_seen); ++ __ br(Assembler::EQ, none); ++ // There is a chance that the checks above (re-reading profiling ++ // data from memory) fail if another thread has just set the ++ // profiling to this obj's klass ++ __ dmb(Assembler::ISHLD); ++ __ ldr(rscratch2, mdo_addr); ++ __ eor(tmp, tmp, rscratch2); ++ __ andr(rscratch1, tmp, TypeEntries::type_klass_mask); ++ __ cbz(rscratch1, next); ++ } ++ } else { ++ assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && ++ ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); ++ ++ __ ldr(tmp, mdo_addr); ++ __ tbnz(tmp, exact_log2(TypeEntries::type_unknown), next); // already unknown. Nothing to do anymore. ++ } ++ ++ // different than before. Cannot keep accurate profile. ++ __ ldr(rscratch2, mdo_addr); ++ __ orr(rscratch2, rscratch2, TypeEntries::type_unknown); ++ __ str(rscratch2, mdo_addr); ++ ++ if (TypeEntries::is_type_none(current_klass)) { ++ __ b(next); ++ ++ __ BIND(none); ++ // first time here. Set profile type. ++ __ str(tmp, mdo_addr); ++ } ++ } else { ++ // There's a single possible klass at this profile point ++ assert(exact_klass != NULL, "should be"); ++ if (TypeEntries::is_type_none(current_klass)) { ++ __ mov_metadata(tmp, exact_klass->constant_encoding()); ++ __ ldr(rscratch2, mdo_addr); ++ __ eor(tmp, tmp, rscratch2); ++ __ andr(rscratch1, tmp, TypeEntries::type_klass_mask); ++ __ cbz(rscratch1, next); ++#ifdef ASSERT ++ { ++ Label ok; ++ __ ldr(rscratch1, mdo_addr); ++ __ cbz(rscratch1, ok); ++ __ cmp(rscratch1, TypeEntries::null_seen); ++ __ br(Assembler::EQ, ok); ++ // may have been set by another thread ++ __ dmb(Assembler::ISHLD); ++ __ mov_metadata(rscratch1, exact_klass->constant_encoding()); ++ __ ldr(rscratch2, mdo_addr); ++ __ eor(rscratch2, rscratch1, rscratch2); ++ __ andr(rscratch2, rscratch2, TypeEntries::type_mask); ++ __ cbz(rscratch2, ok); ++ ++ __ stop("unexpected profiling mismatch"); ++ __ BIND(ok); ++ } ++#endif ++ // first time here. Set profile type. ++ __ ldr(tmp, mdo_addr); ++ } else { ++ assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && ++ ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); ++ ++ __ ldr(tmp, mdo_addr); ++ __ tbnz(tmp, exact_log2(TypeEntries::type_unknown), next); // already unknown. Nothing to do anymore. ++ ++ __ orr(tmp, tmp, TypeEntries::type_unknown); ++ __ str(tmp, mdo_addr); ++ // FIXME: Write barrier needed here? ++ } ++ } ++ ++ __ BIND(next); ++ } ++ COMMENT("} emit_profile_type"); ++} ++ ++ ++void LIR_Assembler::align_backward_branch_target() { ++} ++ ++ ++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"); ++ ++ if (left->is_single_cpu()) { ++ assert(dest->is_single_cpu(), "expect single result reg"); ++ __ negw(dest->as_register(), left->as_register()); ++ } else if (left->is_double_cpu()) { ++ assert(dest->is_double_cpu(), "expect double result reg"); ++ __ neg(dest->as_register_lo(), left->as_register_lo()); ++ } else if (left->is_single_fpu()) { ++ assert(dest->is_single_fpu(), "expect single float result reg"); ++ __ fnegs(dest->as_float_reg(), left->as_float_reg()); ++ } else { ++ assert(left->is_double_fpu(), "expect double float operand reg"); ++ assert(dest->is_double_fpu(), "expect double float result reg"); ++ __ fnegd(dest->as_double_reg(), left->as_double_reg()); ++ } ++} ++ ++ ++void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { ++ assert(patch_code == lir_patch_none, "Patch code not supported"); ++ __ lea(dest->as_register_lo(), as_Address(addr->as_address_ptr())); ++} ++ ++ ++void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { ++ assert(!tmp->is_valid(), "don't need temporary"); ++ ++ CodeBlob *cb = CodeCache::find_blob(dest); ++ if (cb) { ++ __ far_call(RuntimeAddress(dest)); ++ } else { ++ __ mov(rscratch1, RuntimeAddress(dest)); ++ __ blr(rscratch1); ++ } ++ ++ if (info != NULL) { ++ add_call_info_here(info); ++ } ++ __ maybe_isb(); ++} ++ ++void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { ++ if (dest->is_address() || src->is_address()) { ++ move_op(src, dest, type, lir_patch_none, info, ++ /*pop_fpu_stack*/false, /*unaligned*/false, /*wide*/false); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++#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 = Assembler::AL; ++ switch (op->condition()) { ++ case lir_cond_equal: acond = Assembler::EQ; break; ++ case lir_cond_notEqual: acond = Assembler::NE; break; ++ case lir_cond_less: acond = Assembler::LT; break; ++ case lir_cond_lessEqual: acond = Assembler::LE; break; ++ case lir_cond_greaterEqual: acond = Assembler::GE; break; ++ case lir_cond_greater: acond = Assembler::GT; break; ++ case lir_cond_belowEqual: acond = Assembler::LS; break; ++ case lir_cond_aboveEqual: acond = Assembler::HS; break; ++ default: ShouldNotReachHere(); ++ } ++ __ br(acond, ok); ++ } ++ if (op->halt()) { ++ const char* str = __ code_string(op->msg()); ++ __ stop(str); ++ } else { ++ breakpoint(); ++ } ++ __ BIND(ok); ++} ++#endif ++ ++#ifndef PRODUCT ++#define COMMENT(x) do { __ block_comment(x); } while (0) ++#else ++#define COMMENT(x) ++#endif ++ ++void LIR_Assembler::membar() { ++ COMMENT("membar"); ++ __ membar(MacroAssembler::AnyAny); ++} ++ ++void LIR_Assembler::membar_acquire() { ++ __ membar(Assembler::LoadLoad|Assembler::LoadStore); ++} ++ ++void LIR_Assembler::membar_release() { ++ __ membar(Assembler::LoadStore|Assembler::StoreStore); ++} ++ ++void LIR_Assembler::membar_loadload() { ++ __ membar(Assembler::LoadLoad); ++} ++ ++void LIR_Assembler::membar_storestore() { ++ __ membar(MacroAssembler::StoreStore); ++} ++ ++void LIR_Assembler::membar_loadstore() { __ membar(MacroAssembler::LoadStore); } ++ ++void LIR_Assembler::membar_storeload() { __ membar(MacroAssembler::StoreLoad); } ++ ++void LIR_Assembler::on_spin_wait() { ++ Unimplemented(); ++} ++ ++void LIR_Assembler::get_thread(LIR_Opr result_reg) { ++ __ mov(result_reg->as_register(), rthread); ++} ++ ++ ++void LIR_Assembler::peephole(LIR_List *lir) { ++#if 0 ++ if (tableswitch_count >= max_tableswitches) ++ return; ++ ++ /* ++ This finite-state automaton recognizes sequences of compare-and- ++ branch instructions. We will turn them into a tableswitch. You ++ could argue that C1 really shouldn't be doing this sort of ++ optimization, but without it the code is really horrible. ++ */ ++ ++ enum { start_s, cmp1_s, beq_s, cmp_s } state; ++ int first_key, last_key = -2147483648; ++ int next_key = 0; ++ int start_insn = -1; ++ int last_insn = -1; ++ Register reg = noreg; ++ LIR_Opr reg_opr; ++ state = start_s; ++ ++ LIR_OpList* inst = lir->instructions_list(); ++ for (int i = 0; i < inst->length(); i++) { ++ LIR_Op* op = inst->at(i); ++ switch (state) { ++ case start_s: ++ first_key = -1; ++ start_insn = i; ++ switch (op->code()) { ++ case lir_cmp: ++ LIR_Opr opr1 = op->as_Op2()->in_opr1(); ++ LIR_Opr opr2 = op->as_Op2()->in_opr2(); ++ if (opr1->is_cpu_register() && opr1->is_single_cpu() ++ && opr2->is_constant() ++ && opr2->type() == T_INT) { ++ reg_opr = opr1; ++ reg = opr1->as_register(); ++ first_key = opr2->as_constant_ptr()->as_jint(); ++ next_key = first_key + 1; ++ state = cmp_s; ++ goto next_state; ++ } ++ break; ++ } ++ break; ++ case cmp_s: ++ switch (op->code()) { ++ case lir_branch: ++ if (op->as_OpBranch()->cond() == lir_cond_equal) { ++ state = beq_s; ++ last_insn = i; ++ goto next_state; ++ } ++ } ++ state = start_s; ++ break; ++ case beq_s: ++ switch (op->code()) { ++ case lir_cmp: { ++ LIR_Opr opr1 = op->as_Op2()->in_opr1(); ++ LIR_Opr opr2 = op->as_Op2()->in_opr2(); ++ if (opr1->is_cpu_register() && opr1->is_single_cpu() ++ && opr1->as_register() == reg ++ && opr2->is_constant() ++ && opr2->type() == T_INT ++ && opr2->as_constant_ptr()->as_jint() == next_key) { ++ last_key = next_key; ++ next_key++; ++ state = cmp_s; ++ goto next_state; ++ } ++ } ++ } ++ last_key = next_key; ++ state = start_s; ++ break; ++ default: ++ assert(false, "impossible state"); ++ } ++ if (state == start_s) { ++ if (first_key < last_key - 5L && reg != noreg) { ++ { ++ // printf("found run register %d starting at insn %d low value %d high value %d\n", ++ // reg->encoding(), ++ // start_insn, first_key, last_key); ++ // for (int i = 0; i < inst->length(); i++) { ++ // inst->at(i)->print(); ++ // tty->print("\n"); ++ // } ++ // tty->print("\n"); ++ } ++ ++ struct tableswitch *sw = &switches[tableswitch_count]; ++ sw->_insn_index = start_insn, sw->_first_key = first_key, ++ sw->_last_key = last_key, sw->_reg = reg; ++ inst->insert_before(last_insn + 1, new LIR_OpLabel(&sw->_after)); ++ { ++ // Insert the new table of branches ++ int offset = last_insn; ++ for (int n = first_key; n < last_key; n++) { ++ inst->insert_before ++ (last_insn + 1, ++ new LIR_OpBranch(lir_cond_always, T_ILLEGAL, ++ inst->at(offset)->as_OpBranch()->label())); ++ offset -= 2, i++; ++ } ++ } ++ // Delete all the old compare-and-branch instructions ++ for (int n = first_key; n < last_key; n++) { ++ inst->remove_at(start_insn); ++ inst->remove_at(start_insn); ++ } ++ // Insert the tableswitch instruction ++ inst->insert_before(start_insn, ++ new LIR_Op2(lir_cmp, lir_cond_always, ++ LIR_OprFact::intConst(tableswitch_count), ++ reg_opr)); ++ inst->insert_before(start_insn + 1, new LIR_OpLabel(&sw->_branches)); ++ tableswitch_count++; ++ } ++ reg = noreg; ++ last_key = -2147483648; ++ } ++ next_state: ++ ; ++ } ++#endif ++} ++ ++void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp_op) { ++ Address addr = as_Address(src->as_address_ptr()); ++ BasicType type = src->type(); ++ bool is_oop = type == T_OBJECT || type == T_ARRAY; ++ ++ void (MacroAssembler::* add)(Register prev, RegisterOrConstant incr, Register addr); ++ void (MacroAssembler::* xchg)(Register prev, Register newv, Register addr); ++ ++ switch(type) { ++ case T_INT: ++ xchg = &MacroAssembler::atomic_xchgalw; ++//// add = &MacroAssembler::atomic_addalw; ++ break; ++ case T_LONG: ++ xchg = &MacroAssembler::atomic_xchgal; ++ add = &MacroAssembler::atomic_addal; ++ break; ++ case T_OBJECT: ++ case T_ARRAY: ++ if (UseCompressedOops) { ++ xchg = &MacroAssembler::atomic_xchgalw; ++//// add = &MacroAssembler::atomic_addalw; ++ } else { ++ xchg = &MacroAssembler::atomic_xchgal; ++ add = &MacroAssembler::atomic_addal; ++ } ++ break; ++ default: ++ ShouldNotReachHere(); ++ xchg = &MacroAssembler::atomic_xchgal; ++ add = &MacroAssembler::atomic_addal; // unreachable ++ } ++ ++ switch (code) { ++ case lir_xadd: ++ { ++ RegisterOrConstant inc; ++ Register tmp = as_reg(tmp_op); ++ Register dst = as_reg(dest); ++ if (data->is_constant()) { ++ inc = RegisterOrConstant(as_long(data)); ++ assert_different_registers(dst, addr.base(), tmp, ++ rscratch1, rscratch2); ++ } else { ++ inc = RegisterOrConstant(as_reg(data)); ++ assert_different_registers(inc.as_register(), dst, addr.base(), tmp, ++ rscratch1, rscratch2); ++ } ++ __ lea(tmp, addr); ++ (_masm->*add)(dst, inc, tmp); ++ break; ++ } ++ case lir_xchg: ++ { ++ Register tmp = tmp_op->as_register(); ++ Register obj = as_reg(data); ++ Register dst = as_reg(dest); ++ if (is_oop && UseCompressedOops) { ++ __ encode_heap_oop(rscratch2, obj); ++ obj = rscratch2; ++ } ++ assert_different_registers(obj, addr.base(), tmp, rscratch1, dst); ++ __ lea(tmp, addr); ++ (_masm->*xchg)(dst, obj, tmp); ++ if (is_oop && UseCompressedOops) { ++ __ decode_heap_oop(dst); ++ } ++ } ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ __ membar(__ AnyAny); ++} ++ ++#undef __ +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_LIRAssembler_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C1_LIRASSEMBLER_SW64_HPP ++#define CPU_SW64_VM_C1_LIRASSEMBLER_SW64_HPP ++ ++// ArrayCopyStub needs access to bailout ++friend class ArrayCopyStub; ++ ++ private: ++ ++ int array_element_size(BasicType type) const; ++ ++ void arith_fpu_implementation(LIR_Code code, int left_index, int right_index, int dest_index, bool pop_fpu_stack); ++ ++ // helper functions which checks for overflow and sets bailout if it ++ // occurs. Always returns a valid embeddable pointer but in the ++ // bailout case the pointer won't be to unique storage. ++ address float_constant(float f); ++ address double_constant(double d); ++ ++ address int_constant(jlong n); ++ ++ bool is_literal_address(LIR_Address* addr); ++ ++ // When we need to use something other than rscratch1 use this ++ // method. ++ Address as_Address(LIR_Address* addr, Register tmp); ++ ++ // Record the type of the receiver in ReceiverTypeData ++ void type_profile_helper(Register mdo, ++ ciMethodData *md, ciProfileData *data, ++ Register recv, Label* update_done); ++ void add_debug_info_for_branch(address adr, CodeEmitInfo* info); ++ ++ void casw(Register addr, Register newval, Register cmpval); ++ void casl(Register addr, Register newval, Register cmpval); ++ ++ void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = NULL); ++ ++ static const int max_tableswitches = 20; ++ struct tableswitch switches[max_tableswitches]; ++ int tableswitch_count; ++ ++ void init() { tableswitch_count = 0; } ++ ++ void deoptimize_trap(CodeEmitInfo *info); ++ ++ enum { ++ // call stub: CompiledStaticCall::to_interp_stub_size() + ++ // CompiledStaticCall::to_trampoline_stub_size() ++ _call_stub_size = 13, //// * NativeInstruction::instruction_size, //DJX need fix ++ _call_aot_stub_size = 0, ++ _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), ++ _deopt_handler_size = 7 //// * NativeInstruction::instruction_size //DJX need fix ++ }; ++ ++ void arithmetic_idiv(LIR_Op3* op, bool is_irem); ++ ++public: ++ ++ void store_parameter(Register r, int offset_from_esp_in_words); ++ void store_parameter(jint c, int offset_from_esp_in_words); ++ void store_parameter(jobject c, int offset_from_esp_in_words); ++ ++#endif // CPU_SW64_VM_C1_LIRASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_LIRGenerator_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_LIRGenerator_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_LIRGenerator_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_LIRGenerator_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,1386 @@ ++/* ++ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.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/sharedRuntime.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "utilities/macros.hpp" ++#include "vmreg_sw64.inline.hpp" ++ ++#ifdef ASSERT ++#define __ gen()->lir(__FILE__, __LINE__)-> ++#else ++#define __ gen()->lir()-> ++#endif ++ ++// Item will be loaded into a byte register; Intel only ++void LIRItem::load_byte_item() { ++ load_item(); ++} ++ ++ ++void LIRItem::load_nonconstant() { ++ LIR_Opr r = value()->operand(); ++ if (r->is_constant()) { ++ _result = r; ++ } else { ++ load_item(); ++ } ++} ++ ++//-------------------------------------------------------------- ++// LIRGenerator ++//-------------------------------------------------------------- ++ ++ ++LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::r0_oop_opr; } ++LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::r3_opr; } ++LIR_Opr LIRGenerator::divInOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } ++LIR_Opr LIRGenerator::divOutOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } ++LIR_Opr LIRGenerator::remOutOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } ++LIR_Opr LIRGenerator::shiftCountOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } ++LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); } ++LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::r0_opr; } ++LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } ++ ++ ++LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { ++ LIR_Opr opr; ++ switch (type->tag()) { ++ case intTag: opr = FrameMap::r0_opr; break; ++ case objectTag: opr = FrameMap::r0_oop_opr; break; ++ case longTag: opr = FrameMap::long0_opr; break; ++ case floatTag: opr = FrameMap::fpu0_float_opr; break; ++ case doubleTag: opr = FrameMap::fpu0_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_byte(BasicType type) { ++ LIR_Opr reg = new_register(T_INT); ++ set_vreg_flag(reg, LIRGenerator::byte_reg); ++ return reg; ++} ++ ++ ++//--------- loading items into registers -------------------------------- ++ ++ ++bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const { ++ if (v->type()->as_IntConstant() != NULL) { ++ return v->type()->as_IntConstant()->value() == 0L; ++ } 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; ++ } ++} ++ ++bool LIRGenerator::can_inline_as_constant(Value v) const { ++ // FIXME: Just a guess ++ if (v->type()->as_IntConstant() != NULL) { ++ return Assembler::operand_valid_for_add_sub_immediate(v->type()->as_IntConstant()->value()); ++ } 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; ++ } ++} ++ ++ ++bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const { return false; } ++ ++ ++LIR_Opr LIRGenerator::safepoint_poll_register() { ++ return LIR_OprFact::illegalOpr; ++} ++ ++ ++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()) { ++ LIR_Const *constant = index->as_constant_ptr(); ++ if (constant->type() == T_INT) { ++ large_disp += index->as_jint() << shift; ++ } else { ++ assert(constant->type() == T_LONG, "should be"); ++ jlong c = index->as_jlong() << shift; ++ if ((jlong)((jint)c) == c) { ++ large_disp += c; ++ index = LIR_OprFact::illegalOpr; ++ } else { ++ LIR_Opr tmp = new_register(T_LONG); ++ __ move(index, tmp); ++ index = tmp; ++ // apply shift and displacement below ++ } ++ } ++ } ++ ++ 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::operand_valid_for_add_sub_immediate(large_disp)) { ++ __ add(tmp, tmp, LIR_OprFact::intptrConst(large_disp)); ++ index = tmp; ++ } else { ++ __ move(tmp, LIR_OprFact::intptrConst(large_disp)); ++ __ add(tmp, index, tmp); ++ index = tmp; ++ } ++ large_disp = 0; ++ } ++ } else if (large_disp != 0 && !Address::offset_ok_for_immed(large_disp, shift)) { ++ // 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(Address::offset_ok_for_immed(large_disp, 0), "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 offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type); ++ int elem_size = type2aelembytes(type); ++ int shift = exact_log2(elem_size); ++ ++ LIR_Address* addr; ++ if (index_opr->is_constant()) { ++ addr = new LIR_Address(array_opr, ++ offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type); ++ } else { ++ if (offset_in_bytes) { ++ LIR_Opr tmp = new_pointer_register(); ++ __ add(array_opr, LIR_OprFact::intConst(offset_in_bytes), tmp); ++ array_opr = tmp; ++ offset_in_bytes = 0; ++ } ++ addr = new LIR_Address(array_opr, ++ index_opr, ++ LIR_Address::scale(type), ++ offset_in_bytes, type); ++ } ++ return addr; ++} ++ ++LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { ++ LIR_Opr r; ++ if (type == T_LONG) { ++ r = LIR_OprFact::longConst(x); ++ if (!Assembler::operand_valid_for_logical_immediate(false, x)) { ++ LIR_Opr tmp = new_register(type); ++ __ move(r, tmp); ++ return tmp; ++ } ++ } else if (type == T_INT) { ++ r = LIR_OprFact::intConst(x); ++ if (!Assembler::operand_valid_for_logical_immediate(true, x)) { ++ // This is all rather nasty. We don't know whether our constant ++ // is required for a logical or an arithmetic operation, wo we ++ // don't know what the range of valid values is!! ++ LIR_Opr tmp = new_register(type); ++ __ move(r, tmp); ++ return tmp; ++ } ++ } else { ++ ShouldNotReachHere(); ++ r = NULL; // unreachable ++ } ++ 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 imm = NULL; ++ switch(addr->type()) { ++ case T_INT: ++ imm = LIR_OprFact::intConst(step); ++ break; ++ case T_LONG: ++ imm = LIR_OprFact::longConst(step); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ LIR_Opr reg = new_register(addr->type()); ++ __ load(addr, reg); ++ __ add(reg, imm, reg); ++ __ store(reg, addr); ++} ++ ++void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { ++ LIR_Opr reg = new_register(T_INT); ++ __ load(generate_address(base, disp, T_INT), reg, info); ++ __ cmp(condition, reg, LIR_OprFact::intConst(c)); ++} ++ ++void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, int disp, BasicType type, CodeEmitInfo* info) { ++ LIR_Opr reg1 = new_register(T_INT); ++ __ load(generate_address(base, disp, type), reg1, info); ++ __ cmp(condition, reg, reg1); ++} ++ ++ ++bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) { ++ ++ if (is_power_of_2(c - 1)) { ++ __ shift_left(left, exact_log2(c - 1), tmp); ++ __ add(tmp, left, result); ++ return true; ++ } else if (is_power_of_2(c + 1)) { ++ __ shift_left(left, exact_log2(c + 1), tmp); ++ __ sub(tmp, left, result); ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) { ++ BasicType type = item->type(); ++ __ store(item, new LIR_Address(FrameMap::sp_opr, in_bytes(offset_from_sp), type)); ++} ++ ++void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { ++ LIR_Opr tmp1 = new_register(objectType); ++ LIR_Opr tmp2 = new_register(objectType); ++ LIR_Opr tmp3 = new_register(objectType); ++ __ 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); ++ ++ // "lock" stores the address of the monitor stack slot, so this is not an oop ++ LIR_Opr lock = new_register(T_INT); ++ // Need a scratch register for biased locking ++ LIR_Opr scratch = LIR_OprFact::illegalOpr; ++ if (UseBiasedLocking) { ++ scratch = new_register(T_INT); ++ } ++ ++ 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 expect object to be unlocked) ++ CodeEmitInfo* info = state_for(x, x->state(), true); ++ monitor_enter(obj.result(), lock, syncTempOpr(), 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(); ++ ++ LIR_Opr lock = new_register(T_INT); ++ LIR_Opr obj_temp = new_register(T_INT); ++ set_no_result(x); ++ monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no()); ++} ++ ++ ++void LIRGenerator::do_NegateOp(NegateOp* x) { ++ ++ LIRItem from(x->x(), this); ++ from.load_item(); ++ LIR_Opr result = rlock_result(x); ++ __ negate (from.result(), result); ++ ++} ++ ++// for _fadd, _fmul, _fsub, _fdiv, _frem ++// _dadd, _dmul, _dsub, _ddiv, _drem ++void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { ++ ++ if (x->op() == Bytecodes::_frem || x->op() == Bytecodes::_drem) { ++ // float remainder is implemented as a direct call into the runtime ++ LIRItem right(x->x(), this); ++ LIRItem left(x->y(), this); ++ ++ BasicTypeList signature(2); ++ if (x->op() == Bytecodes::_frem) { ++ signature.append(T_FLOAT); ++ signature.append(T_FLOAT); ++ } else { ++ signature.append(T_DOUBLE); ++ signature.append(T_DOUBLE); ++ } ++ CallingConvention* cc = frame_map()->c_calling_convention(&signature); ++ ++ const LIR_Opr result_reg = result_register_for(x->type()); ++ left.load_item_force(cc->at(1)); ++ right.load_item(); ++ ++ __ move(right.result(), cc->at(0)); ++ ++ address entry; ++ if (x->op() == Bytecodes::_frem) { ++ entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem); ++ } else { ++ entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem); ++ } ++ ++ LIR_Opr result = rlock_result(x); ++ __ call_runtime_leaf(entry, getThreadTemp(), result_reg, cc->args()); ++ __ move(result_reg, result); ++ ++ return; ++ } ++ ++ LIRItem left(x->x(), this); ++ LIRItem right(x->y(), this); ++ LIRItem* left_arg = &left; ++ LIRItem* right_arg = &right; ++ ++ // Always load right hand side. ++ right.load_item(); ++ ++ if (!left.is_register()) ++ left.load_item(); ++ ++ LIR_Opr reg = rlock(x); ++ LIR_Opr tmp = LIR_OprFact::illegalOpr; ++ if (x->is_strictfp() && (x->op() == Bytecodes::_dmul || x->op() == Bytecodes::_ddiv)) { ++ tmp = new_register(T_DOUBLE); ++ } ++ ++ arithmetic_op_fpu(x->op(), reg, left.result(), right.result(), x->is_strictfp()); ++ ++ set_result(x, round_item(reg)); ++} ++ ++// for _ladd, _lmul, _lsub, _ldiv, _lrem ++void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) { ++ ++ // missing test if instr is commutative and if we should swap ++ LIRItem left(x->x(), this); ++ LIRItem right(x->y(), this); ++ ++ if (x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem) { ++ ++ // the check for division by zero destroys the right operand ++ right.set_destroys_register(); ++ ++ // check for division by zero (destroys registers of right operand!) ++ CodeEmitInfo* info = state_for(x); ++ ++ left.load_item(); ++ right.load_item(); ++ ++ __ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0)); ++ __ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info)); ++ ++ rlock_result(x); ++ switch (x->op()) { ++ case Bytecodes::_lrem: ++ __ rem (left.result(), right.result(), x->operand()); ++ break; ++ case Bytecodes::_ldiv: ++ __ div (left.result(), right.result(), x->operand()); ++ break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ ++ ++ } else { ++ assert (x->op() == Bytecodes::_lmul || x->op() == Bytecodes::_ladd || x->op() == Bytecodes::_lsub, ++ "expect lmul, ladd or lsub"); ++ // add, sub, mul ++ left.load_item(); ++ if (! right.is_register()) { ++ if (x->op() == Bytecodes::_lmul ++ || ! right.is_constant() ++ || ! Assembler::operand_valid_for_add_sub_immediate(right.get_jlong_constant())) { ++ right.load_item(); ++ } else { // add, sub ++ assert (x->op() == Bytecodes::_ladd || x->op() == Bytecodes::_lsub, "expect ladd or lsub"); ++ // don't load constants to save register ++ right.load_nonconstant(); ++ } ++ } ++ rlock_result(x); ++ arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL); ++ } ++} ++ ++// for: _iadd, _imul, _isub, _idiv, _irem ++void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) { ++ ++ // Test if instr is commutative and if we should swap ++ LIRItem left(x->x(), this); ++ LIRItem right(x->y(), this); ++ LIRItem* left_arg = &left; ++ LIRItem* right_arg = &right; ++ if (x->is_commutative() && left.is_stack() && right.is_register()) { ++ // swap them if left is real stack (or cached) and right is real register(not cached) ++ left_arg = &right; ++ right_arg = &left; ++ } ++ ++ left_arg->load_item(); ++ ++ // do not need to load right, as we can handle stack and constants ++ if (x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem) { ++ ++ right_arg->load_item(); ++ rlock_result(x); ++ ++ CodeEmitInfo* info = state_for(x); ++ LIR_Opr tmp = new_register(T_INT); ++ __ cmp(lir_cond_equal, right_arg->result(), LIR_OprFact::longConst(0)); ++ __ branch(lir_cond_equal, T_INT, new DivByZeroStub(info)); ++ info = state_for(x); ++ ++ if (x->op() == Bytecodes::_irem) { ++ __ irem(left_arg->result(), right_arg->result(), x->operand(), tmp, NULL); ++ } else if (x->op() == Bytecodes::_idiv) { ++ __ idiv(left_arg->result(), right_arg->result(), x->operand(), tmp, NULL); ++ } ++ ++ } else if (x->op() == Bytecodes::_iadd || x->op() == Bytecodes::_isub) { ++ if (right.is_constant() ++ && Assembler::operand_valid_for_add_sub_immediate(right.get_jint_constant())) { ++ right.load_nonconstant(); ++ } else { ++ right.load_item(); ++ } ++ rlock_result(x); ++ arithmetic_op_int(x->op(), x->operand(), left_arg->result(), right_arg->result(), LIR_OprFact::illegalOpr); ++ } else { ++ assert (x->op() == Bytecodes::_imul, "expect imul"); ++ if (right.is_constant()) { ++ jint c = right.get_jint_constant(); ++ if (c > 0 && c < max_jint && (is_power_of_2(c) || is_power_of_2(c - 1) || is_power_of_2(c + 1))) { ++ right_arg->dont_load_item(); ++ } else { ++ // Cannot use constant op. ++ right_arg->load_item(); ++ } ++ } else { ++ right.load_item(); ++ } ++ rlock_result(x); ++ arithmetic_op_int(x->op(), x->operand(), left_arg->result(), right_arg->result(), new_register(T_INT)); ++ } ++} ++ ++void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) { ++ // when an operand with use count 1 is the left operand, then it is ++ // likely that no move for 2-operand-LIR-form is necessary ++ if (x->is_commutative() && x->y()->as_Constant() == NULL && x->x()->use_count() > x->y()->use_count()) { ++ x->swap_operands(); ++ } ++ ++ 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 left(x->x(), this); ++ LIRItem right(x->y(), this); ++ ++ left.load_item(); ++ ++ rlock_result(x); ++ if (right.is_constant()) { ++ right.dont_load_item(); ++ ++ switch (x->op()) { ++ case Bytecodes::_ishl: { ++ int c = right.get_jint_constant() & 0x1f; ++ __ shift_left(left.result(), c, x->operand()); ++ break; ++ } ++ case Bytecodes::_ishr: { ++ int c = right.get_jint_constant() & 0x1f; ++ __ shift_right(left.result(), c, x->operand()); ++ break; ++ } ++ case Bytecodes::_iushr: { ++ int c = right.get_jint_constant() & 0x1f; ++ __ unsigned_shift_right(left.result(), c, x->operand()); ++ break; ++ } ++ case Bytecodes::_lshl: { ++ int c = right.get_jint_constant() & 0x3f; ++ __ shift_left(left.result(), c, x->operand()); ++ break; ++ } ++ case Bytecodes::_lshr: { ++ int c = right.get_jint_constant() & 0x3f; ++ __ shift_right(left.result(), c, x->operand()); ++ break; ++ } ++ case Bytecodes::_lushr: { ++ int c = right.get_jint_constant() & 0x3f; ++ __ unsigned_shift_right(left.result(), c, x->operand()); ++ break; ++ } ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { ++ right.load_item(); ++ LIR_Opr tmp = new_register(T_INT); ++ switch (x->op()) { ++ case Bytecodes::_ishl: { ++ __ logical_and(right.result(), LIR_OprFact::intConst(0x1f), tmp); ++ __ shift_left(left.result(), tmp, x->operand(), tmp); ++ break; ++ } ++ case Bytecodes::_ishr: { ++ __ logical_and(right.result(), LIR_OprFact::intConst(0x1f), tmp); ++ __ shift_right(left.result(), tmp, x->operand(), tmp); ++ break; ++ } ++ case Bytecodes::_iushr: { ++ __ logical_and(right.result(), LIR_OprFact::intConst(0x1f), tmp); ++ __ unsigned_shift_right(left.result(), tmp, x->operand(), tmp); ++ break; ++ } ++ case Bytecodes::_lshl: { ++ __ logical_and(right.result(), LIR_OprFact::intConst(0x3f), tmp); ++ __ shift_left(left.result(), tmp, x->operand(), tmp); ++ break; ++ } ++ case Bytecodes::_lshr: { ++ __ logical_and(right.result(), LIR_OprFact::intConst(0x3f), tmp); ++ __ shift_right(left.result(), tmp, x->operand(), tmp); ++ break; ++ } ++ case Bytecodes::_lushr: { ++ __ logical_and(right.result(), LIR_OprFact::intConst(0x3f), tmp); ++ __ unsigned_shift_right(left.result(), tmp, x->operand(), tmp); ++ break; ++ } ++ default: ++ ShouldNotReachHere(); ++ } ++ } ++} ++ ++// _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(); ++ ++ rlock_result(x); ++ if (right.is_constant() ++ && ((right.type()->tag() == intTag ++ && Assembler::operand_valid_for_logical_immediate(true, right.get_jint_constant())) ++ || (right.type()->tag() == longTag ++ && Assembler::operand_valid_for_logical_immediate(false, right.get_jlong_constant())))) { ++ right.dont_load_item(); ++ } else { ++ right.load_item(); ++ } ++ switch (x->op()) { ++ case Bytecodes::_iand: ++ case Bytecodes::_land: ++ __ logical_and(left.result(), right.result(), x->operand()); break; ++ case Bytecodes::_ior: ++ case Bytecodes::_lor: ++ __ logical_or (left.result(), right.result(), x->operand()); break; ++ case Bytecodes::_ixor: ++ case Bytecodes::_lxor: ++ __ logical_xor(left.result(), right.result(), x->operand()); break; ++ default: Unimplemented(); ++ } ++} ++ ++// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg ++void LIRGenerator::do_CompareOp(CompareOp* x) { ++ LIRItem left(x->x(), this); ++ LIRItem right(x->y(), this); ++ ValueTag tag = x->x()->type()->tag(); ++ if (tag == longTag) { ++ left.set_destroys_register(); ++ } ++ 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 ill = LIR_OprFact::illegalOpr; // for convenience ++ new_value.load_item(); ++ cmp_value.load_item(); ++ LIR_Opr result = new_register(T_INT); ++ if (type == T_OBJECT || type == T_ARRAY) { ++ __ cas_obj(addr, cmp_value.result(), new_value.result(), new_register(T_INT), new_register(T_INT), result); ++ } else if (type == T_INT) { ++ __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); ++ } else if (type == T_LONG) { ++ __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); ++ } else { ++ ShouldNotReachHere(); ++ Unimplemented(); ++ } ++ __ logical_xor(FrameMap::r8_opr, LIR_OprFact::intConst(1), result); ++ return result; ++} ++ ++LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { ++ bool is_oop = type == T_OBJECT || type == T_ARRAY; ++ LIR_Opr result = new_register(type); ++ value.load_item(); ++ assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); ++ LIR_Opr tmp = new_register(T_INT); ++ __ xchg(addr, value.result(), result, tmp); ++ return result; ++} ++ ++LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { ++ LIR_Opr result = new_register(type); ++ value.load_item(); ++ assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type"); ++ LIR_Opr tmp = new_register(T_INT); ++ __ xadd(addr, value.result(), result, tmp); ++ return result; ++} ++ ++void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { ++ assert(x->number_of_arguments() == 1 || (x->number_of_arguments() == 2 && x->id() == vmIntrinsics::_dpow), "wrong type"); ++ if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog || ++ x->id() == vmIntrinsics::_dpow || x->id() == vmIntrinsics::_dcos || ++ x->id() == vmIntrinsics::_dsin || x->id() == vmIntrinsics::_dtan || ++ x->id() == vmIntrinsics::_dlog10) { ++ do_LibmIntrinsic(x); ++ return; ++ } ++ 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; ++ } ++ } ++} ++ ++void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { ++ LIRItem value(x->argument_at(0), this); ++ value.set_destroys_register(); ++ ++ LIR_Opr calc_result = rlock_result(x); ++ LIR_Opr result_reg = result_register_for(x->type()); ++ ++ CallingConvention* cc = NULL; ++ ++ if (x->id() == vmIntrinsics::_dpow) { ++ LIRItem value1(x->argument_at(1), this); ++ ++ value1.set_destroys_register(); ++ ++ BasicTypeList signature(2); ++ signature.append(T_DOUBLE); ++ signature.append(T_DOUBLE); ++ cc = frame_map()->c_calling_convention(&signature); ++ value.load_item_force(cc->at(0)); ++ value1.load_item_force(cc->at(1)); ++ } else { ++ BasicTypeList signature(1); ++ signature.append(T_DOUBLE); ++ cc = frame_map()->c_calling_convention(&signature); ++ value.load_item_force(cc->at(0)); ++ } ++ ++ switch (x->id()) { ++ case vmIntrinsics::_dexp: ++ if (StubRoutines::dexp() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dexp(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dexp), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ case vmIntrinsics::_dlog: ++ if (StubRoutines::dlog() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dlog(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ case vmIntrinsics::_dlog10: ++ if (StubRoutines::dlog10() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dlog10(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog10), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ case vmIntrinsics::_dpow: ++ if (StubRoutines::dpow() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dpow(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ case vmIntrinsics::_dsin: ++ if (StubRoutines::dsin() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dsin(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dsin), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ case vmIntrinsics::_dcos: ++ if (StubRoutines::dcos() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dcos(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dcos), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ case vmIntrinsics::_dtan: ++ if (StubRoutines::dtan() != NULL) { ++ __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args()); ++ } else { ++ __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), getThreadTemp(), result_reg, cc->args()); ++ } ++ break; ++ default: ShouldNotReachHere(); ++ } ++ __ move(result_reg, calc_result); ++} ++ ++ ++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()); ++ ++ 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); ++ ++ // operands for arraycopy must use fixed registers, otherwise ++ // LinearScan will fail allocation (because arraycopy always needs a ++ // call) ++ ++ // The java calling convention will give us enough registers ++ // so that on the stub side the args will be perfect already. ++ // On the other slow/special case side we call C and the arg ++ // positions are not similar enough to pick one as the best. ++ // Also because the java calling convention is a "shifted" version ++ // of the C convention we can process the java args trivially into C ++ // args without worry of overwriting during the xfer ++ ++ src.load_item_force (FrameMap::as_oop_opr(j_rarg0)); ++ src_pos.load_item_force (FrameMap::as_opr(j_rarg1)); ++ dst.load_item_force (FrameMap::as_oop_opr(j_rarg2)); ++ dst_pos.load_item_force (FrameMap::as_opr(j_rarg3)); ++ length.load_item_force (FrameMap::as_opr(j_rarg4)); ++ ++ LIR_Opr tmp = FrameMap::as_opr(j_rarg5); ++ ++ set_no_result(x); ++ ++ int flags; ++ ciArrayKlass* expected_type; ++ arraycopy_helper(x, &flags, &expected_type); ++ ++ __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), length.result(), tmp, expected_type, flags, info); // does add_safepoint ++} ++ ++void LIRGenerator::do_update_CRC32(Intrinsic* x) { ++ assert(UseCRC32Intrinsics, "why are we here?"); ++ // 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 (offset) { ++ LIR_Opr tmp = new_pointer_register(); ++ __ add(base_op, LIR_OprFact::intConst(offset), tmp); ++ base_op = tmp; ++ offset = 0; ++ } ++ ++ LIR_Address* a = new LIR_Address(base_op, ++ index, ++ 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) { ++ assert(UseCRC32CIntrinsics, "why are we here?"); ++ // 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 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; ++ 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 (offset) { ++ LIR_Opr tmp = new_pointer_register(); ++ __ add(base_op, LIR_OprFact::intConst(offset), tmp); ++ base_op = tmp; ++ offset = 0; ++ } ++ ++ LIR_Address* a = new LIR_Address(base_op, ++ index, ++ 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 value(x->argument_at(0), this); ++ LIRItem value1(x->argument_at(1), this); ++ LIRItem value2(x->argument_at(2), this); ++ ++ value.load_item(); ++ value1.load_item(); ++ value2.load_item(); ++ ++ LIR_Opr calc_input = value.result(); ++ LIR_Opr calc_input1 = value1.result(); ++ LIR_Opr calc_input2 = value2.result(); ++ LIR_Opr calc_result = rlock_result(x); ++ ++ switch (x->id()) { ++ case vmIntrinsics::_fmaD: __ fmad(calc_input, calc_input1, calc_input2, calc_result); break; ++ case vmIntrinsics::_fmaF: __ fmaf(calc_input, calc_input1, calc_input2, calc_result); break; ++ default: ShouldNotReachHere(); ++ } ++} ++ ++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) { ++ LIRItem value(x->value(), this); ++ value.load_item(); ++ LIR_Opr input = value.result(); ++ LIR_Opr result = rlock(x); ++ ++ // arguments of lir_convert ++ LIR_Opr conv_input = input; ++ LIR_Opr conv_result = result; ++ ConversionStub* stub = NULL; ++ ++ __ convert(x->op(), conv_input, conv_result); ++ ++ assert(result->is_virtual(), "result must be virtual register"); ++ set_result(x, result); ++} ++ ++void LIRGenerator::do_NewInstance(NewInstance* x) { ++#ifndef PRODUCT ++ if (PrintNotLoaded && !x->klass()->is_loaded()) { ++ tty->print_cr(" ###class not loaded at new bci %d", x->printable_bci()); ++ } ++#endif ++ CodeEmitInfo* info = state_for(x, x->state()); ++ LIR_Opr reg = result_register_for(x->type()); ++ new_instance(reg, x->klass(), x->is_unresolved(), ++ FrameMap::r2_oop_opr, ++ FrameMap::r5_oop_opr, ++ FrameMap::r4_oop_opr, ++ LIR_OprFact::illegalOpr, ++ FrameMap::r3_metadata_opr, info); ++ LIR_Opr result = rlock_result(x); ++ __ move(reg, result); ++} ++ ++void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { ++ CodeEmitInfo* info = state_for(x, x->state()); ++ ++ LIRItem length(x->length(), this); ++ length.load_item_force(FrameMap::r19_opr); ++ ++ LIR_Opr reg = result_register_for(x->type()); ++ LIR_Opr tmp1 = FrameMap::r2_oop_opr; ++ LIR_Opr tmp2 = FrameMap::r4_oop_opr; ++ LIR_Opr tmp3 = FrameMap::r5_oop_opr; ++ LIR_Opr tmp4 = reg; ++ LIR_Opr klass_reg = FrameMap::r3_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) { ++ LIRItem length(x->length(), this); ++ // 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()); ++ } ++ ++ CodeEmitInfo* info = state_for(x, x->state()); ++ ++ LIR_Opr reg = result_register_for(x->type()); ++ LIR_Opr tmp1 = FrameMap::r2_oop_opr; ++ LIR_Opr tmp2 = FrameMap::r4_oop_opr; ++ LIR_Opr tmp3 = FrameMap::r5_oop_opr; ++ LIR_Opr tmp4 = reg; ++ LIR_Opr klass_reg = FrameMap::r3_metadata_opr; ++ ++ length.load_item_force(FrameMap::r19_opr); ++ LIR_Opr len = length.result(); ++ ++ CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info); ++ ciKlass* obj = (ciKlass*) 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(i*4)); ++ } ++ ++ LIR_Opr klass_reg = FrameMap::r0_metadata_opr; ++ klass2reg_with_patching(klass_reg, x->klass(), patching_info); ++ ++ LIR_Opr rank = FrameMap::r19_opr; ++ __ move(LIR_OprFact::intConst(x->rank()), rank); ++ LIR_Opr varargs = FrameMap::r2_opr; ++ __ move(FrameMap::sp_opr, varargs); ++ LIR_OprList* args = new LIR_OprList(3); ++ args->append(klass_reg); ++ args->append(rank); ++ args->append(varargs); ++ 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) { ++ // nothing to do for now ++} ++ ++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 (the latter is for deoptimization) ++ patching_info = state_for(x, x->state_before()); ++ } ++ obj.load_item(); ++ ++ // info for exceptions ++ CodeEmitInfo* info_for_exception = ++ (x->needs_exception_state() ? state_for(x) : ++ state_for(x, x->state_before(), true /*ignore_xhandler*/)); ++ ++ CodeStub* stub; ++ 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 reg = rlock_result(x); ++ LIR_Opr tmp3 = LIR_OprFact::illegalOpr; ++ if (!x->klass()->is_loaded() || UseCompressedClassPointers) { ++ tmp3 = new_register(objectType); ++ } ++ __ checkcast(reg, obj.result(), x->klass(), ++ new_register(objectType), new_register(objectType), 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); ++ ++ // result and test object may not be in same register ++ LIR_Opr reg = rlock_result(x); ++ CodeEmitInfo* patching_info = NULL; ++ if ((!x->klass()->is_loaded() || PatchALot)) { ++ // must do this before locking the destination register as an oop register ++ patching_info = state_for(x, x->state_before()); ++ } ++ obj.load_item(); ++ LIR_Opr tmp3 = LIR_OprFact::illegalOpr; ++ if (!x->klass()->is_loaded() || UseCompressedClassPointers) { ++ tmp3 = new_register(objectType); ++ } ++ __ instanceof(reg, obj.result(), x->klass(), ++ new_register(objectType), new_register(objectType), 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(); ++ bool is_safepoint = x->is_safepoint(); ++ ++ If::Condition cond = x->cond(); ++ ++ LIRItem xitem(x->x(), this); ++ LIRItem yitem(x->y(), this); ++ LIRItem* xin = &xitem; ++ LIRItem* yin = &yitem; ++ ++ if (tag == longTag) { ++ // for longs, only conditions "eql", "neq", "lss", "geq" are valid; ++ // mirror for other conditions ++ if (cond == If::gtr || cond == If::leq) { ++ cond = Instruction::mirror(cond); ++ xin = &yitem; ++ yin = &xitem; ++ } ++ xin->set_destroys_register(); ++ } ++ xin->load_item(); ++ ++ if (tag == longTag) { ++ if (yin->is_constant() ++ && Assembler::operand_valid_for_add_sub_immediate(yin->get_jlong_constant())) { ++ yin->dont_load_item(); ++ } else { ++ yin->load_item(); ++ } ++ } else if (tag == intTag) { ++ if (yin->is_constant() ++ && Assembler::operand_valid_for_add_sub_immediate(yin->get_jint_constant())) { ++ yin->dont_load_item(); ++ } else { ++ yin->load_item(); ++ } ++ } else { ++ yin->load_item(); ++ } ++ ++ set_no_result(x); ++ ++ LIR_Opr left = xin->result(); ++ LIR_Opr right = yin->result(); ++ ++ // 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(LIR_OprFact::illegalOpr, 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(rthread); ++} ++ ++void LIRGenerator::trace_block_entry(BlockBegin* block) { Unimplemented(); } ++ ++void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, ++ CodeEmitInfo* info) { ++ __ volatile_store_mem_reg(value, address, info); ++} ++ ++void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, ++ CodeEmitInfo* info) { ++ // 8179954: We need to make sure that the code generated for ++ // volatile accesses forms a sequentially-consistent set of ++ // operations when combined with STLR and LDAR. Without a leading ++ // membar it's possible for a simple Dekker test to fail if loads ++ // use LD;DMB but stores use STLR. This can happen if C2 compiles ++ // the stores in one method and C1 compiles the loads in another. ++ if (! UseBarriersForVolatile) { ++ __ membar(); ++ } ++ ++ __ volatile_load_mem_reg(address, result, info); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_LIR_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_LIR_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_LIR_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_LIR_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,54 @@ ++/* ++ * 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_LIR.hpp" ++ ++FloatRegister LIR_OprDesc::as_float_reg() const { ++ return as_FloatRegister(fpu_regnr()); ++} ++ ++FloatRegister LIR_OprDesc::as_double_reg() const { ++ return as_FloatRegister(fpu_regnrLo()); ++} ++ ++// Reg2 unused. ++LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { ++ assert(as_FloatRegister(reg2) == fnoreg, "Not used on this platform"); ++ return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | ++ (reg1 << LIR_OprDesc::reg2_shift) | ++ LIR_OprDesc::double_type | ++ LIR_OprDesc::fpu_register | ++ LIR_OprDesc::double_size); ++} ++ ++#ifndef PRODUCT ++void LIR_Address::verify() const { ++ assert(base()->is_cpu_register(), "wrong base operand"); ++ assert(index()->is_illegal() || index()->is_double_cpu() || index()->is_single_cpu(), "wrong index operand"); ++ assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA, ++ "wrong type for addresses"); ++} ++#endif // PRODUCT +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,399 @@ ++/* ++ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "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/markOop.hpp" ++#include "runtime/basicLock.hpp" ++#include "runtime/biasedLocking.hpp" ++#include "runtime/os.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/stubRoutines.hpp" ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, ++ FloatRegister f0, FloatRegister f1, ++ Register result) ++{ ++ Label done; ++ if (is_float) { ++ fcmps(f0, f1); ++ } else { ++ fcmpd(f0, f1); ++ } ++ if (unordered_result < 0) { ++ // we want -1 for unordered or less than, 0 for equal and 1 for ++ // greater than. ++ cset(result, NE); // Not equal or unordered ++ cneg(result, result, LT); // Less than or unordered ++ } else { ++ // we want -1 for less than, 0 for equal and 1 for unordered or ++ // greater than. ++ cset(result, NE); // Not equal or unordered ++ cneg(result, result, LO); // Less than ++ } ++} ++ ++int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) { ++ const int aligned_mask = BytesPerWord -1; ++ const int hdr_offset = oopDesc::mark_offset_in_bytes(); ++ assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); ++ Label done, fail; ++ int null_check_offset = -1; ++ ++ verify_oop(obj); ++ ++ // save object being locked into the BasicObjectLock ++ str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes())); ++ ++ if (UseBiasedLocking) { ++ assert(scratch != noreg, "should have scratch register at this point"); ++ null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case); ++ } else { ++ null_check_offset = offset(); ++ } ++ ++ // Load object header ++ ldr(hdr, Address(obj, hdr_offset)); ++ // and mark it as unlocked ++ orr(hdr, hdr, markOopDesc::unlocked_value); ++ // save unlocked object header into the displaced header location on the stack ++ str(hdr, Address(disp_hdr, 0)); ++ // test if object header is still the same (i.e. unlocked), and if so, store the ++ // displaced header address in the object header - if it is not the same, get the ++ // object header instead ++ lea(rscratch2, Address(obj, hdr_offset)); ++ cmpxchgptr(hdr, disp_hdr, rscratch2, rscratch1, done, /*fallthough*/NULL); ++ // if the object header was the same, we're done ++ // if the object header was not the same, it is now in the hdr register ++ // => test if it is a stack pointer into the same stack (recursive locking), i.e.: ++ // ++ // 1) (hdr & aligned_mask) == 0 ++ // 2) sp <= hdr ++ // 3) hdr <= sp + page_size ++ // ++ // these 3 tests can be done by evaluating the following expression: ++ // ++ // (hdr - sp) & (aligned_mask - page_size) ++ // ++ // assuming both the stack pointer and page_size have their least ++ // significant 2 bits cleared and page_size is a power of 2 ++ mov(rscratch1, sp); ++ sub(hdr, hdr, rscratch1); ++ ands(hdr, hdr, aligned_mask - os::vm_page_size()); ++ // for recursive locking, the result is zero => save it in the displaced header ++ // location (NULL in the displaced hdr location indicates recursive locking) ++ str(hdr, Address(disp_hdr, 0)); ++ // otherwise we don't care about the result and handle locking via runtime call ++ cbnz(hdr, slow_case); ++ // done ++ BIND(done); ++ if (PrintBiasedLockingStatistics) { ++ lea(rscratch2, ExternalAddress((address)BiasedLocking::fast_path_entry_count_addr())); ++ addmw(Address(rscratch2, 0), 1, rscratch1); ++ } ++ return null_check_offset; ++} ++ ++ ++void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { ++ const int aligned_mask = BytesPerWord -1; ++ const int hdr_offset = oopDesc::mark_offset_in_bytes(); ++ assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); ++ Label done; ++ ++ if (UseBiasedLocking) { ++ // load object ++ ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes())); ++ biased_locking_exit(obj, hdr, done); ++ } ++ ++ // load displaced header ++ ldr(hdr, Address(disp_hdr, 0)); ++ // if the loaded hdr is NULL we had recursive locking ++ // if we had recursive locking, we are done ++ cbz(hdr, done); ++ if (!UseBiasedLocking) { ++ // load object ++ ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes())); ++ } ++ verify_oop(obj); ++ // test if object header is pointing to the displaced header, and if so, restore ++ // the displaced header in the object - if the object header is not pointing to ++ // the displaced header, get the object header instead ++ // if the object header was not pointing to the displaced header, ++ // we do unlocking via runtime call ++ if (hdr_offset) { ++ lea(rscratch1, Address(obj, hdr_offset)); ++ cmpxchgptr(disp_hdr, hdr, rscratch1, rscratch2, done, &slow_case); ++ } else { ++ cmpxchgptr(disp_hdr, hdr, obj, rscratch2, done, &slow_case); ++ } ++ // done ++ BIND(done); ++} ++ ++ ++// Defines obj, preserves var_size_in_bytes ++void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) { ++ if (UseTLAB) { ++ tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); ++ } else { ++ eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); ++ } ++} ++ ++void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) { ++ assert_different_registers(obj, klass, len); ++ if (UseBiasedLocking && !len->is_valid()) { ++ assert_different_registers(obj, klass, len, t1, t2); ++ ldr(t1, Address(klass, Klass::prototype_header_offset())); ++ } else { ++ // This assumes that all prototype bits fit in an int32_t ++ mov(t1, (int32_t)(intptr_t)markOopDesc::prototype()); ++ } ++ str(t1, Address(obj, oopDesc::mark_offset_in_bytes())); ++ ++ if (UseCompressedClassPointers) { // Take care not to kill klass ++ encode_klass_not_null(t1, klass); ++ strw(t1, Address(obj, oopDesc::klass_offset_in_bytes())); ++ } else { ++ str(klass, Address(obj, oopDesc::klass_offset_in_bytes())); ++ } ++ ++ if (len->is_valid()) { ++ strw(len, Address(obj, arrayOopDesc::length_offset_in_bytes())); ++ } else if (UseCompressedClassPointers) { ++ store_klass_gap(obj, zr); ++ } ++} ++ ++// preserves obj, destroys len_in_bytes ++void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1) { ++ assert(hdr_size_in_bytes >= 0, "header size must be positive or 0"); ++ Label done; ++ ++ // len_in_bytes is positive and ptr sized ++ subs(len_in_bytes, len_in_bytes, hdr_size_in_bytes); ++ br(Assembler::EQ, done); ++ ++ // Preserve obj ++ if (hdr_size_in_bytes) ++ add(obj, obj, hdr_size_in_bytes); ++ zero_memory(obj, len_in_bytes, t1); ++ if (hdr_size_in_bytes) ++ sub(obj, obj, hdr_size_in_bytes); ++ ++ BIND(done); ++} ++ ++ ++void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case) { ++ assert_different_registers(obj, t1, t2); // XXX really? ++ assert(header_size >= 0 && object_size >= header_size, "illegal sizes"); ++ ++ try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case); ++ ++ initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2, UseTLAB); ++} ++ ++void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, bool is_tlab_allocated) { ++ assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, ++ "con_size_in_bytes is not multiple of alignment"); ++ const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize; ++ ++ initialize_header(obj, klass, noreg, t1, t2); ++ ++ if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) { ++ // clear rest of allocated space ++ const Register index = t2; ++ const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below) ++ if (var_size_in_bytes != noreg) { ++ mov(index, var_size_in_bytes); ++ initialize_body(obj, index, hdr_size_in_bytes, t1); ++ } else if (con_size_in_bytes <= threshold) { ++ // use explicit null stores ++ int i = hdr_size_in_bytes; ++ if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) { ++ str(zr, Address(obj, i)); ++ i += BytesPerWord; ++ } ++ for (; i < con_size_in_bytes; i += 2 * BytesPerWord) ++ stp(zr, zr, Address(obj, i)); ++ } else if (con_size_in_bytes > hdr_size_in_bytes) { ++ block_comment("zero memory"); ++ // use loop to null out the fields ++ ++ int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord; ++ mov(index, words / 8); ++ ++ const int unroll = 8; // Number of str(zr) instructions we'll unroll ++ int remainder = words % unroll; ++ lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord)); ++ ++ Label entry_point, loop; ++ b(entry_point); ++ ++ BIND(loop); ++ sub(index, index, 1); ++ for (int i = -unroll; i < 0; i++) { ++ if (-i == remainder) ++ BIND(entry_point); ++ str(zr, Address(rscratch1, i * wordSize)); ++ } ++ if (remainder == 0) ++ BIND(entry_point); ++ add(rscratch1, rscratch1, unroll * wordSize); ++ cbnz(index, loop); ++ ++ } ++ } ++ ++ membar(StoreStore); ++ ++ if (CURRENT_ENV->dtrace_alloc_probes()) { ++ assert(obj == i0, "must be"); ++ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id))); ++ } ++ ++ verify_oop(obj); ++} ++void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, int f, Register klass, Label& slow_case) { ++ assert_different_registers(obj, len, t1, t2, klass); ++ ++ // determine alignment mask ++ assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work"); ++ ++ // check for negative or excessive length ++ mov(rscratch1, (int32_t)max_array_allocation_length); ++ cmp(len, rscratch1); ++ br(Assembler::HS, slow_case); ++ ++ const Register arr_size = t2; // okay to be the same ++ // align object end ++ mov(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask); ++ add(arr_size, arr_size, len, ext::uxtw, f); ++ andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask); ++ ++ try_allocate(obj, arr_size, 0, t1, t2, slow_case); ++ ++ initialize_header(obj, klass, len, t1, t2); ++ ++ // clear rest of allocated space ++ const Register len_zero = len; ++ initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero); ++ ++ membar(StoreStore); ++ ++ if (CURRENT_ENV->dtrace_alloc_probes()) { ++ assert(obj == i0, "must be"); ++ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id))); ++ } ++ ++ verify_oop(obj); ++} ++ ++ ++void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { ++ verify_oop(receiver); ++ // explicit NULL check not needed since load from [klass_offset] causes a trap ++ // check against inline cache ++ assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check"); ++ ++ cmp_klass(receiver, iCache, rscratch1); ++} ++ ++ ++void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) { ++ // If we have to make this method not-entrant we'll overwrite its ++ // first instruction with a jump. For this action to be legal we ++ // must ensure that this first instruction is a B, BL, NOP, BKPT, ++ // SVC, HVC, or SMC. Make it a NOP. ++ nop(); ++ assert(bang_size_in_bytes >= framesize, "stack bang size incorrect"); ++ // Make sure there is enough stack space for this method's activation. ++ // Note that we do this before doing an enter(). ++ generate_stack_overflow_check(bang_size_in_bytes); ++ MacroAssembler::build_frame(framesize + 2 * wordSize); ++} ++ ++void C1_MacroAssembler::remove_frame(int framesize) { ++ MacroAssembler::remove_frame(framesize + 2 * wordSize); ++} ++ ++ ++void C1_MacroAssembler::verified_entry() { ++} ++ ++void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) { ++ // rbp, + 0: link ++ // + 1: return address ++ // + 2: argument with offset 0 ++ // + 3: argument with offset 1 ++ // + 4: ... ++ ++ ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord)); ++} ++ ++#ifndef PRODUCT ++ ++void C1_MacroAssembler::verify_stack_oop(int stack_offset) { ++ if (!VerifyOops) return; ++ verify_oop_addr(Address(sp, stack_offset), "oop"); ++} ++ ++void C1_MacroAssembler::verify_not_null_oop(Register r) { ++ if (!VerifyOops) return; ++ Label not_null; ++ cbnz(r, not_null); ++ stop("non-null oop required"); ++ BIND(not_null); ++ verify_oop(r); ++} ++ ++void C1_MacroAssembler::invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) { ++#ifdef ASSERT ++ static int nn; ++ if (inv_r0) mov(i0, 0xDEAD); ++ if (inv_r19) mov(i19, 0xDEAD); ++ if (inv_r2) mov(i2, nn++); ++ if (inv_r3) mov(i3, 0xDEAD); ++ if (inv_r4) mov(i4, 0xDEAD); ++ if (inv_r5) mov(i5, 0xDEAD); ++#endif ++} ++#endif // ifndef PRODUCT +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_MacroAssembler_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * 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_SW64_VM_C1_MACROASSEMBLER_SW64_HPP ++#define CPU_SW64_VM_C1_MACROASSEMBLER_SW64_HPP ++ ++using MacroAssembler::build_frame; ++using MacroAssembler::null_check; ++ ++// C1_MacroAssembler contains high-level macros for C1 ++ ++ private: ++ int _rsp_offset; // track rsp changes ++ // initialization ++ void pd_init() { _rsp_offset = 0; } ++ ++ ++ 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 obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1); ++ ++ void float_cmp(bool is_float, int unordered_result, ++ FloatRegister f0, FloatRegister f1, ++ Register result); ++ ++ // locking ++ // hdr : must be r0, contents destroyed ++ // obj : must point to the object to lock, contents preserved ++ // disp_hdr: must point to the displaced header location, contents preserved ++ // scratch : scratch register, contents destroyed ++ // returns code offset at which to add null check debug information ++ int lock_object (Register swap, Register obj, Register disp_hdr, Register scratch, Label& slow_case); ++ ++ // unlocking ++ // hdr : contents destroyed ++ // obj : must point to the object to lock, contents preserved ++ // disp_hdr: must be r0 & must point to the displaced header location, contents destroyed ++ void unlock_object(Register swap, Register obj, Register lock, Label& slow_case); ++ ++ 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) ++ // obj : will contain pointer to allocated object ++ // t1, t2 : scratch registers - contents destroyed ++ // header_size: size of object header in words ++ // object_size: total size of object in words ++ // slow_case : exit to slow case implementation if fast allocation fails ++ void allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case); ++ ++ enum { ++ max_array_allocation_length = 0x00FFFFFF ++ }; ++ ++ // allocation of arrays ++ // obj : will contain pointer to allocated object ++ // len : array length in number of elements ++ // t : scratch register - contents destroyed ++ // header_size: size of object header in words ++ // f : element scale factor ++ // slow_case : exit to slow case implementation if fast allocation fails ++ void allocate_array(Register obj, Register len, Register t, Register t2, int header_size, int f, Register klass, Label& slow_case); ++ ++ int rsp_offset() const { return _rsp_offset; } ++ void set_rsp_offset(int n) { _rsp_offset = n; } ++ ++ void invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) PRODUCT_RETURN; ++ ++ // 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 load_parameter(int offset_in_words, Register reg); ++ ++#endif // CPU_SW64_VM_C1_MACROASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c1_Runtime1_sw64.cpp afu11u/src/hotspot/cpu/sw64/c1_Runtime1_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c1_Runtime1_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c1_Runtime1_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,1157 @@ ++/* ++ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/assembler.hpp" ++#include "c1/c1_CodeStubs.hpp" ++#include "c1/c1_Defs.hpp" ++#include "c1/c1_MacroAssembler.hpp" ++#include "c1/c1_Runtime1.hpp" ++#include "compiler/disassembler.hpp" ++#include "gc/shared/cardTable.hpp" ++#include "gc/shared/cardTableBarrierSet.hpp" ++#include "interpreter/interpreter.hpp" ++#include "nativeInst_sw64.hpp" ++#include "oops/compiledICHolder.hpp" ++#include "oops/oop.inline.hpp" ++#include "prims/jvmtiExport.hpp" ++#include "register_sw64.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/signature.hpp" ++#include "runtime/vframe.hpp" ++#include "runtime/vframeArray.hpp" ++#include "vmreg_sw64.inline.hpp" ++ ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++// Implementation of StubAssembler ++ ++int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) { ++ // setup registers ++ assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different"); ++ assert(oop_result1 != rthread && metadata_result != rthread, "registers must be different"); ++ assert(args_size >= 0, "illegal args_size"); ++ bool align_stack = false; ++ ++ mov(c_rarg0, rthread); ++ set_num_rt_args(0); // Nothing on stack ++ ++ Label retaddr; ++ set_last_Java_frame(sp, rfp, retaddr, rscratch1); ++ ++ // do the call ++ lea(rscratch1, RuntimeAddress(entry)); ++ blr(rscratch1); ++ BIND(retaddr); ++ int call_offset = offset(); ++ // verify callee-saved register ++#ifdef ASSERT ++ push(i0, sp); ++ { Label L; ++ get_thread(i0); ++ cmp(rthread, i0); ++ br(Assembler::EQ, L); ++ stop("StubAssembler::call_RT: rthread not callee saved?"); ++ BIND(L); ++ } ++ pop(i0, sp); ++#endif ++ reset_last_Java_frame(true); ++ maybe_isb(); ++ ++ // check for pending exceptions ++ { Label L; ++ // check for pending exceptions (java_thread is set upon return) ++ ldr(rscratch1, Address(rthread, in_bytes(Thread::pending_exception_offset()))); ++ cbz(rscratch1, L); ++ // exception pending => remove activation and forward to exception handler ++ // make sure that the vm_results are cleared ++ if (oop_result1->is_valid()) { ++ str(zr, Address(rthread, JavaThread::vm_result_offset())); ++ } ++ if (metadata_result->is_valid()) { ++ str(zr, Address(rthread, JavaThread::vm_result_2_offset())); ++ } ++ if (frame_size() == no_frame_size) { ++ leave(); ++ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); ++ } else if (_stub_id == Runtime1::forward_exception_id) { ++ should_not_reach_here(); ++ } else { ++ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id))); ++ } ++ BIND(L); ++ } ++ // get oop results if there are any and reset the values in the thread ++ if (oop_result1->is_valid()) { ++ get_vm_result(oop_result1, rthread); ++ } ++ if (metadata_result->is_valid()) { ++ get_vm_result_2(metadata_result, rthread); ++ } ++ return call_offset; ++} ++ ++ ++int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { ++ mov(c_rarg1, arg1); ++ 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) { ++ if (c_rarg1 == arg2) { ++ if (c_rarg2 == arg1) { ++ mov(rscratch1, arg1); ++ mov(arg1, arg2); ++ mov(arg2, rscratch1); ++ } else { ++ mov(c_rarg2, arg2); ++ mov(c_rarg1, arg1); ++ } ++ } else { ++ mov(c_rarg1, arg1); ++ mov(c_rarg2, arg2); ++ } ++ 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) { ++ // if there is any conflict use the stack ++ if (arg1 == c_rarg2 || arg1 == c_rarg3 || ++ arg2 == c_rarg1 || arg1 == c_rarg3 || ++ arg3 == c_rarg1 || arg1 == c_rarg2) { ++ stp(arg3, arg2, Address(pre(sp, 2 * wordSize))); ++ stp(arg1, zr, Address(pre(sp, -2 * wordSize))); ++ ldp(c_rarg1, zr, Address(post(sp, 2 * wordSize))); ++ ldp(c_rarg3, c_rarg2, Address(post(sp, 2 * wordSize))); ++ } else { ++ mov(c_rarg1, arg1); ++ mov(c_rarg2, arg2); ++ mov(c_rarg3, arg3); ++ } ++ return call_RT(oop_result1, metadata_result, entry, 3); ++} ++ ++// Implementation of StubFrame ++ ++class StubFrame: public StackObj { ++ private: ++ StubAssembler* _sasm; ++ ++ public: ++ StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments); ++ void load_argument(int offset_in_words, Register reg); ++ ++ ~StubFrame(); ++};; ++ ++void StubAssembler::prologue(const char* name, bool must_gc_arguments) { ++ set_info(name, must_gc_arguments); ++ enter(); ++} ++ ++void StubAssembler::epilogue() { ++ leave(); ++ ret(lr); ++} ++#undef BLOCK_COMMENT ++#undef BIND ++#define __ _sasm-> ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) { ++ _sasm = sasm; ++ __ prologue(name, must_gc_arguments); ++} ++ ++// load parameters that were stored with LIR_Assembler::store_parameter ++// Note: offsets for store_parameter and load_argument must match ++void StubFrame::load_argument(int offset_in_words, Register reg) { ++ __ load_parameter(offset_in_words, reg); ++} ++ ++ ++StubFrame::~StubFrame() { ++ __ epilogue(); ++} ++ ++#undef __ ++ ++ ++// Implementation of Runtime1 ++ ++#define __ sasm-> ++ ++const int float_regs_as_doubles_size_in_slots = pd_nof_fpu_regs_frame_map * 2; ++ ++// Stack layout for saving/restoring all the registers needed during a runtime ++// call (this includes deoptimization) ++// Note: note that users of this frame may well have arguments to some runtime ++// while these values are on the stack. These positions neglect those arguments ++// but the code in save_live_registers will take the argument count into ++// account. ++// ++ ++enum reg_save_layout { ++ reg_save_frame_size = 32 /* float */ + 32 /* integer */ ++}; ++ ++// Save off registers which might be killed by calls into the runtime. ++// Tries to smart of about FP registers. In particular we separate ++// saving and describing the FPU registers for deoptimization since we ++// have to save the FPU registers twice if we describe them. The ++// deopt blob is the only thing which needs to describe FPU registers. ++// In all other cases it should be sufficient to simply save their ++// current value. ++ ++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) { ++ int frame_size_in_bytes = reg_save_frame_size * BytesPerWord; ++ 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); ++ ++ for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { ++ Register r = as_Register(i); ++ if (i <= 18 && i != rscratch1->encoding() && i != rscratch2->encoding()) { ++ 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 (int 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; ++} ++ ++static OopMap* save_live_registers(StubAssembler* sasm, ++ bool save_fpu_registers = true) { ++ __ block_comment("save_live_registers"); ++ ++ __ push(RegSet::range(i0, i29), sp); // integer registers except lr & sp ++ ++ if (save_fpu_registers) { ++ for (int i = 31; i>= 0; i -= 4) { ++ __ sub(sp, sp, 4 * wordSize); // no pre-increment for st1. Emulate it without modifying other registers ++ __ st1(as_FloatRegister(i-3), as_FloatRegister(i-2), as_FloatRegister(i-1), ++ as_FloatRegister(i), __ T1D, Address(sp)); ++ } ++ } else { ++ __ add(sp, sp, -32 * wordSize); ++ } ++ ++ return generate_oop_map(sasm, save_fpu_registers); ++} ++ ++static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { ++ if (restore_fpu_registers) { ++ for (int i = 0; i < 32; i += 4) ++ __ ld1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2), ++ as_FloatRegister(i+3), __ T1D, Address(__ post(sp, 4 * wordSize))); ++ } else { ++ __ add(sp, sp, 32 * wordSize); ++ } ++ ++ __ pop(RegSet::range(i0, i29), sp); ++} ++ ++static void restore_live_registers_except_r0(StubAssembler* sasm, bool restore_fpu_registers = true) { ++ ++ if (restore_fpu_registers) { ++ for (int i = 0; i < 32; i += 4) ++ __ ld1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2), ++ as_FloatRegister(i+3), __ T1D, Address(__ post(sp, 4 * wordSize))); ++ } else { ++ __ add(sp, sp, 32 * wordSize); ++ } ++ ++ __ ldp(zr, i1, Address(__ post(sp, 16))); ++ __ pop(RegSet::range(i2, i29), sp); ++} ++ ++ ++ ++void Runtime1::initialize_pd() { ++ int i; ++ int sp_offset = 0; ++ ++ // 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 += 2; // SP offsets are in halfwords ++ } ++ ++ for (i = 0; i < FrameMap::nof_cpu_regs; i++) { ++ Register r = as_Register(i); ++ cpu_reg_save_offsets[i] = sp_offset; ++ sp_offset += 2; // SP offsets are in halfwords ++ } ++} ++ ++ ++// target: the entry point of the method that creates and posts the exception oop ++// has_argument: true if the exception needs arguments (passed in rscratch1 and rscratch2) ++ ++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 { ++ __ mov(c_rarg1, rscratch1); ++ __ mov(c_rarg2, rscratch2); ++ call_offset = __ call_RT(noreg, noreg, target); ++ } ++ OopMapSet* oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, oop_map); ++ ++ __ should_not_reach_here(); ++ return oop_maps; ++} ++ ++ ++OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { ++ __ block_comment("generate_handle_exception"); ++ ++ // incoming parameters ++ const Register exception_oop = i0; ++ const Register exception_pc = i3; ++ // other registers used in this stub ++ ++ // 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, 1 /*thread*/); ++ ++ // load and clear pending exception oop into i0 ++ __ ldr(exception_oop, Address(rthread, Thread::pending_exception_offset())); ++ __ str(zr, Address(rthread, Thread::pending_exception_offset())); ++ ++ // load issuing PC (the return address for this stub) into i3 ++ __ ldr(exception_pc, Address(rfp, 1*BytesPerWord)); ++ ++ // make sure that the vm_results are cleared (may be unnecessary) ++ __ str(zr, Address(rthread, JavaThread::vm_result_offset())); ++ __ str(zr, Address(rthread, JavaThread::vm_result_2_offset())); ++ break; ++ case handle_exception_nofpu_id: ++ case handle_exception_id: ++ // At this point all registers MAY be live. ++ oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id); ++ break; ++ case handle_exception_from_callee_id: { ++ // At this point all registers except exception oop (i0) and ++ // exception pc (lr) are dead. ++ const int frame_size = 2 /*fp, return address*/; ++ oop_map = new OopMap(frame_size * VMRegImpl::slots_per_word, 0); ++ sasm->set_frame_size(frame_size); ++ break; ++ } ++ default: ++ __ should_not_reach_here(); ++ break; ++ } ++ ++ // verify that only i0 and i3 are valid at this time ++ __ invalidate_registers(false, true, true, false, true, true); ++ // verify that i0 contains a valid exception ++ __ verify_not_null_oop(exception_oop); ++ ++#ifdef ASSERT ++ // check that fields in JavaThread for exception oop and issuing pc are ++ // empty before writing to them ++ Label oop_empty; ++ __ ldr(rscratch1, Address(rthread, JavaThread::exception_oop_offset())); ++ __ cbz(rscratch1, oop_empty); ++ __ stop("exception oop already set"); ++ __ BIND(oop_empty); ++ ++ Label pc_empty; ++ __ ldr(rscratch1, Address(rthread, JavaThread::exception_pc_offset())); ++ __ cbz(rscratch1, pc_empty); ++ __ stop("exception pc already set"); ++ __ BIND(pc_empty); ++#endif ++ ++ // save exception oop and issuing pc into JavaThread ++ // (exception handler will load it from here) ++ __ str(exception_oop, Address(rthread, JavaThread::exception_oop_offset())); ++ __ str(exception_pc, Address(rthread, JavaThread::exception_pc_offset())); ++ ++ // patch throwing pc into return address (has bci & oop map) ++ __ str(exception_pc, Address(rfp, 1*BytesPerWord)); ++ ++ // compute the exception handler. ++ // the exception oop and the throwing pc are read from the fields in JavaThread ++ 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); ++ ++ // i0: handler address ++ // will be the deopt blob if nmethod was deoptimized while we looked up ++ // handler regardless of whether handler existed in the nmethod. ++ ++ // only i0 is valid at this time, all other registers have been destroyed by the runtime call ++ __ invalidate_registers(false, true, true, true, true, true); ++ ++ // patch the return address, this stub will directly return to the exception handler ++ __ str(i0, Address(rfp, 1*BytesPerWord)); ++ ++ switch (id) { ++ case forward_exception_id: ++ case handle_exception_nofpu_id: ++ case handle_exception_id: ++ // Restore the registers that were saved at the beginning. ++ restore_live_registers(sasm, id != handle_exception_nofpu_id); ++ break; ++ case handle_exception_from_callee_id: ++ // Pop the return address. ++ __ leave(); ++ __ ret(lr); // jump to exception handler ++ break; ++ default: ShouldNotReachHere(); ++ } ++ ++ return oop_maps; ++} ++ ++ ++void Runtime1::generate_unwind_exception(StubAssembler *sasm) { ++ // incoming parameters ++ const Register exception_oop = i0; ++ // callee-saved copy of exception_oop during runtime call ++ const Register exception_oop_callee_saved = i19; ++ // other registers used in this stub ++ const Register exception_pc = i3; ++ const Register handler_addr = i1; ++ ++ // verify that only i0, is valid at this time ++ __ invalidate_registers(false, true, true, true, true, true); ++ ++#ifdef ASSERT ++ // check that fields in JavaThread for exception oop and issuing pc are empty ++ Label oop_empty; ++ __ ldr(rscratch1, Address(rthread, JavaThread::exception_oop_offset())); ++ __ cbz(rscratch1, oop_empty); ++ __ stop("exception oop must be empty"); ++ __ BIND(oop_empty); ++ ++ Label pc_empty; ++ __ ldr(rscratch1, Address(rthread, JavaThread::exception_pc_offset())); ++ __ cbz(rscratch1, pc_empty); ++ __ stop("exception pc must be empty"); ++ __ BIND(pc_empty); ++#endif ++ ++ // Save our return address because ++ // exception_handler_for_return_address will destroy it. We also ++ // save exception_oop ++ __ stp(lr, exception_oop, Address(__ pre(sp, -2 * wordSize))); ++ ++ // search the exception handler address of the caller (using the return address) ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, lr); ++ // i0: exception handler address of the caller ++ ++ // Only R0 is valid at this time; all other registers have been ++ // destroyed by the call. ++ __ invalidate_registers(false, true, true, true, false, true); ++ ++ // move result of call into correct register ++ __ mov(handler_addr, i0); ++ ++ // get throwing pc (= return address). ++ // lr has been destroyed by the call ++ __ ldp(lr, exception_oop, Address(__ post(sp, 2 * wordSize))); ++ __ mov(i3, lr); ++ ++ __ verify_not_null_oop(exception_oop); ++ ++ // continue at exception handler (return address removed) ++ // note: do *not* remove arguments when unwinding the ++ // activation since the caller assumes having ++ // all arguments on the stack when entering the ++ // runtime to determine the exception handler ++ // (GC happens at call site with arguments!) ++ // i0: exception oop ++ // i3: throwing pc ++ // i1: exception handler ++ __ br(handler_addr); ++} ++ ++ ++ ++OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { ++ // use the maximum number of runtime-arguments here because it is difficult to ++ // distinguish each RT-Call. ++ // Note: This number affects also the RT-Call in generate_handle_exception because ++ // the oop-map is shared for all calls. ++ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); ++ assert(deopt_blob != NULL, "deoptimization blob must have been created"); ++ ++ OopMap* oop_map = save_live_registers(sasm); ++ ++ __ mov(c_rarg0, rthread); ++ Label retaddr; ++ __ set_last_Java_frame(sp, rfp, retaddr, rscratch1); ++ // do the call ++ __ lea(rscratch1, RuntimeAddress(target)); ++ __ blr(rscratch1); ++ __ BIND(retaddr); ++ OopMapSet* oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(__ offset(), oop_map); ++ // verify callee-saved register ++#ifdef ASSERT ++ { Label L; ++ __ get_thread(rscratch1); ++ __ cmp(rthread, rscratch1); ++ __ br(Assembler::EQ, L); ++ __ stop("StubAssembler::call_RT: rthread not callee saved?"); ++ __ BIND(L); ++ } ++#endif ++ __ reset_last_Java_frame(true); ++ __ maybe_isb(); ++ ++ // check for pending exceptions ++ { Label L; ++ __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); ++ __ cbz(rscratch1, L); ++ // exception pending => remove activation and forward to exception handler ++ ++ { Label L1; ++ __ cbnz(i0, L1); // have we deoptimized? ++ __ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id))); ++ __ BIND(L1); ++ } ++ ++ // the deopt blob expects exceptions in the special fields of ++ // JavaThread, so copy and clear pending exception. ++ ++ // load and clear pending exception ++ __ ldr(i0, Address(rthread, Thread::pending_exception_offset())); ++ __ str(zr, Address(rthread, Thread::pending_exception_offset())); ++ ++ // check that there is really a valid exception ++ __ verify_not_null_oop(i0); ++ ++ // load throwing pc: this is the return address of the stub ++ __ mov(i3, lr); ++ ++#ifdef ASSERT ++ // check that fields in JavaThread for exception oop and issuing pc are empty ++ Label oop_empty; ++ __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); ++ __ cbz(rscratch1, oop_empty); ++ __ stop("exception oop must be empty"); ++ __ BIND(oop_empty); ++ ++ Label pc_empty; ++ __ ldr(rscratch1, Address(rthread, JavaThread::exception_pc_offset())); ++ __ cbz(rscratch1, pc_empty); ++ __ stop("exception pc must be empty"); ++ __ BIND(pc_empty); ++#endif ++ ++ // store exception oop and throwing pc to JavaThread ++ __ str(i0, Address(rthread, JavaThread::exception_oop_offset())); ++ __ str(i3, Address(rthread, JavaThread::exception_pc_offset())); ++ ++ restore_live_registers(sasm); ++ ++ __ leave(); ++ ++ // Forward the exception directly to deopt blob. We can blow no ++ // registers and must leave throwing pc on the stack. A patch may ++ // have values live in registers so the entry point with the ++ // exception in tls. ++ __ far_jump(RuntimeAddress(deopt_blob->unpack_with_exception_in_tls())); ++ ++ __ BIND(L); ++ } ++ ++ ++ // Runtime will return true if the nmethod has been deoptimized during ++ // the patching process. In that case we must do a deopt reexecute instead. ++ ++ Label reexecuteEntry, cont; ++ ++ __ cbz(i0, cont); // have we deoptimized? ++ ++ // Will reexecute. Proper return address is already on the stack we just restore ++ // registers, pop all of our frame but the return address and jump to the deopt blob ++ restore_live_registers(sasm); ++ __ leave(); ++ __ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); ++ ++ __ BIND(cont); ++ restore_live_registers(sasm); ++ __ leave(); ++ __ ret(lr); ++ ++ return oop_maps; ++} ++ ++ ++OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { ++ ++ const Register exception_oop = i0; ++ const Register exception_pc = i3; ++ ++ // for better readability ++ const bool must_gc_arguments = true; ++ const bool dont_gc_arguments = false; ++ ++ // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu ++ bool save_fpu_registers = true; ++ ++ // stub code & info for the different stubs ++ OopMapSet* oop_maps = NULL; ++ OopMap* oop_map = NULL; ++ switch (id) { ++ { ++ case forward_exception_id: ++ { ++ oop_maps = generate_handle_exception(id, sasm); ++ __ leave(); ++ __ ret(lr); ++ } ++ break; ++ ++ case throw_div0_exception_id: ++ { StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments); ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); ++ } ++ break; ++ ++ case throw_null_pointer_exception_id: ++ { StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments); ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); ++ } ++ break; ++ ++ case new_instance_id: ++ case fast_new_instance_id: ++ case fast_new_instance_init_check_id: ++ { ++ Register klass = i3; // Incoming ++ Register obj = i0; // Result ++ ++ 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 obj_size = i2; ++ Register t1 = i19; ++ Register t2 = i4; ++ assert_different_registers(klass, obj, obj_size, t1, t2); ++ ++ __ stp(i19, zr, Address(__ pre(sp, -2 * wordSize))); ++ ++ if (id == fast_new_instance_init_check_id) { ++ // make sure the klass is initialized ++ __ ldrb(rscratch1, Address(klass, InstanceKlass::init_state_offset())); ++ __ cmpw(rscratch1, InstanceKlass::fully_initialized); ++ __ br(Assembler::NE, slow_path); ++ } ++ ++#ifdef ASSERT ++ // assert object can be fast path allocated ++ { ++ Label ok, not_ok; ++ __ ldrw(obj_size, Address(klass, Klass::layout_helper_offset())); ++ __ cmp(obj_size, 0u); ++ __ br(Assembler::LE, not_ok); // make sure it's an instance (LH > 0) ++ __ tstw(obj_size, Klass::_lh_instance_slow_path_bit); ++ __ br(Assembler::EQ, ok); ++ __ BIND(not_ok); ++ __ stop("assert(can be fast path allocated)"); ++ __ should_not_reach_here(); ++ __ BIND(ok); ++ } ++#endif // ASSERT ++ ++ // get the instance size (size is postive so movl is fine for 64bit) ++ __ ldrw(obj_size, Address(klass, Klass::layout_helper_offset())); ++ ++ __ eden_allocate(obj, obj_size, 0, t1, slow_path); ++ ++ __ initialize_object(obj, klass, obj_size, 0, t1, t2, /* is_tlab_allocated */ false); ++ __ verify_oop(obj); ++ __ ldp(i19, zr, Address(__ post(sp, 2 * wordSize))); ++ __ ret(lr); ++ ++ __ BIND(slow_path); ++ __ ldp(i19, zr, Address(__ post(sp, 2 * wordSize))); ++ } ++ ++ __ enter(); ++ OopMap* map = save_live_registers(sasm); ++ int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass); ++ oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, map); ++ restore_live_registers_except_r0(sasm); ++ __ verify_oop(obj); ++ __ leave(); ++ __ ret(lr); ++ ++ // i0,: new instance ++ } ++ ++ break; ++ ++ case counter_overflow_id: ++ { ++ Register bci = i0, method = i1; ++ __ enter(); ++ OopMap* map = save_live_registers(sasm); ++ // Retrieve bci ++ __ ldrw(bci, Address(rfp, 2*BytesPerWord)); ++ // And a pointer to the Method* ++ __ ldr(method, Address(rfp, 3*BytesPerWord)); ++ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci, method); ++ oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, map); ++ restore_live_registers(sasm); ++ __ leave(); ++ __ ret(lr); ++ } ++ break; ++ ++ case new_type_array_id: ++ case new_object_array_id: ++ { ++ Register length = i19; // Incoming ++ Register klass = i3; // Incoming ++ Register obj = i0; // Result ++ ++ 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 t0 = obj; ++ __ ldrw(t0, Address(klass, Klass::layout_helper_offset())); ++ __ asrw(t0, t0, Klass::_lh_array_tag_shift); ++ int tag = ((id == new_type_array_id) ++ ? Klass::_lh_array_tag_type_value ++ : Klass::_lh_array_tag_obj_value); ++ __ mov(rscratch1, tag); ++ __ cmpw(t0, rscratch1); ++ __ br(Assembler::EQ, ok); ++ __ stop("assert(is an array klass)"); ++ __ should_not_reach_here(); ++ __ BIND(ok); ++ } ++#endif // ASSERT ++ ++ // If TLAB is disabled, see if there is support for inlining contiguous ++ // allocations. ++ // Otherwise, just go to the slow path. ++ if (!UseTLAB && Universe::heap()->supports_inline_contig_alloc()) { ++ Register arr_size = i4; ++ Register t1 = i2; ++ Register t2 = i5; ++ Label slow_path; ++ assert_different_registers(length, klass, obj, arr_size, t1, t2); ++ ++ // check that array length is small enough for fast path. ++ __ mov(rscratch1, C1_MacroAssembler::max_array_allocation_length); ++ __ cmpw(length, rscratch1); ++ __ br(Assembler::HI, slow_path); ++ ++ // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F)) ++ // since size is positive ldrw does right thing on 64bit ++ __ ldrw(t1, Address(klass, Klass::layout_helper_offset())); ++ // since size is positive movw does right thing on 64bit ++ __ movw(arr_size, length); ++ __ lslvw(arr_size, length, t1); ++ __ ubfx(t1, t1, Klass::_lh_header_size_shift, ++ exact_log2(Klass::_lh_header_size_mask + 1)); ++ __ add(arr_size, arr_size, t1); ++ __ add(arr_size, arr_size, MinObjAlignmentInBytesMask); // align up ++ __ andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask); ++ ++ __ eden_allocate(obj, arr_size, 0, t1, slow_path); // preserves arr_size ++ ++ __ initialize_header(obj, klass, length, t1, t2); ++ __ ldrb(t1, Address(klass, in_bytes(Klass::layout_helper_offset()) + (Klass::_lh_header_size_shift / BitsPerByte))); ++ assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise"); ++ assert(Klass::_lh_header_size_mask <= 0xFF, "bytewise"); ++ __ andr(t1, t1, Klass::_lh_header_size_mask); ++ __ sub(arr_size, arr_size, t1); // body length ++ __ add(t1, t1, obj); // body start ++ __ initialize_body(t1, arr_size, 0, t2); ++ __ membar(Assembler::StoreStore); ++ __ verify_oop(obj); ++ ++ __ ret(lr); ++ ++ __ BIND(slow_path); ++ } ++ ++ __ enter(); ++ OopMap* map = save_live_registers(sasm); ++ int call_offset; ++ if (id == new_type_array_id) { ++ call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length); ++ } else { ++ call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length); ++ } ++ ++ oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, map); ++ restore_live_registers_except_r0(sasm); ++ ++ __ verify_oop(obj); ++ __ leave(); ++ __ ret(lr); ++ ++ // i0: new array ++ } ++ break; ++ ++ case new_multi_array_id: ++ { StubFrame f(sasm, "new_multi_array", dont_gc_arguments); ++ // i0,: klass ++ // i19,: rank ++ // i2: address of 1st dimension ++ OopMap* map = save_live_registers(sasm); ++ __ mov(c_rarg1, i0); ++ __ mov(c_rarg3, i2); ++ __ mov(c_rarg2, i19); ++ int call_offset = __ call_RT(i0, noreg, CAST_FROM_FN_PTR(address, new_multi_array), i1, i2, i3); ++ ++ oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, map); ++ restore_live_registers_except_r0(sasm); ++ ++ // i0,: new multi array ++ __ verify_oop(i0); ++ } ++ break; ++ ++ case register_finalizer_id: ++ { ++ __ set_info("register_finalizer", dont_gc_arguments); ++ ++ // This is called via call_runtime so the arguments ++ // will be place in C abi locations ++ ++ __ verify_oop(c_rarg0); ++ ++ // load the klass and check the has finalizer flag ++ Label register_finalizer; ++ Register t = i5; ++ __ load_klass(t, i0); ++ __ ldrw(t, Address(t, Klass::access_flags_offset())); ++ __ tbnz(t, exact_log2(JVM_ACC_HAS_FINALIZER), register_finalizer); ++ __ ret(lr); ++ ++ __ BIND(register_finalizer); ++ __ enter(); ++ 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); ++ ++ __ leave(); ++ __ ret(lr); ++ } ++ break; ++ ++ case throw_class_cast_exception_id: ++ { StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments); ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true); ++ } ++ break; ++ ++ case throw_incompatible_class_change_error_id: ++ { StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments); ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false); ++ } ++ break; ++ ++ case slow_subtype_check_id: ++ { ++ // Typical calling sequence: ++ // __ push(klass_RInfo); // object klass or other subclass ++ // __ push(sup_k_RInfo); // array element klass or other superclass ++ // __ bl(slow_subtype_check); ++ // Note that the subclass is pushed first, and is therefore deepest. ++ enum layout { ++ r0_off, r0_off_hi, ++ r2_off, r2_off_hi, ++ r4_off, r4_off_hi, ++ r5_off, r5_off_hi, ++ sup_k_off, sup_k_off_hi, ++ klass_off, klass_off_hi, ++ framesize, ++ result_off = sup_k_off ++ }; ++ ++ __ set_info("slow_subtype_check", dont_gc_arguments); ++ __ push(RegSet::of(i0, i2, i4, i5), sp); ++ ++ // This is called by pushing args and not with C abi ++ // __ ldr(r4, Address(sp, (klass_off) * VMRegImpl::stack_slot_size)); // subclass ++ // __ ldr(r0, Address(sp, (sup_k_off) * VMRegImpl::stack_slot_size)); // superclass ++ ++ __ ldp(i4, i0, Address(sp, (sup_k_off) * VMRegImpl::stack_slot_size)); ++ ++ Label miss; ++ __ check_klass_subtype_slow_path(i4, i0, i2, i5, NULL, &miss); ++ ++ // fallthrough on success: ++ __ mov(rscratch1, 1); ++ __ str(rscratch1, Address(sp, (result_off) * VMRegImpl::stack_slot_size)); // result ++ __ pop(RegSet::of(i0, i2, i4, i5), sp); ++ __ ret(lr); ++ ++ __ BIND(miss); ++ __ str(zr, Address(sp, (result_off) * VMRegImpl::stack_slot_size)); // result ++ __ pop(RegSet::of(i0, i2, i4, i5), sp); ++ __ ret(lr); ++ } ++ break; ++ ++ case monitorenter_nofpu_id: ++ save_fpu_registers = false; ++ // fall through ++ case monitorenter_id: ++ { ++ StubFrame f(sasm, "monitorenter", dont_gc_arguments); ++ OopMap* map = save_live_registers(sasm, save_fpu_registers); ++ ++ // Called with store_parameter and not C abi ++ ++ f.load_argument(1, i0); // i0,: object ++ f.load_argument(0, i1); // i1,: lock address ++ ++ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), i0, i1); ++ ++ oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, map); ++ restore_live_registers(sasm, save_fpu_registers); ++ } ++ break; ++ ++ case monitorexit_nofpu_id: ++ save_fpu_registers = false; ++ // fall through ++ case monitorexit_id: ++ { ++ StubFrame f(sasm, "monitorexit", dont_gc_arguments); ++ OopMap* map = save_live_registers(sasm, save_fpu_registers); ++ ++ // Called with store_parameter and not C abi ++ ++ f.load_argument(0, i0); // i0,: 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) ++ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), i0); ++ ++ oop_maps = new OopMapSet(); ++ oop_maps->add_gc_map(call_offset, map); ++ restore_live_registers(sasm, save_fpu_registers); ++ } ++ break; ++ ++ case deoptimize_id: ++ { ++ StubFrame f(sasm, "deoptimize", dont_gc_arguments); ++ OopMap* oop_map = save_live_registers(sasm); ++ f.load_argument(0, c_rarg1); ++ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize), c_rarg1); ++ ++ 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"); ++ __ leave(); ++ __ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); ++ } ++ break; ++ ++ case throw_range_check_failed_id: ++ { StubFrame f(sasm, "range_check_failed", dont_gc_arguments); ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true); ++ } ++ break; ++ ++ case unwind_exception_id: ++ { __ set_info("unwind_exception", dont_gc_arguments); ++ // note: no stubframe since we are about to leave the current ++ // activation and we are calling a leaf VM function only. ++ generate_unwind_exception(sasm); ++ } ++ break; ++ ++ case access_field_patching_id: ++ { StubFrame f(sasm, "access_field_patching", dont_gc_arguments); ++ // we should set up register map ++ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); ++ } ++ break; ++ ++ case load_klass_patching_id: ++ { StubFrame f(sasm, "load_klass_patching", dont_gc_arguments); ++ // we should set up register map ++ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)); ++ } ++ break; ++ ++ case load_mirror_patching_id: ++ { StubFrame f(sasm, "load_mirror_patching", dont_gc_arguments); ++ // we should set up register map ++ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching)); ++ } ++ break; ++ ++ case load_appendix_patching_id: ++ { StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments); ++ // we should set up register map ++ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching)); ++ } ++ break; ++ ++ case handle_exception_nofpu_id: ++ case handle_exception_id: ++ { StubFrame f(sasm, "handle_exception", dont_gc_arguments); ++ oop_maps = generate_handle_exception(id, sasm); ++ } ++ break; ++ ++ case handle_exception_from_callee_id: ++ { StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments); ++ oop_maps = generate_handle_exception(id, sasm); ++ } ++ break; ++ ++ case throw_index_exception_id: ++ { StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments); ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true); ++ } ++ break; ++ ++ case throw_array_store_exception_id: ++ { StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments); ++ // tos + 0: link ++ // + 1: return address ++ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true); ++ } ++ break; ++ ++ case predicate_failed_trap_id: ++ { ++ StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments); ++ ++ OopMap* 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, map); ++ restore_live_registers(sasm); ++ __ leave(); ++ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); ++ assert(deopt_blob != NULL, "deoptimization blob must have been created"); ++ ++ __ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); ++ } ++ break; ++ ++ ++ default: ++ { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); ++ __ mov(i0, (int)id); ++ __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), i0); ++ __ should_not_reach_here(); ++ } ++ break; ++ } ++ } ++ return oop_maps; ++} ++ ++#undef __ ++ ++const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; } +diff -uNr openjdk/src/hotspot/cpu/sw64/c2_globals_sw64.hpp afu11u/src/hotspot/cpu/sw64/c2_globals_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/c2_globals_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c2_globals_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_C2_GLOBALS_SW64_HPP ++#define CPU_SW64_VM_C2_GLOBALS_SW64_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, UseTLAB, true); ++define_pd_global(bool, ResizeTLAB, 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, 3); ++define_pd_global(intx, FLOATPRESSURE, 64); ++define_pd_global(intx, FreqInlineSize, 325); ++define_pd_global(intx, MinJumpTableSize, 10); ++define_pd_global(intx, INTPRESSURE, 22); //TODO check (value 24 will cause compile skiped) ++define_pd_global(intx, InteriorEntryAlignment, 16); ++define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); ++define_pd_global(intx, LoopUnrollLimit, 60); ++define_pd_global(intx, LoopPercentProfileLimit, 10); ++// InitialCodeCacheSize derived from specjbb2000 run. ++define_pd_global(intx, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize ++define_pd_global(intx, CodeCacheExpansionSize, 64*K); ++ ++// Ergonomics related flags ++define_pd_global(uint64_t,MaxRAM, 128ULL*G); ++define_pd_global(intx, RegisterCostAreaRatio, 16000); ++ ++// 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, OptoScheduling, false); ++define_pd_global(bool, OptoBundling, false); ++define_pd_global(bool, OptoRegScheduling, false); ++define_pd_global(bool, SuperWordLoopUnrollAnalysis, true); ++define_pd_global(bool, IdealizeClearArrayNode, true); ++ ++define_pd_global(intx, ReservedCodeCacheSize, 240*M); ++define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); ++define_pd_global(intx, ProfiledCodeHeapSize, 22*M); ++define_pd_global(intx, NonNMethodCodeHeapSize, 5*M ); ++define_pd_global(uintx, CodeCacheMinBlockLength, 6); ++define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); ++ ++// Heap related flags ++define_pd_global(uintx,MetaspaceSize, ScaleForWordSize(16*M)); ++ ++// Ergonomics related flags ++define_pd_global(bool, NeverActAsServerClassMachine, false); ++ ++define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed. ++ ++#endif // CPU_SW64_VM_C2_GLOBALS_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/c2_init_sw64.cpp afu11u/src/hotspot/cpu/sw64/c2_init_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/c2_init_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/c2_init_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "opto/compile.hpp" ++#include "opto/node.hpp" ++ ++// processor dependent initialization for i486 ++ ++void Compile::pd_compiler2_init() { ++ guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" ); ++ // QQQ presumably all 64bit cpu's support this. Seems like the ifdef could ++ // simply be left out. ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/cas.m4 afu11u/src/hotspot/cpu/sw64/cas.m4 +--- openjdk/src/hotspot/cpu/sw64/cas.m4 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/cas.m4 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,142 @@ ++dnl Copyright (c) 2016, Red Hat Inc. All rights reserved. ++dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++dnl ++dnl This code is free software; you can redistribute it and/or modify it ++dnl under the terms of the GNU General Public License version 2 only, as ++dnl published by the Free Software Foundation. ++dnl ++dnl This code is distributed in the hope that it will be useful, but WITHOUT ++dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++dnl version 2 for more details (a copy is included in the LICENSE file that ++dnl accompanied this code). ++dnl ++dnl You should have received a copy of the GNU General Public License version ++dnl 2 along with this work; if not, write to the Free Software Foundation, ++dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++dnl ++dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++dnl or visit www.oracle.com if you need additional information or have any ++dnl questions. ++dnl ++dnl ++dnl Process this file with m4 cas.m4 to generate the CAE and wCAS ++dnl instructions used in sw64.ad. ++dnl ++ ++// BEGIN This section of the file is automatically generated. Do not edit -------------- ++ ++// Sundry CAS operations. Note that release is always true, ++// regardless of the memory ordering of the CAS. This is because we ++// need the volatile case to be sequentially consistent but there is ++// no trailing StoreLoad barrier emitted by C2. Unfortunately we ++// can't check the type of memory ordering here, so we always emit a ++// STLXR. ++ ++// This section is generated from sw64_ad_cas.m4 ++ ++ ++define(`CAS_INSN', ++` ++instruct compareAndExchange$1$5(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ++ match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); ++ ifelse($5,Acq,' predicate(needs_acquiring_load_exclusive(n)); ++ ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`) ++ effect(TEMP_DEF res, KILL cr); ++ format %{ ++ "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" ++ %} ++ ins_encode %{ ++ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, ++ Assembler::$4, /*acquire*/ ifelse($5,Acq,true,false), /*release*/ true, ++ /*weak*/ false, $res$$Register); ++ %} ++ ins_pipe(pipe_slow); ++%}')dnl ++define(`CAS_INSN4', ++` ++instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ++ match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); ++ ifelse($7,Acq,' predicate(needs_acquiring_load_exclusive(n)); ++ ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`) ++ effect(TEMP_DEF res, KILL cr); ++ format %{ ++ "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" ++ %} ++ ins_encode %{ ++ __ $5(rscratch2, $oldval$$Register); ++ __ cmpxchg($mem$$Register, rscratch2, $newval$$Register, ++ Assembler::$4, /*acquire*/ ifelse($5,Acq,true,false), /*release*/ true, ++ /*weak*/ false, $res$$Register); ++ __ $6($res$$Register, $res$$Register); ++ %} ++ ins_pipe(pipe_slow); ++%}')dnl ++CAS_INSN4(B,I,byte,byte,uxtbw,sxtbw) ++CAS_INSN4(S,I,short,halfword,uxthw,sxthw) ++CAS_INSN(I,I,int,word) ++CAS_INSN(L,L,long,xword) ++CAS_INSN(N,N,narrow oop,word) ++CAS_INSN(P,P,ptr,xword) ++dnl ++dnl CAS_INSN4(B,I,byte,byte,uxtbw,sxtbw,Acq) ++dnl CAS_INSN4(S,I,short,halfword,uxthw,sxthw,Acq) ++dnl CAS_INSN(I,I,int,word,Acq) ++dnl CAS_INSN(L,L,long,xword,Acq) ++dnl CAS_INSN(N,N,narrow oop,word,Acq) ++dnl CAS_INSN(P,P,ptr,xword,Acq) ++dnl ++define(`CAS_INSN2', ++` ++instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ++ match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval))); ++ ifelse($6,Acq,' predicate(needs_acquiring_load_exclusive(n)); ++ ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`) ++ effect(KILL cr); ++ format %{ ++ "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" ++ "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" ++ %} ++ ins_encode %{ ++ __ uxt$5(rscratch2, $oldval$$Register); ++ __ cmpxchg($mem$$Register, rscratch2, $newval$$Register, ++ Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, ++ /*weak*/ true, noreg); ++ __ csetw($res$$Register, Assembler::EQ); ++ %} ++ ins_pipe(pipe_slow); ++%}')dnl ++define(`CAS_INSN3', ++` ++instruct weakCompareAndSwap$1$5(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ++ match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval))); ++ ifelse($5,Acq,' predicate(needs_acquiring_load_exclusive(n)); ++ ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`) ++ effect(KILL cr); ++ format %{ ++ "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" ++ "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" ++ %} ++ ins_encode %{ ++ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, ++ Assembler::$4, /*acquire*/ ifelse($5,Acq,true,false), /*release*/ true, ++ /*weak*/ true, noreg); ++ __ csetw($res$$Register, Assembler::EQ); ++ %} ++ ins_pipe(pipe_slow); ++%}')dnl ++CAS_INSN2(B,I,byte,byte,bw) ++CAS_INSN2(S,I,short,halfword,hw) ++CAS_INSN3(I,I,int,word) ++CAS_INSN3(L,L,long,xword) ++CAS_INSN3(N,N,narrow oop,word) ++CAS_INSN3(P,P,ptr,xword) ++dnl CAS_INSN2(B,I,byte,byte,bw,Acq) ++dnl CAS_INSN2(S,I,short,halfword,hw,Acq) ++dnl CAS_INSN3(I,I,int,word,Acq) ++dnl CAS_INSN3(L,L,long,xword,Acq) ++dnl CAS_INSN3(N,N,narrow oop,word,Acq) ++dnl CAS_INSN3(P,P,ptr,xword,Acq) ++dnl ++ ++// END This section of the file is automatically generated. Do not edit -------------- +diff -uNr openjdk/src/hotspot/cpu/sw64/codeBuffer_sw64.hpp afu11u/src/hotspot/cpu/sw64/codeBuffer_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/codeBuffer_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/codeBuffer_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_CODEBUFFER_SW64_HPP ++#define CPU_SW64_VM_CODEBUFFER_SW64_HPP ++ ++private: ++ void pd_initialize() {} ++ ++public: ++ void flush_bundle(bool start_new_bundle) {} ++ ++#endif // CPU_SW64_VM_CODEBUFFER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/compiledIC_aot_sw64.cpp afu11u/src/hotspot/cpu/sw64/compiledIC_aot_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/compiledIC_aot_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/compiledIC_aot_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include "aot/compiledIC_aot.hpp" ++#include "code/codeCache.hpp" ++#include "memory/resourceArea.hpp" ++ ++void CompiledDirectStaticCall::set_to_far(const methodHandle& callee, address entry) { ++ if (TraceICs) { ++ ResourceMark rm; ++ tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_far %s", ++ p2i(instruction_address()), ++ callee->name_and_sig_as_C_string()); ++ } ++ ++ set_destination_mt_safe(entry); ++} ++ ++void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { ++ address stub = find_stub(); ++ guarantee(stub != NULL, "stub not found"); ++ if (TraceICs) { ++ ResourceMark rm; ++ tty->print_cr("CompiledPltStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", ++ p2i(instruction_address()), ++ callee->name_and_sig_as_C_string()); ++ } ++ ++ // Creation also verifies the object. ++ NativeLoadGot* method_loader = nativeLoadGot_at(stub); ++ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address()); ++ ++ intptr_t data = method_loader->data(); ++ address destination = jump->destination(); ++ assert(data == 0 || data == (intptr_t)callee(), ++ "a) MT-unsafe modification of inline cache"); ++ assert(destination == (address)Universe::non_oop_word() ++ || destination == entry, ++ "b) MT-unsafe modification of inline cache"); ++ ++ // Update stub. ++ method_loader->set_data((intptr_t)callee()); ++ jump->set_jump_destination(entry); ++ ++ // Update jump to call. ++ set_destination_mt_safe(stub); ++} ++ ++#ifdef NEVER_CALLED ++void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { ++ assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call"); ++ // Reset stub. ++ address stub = static_stub->addr(); ++ assert(stub != NULL, "stub not found"); ++ // Creation also verifies the object. ++ NativeLoadGot* method_loader = nativeLoadGot_at(stub); ++ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address()); ++ method_loader->set_data(0); ++ jump->set_jump_destination((address)-1); ++} ++#endif ++ ++#ifndef PRODUCT ++void CompiledPltStaticCall::verify() { ++ // Verify call. ++ _call->verify(); ++ ++#ifdef ASSERT ++ CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call); ++ assert(cb && cb->is_aot(), "CompiledPltStaticCall can only be used on AOTCompiledMethod"); ++#endif ++ ++ // Verify stub. ++ address stub = find_stub(); ++ assert(stub != NULL, "no stub found for static call"); ++ // Creation also verifies the object. ++ NativeLoadGot* method_loader = nativeLoadGot_at(stub); ++ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address()); ++ // Verify state. ++ assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); ++} ++#endif // !PRODUCT +diff -uNr openjdk/src/hotspot/cpu/sw64/compiledIC_sw64.cpp afu11u/src/hotspot/cpu/sw64/compiledIC_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/compiledIC_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/compiledIC_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,222 @@ ++/* ++ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "code/codeCache.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" ++ ++// ---------------------------------------------------------------------------- ++ ++#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. ++ // movq rbx, 0 ++ // jmp -5 # to self ++ Register rbx = rmethod; ++ ++ if (mark == NULL) { ++ mark = cbuf.insts_mark(); // Get mark within main instrs section. ++ } ++ ++ // Note that the code buffer's insts_mark is always relative to insts. ++ // That's why we must use the macroassembler to generate a stub. ++ MacroAssembler _masm(&cbuf); ++ //__ stop("emit_to_interp_stub :not check jzy"); ++ 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, false)); ++ // Static stub relocation also tags the Method* in the code-stream. ++ //__ movl(rbx, R0); // Method is zapped till fixup time. ++ __ prepare_patch_li48(rbx, 0); ++ ++ // This is recognized as unresolved by relocs/nativeinst/ic code. ++ __ relocate(relocInfo::runtime_call_type); ++ cbuf.set_insts_mark(); ++ address call_pc = (address)-1; ++ __ patchable_jump(call_pc); ++ __ align(16); ++ ++ assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); ++ ++ // Update current stubs pointer and restore insts_end. ++ __ end_a_stub(); ++ return base; ++} ++#undef __ ++ ++int CompiledStaticCall::to_interp_stub_size() {//TODO:check jzy ++ int size = 4 * 4 + NativeCall::instruction_size; // sizeof(prepare_patch_li48) + NativeCall::instruction_size ++ return round_to(size, 16); ++} ++ ++int CompiledStaticCall::to_trampoline_stub_size() {//Unimplemented(); ++ // x86 doesn't use trampolines. ++ return 0; ++} ++ ++// Relocation entries for call stub, compiled java to interpreter. ++int CompiledStaticCall::reloc_to_interp_stub() {//Unimplemented(); ++ return 16; // todo:not check jzy ++} ++ ++#if INCLUDE_AOT ++#define __ _masm. ++void CompiledStaticCall::emit_to_aot_stub(CodeBuffer &cbuf, address mark) {Unimplemented(); ++ if (!UseAOT) { ++ return; ++ } ++ // Stub is fixed up when the corresponding call is converted from ++ // calling compiled code to calling aot code. ++ // movq rax, imm64_aot_code_address ++ // jmp rax ++ ++ if (mark == NULL) { ++ mark = cbuf.insts_mark(); // Get mark within main instrs section. ++ } ++ ++ // Note that the code buffer's insts_mark is always relative to insts. ++ // That's why we must use the macroassembler to generate a stub. ++ MacroAssembler _masm(&cbuf); ++ ++ address base = ++ __ start_a_stub(to_aot_stub_size()); ++ guarantee(base != NULL, "out of space"); ++ ++ // Static stub relocation stores the instruction address of the call. ++ __ relocate(static_stub_Relocation::spec(mark, true /* is_aot */), Assembler::imm_operand); ++ // Load destination AOT code address. ++ __ movl(rscratch1, R0); // address is zapped till fixup time. ++ // This is recognized as unresolved by relocs/nativeinst/ic code. ++ __ jmp(rscratch1); ++ ++ assert(__ pc() - base <= to_aot_stub_size(), "wrong stub size"); ++ ++ // Update current stubs pointer and restore insts_end. ++ __ end_a_stub(); ++} ++#undef __ ++ ++int CompiledStaticCall::to_aot_stub_size() {Unimplemented(); ++ if (UseAOT) { ++ return 12; // ++ } else { ++ return 0; ++ } ++} ++ ++// Relocation entries for call stub, compiled java to aot. ++int CompiledStaticCall::reloc_to_aot_stub() {Unimplemented(); ++ if (UseAOT) { ++ return 2; // 1 in emit_to_aot_stub + 1 in emit_call ++ } else { ++ return 0; ++ } ++} ++#endif // INCLUDE_AOT ++ ++void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { ++ address stub = find_stub(false /* is_aot */); ++ 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()); ++ ++#ifdef ASSERT ++ // read the value once ++ volatile intptr_t data = method_holder->data(); ++ volatile address destination = jump->jump_destination(); ++ assert(data == 0 || data == (intptr_t)callee(), ++ "a) MT-unsafe modification of inline cache"); ++ assert(destination == (address)-1 || destination == entry, ++ "b) MT-unsafe modification of inline cache"); ++#endif ++ ++ // 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) { ++ assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call"); ++ // Reset stub. ++ address stub = static_stub->addr(); ++ assert(stub != NULL, "stub not found"); ++ // Creation also verifies the object. ++ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); ++ method_holder->set_data(0); ++ if (!static_stub->is_aot()) { ++ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); ++ jump->set_jump_destination((address)-1); ++ } ++} ++ ++ ++//----------------------------------------------------------------------------- ++// Non-product mode code ++#ifndef PRODUCT ++ ++void CompiledDirectStaticCall::verify() { ++ // Verify call. ++ _call->verify(); ++ if (os::is_MP()) { ++ _call->verify_alignment(); ++ } ++ ++#ifdef ASSERT ++ CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call); ++ assert(cb && !cb->is_aot(), "CompiledDirectStaticCall cannot be used on AOTCompiledMethod"); ++#endif ++ ++ // Verify stub. ++ address stub = find_stub(false /* is_aot */); ++ 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 -uNr openjdk/src/hotspot/cpu/sw64/copy_sw64.hpp afu11u/src/hotspot/cpu/sw64/copy_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/copy_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/copy_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_COPY_SW64_HPP ++#define CPU_SW64_VM_COPY_SW64_HPP ++ ++// Inline functions for memory copy and fill. ++ ++// Contains inline asm implementations ++#include OS_CPU_HEADER_INLINE(copy) ++ ++ ++static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) { ++ julong* to = (julong*) tohw; ++ julong v = ((julong) value << 32) | value; ++ while (count-- > 0) { ++ *to++ = v; ++ } ++} ++ ++static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) { ++ pd_fill_to_words(tohw, count, 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_SW64_VM_COPY_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/depChecker_sw64.cpp afu11u/src/hotspot/cpu/sw64/depChecker_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/depChecker_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/depChecker_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "compiler/disassembler.hpp" ++#include "depChecker_sw64.hpp" ++ ++// Nothing to do on sw64 +diff -uNr openjdk/src/hotspot/cpu/sw64/depChecker_sw64.hpp afu11u/src/hotspot/cpu/sw64/depChecker_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/depChecker_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/depChecker_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_DEPCHECKER_SW64_HPP ++#define CPU_SW64_VM_DEPCHECKER_SW64_HPP ++ ++// Nothing to do on sw64 ++ ++#endif // CPU_SW64_VM_DEPCHECKER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/disassembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/disassembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/disassembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/disassembler_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_DISASSEMBLER_SW64_HPP ++#define CPU_SW64_VM_DISASSEMBLER_SW64_HPP ++ ++ static int pd_instruction_alignment() { ++ return sizeof(int); ++ } ++ ++ static const char* pd_cpu_opts() { ++ return "sw64only"; ++ } ++ ++#endif // CPU_SW64_VM_DISASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/frame_sw64.cpp afu11u/src/hotspot/cpu/sw64/frame_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/frame_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/frame_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,808 @@ ++/* ++ * 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 "interpreter/interpreter.hpp" ++#include "memory/resourceArea.hpp" ++#include "oops/markOop.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/os.inline.hpp" ++#include "runtime/signature.hpp" ++#include "runtime/stubCodeGenerator.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "vmreg_sw64.inline.hpp" ++#ifdef COMPILER1 ++#include "c1/c1_Runtime1.hpp" ++#include "runtime/vframeArray.hpp" ++#endif ++ ++#ifdef ASSERT ++void RegisterMap::check_location_valid() { ++} ++#endif ++ ++// Profiling/safepoint support ++ ++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 ++ static size_t stack_guard_size = os::uses_stack_guard_pages() ? ++ JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size() : 0; ++ size_t usable_stack_size = thread->stack_size() - stack_guard_size; ++ ++ // sp must be within the usable part of the stack (not in guards) ++ bool sp_safe = (sp < thread->stack_base()) && ++ (sp >= thread->stack_base() - usable_stack_size); ++ ++ ++ if (!sp_safe) { ++ return false; ++ } ++ ++ // unextended sp must be within the stack and above or equal sp ++ bool unextended_sp_safe = (unextended_sp < thread->stack_base()) && ++ (unextended_sp >= sp); ++ ++ if (!unextended_sp_safe) { ++ return false; ++ } ++ ++ // an fp must be within the stack and above (but not equal) sp ++ // second evaluation on fp+ is added to handle situation where fp is -1 ++ bool fp_safe = ((fp!=NULL) && fp < thread->stack_base() && (fp >= sp) && (((fp + (return_addr_offset * sizeof(void*))) < thread->stack_base()))); ++ ++ // 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* sender_sp = NULL; ++ intptr_t* sender_unextended_sp = NULL; ++ address sender_pc = NULL; ++ intptr_t* saved_fp = NULL; ++ ++ if (is_interpreted_frame()) { ++ // fp must be safe ++ if (!fp_safe) { ++ return false; ++ } ++ ++ sender_pc = (address) this->fp()[return_addr_offset]; ++ // for interpreted frames, the value below is the sender "raw" sp, ++ // which can be different from the sender unextended sp (the sp seen ++ // by the sender) because of current frame local variables ++ sender_sp = (intptr_t*) addr_at(sender_sp_offset); ++ sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset]; ++ saved_fp = (intptr_t*) this->fp()[link_offset]; ++ ++ } else { ++ // must be some sort of compiled/runtime frame ++ // fp does not have to be safe (although it could be check for c1?) ++ ++ // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc ++ if (_cb->frame_size() <= 0) { ++ return false; ++} ++ ++ sender_sp = _unextended_sp + _cb->frame_size(); ++ // Is sender_sp safe? ++ if ((address)sender_sp >= thread->stack_base()) { ++ return false; ++ } ++ sender_unextended_sp = sender_sp; ++ // On Intel the return_address is always the word on the stack ++ sender_pc = (address) *(sender_sp-1); ++ // Note: frame::sender_sp_offset is only valid for compiled frame ++ saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset); ++ } ++ ++ ++ // If the potential sender is the interpreter then we can do some more checking ++ if (Interpreter::contains(sender_pc)) { ++ ++ // ebp is always saved in a recognizable place in any code we generate. However ++ // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved ebp ++ // is really a frame pointer. ++ ++ bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp); ++ ++ if (!saved_fp_safe) { ++ return false; ++ } ++ ++ // construct the potential sender ++ ++ frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); ++ ++ return sender.is_interpreted_frame_valid(thread); ++ ++ } ++ ++ // 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; ++ } ++ ++ // Could just be some random pointer within the codeBlob ++ if (!sender_blob->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; ++ } ++ ++ // Could be the call_stub ++ if (StubRoutines::returns_to_call_stub(sender_pc)) { ++ bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp); ++ ++ if (!saved_fp_safe) { ++ return false; ++ } ++ ++ // construct the potential sender ++ ++ frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); ++ ++ // Validate the JavaCallWrapper an entry frame must have ++ address jcw = (address)sender.entry_frame_call_wrapper(); ++ ++ bool jcw_safe = (jcw < thread->stack_base()) && (jcw > (address)sender.fp()); ++ ++ return jcw_safe; ++ } ++ ++ CompiledMethod* nm = sender_blob->as_compiled_method_or_null(); ++ if (nm != NULL) { ++ if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || ++ nm->method()->is_method_handle_intrinsic()) { ++ return false; ++ } ++ } ++ ++ // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size ++ // because the return address counts against the callee's frame. ++ ++ if (sender_blob->frame_size() <= 0) { ++ assert(!sender_blob->is_compiled(), "should count return address at least"); ++ return false; ++ } ++ ++ // We should never be able to see anything here except an nmethod. If something in the ++ // code cache (current frame) is called by an entity within the code cache that entity ++ // should not be anything but the call stub (already covered), the interpreter (already covered) ++ // or an nmethod. ++ ++ 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; ++ } ++ ++ // Will the pc we fetch be non-zero (which we'll find at the oldest frame) ++ ++ if ( (address) this->fp()[return_addr_offset] == NULL) return false; ++ ++ ++ // could try and do some more potential verification of native frame if we could think of some... ++ ++ return true; ++ ++} ++ ++ ++void frame::patch_pc(Thread* thread, address pc) { ++ address* pc_addr = &(((address*) sp())[-1]); ++ if (TracePcPatching) { ++ tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", ++ p2i(pc_addr), p2i(*pc_addr), p2i(pc)); ++ } ++ // Either the return address is the original one or we are going to ++ // patch in the same address that's already there. ++ assert(_pc == *pc_addr || pc == *pc_addr, "must be"); ++ *pc_addr = pc; ++ _cb = CodeCache::find_blob(pc); ++ address original_pc = CompiledMethod::get_deopt_original_pc(this); ++ if (original_pc != NULL) { ++ assert(original_pc == _pc, "expected original PC to be stored before patching"); ++ _deopt_state = is_deoptimized; ++ // leave _pc as is ++ } else { ++ _deopt_state = not_deoptimized; ++ _pc = pc; ++ } ++} ++ ++bool frame::is_interpreted_frame() const { ++ return Interpreter::contains(pc()); ++} ++ ++int frame::frame_size(RegisterMap* map) const { ++ frame sender = this->sender(map); ++ return sender.sp() - 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); ++ // Entry frame's arguments are always in relation to unextended_sp() ++ return &unextended_sp()[index]; ++} ++ ++// sender_sp ++ ++intptr_t* frame::interpreter_frame_sender_sp() const { ++ assert(is_interpreted_frame(), "interpreted frame expected"); ++ return (intptr_t*) at(interpreter_frame_sender_sp_offset); ++} ++ ++void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) { ++ assert(is_interpreted_frame(), "interpreted frame expected"); ++ ptr_at_put(interpreter_frame_sender_sp_offset, (intptr_t) sender_sp); ++} ++ ++ ++// monitor elements ++ ++BasicObjectLock* frame::interpreter_frame_monitor_begin() const { ++ return (BasicObjectLock*) addr_at(interpreter_frame_monitor_block_bottom_offset); ++} ++ ++BasicObjectLock* frame::interpreter_frame_monitor_end() const { ++ BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset); ++ // make sure the pointer points inside the frame ++ assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer"); ++ assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer"); ++ return result; ++} ++ ++void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) { ++ *((BasicObjectLock**)addr_at(interpreter_frame_monitor_block_top_offset)) = value; ++} ++ ++// Used by template based interpreter deoptimization ++void frame::interpreter_frame_set_last_sp(intptr_t* sp) { ++ *((intptr_t**)addr_at(interpreter_frame_last_sp_offset)) = sp; ++} ++ ++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"); ++ // 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(); ++ } ++ map->clear(); ++ assert(map->include_argument_oops(), "should be set by clear"); ++ vmassert(jfa->last_Java_pc() != NULL, "not walkable"); ++ frame fr(jfa->last_Java_sp(), jfa->last_Java_fp(), jfa->last_Java_pc()); ++ return fr; ++ } ++ ++//------------------------------------------------------------------------------ ++// frame::verify_deopt_original_pc ++// ++// Verifies the calculated original PC of a deoptimization PC for the ++// given unextended SP. ++#ifdef ASSERT ++void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) { ++ frame fr; ++ ++ // This is ugly but it's better than to change {get,set}_original_pc ++ // to take an SP value as argument. And it's only a debugging ++ // method anyway. ++ fr._unextended_sp = unextended_sp; ++ ++ address original_pc = nm->get_original_pc(&fr); ++ assert(nm->insts_contains_inclusive(original_pc), ++ "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); ++} ++#endif ++ ++//------------------------------------------------------------------------------ ++// frame::adjust_unextended_sp ++#ifdef ASSERT ++void frame::adjust_unextended_sp() { ++ // On sw64, sites calling method handle intrinsics and lambda forms are treated ++ // as any other call site. Therefore, no special action is needed when we are ++ // returning to any of these call sites. ++ ++ if (_cb != NULL) { ++ CompiledMethod* sender_cm = _cb->as_compiled_method_or_null(); ++ if (sender_cm != NULL) { ++ // If the sender PC is a deoptimization point, get the original PC. ++ if (sender_cm->is_deopt_entry(_pc) || ++ sender_cm->is_deopt_mh_entry(_pc)) { ++ verify_deopt_original_pc(sender_cm, _unextended_sp); ++ } ++ } ++ } ++} ++#endif ++ ++//------------------------------------------------------------------------------ ++// frame::update_map_with_saved_link ++void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) { ++ // The interpreter and compiler(s) always save EBP/RBP in a known ++ // location on entry. We must record where that location is ++ // so this if EBP/RBP was live on callout from c2 we can find ++ // the saved copy no matter what it called. ++ ++ // Since the interpreter always saves EBP/RBP if we record where it is then ++ // we don't have to always save EBP/RBP on entry and exit to c2 compiled ++ // code, on entry will be enough. ++ map->set_location(rfp->as_VMReg(), (address) link_addr); ++ ++ // this is weird "H" ought to be at a higher address however the ++ // oopMaps seems to have the "H" regs at the same address and the ++ // vanilla register. ++ // XXXX make this go away ++ if (true) { ++ map->set_location(rfp->as_VMReg()->next(), (address) link_addr); ++ } ++ ++} ++ ++ ++//------------------------------------------------------------------------------ ++// frame::sender_for_interpreter_frame ++frame frame::sender_for_interpreter_frame(RegisterMap* map) const { ++ // SP is the raw SP from the sender after adapter or interpreter ++ // extension. ++ intptr_t* sender_sp = this->sender_sp(); ++ ++ // This is the sp before any possible extension (adapter/locals). ++ intptr_t* unextended_sp = interpreter_frame_sender_sp(); ++ ++#if COMPILER2_OR_JVMCI ++ if (map->update_map()) { ++ update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); ++ } ++#endif // COMPILER2_OR_JVMCI ++ ++ return frame(sender_sp, unextended_sp, link(), sender_pc()); ++} ++ ++ ++//------------------------------------------------------------------------------ ++// frame::sender_for_compiled_frame ++frame frame::sender_for_compiled_frame(RegisterMap* map) const { ++ assert(map != NULL, "map must be set"); ++ ++ // frame owned by optimizing compiler ++ assert(_cb->frame_size() >= 0, "must have non-zero frame size"); ++ intptr_t* sender_sp = unextended_sp() + _cb->frame_size(); ++ intptr_t* unextended_sp = sender_sp; ++ ++ // On Intel the return_address is always the word on the stack ++ address sender_pc = (address) *(sender_sp-1); ++ ++ // This is the saved value of EBP which may or may not really be an FP. ++ // It is only an FP if the sender is an interpreter frame (or C1?). ++ intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset); ++ ++ 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); ++ } ++ ++ // Since the prolog does the save and restore of EBP there is no oopmap ++ // for it so we must fill in its location as if there was an oopmap entry ++ // since if our caller was compiled code there could be live jvm state in it. ++ update_map_with_saved_link(map, saved_fp_addr); ++ } ++ ++ assert(sender_sp != sp(), "must have changed"); ++ return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc); ++} ++ ++ ++//------------------------------------------------------------------------------ ++// frame::sender ++frame frame::sender(RegisterMap* map) const { ++ // Default is we done have to follow them. The sender_for_xxx will ++ // update it accordingly ++ map->set_include_argument_oops(false); ++ ++ if (is_entry_frame()) return sender_for_entry_frame(map); ++ if (is_interpreted_frame()) return sender_for_interpreter_frame(map); ++ assert(_cb == CodeCache::find_blob(pc()),"Must be the same"); ++ ++ if (_cb != NULL) { ++ return sender_for_compiled_frame(map); ++ } ++ // Must be native-compiled frame, i.e. the marshaling code for native ++ // methods that exists in the core system. ++ return frame(sender_sp(), link(), sender_pc()); ++} ++ ++bool frame::is_interpreted_frame_valid(JavaThread* thread) const { ++ assert(is_interpreted_frame(), "Not an interpreted frame"); ++ // These are reasonable sanity checks ++ if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { ++ return false; ++ } ++ if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) { ++ return false; ++ } ++ 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 ++ // this test requires the use the unextended_sp which is the sp as seen by ++ // the current frame, and not sp which is the "raw" pc which could point ++ // further because of local variables of the callee method inserted after ++ // method arguments ++ 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(); ++ ++ if (locals > thread->stack_base() || locals < (address) fp()) return false; ++ ++ // We'd have to be pretty unlucky to be mislead at this point ++ return true; ++} ++ ++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(); ++ ++ intptr_t* tos_addr; ++ if (method->is_native()) { ++ // Prior to calling into the runtime to report the method_exit the possible ++ // return value is pushed to the native stack. If the result is a jfloat/jdouble ++ // then ST0 is saved before EAX/EDX. See the note in generate_native_result ++ tos_addr = (intptr_t*)sp(); ++ if (type == T_FLOAT || type == T_DOUBLE) { ++ // QQQ seems like this code is equivalent on the two platforms ++ // This is times two because we do a push(ltos) after pushing XMM0 ++ // and that takes two interpreter stack slots. ++ tos_addr += 2 * Interpreter::stackElementWords; ++ } ++ } else { ++ tos_addr = (intptr_t*)interpreter_frame_tos_address(); ++ } ++ ++ switch (type) { ++ case T_OBJECT : ++ case T_ARRAY : { ++ oop obj; ++ if (method->is_native()) { ++ obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); ++ } else { ++ oop* obj_p = (oop*)tos_addr; ++ obj = (obj_p == NULL) ? (oop)NULL : *obj_p; ++ } ++ assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); ++ *oop_result = obj; ++ break; ++ } ++ case T_BOOLEAN : value_result->z = *(jboolean*)tos_addr; break; ++ case T_BYTE : value_result->b = *(jbyte*)tos_addr; break; ++ case T_CHAR : value_result->c = *(jchar*)tos_addr; break; ++ case T_SHORT : value_result->s = *(jshort*)tos_addr; 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; ++// yj not sure ++// case T_FLOAT : { ++// if (method->is_native()) { ++// jdouble d = *(jdouble*)tos_addr; // Result was in ST0 so need to convert to jfloat ++// value_result->f = (jfloat)d; ++// } else { ++// 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; ++} ++ ++ ++intptr_t* frame::interpreter_frame_tos_at(jint offset) const { ++ int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize); ++ 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) { ++ if (is_interpreted_frame()) { ++ DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp); ++ DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); ++ DESCRIBE_FP_OFFSET(interpreter_frame_method); ++ DESCRIBE_FP_OFFSET(interpreter_frame_mirror); ++ DESCRIBE_FP_OFFSET(interpreter_frame_mdp); ++ DESCRIBE_FP_OFFSET(interpreter_frame_cache); ++ DESCRIBE_FP_OFFSET(interpreter_frame_locals); ++ DESCRIBE_FP_OFFSET(interpreter_frame_bcp); ++ DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); ++ } else if (is_entry_frame()) { ++ // This could be more descriptive if we use the enum in ++ // stubGenerator to map to real names but it's most important to ++ // claim these frame slots so the error checking works. ++ for (int i = 0; i < entry_frame_after_call_words; i++) { ++ values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i)); ++ } ++ } ++} ++#endif // !PRODUCT ++ ++intptr_t *frame::initial_deoptimization_info() { ++ // used to reset the saved FP ++ return fp(); ++} ++ ++intptr_t* frame::real_fp() const { ++ if (_cb != NULL) { ++ // use the frame size if valid ++ int size = _cb->frame_size(); ++ if (size > 0) { ++ return unextended_sp() + size; ++ } ++ } ++ // else rely on fp() ++ assert(! is_compiled_frame(), "unknown compiled frame size"); ++ return fp(); ++} ++ ++void frame::init(intptr_t* sp, intptr_t* fp, address pc) { ++ assert(pc != NULL, "no pc?"); ++ _cb = CodeCache::find_blob(pc); ++ if (sp == NULL && _cb != NULL) { ++ sp = fp - _cb->frame_size() + 2; ++ } ++ _sp = sp; ++ _unextended_sp = sp; ++ _fp = fp; ++ _pc = pc; ++ ++ adjust_unextended_sp(); ++ ++ 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; ++ } ++ ++ _is_c_frame = false; ++ _sender_fp_for_c_frame = NULL; ++ _sender_address_for_c_frame = NULL; ++ init_sender_for_c_frame(); ++} ++// if this C frame is not leaf function,will be initial sender sf/fp at here ++// if not should initial sender sf/fp with context ++void frame::init_sender_for_c_frame() { ++ if (is_java_frame() || ++ is_native_frame() || ++ is_runtime_frame() || ++ is_stub_frame()) { ++ _is_c_frame = false; ++ return; ++ } ++ _is_c_frame = true; ++ if (_fp == NULL) return; ++ bool stop_flag = false; ++ address pinsn = _pc ; ++ while ((_sender_fp_for_c_frame == NULL || _sender_address_for_c_frame == NULL) && (*((int *) pinsn)) && !stop_flag) { ++ int insn = *((int *) pinsn); ++ if (_sender_fp_for_c_frame == NULL && (insn & 0xffff0000) == 0xadfe0000) { // stl fp,yy(sp) ++ int yy = (insn & 0x0000ffff) / 8; ++ _sender_fp_for_c_frame = (intptr_t *) (*(_fp + yy)); ++ } else if ( _sender_address_for_c_frame == NULL && (insn & 0xffff0000) == 0xaf5e0000) { // stl ra,xx(sp) ++ int xx = (insn & 0x0000ffff) / 8; ++ _sender_address_for_c_frame = (address) (*(_fp + xx)); ++ } else if ((insn & 0xffff0000) == 0xffbb0000){ // ldih gp,zz(t12) ++ stop_flag = true; ++ } ++ pinsn -= 4; ++ // scan function to _pc ++ } ++//} ++} ++ ++void frame::init_sender_for_c_frame(address f_start_pc) { ++ do { ++ int insn = *((int *) f_start_pc); ++ if ( _sender_address_for_c_frame == NULL && (insn & 0xffff0000) == 0xaf5e0000) { // stl ra,xx(sp) ++ int xx = (insn & 0x0000ffff) / 8; ++ _sender_address_for_c_frame = (address) (*(_sp + xx)); ++ } else if (_sender_fp_for_c_frame == NULL && (insn & 0xffff0000) == 0xadfe0000) { // stl fp,yy(sp) ++ int yy = (insn & 0x0000ffff) / 8; ++ _sender_fp_for_c_frame = (intptr_t *) (*(_sp + yy)); ++ } ++ f_start_pc += 4; ++ // scan function to _pc ++ } while ((_sender_fp_for_c_frame == NULL || _sender_address_for_c_frame == NULL) && (*((int *) f_start_pc))); ++} ++ ++// when thread stop before stl ra at stack ++void frame::fixRa(const void* ucVoid) { ++ if (!_is_c_frame) return; ++ if (_sender_address_for_c_frame != NULL) { ++ return; ++ } else { ++ const ucontext_t *uc = (const ucontext_t *) ucVoid; ++ if (uc != NULL) { ++ _sender_address_for_c_frame = os::ucontext_get_ra(uc); ++ } else { ++ _sender_address_for_c_frame = NULL; ++ } ++ } ++} ++ ++intptr_t* frame::sender_sp() const { ++ if (_is_c_frame) { ++ return _sender_fp_for_c_frame;// for sw C frame, sp is always the same as fp ++ } else { ++ return addr_at(sender_sp_offset); ++ } ++} ++ ++intptr_t* frame::link() const { ++ if (_is_c_frame) ++ return _sender_fp_for_c_frame; ++ else ++ return (intptr_t*) *(intptr_t **)addr_at(link_offset); ++} ++ ++address frame::sender_pc() const { ++ if (_is_c_frame) ++ return _sender_address_for_c_frame; ++ else { ++ return *sender_pc_addr(); ++ } ++} ++ ++#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, (intptr_t*)fp, (address)pc); ++} ++ ++void frame::pd_ps() {} ++#endif ++ ++void JavaFrameAnchor::make_walkable(JavaThread* thread) { ++ //tty->print_cr("to check here: yj"); ++ // last frame set? ++ if (last_Java_sp() == NULL) return; ++ // already walkable? ++ if (walkable()) return;//assert(false, "to check here: yj"); ++ vmassert(Thread::current() == (Thread*)thread, "not current thread"); ++ vmassert(last_Java_sp() != NULL, "not called from Java code?"); ++ vmassert(last_Java_pc() == NULL, "already walkable"); ++ capture_last_Java_pc(); ++ vmassert(walkable(), "something went wrong"); ++} ++ ++void JavaFrameAnchor::capture_last_Java_pc() { ++ vmassert(_last_Java_sp != NULL, "no last frame set"); ++ vmassert(_last_Java_pc == NULL, "already walkable"); ++ _last_Java_pc = (address)_last_Java_sp[-1]; ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/frame_sw64.hpp afu11u/src/hotspot/cpu/sw64/frame_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/frame_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/frame_sw64.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,160 @@ ++/* ++ * 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. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_FRAME_SW64_HPP ++#define CPU_SW64_VM_FRAME_SW64_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, fp, sp} ++// ------------------------------ Asm interpreter ---------------------------------------- ++// Layout of asm interpreter frame: ++// [expression stack ] * <- sp ++// [monitors ] \ ++// ... | monitor block size ++// [monitors ] / ++// [monitor block size ] ++// [byte code pointer ] = bcp() bcp_offset ++// [pointer to locals ] = locals() locals_offset ++// [constant pool cache ] = cache() cache_offset ++// [methodData ] = mdp() mdx_offset ++// [Method* ] = method() method_offset ++// [last sp ] = last_sp() last_sp_offset ++// [old stack pointer ] (sender_sp) sender_sp_offset ++// [old frame pointer ] <- fp = link() ++// [return pc ] ++// [oop temp ] (only for native calls) ++// [locals and parameters ] ++// <- sender sp ++// ------------------------------ Asm interpreter ---------------------------------------- ++ ++ public: ++ enum { ++ pc_return_offset = 0, ++ // All frames ++ link_offset = 0, ++ return_addr_offset = 1, ++ // non-interpreter frames ++ sender_sp_offset = 2, ++ ++ // Interpreter frames ++ interpreter_frame_result_handler_offset = 3, // for native calls only ++ interpreter_frame_oop_temp_offset = 2, // for native calls only ++ ++ interpreter_frame_sender_sp_offset = -1, ++ // outgoing sp before a call to an invoked method ++ interpreter_frame_last_sp_offset = interpreter_frame_sender_sp_offset - 1, ++ interpreter_frame_method_offset = interpreter_frame_last_sp_offset - 1, ++ interpreter_frame_mirror_offset = interpreter_frame_method_offset - 1, ++ interpreter_frame_mdp_offset = interpreter_frame_mirror_offset - 1, ++ interpreter_frame_cache_offset = interpreter_frame_mdp_offset - 1, ++ interpreter_frame_locals_offset = interpreter_frame_cache_offset - 1, ++ interpreter_frame_bcp_offset = interpreter_frame_locals_offset - 1, ++ interpreter_frame_initial_sp_offset = interpreter_frame_bcp_offset - 1, ++ ++ interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset, ++ interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset, ++ ++ // Entry frames ++ // n.b. these values are determined by the layout defined in ++ // stubGenerator for the Java call stub ++ entry_frame_after_call_words = 21, ++ entry_frame_call_wrapper_offset = -6, //generate_call_stub's call_wrapper_off ++ ++ arg_reg_save_area_bytes = 0 ++ }; ++ ++ intptr_t ptr_at(int offset) const { ++ return *ptr_at_addr(offset); ++ } ++ ++ void ptr_at_put(int offset, intptr_t value) { ++ *ptr_at_addr(offset) = value; ++ } ++ ++ private: ++ // an additional field beyond _sp and _pc: ++ intptr_t* _fp; // frame pointer ++ ++ bool _is_c_frame; ++ intptr_t* _sender_fp_for_c_frame; ++ address _sender_address_for_c_frame; ++ void init_sender_for_c_frame(); ++ ++ // The interpreter and adapters will extend the frame of the caller. ++ // Since oopMaps are based on the sp of the caller before extension ++ // we need to know that value. However in order to compute the address ++ // of the return address we need the real "raw" sp. Since sparc already ++ // uses sp() to mean "raw" sp and unextended_sp() to mean the caller's ++ // original sp we use that convention. ++ ++ intptr_t* _unextended_sp; ++ void adjust_unextended_sp() NOT_DEBUG_RETURN; ++ ++ intptr_t* ptr_at_addr(int offset) const { ++ return (intptr_t*) addr_at(offset); ++ } ++ ++#ifdef ASSERT ++ // Used in frame::sender_for_{interpreter,compiled}_frame ++ static void verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp); ++#endif ++ ++ public: ++ // Constructors ++ ++ frame(intptr_t* sp, intptr_t* fp, address pc); ++ ++ frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc); ++ ++ frame(intptr_t* sp, intptr_t* fp); ++ ++ void init(intptr_t* sp, intptr_t* fp, address pc); ++ ++ // accessors for the instance variables ++ // Note: not necessarily the real 'frame pointer' (see real_fp) ++ intptr_t* fp() const { return _fp; } ++ ++ inline address* sender_pc_addr() const; ++ ++ // expression stack tos if we are nested in a java call ++ intptr_t* interpreter_frame_last_sp() const; ++ ++ // helper to update a map with callee-saved RBP ++ static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr); ++ ++ // deoptimization support ++ void interpreter_frame_set_last_sp(intptr_t* sp); ++ ++ static jint interpreter_frame_expression_stack_direction() { return -1; } ++ ++ void fixRa(const void* ucVoid); ++ ++ void init_sender_for_c_frame(address f_start_pc); ++ ++#endif // CPU_SW64_VM_FRAME_SW64_HPP +\ 文件尾没有换行符 +diff -uNr openjdk/src/hotspot/cpu/sw64/frame_sw64.inline.hpp afu11u/src/hotspot/cpu/sw64/frame_sw64.inline.hpp +--- openjdk/src/hotspot/cpu/sw64/frame_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/frame_sw64.inline.hpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,225 @@ ++/* ++ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_FRAME_SW64_INLINE_HPP ++#define CPU_SW64_VM_FRAME_SW64_INLINE_HPP ++ ++#include "code/codeCache.hpp" ++#include "code/vmreg.inline.hpp" ++ ++// Inline functions for Sw64 frames: ++ ++// Constructors: ++ ++inline frame::frame() { ++ _pc = NULL; ++ _sp = NULL; ++ _unextended_sp = NULL; ++ _fp = NULL; ++ _cb = NULL; ++ _deopt_state = unknown; ++} ++ ++inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { ++ init(sp, fp, pc); ++} ++ ++inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) { ++ _sp = sp; ++ _unextended_sp = unextended_sp; ++ _fp = fp; ++ _pc = pc; ++ assert(pc != NULL, "no pc?"); ++ _cb = CodeCache::find_blob(pc); ++ adjust_unextended_sp(); ++ ++ address original_pc = CompiledMethod::get_deopt_original_pc(this); ++ if (original_pc != NULL) { ++ _pc = original_pc; ++ _deopt_state = is_deoptimized; ++ } else { ++ if (_cb->is_deoptimization_stub()) { ++ _deopt_state = is_deoptimized; ++ } else { ++ _deopt_state = not_deoptimized; ++ } ++ } ++ _is_c_frame = false; ++} ++ ++inline frame::frame(intptr_t* sp, intptr_t* fp) { ++ _sp = sp; ++ _unextended_sp = sp; ++ _fp = fp; ++ _pc = (address)(sp[-1]); ++ Unimplemented(); //ZHJ ++ ++ // Here's a sticky one. This constructor can be called via AsyncGetCallTrace ++ // when last_Java_sp is non-null but the pc fetched is junk. If we are truly ++ // unlucky the junk value could be to a zombied method and we'll die on the ++ // find_blob call. This is also why we can have no asserts on the validity ++ // of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler ++ // -> pd_last_frame should use a specialized version of pd_last_frame which could ++ // call a specilaized frame constructor instead of this one. ++ // Then we could use the assert below. However this assert is of somewhat dubious ++ // value. ++ // assert(_pc != NULL, "no pc?"); ++ ++ _cb = CodeCache::find_blob(_pc); ++ adjust_unextended_sp(); ++ ++ 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; ++ } ++} ++ ++// Accessors ++ ++inline bool frame::equal(frame other) const { ++ bool ret = sp() == other.sp() ++ && unextended_sp() == other.unextended_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(); } ++ ++// Relationals on frames based ++// Return true if the frame is younger (more recent activation) than the frame represented by id ++inline bool frame::is_younger(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); ++ return this->id() < id ; } ++ ++// 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 intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } ++ ++ ++inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } ++ ++// Return address: ++ ++inline address* frame::sender_pc_addr() const { return (address*) addr_at( return_addr_offset); } ++//inline address frame::sender_pc() const { return *sender_pc_addr(); } ++// ++//inline intptr_t* frame::sender_sp() const { return addr_at(sender_sp_offset); } ++ ++inline intptr_t** frame::interpreter_frame_locals_addr() const { ++ return (intptr_t**)addr_at(interpreter_frame_locals_offset); ++} ++ ++inline intptr_t* frame::interpreter_frame_last_sp() const { ++ return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset); ++} ++ ++inline intptr_t* frame::interpreter_frame_bcp_addr() const { ++ return (intptr_t*)addr_at(interpreter_frame_bcp_offset); ++} ++ ++inline intptr_t* frame::interpreter_frame_mdp_addr() const { ++ return (intptr_t*)addr_at(interpreter_frame_mdp_offset); ++} ++ ++ ++// Constant pool cache ++ ++inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { ++ return (ConstantPoolCache**)addr_at(interpreter_frame_cache_offset); ++} ++ ++// Method ++ ++inline Method** frame::interpreter_frame_method_addr() const { ++ return (Method**)addr_at(interpreter_frame_method_offset); ++} ++ ++// Mirror ++ ++inline oop* frame::interpreter_frame_mirror_addr() const { ++ return (oop*)addr_at(interpreter_frame_mirror_offset); ++} ++ ++// top of expression stack ++inline intptr_t* frame::interpreter_frame_tos_address() const { ++ intptr_t* last_sp = interpreter_frame_last_sp(); ++ if (last_sp == NULL) { ++ return sp(); ++ } else { ++ // sp() may have been extended or shrunk by an adapter. At least ++ // check that we don't fall behind the legal region. ++ // For top deoptimized frame last_sp == interpreter_frame_monitor_end. ++ assert(last_sp <= (intptr_t*) interpreter_frame_monitor_end(), "bad tos"); ++ return last_sp; ++ } ++} ++ ++inline oop* frame::interpreter_frame_temp_oop_addr() const { ++ return (oop *)(fp() + interpreter_frame_oop_temp_offset); ++} ++ ++inline int frame::interpreter_frame_monitor_size() { ++ return BasicObjectLock::size(); ++} ++ ++ ++// expression stack ++// (the max_stack arguments are used by the GC; see class FrameClosure) ++ ++inline intptr_t* frame::interpreter_frame_expression_stack() const { ++ intptr_t* monitor_end = (intptr_t*) interpreter_frame_monitor_end(); ++ return monitor_end-1; ++} ++ ++ ++// Entry frames ++ ++inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const { ++ return (JavaCallWrapper**)addr_at(entry_frame_call_wrapper_offset); ++} ++ ++ ++// Compiled frames ++ ++inline oop frame::saved_oop_result(RegisterMap* map) const { ++ return *((oop*) map->location(V0->as_VMReg())); ++} ++ ++inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { ++ *((oop*) map->location(V0->as_VMReg())) = obj; ++} ++ ++#endif // CPU_SW64_VM_FRAME_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.cpp 2025-05-09 10:05:55.876290534 +0800 +@@ -0,0 +1,585 @@ ++/* ++ * 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/g1/g1BarrierSet.hpp" ++#include "gc/g1/g1BarrierSetAssembler.hpp" ++#include "gc/g1/g1BarrierSetRuntime.hpp" ++#include "gc/g1/g1CardTable.hpp" ++#include "gc/g1/g1ThreadLocalData.hpp" ++#include "gc/g1/heapRegion.hpp" ++#include "gc/shared/collectedHeap.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/thread.hpp" ++#include "interpreter/interp_masm.hpp" ++#include "runtime/sharedRuntime.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) {SCOPEMARK_NAME(G1BarrierSetAssembler::gen_write_ref_array_pre_barrier, masm) ++ bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; ++// __ stop("TODO:should check gen_write_ref_array_pre_barrier jzy"); ++// ShouldNotReachHere(); ++ if (!dest_uninitialized) { ++ Register thread = rthread; ++ ++ Label filtered; ++ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); ++ // Is marking active? ++ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ++ __ cmpw(in_progress, 0); ++ } else { ++ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ++ __ cmpb(in_progress, 0); ++ } ++ ++ __ jcc(Assembler::equal, filtered); ++ ++ __ pushad(); // push registers ++ ++ if (count == c_rarg0) { ++ if (addr == c_rarg1) { ++ // exactly backwards!! ++ __ xchgptr(c_rarg1, c_rarg0); ++ } else { ++ __ movl(c_rarg1, count); ++ __ movl(c_rarg0, addr); ++ } ++ } else { ++ __ movl(c_rarg0, addr); ++ __ movl(c_rarg1, count); ++ } ++ if (UseCompressedOops) { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry), 2); ++ } else { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2); ++ } ++ ++ __ popad(); ++ ++ __ bind(filtered); ++ } ++} ++ ++void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, ++ Register addr, Register count, Register tmp) { ++ __ pushad(); // push registers (overkill) ++// __ stop("should check:gen_write_ref_array_post_barrier jzy"); ++ if (c_rarg0 == count) { // On win64 c_rarg0 == rcx ?jzy ++ assert_different_registers(c_rarg1, addr); ++ __ movl(c_rarg1, count); ++ __ movl(c_rarg0, addr); ++ } else { ++ assert_different_registers(c_rarg0, count); ++ __ movl(c_rarg0, addr); ++ __ movl(c_rarg1, count); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2); ++ ++ __ popad(); ++} ++ ++void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Register dst, Address src, Register tmp1, Register tmp_thread) { ++ bool on_oop = type == T_OBJECT || type == T_ARRAY; ++ // __ stop("TODO:check load_at jzy"); ++ 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; ++ ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); ++ if (on_oop && on_reference) { ++ const Register thread = rthread; ++ __ enter(); ++ //__ sys_call(0xabc); ++ //__ br(R0, -1); ++ ++ // Generate the G1 pre-barrier code to log the value of ++ // the referent field in an SATB buffer. ++ g1_write_barrier_pre(masm /* masm */, ++ noreg /* obj */, ++ dst /* pre_val */, ++ thread /* thread */, ++ tmp1 /* tmp */, ++ true /* tosca_live */, ++ true /* expand_call */); ++ __ leave(); ++ } ++} ++ ++void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, ++ Register obj, ++ Register pre_val, ++ Register thread, ++ Register tmp, ++ bool tosca_live, ++ bool expand_call) { ++ // If expand_call is true then we expand the call_VM_leaf macro ++ // directly to skip generating the check by ++ // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. ++ ++ assert(thread == rthread, "must be"); ++ const Register rax = V0; ++ Label done; ++ Label runtime; ++ assert(pre_val != noreg, "check this code"); ++ ++ if (obj != noreg) { ++ assert_different_registers(obj, pre_val, tmp); ++ assert(pre_val != rax, "check this code"); ++ } ++ ++ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); ++ Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); ++ Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); ++ ++ // Is marking active? ++ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ++ __ cmpw(in_progress, 0); ++ } else { ++ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ++ __ ldbu(rscratch4, in_progress); ++ __ sextb(rscratch4, rcc); ++// __ cmpb(in_progress, 0); ++ } ++ __ jcc(Assembler::equal, done); ++ ++ // Do we need to load the previous value? ++ if (obj != noreg) { ++ __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); ++ } ++ ++ // Is the previous value null? ++ __ cmpptr(pre_val, (int32_t) NULL_WORD); ++ __ jcc(Assembler::equal, done); ++ ++ // Can we store original value in the thread's buffer? ++ // Is index == 0? ++ // (The index field is typed as size_t.) ++ ++ __ ldptr(tmp, index); // tmp := *index_adr ++ __ cmpptr(tmp, 0); // tmp == 0? ++ __ jcc(Assembler::equal, runtime); // If yes, goto runtime//sny beq(tmp, runtime); ++ ++ __ subptr(tmp, wordSize, tmp); // tmp := tmp - wordSize ++ __ stptr(tmp, index); // *index_adr := tmp ++ __ addptr(tmp, buffer); // tmp := tmp + *buffer_adr tmp=T5 ++ ++ // Record the previous value ++ __ stptr(pre_val, Address(tmp, 0)); ++ __ jmp(done); ++ ++ __ bind(runtime); ++ // save the live input values ++ if(tosca_live) __ push(rax); ++ ++ if (obj != noreg && obj != rax) ++ __ push(obj); ++ ++ if (pre_val != rax) ++ __ push(pre_val); ++ ++ // Calling the runtime using the regular call_VM_leaf mechanism generates ++ // code (generated by InterpreterMacroAssember::call_VM_leaf_base) ++ // that checks that the *(ebp+frame::interpreter_frame_last_sp) == NULL. ++ // ++ // If we care generating the pre-barrier without a frame (e.g. in the ++ // intrinsified Reference.get() routine) then ebp might be pointing to ++ // the caller frame and so this check will most likely fail at runtime. ++ // ++ // Expanding the call directly bypasses the generation of the check. ++ // So when we do not have have a full interpreter frame on the stack ++ // expand_call should be passed true. ++ ++ ++ if (expand_call) { ++ assert(pre_val != c_rarg1, "smashed arg"); ++ ++ if (c_rarg1 != thread) { ++ __ movl(c_rarg1, thread); ++ } ++ if (c_rarg0 != pre_val) { ++ __ movl(c_rarg0, pre_val); ++ } ++ ++ __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), 2); ++ } else { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); ++ } ++ ++ // save the live input values ++ if (pre_val != rax) ++ __ pop(pre_val); ++ ++ if (obj != noreg && obj != rax) ++ __ pop(obj); ++ ++ if(tosca_live) __ pop(rax); ++ ++ __ bind(done); ++} ++ ++void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, ++ Register store_addr, ++ Register new_val, ++ Register thread, ++ Register tmp, ++ Register tmp2) { ++ ++ assert(thread == rthread, "must be"); ++ assert(tmp != AT, "must be"); ++ assert(tmp2 != AT, "must be"); ++ Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); ++ Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); ++ ++ CardTableBarrierSet* ct = ++ barrier_set_cast(BarrierSet::barrier_set()); ++ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code"); ++ ++ Label done; ++ Label runtime; ++ ++ // Does store cross heap regions? ++ ++// __ movl(rscratch4, store_addr); ++ __ xorptr(store_addr, new_val, rscratch4); ++ __ srll(rscratch4, HeapRegion::LogOfHRGrainBytes, rscratch4); ++ __ jcc(Assembler::equal, done, rscratch4); ++ ++ // crosses regions, storing NULL? ++ ++ __ cmpptr(new_val, (int32_t) NULL_WORD); ++ __ jcc(Assembler::equal, done); ++ ++ // storing region crossing non-NULL, is card already dirty? ++ ++ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code"); //dx? ++ ++ const Register card_addr = tmp; ++ const Register cardtable = tmp2; ++ ++ __ movl(card_addr, store_addr); ++ __ srll(card_addr, CardTable::card_shift, card_addr); ++ // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT ++ // a valid address and therefore is not properly handled by the relocation code. ++ __ mov_immediate64(cardtable, (intptr_t)ct->card_table()->byte_map_base()); ++ __ addptr(card_addr, cardtable, card_addr); ++ ++ __ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val()); ++ __ jcc(Assembler::equal, done); ++ ++ assert((int)CardTable::dirty_card_val() == 0, "must be 0"); //dx? ++ ++ //__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); ++ __ memb(); ++ __ cmpb(Address(card_addr, 0), (int)G1CardTable::dirty_card_val()); ++ __ jcc(Assembler::equal, done); ++ ++ ++ // storing a region crossing, non-NULL oop, card is clean. ++ // dirty card and log. ++ __ mov_immediate32(rscratch4, (int)G1CardTable::dirty_card_val()); ++ __ stb(rscratch4, Address(card_addr, 0));//movb ++ ++ __ ldws(rcc, queue_index); ++ __ beq_l(rcc, runtime); ++ __ jcc(Assembler::equal, runtime); ++ __ subl(rcc, wordSize, rcc); ++ __ stw (rcc, queue_index); //LSP!! ++ __ ldptr(tmp2, buffer); ++ __ ldl(rscratch4, queue_index);//?sny ldw ++ __ addl(tmp2, rscratch4, tmp2); ++ __ stl(card_addr, Address(tmp2, 0)); ++ ++ __ jmp(done); ++ ++ __ bind(runtime); ++ // save the live input values ++ __ push(store_addr); ++ __ push(new_val); ++ ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); ++ ++ __ pop(new_val); ++ __ pop(store_addr); ++ ++ __ bind(done); ++} ++ ++void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2) { ++ bool in_heap = (decorators & IN_HEAP) != 0; ++ bool as_normal = (decorators & AS_NORMAL) != 0; ++ assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported"); ++ // __ stop("TODO:check oop_store_at jzy"); ++ bool needs_pre_barrier = as_normal; ++ bool needs_post_barrier = val != noreg && in_heap; ++ ++ Register tmp3 = r8; //need different? x86 uses r8 ++ Register thread = rthread; ++ assert_different_registers(tmp1, tmp2, tmp3, thread); //need this check? jzy ++ ++ // flatten object address if needed ++ // We do it regardless of precise because we need the registers ++ if (dst.index() == noreg && dst.disp() == 0) { ++ if (dst.base() != tmp1) { ++ __ movl(tmp1, dst.base()); // ! ++ } ++ } else { ++ __ lea(tmp1, dst); ++ } ++ ++ ++ if (needs_pre_barrier) { ++ g1_write_barrier_pre(masm /*masm*/, ++ tmp1 /* obj */, ++ tmp2 /* pre_val */, ++ thread /* thread */, ++ tmp3 /* tmp */, ++ val != noreg /* tosca_live */, ++ false /* expand_call */); ++ } ++ if (val == noreg) { ++ BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); ++ } else { ++ Register new_val = val; ++ if (needs_post_barrier) { ++ // G1 barrier needs uncompressed oop for region cross check. ++ if (UseCompressedOops) { ++ new_val = tmp2; ++ __ movl(new_val, val); ++ } ++ } ++ BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); ++ if (needs_post_barrier) { ++ g1_write_barrier_post(masm /*masm*/, ++ tmp1 /* store_adr */, ++ new_val /* new_val */, ++ thread /* thread */, ++ tmp3 /* tmp */, ++ tmp2 /* tmp2 */); ++ } ++} ++ ++} ++ ++#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. ++ // __ stop("TODO:check gen_pre_barrier_stub jzy"); ++ __ 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*/); ++ } ++ ++ __ cmpptr(pre_val_reg, (int32_t)NULL_WORD); ++ __ jcc(Assembler::equal, *stub->continuation()); ++ ce->store_parameter(stub->pre_val()->as_register(), 0); ++ __ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); ++ __ jmp(*stub->continuation()); ++ ++} ++ ++void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { ++ G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); ++ // __ stop("TODO:check gen_post_barrier_stub jzy"); ++ __ bind(*stub->entry()); ++ assert(stub->addr()->is_register(), "Precondition."); ++ assert(stub->new_val()->is_register(), "Precondition."); ++ Register new_val_reg = stub->new_val()->as_register(); ++ __ cmpptr(new_val_reg, (int32_t) NULL_WORD); ++ __ jcc(Assembler::equal, *stub->continuation()); ++ ce->store_parameter(stub->addr()->as_pointer_register(), 0); ++ __ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin())); ++ __ jmp(*stub->continuation()); ++} ++ ++#undef __ ++ ++#define __ sasm-> ++ ++void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { ++ __ prologue("g1_pre_barrier", false); ++ // arg0 : previous value of memory ++ const Register rax = V0; ++ const Register rdx = T0; ++ const Register rcx = T1; ++ // __ stop("TODO:check generate_c1_pre_barrier_runtime_stub jzy"); ++ __ push(rax); ++ __ push(rdx); ++ ++ const Register pre_val = rax; ++ const Register thread = rthread; ++ const Register tmp = rdx; ++ ++ ++ Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); ++ Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); ++ Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); ++ ++ Label done; ++ Label runtime; ++ ++ // Is marking still active? ++ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ++ __ cmpw(queue_active, 0); ++ } else { ++ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ++ __ cmpb(queue_active, 0); ++ } ++ __ jcc(Assembler::equal, done); ++ ++ // Can we store original value in the thread's buffer? ++ ++ __ ldptr(tmp, queue_index); ++ __ jcc(Assembler::zero, runtime, tmp); ++ __ subptr(tmp, wordSize, tmp); ++ __ stl(tmp, queue_index); ++ __ addptr(tmp, buffer, tmp); ++ ++ // prev_val (rax) ++ __ load_parameter(0, pre_val); ++ __ stl(pre_val, Address(tmp, 0)); ++ __ jmp(done); ++ ++ __ bind(runtime); ++ ++ __ save_live_registers_no_oop_map(true); ++ ++ // load the pre-value ++ __ load_parameter(0, rcx); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), rcx, thread); ++ ++ __ restore_live_registers(true); ++ ++ __ bind(done); ++ ++ __ pop(rdx); ++ __ pop(rax); ++ ++ __ epilogue(); ++} ++ ++void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { ++ __ prologue("g1_post_barrier", false); ++ ++ // arg0: store_address ++ Address store_addr(rbp, 2*BytesPerWord); ++ // __ stop("TODO:check generate_c1_post_barrier_runtime_stub jzy"); ++ CardTableBarrierSet* ct = ++ barrier_set_cast(BarrierSet::barrier_set()); ++ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code"); ++ ++ Label done; ++ Label enqueued; ++ Label runtime; ++ ++ // At this point we know new_value is non-NULL and the new_value crosses regions. ++ // Must check to see if card is already dirty ++ const Register rax = V0; ++ const Register rdx = T0; ++ const Register rcx = T1; ++ ++ const Register thread = NOT_LP64(rax) LP64_ONLY(rthread); ++ ++ Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); ++ Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); ++ ++ __ push(rax); ++ __ push(rcx); ++ ++ const Register cardtable = rax; ++ const Register card_addr = rcx; ++ ++ __ load_parameter(0, card_addr); ++ __ srll(card_addr, CardTable::card_shift, card_addr); ++ // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT ++ // a valid address and therefore is not properly handled by the relocation code. ++ __ mov_immediate64(cardtable, (intptr_t)ct->card_table()->byte_map_base()); ++ __ addptr(card_addr, cardtable, card_addr); ++ ++ ++ __ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val()); ++ __ jcc(Assembler::equal, done); ++ ++ //__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); ++ __ memb(); ++ __ cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val()); ++ __ jcc(Assembler::equal, done); ++ ++ // storing region crossing non-NULL, card is clean. ++ // dirty card and log. ++ const Register tmp = rdx; ++ __ push(rdx); ++ ++ __ mov_immediate32(tmp, (int)CardTable::dirty_card_val()); ++ __ stb(tmp, Address(card_addr, 0)); ++ ++ __ ldptr(tmp, queue_index); ++ __ jcc(Assembler::zero, runtime, tmp); ++ __ subptr(tmp, wordSize, tmp); ++ __ stl(tmp, queue_index); ++ __ addptr(tmp, buffer, tmp); ++ __ stl(card_addr, Address(tmp, 0)); ++ __ jmp(enqueued); ++ ++ __ bind(runtime); ++ ++ __ save_live_registers_no_oop_map(true); ++ ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); ++ ++ __ restore_live_registers(true); ++ ++ __ bind(enqueued); ++ __ pop(rdx); ++ ++ __ bind(done); ++ __ pop(rcx); ++ __ pop(rax); ++ ++ __ epilogue(); ++} ++ ++#undef __ ++ ++#endif // COMPILER1 +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/g1/g1BarrierSetAssembler_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,75 @@ ++/* ++ * 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_SW64_GC_G1_G1BARRIERSETASSEMBLER_SW64_HPP ++#define CPU_SW64_GC_G1_G1BARRIERSETASSEMBLER_SW64_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: ++ void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, ++ Register addr, Register count); ++ void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, ++ Register start, Register count, Register tmp); ++ ++ void g1_write_barrier_pre(MacroAssembler* masm, ++ Register obj, ++ Register pre_val, ++ Register thread, ++ Register tmp, ++ bool tosca_live, ++ bool expand_call); ++ ++ void g1_write_barrier_post(MacroAssembler* masm, ++ Register store_addr, ++ Register new_val, ++ Register thread, ++ Register tmp, ++ Register tmp2); ++ ++ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2); ++ ++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 ++ ++ void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Register dst, Address src, Register tmp1, Register tmp_thread); ++}; ++ ++#endif // CPU_SW64_GC_G1_G1BARRIERSETASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,272 @@ ++/* ++ * 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/barrierSetAssembler.hpp" ++#include "gc/shared/collectedHeap.hpp" ++#include "interpreter/interp_masm.hpp" ++#include "runtime/jniHandles.hpp" ++#include "runtime/thread.hpp" ++ ++#define __ masm-> ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Register dst, Address src, Register tmp1, Register tmp_thread) {SCOPEMARK_NAME(BarrierSetAssembler::load_at, masm) ++ bool in_heap = (decorators & IN_HEAP) != 0; ++ bool in_native = (decorators & IN_NATIVE) != 0; ++ bool is_not_null = (decorators & IS_NOT_NULL) != 0; ++ bool atomic = (decorators & MO_RELAXED) != 0; ++ ++ switch (type) { ++ case T_OBJECT: ++ case T_ARRAY: { ++ if (in_heap) { ++ if (UseCompressedOops) { ++ __ ldwu(dst, src); ++ if (is_not_null) { ++ __ decode_heap_oop_not_null(dst); ++ } else { ++ __ decode_heap_oop(dst); // ++ } ++ } else { ++ __ ldl(dst, src); ++ } ++ } else { ++ assert(in_native, "why else?"); ++ __ ldl(dst, src); ++ } ++ break; ++ } ++ case T_BOOLEAN: __ load_unsigned_byte(dst, src); break; ++ case T_BYTE: __ load_signed_byte64(dst, src); break; ++ case T_CHAR: __ load_unsigned_short(dst, src); break; ++ case T_SHORT: __ load_signed_short(dst, src); break; ++ case T_INT: __ ldws (dst, src); break; ++ case T_ADDRESS: __ ldl (dst, src); break; ++ case T_FLOAT: ++ assert(dst == noreg, "only to ftos"); ++ __ load_float(FSF, src); ++ break; ++ case T_DOUBLE: ++ assert(dst == noreg, "only to dtos"); ++ __ load_double(FSF, src); ++ break; ++ case T_LONG: ++ assert(dst == noreg, "only to ltos"); ++ __ ldl(FSR, src); ++ break; ++ default: Unimplemented(); ++ } ++} ++ ++void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2) { ++ bool in_heap = (decorators & IN_HEAP) != 0; ++ bool in_native = (decorators & IN_NATIVE) != 0; ++ bool is_not_null = (decorators & IS_NOT_NULL) != 0; ++ bool atomic = (decorators & MO_RELAXED) != 0; ++ ++ switch (type) { ++ case T_OBJECT: ++ case T_ARRAY: { ++ if (in_heap) { ++ if (val == noreg) { ++ assert(!is_not_null, "inconsistent access"); ++ ++ if (UseCompressedOops) { ++ __ stw(R0, dst); ++ } else { ++ __ stl(R0, dst); ++ } ++ ++ } else { ++ ++ if (UseCompressedOops) { ++ assert(!dst.uses(val), "not enough registers"); ++ if (is_not_null) { ++ __ encode_heap_oop_not_null(val); ++ } else { ++ __ encode_heap_oop(val); ++ } ++ __ stw(val, dst); ++ } else { ++ __ stl(val, dst); ++ } ++ } ++ } else { ++ assert(in_native, "why else?"); ++ assert(val != noreg, "not supported"); ++ __ stl(val, dst); ++ } ++ break; ++ } ++ case T_BOOLEAN: ++ __ andw(val, 0x1, val); // boolean is true if LSB is 1 ++ __ stb(val, dst); ++ break; ++ case T_BYTE: ++ __ stb(val, dst); ++ break; ++ case T_SHORT: ++ __ sth(val, dst); ++ break; ++ case T_CHAR: ++ __ sth(val, dst); ++ break; ++ case T_INT: ++ __ stw(val, dst); ++ break; ++ case T_LONG: ++ assert(val == noreg, "only tos"); ++ __ stl(FSR, dst); ++ break; ++ case T_FLOAT: ++ assert(val == noreg, "only tos"); ++ __ store_float(FSF, dst); ++ break; ++ case T_DOUBLE: ++ assert(val == noreg, "only tos"); ++ __ store_double(FSF, dst); ++ break; ++ case T_ADDRESS: ++ __ stptr(val, dst); ++ break; ++ default: Unimplemented(); ++ } ++} ++/* ++void BarrierSetAssembler::obj_equals(MacroAssembler* masm, ++ Register obj1, Address obj2) { ++ __ cmpptr(obj1, obj2); ++} ++*/ ++void BarrierSetAssembler::obj_equals(MacroAssembler* masm, ++ Register obj1, Register obj2, Register cc) { ++ __ cmpptr(obj1, obj2, cc); ++} ++ ++// yj todo: below ++void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, ++ Register obj, Register tmp, Label& slowpath) { ++ const int32_t inverted_jweak_mask = ~static_cast(JNIHandles::weak_tag_mask); ++ STATIC_ASSERT(inverted_jweak_mask == -2); // otherwise check this code ++ __ andptr(obj, inverted_jweak_mask, obj); ++ __ ldptr(obj, Address(obj, 0)); // *obj ++} ++ ++void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, ++ Register thread, Register obj, ++ Register var_size_in_bytes, ++ int con_size_in_bytes, ++ Register t1, ++ Register t2, ++ Label& slow_case) { ++ assert_different_registers(obj, t1, t2); ++ assert_different_registers(obj, var_size_in_bytes, t1); ++ Register end = t2; ++ if (!thread->is_valid()) { ++ thread = rthread; ++ } ++ ++ __ verify_tlab(); ++ ++ __ ldptr(obj, Address(thread, JavaThread::tlab_top_offset())); ++ if (var_size_in_bytes == noreg) { ++ __ lea(end, Address(obj, con_size_in_bytes)); ++ } else { ++ __ lea(end, Address(obj, var_size_in_bytes, Address::times_1)); ++ } ++ __ cmpptr(end, Address(thread, JavaThread::tlab_end_offset())); ++ __ jcc(Assembler::above, slow_case); ++ ++ // update the tlab top pointer ++ __ stptr(end, Address(thread, JavaThread::tlab_top_offset())); ++ ++ // recover var_size_in_bytes if necessary ++ if (var_size_in_bytes == end) { ++ __ subptr(var_size_in_bytes, obj, var_size_in_bytes); ++ } ++ __ verify_tlab(); ++} ++ ++// Defines obj, preserves var_size_in_bytes ++void BarrierSetAssembler::eden_allocate(MacroAssembler* masm, ++ Register thread, Register obj, ++ Register var_size_in_bytes, ++ int con_size_in_bytes, ++ Register t1, ++ Label& slow_case) { ++ Register rax = V0; ++ assert(obj == rax, "obj must be in rax, for cmpxchg"); ++ assert_different_registers(obj, var_size_in_bytes, t1); ++ if (!Universe::heap()->supports_inline_contig_alloc()) { ++ __ jmp(slow_case); ++ } else { ++ Register end = t1; ++ Label retry; ++ __ bind(retry); ++ ExternalAddress heap_top((address) Universe::heap()->top_addr()); ++ __ ldptr(obj, heap_top); ++ if (var_size_in_bytes == noreg) { ++ __ lea(end, Address(obj, con_size_in_bytes)); ++ } else { ++ __ lea(end, Address(obj, var_size_in_bytes, Address::times_1)); ++ } ++ // if end < obj then we wrapped around => object too long => slow case ++ __ cmpptr(end, obj); ++ __ jcc(Assembler::below, slow_case); ++ __ cmpptr(end, ExternalAddress((address) Universe::heap()->end_addr())); ++ __ jcc(Assembler::above, slow_case); ++ // Compare obj with the top addr, and if still equal, store the new top addr in ++ // end at the address of the top addr pointer. Sets ZF if was equal, and clears ++ // it otherwise. Use lock prefix for atomicity on MPs. ++ __ cmpxchgptr(end, heap_top, obj, rscratch2);//AT==0 should retry, it's special TODO:Fixme jzy ++ __ jcc(Assembler::failed, retry); ++ incr_allocated_bytes(masm, thread, var_size_in_bytes, con_size_in_bytes); ++ } ++} ++ ++void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, Register thread, ++ Register var_size_in_bytes, ++ int con_size_in_bytes) { ++ if (!thread->is_valid()) { ++ thread = rthread; ++ } ++ ++ __ ldl(rscratch4, Address(thread, in_bytes(JavaThread::allocated_bytes_offset()))); ++ if (var_size_in_bytes->is_valid()) { ++ __ addl(rscratch4, var_size_in_bytes, rscratch4); ++ } else { ++ __ addl(rscratch4, con_size_in_bytes, rscratch4); ++ } ++ __ stl(rscratch4, Address(thread, in_bytes(JavaThread::allocated_bytes_offset()))); ++} ++ ++ +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/shared/barrierSetAssembler_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,75 @@ ++/* ++ * 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_SW64_GC_SHARED_BARRIERSETASSEMBLER_SW64_HPP ++#define CPU_SW64_GC_SHARED_BARRIERSETASSEMBLER_SW64_HPP ++ ++#include "asm/macroAssembler.hpp" ++#include "memory/allocation.hpp" ++#include "oops/access.hpp" ++ ++class BarrierSetAssembler: public CHeapObj { ++private: ++ void incr_allocated_bytes(MacroAssembler* masm, Register thread, ++ Register var_size_in_bytes, int con_size_in_bytes); ++ ++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 start, Register end, Register tmp) {} ++ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Register dst, Address src, Register tmp1, Register tmp_thread); ++ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2); ++ ++ virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, ++ Register obj, Register tmp, Label& slowpath); ++ ++ virtual void tlab_allocate(MacroAssembler* masm, ++ Register thread, // Current thread ++ 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 eden_allocate(MacroAssembler* masm, ++ Register thread, // Current thread ++ 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 ++ ); ++ virtual void barrier_stubs_init() {} ++ ++ virtual void obj_equals(MacroAssembler* masm, ++ Register obj1, Register obj2, Register cc=rcc); ++ ++}; ++ ++#endif // CPU_SW64_GC_SHARED_BARRIERSETASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,149 @@ ++/* ++ * 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) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++#define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8) ++ ++void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, ++ Register addr, Register count, Register tmp) {SCOPEMARK_NAME(CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier, masm) ++// ShouldNotReachHere(); ++ BarrierSet *bs = BarrierSet::barrier_set(); ++ CardTableBarrierSet* ctbs = barrier_set_cast(bs); ++ CardTable* ct = ctbs->card_table(); ++ assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code"); ++ intptr_t disp = (intptr_t) ct->byte_map_base(); ++ ++ Label L_loop, L_done; ++ const Register end = count; ++ assert_different_registers(addr, end); ++ ++ __ testw(count, count); ++ __ jcc(Assembler::zero, L_done); // zero count - nothing to do ++ ++ ++ __ lea(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size ++ __ subptr(end, BytesPerHeapOop, end); // end - 1 to make inclusive ++ __ srll(addr, CardTable::card_shift, addr); ++ __ srll(end, CardTable::card_shift, end); ++ __ subptr(end, addr, end); // end --> cards count ++ ++ __ mov_immediate64(tmp, disp); ++ __ addptr(addr, tmp, addr); ++ __ bind(L_loop); ++ __ stb(R0, Address(addr, count, Address::times_1)); ++ __ decrement(count); ++ __ jcc(Assembler::greaterEqual, L_loop, count); ++ ++ __ bind(L_done); ++} ++ ++void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst) {SCOPEMARK_NAME(CardTableBarrierSetAssembler::store_check, masm) ++ // Does a store check for the oop in register obj. The content of ++ // register obj is destroyed afterwards. ++ BarrierSet* bs = BarrierSet::barrier_set(); ++ ++ CardTableBarrierSet* ctbs = barrier_set_cast(bs); ++ CardTable* ct = ctbs->card_table(); ++ assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code"); ++ ++ __ srll(obj, CardTable::card_shift, obj); ++ ++ Address card_addr; ++ ++ // The calculation for byte_map_base is as follows: ++ // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift); ++ // So this essentially converts an address to a displacement and it will ++ // never need to be relocated. On 64bit however the value may be too ++ // large for a 32bit displacement. ++ intptr_t byte_map_base = (intptr_t)ct->byte_map_base(); ++ if (__ is_simm32(byte_map_base)) { ++ card_addr = Address(noreg, obj, Address::times_1, byte_map_base); ++ } else { ++ // By doing it as an ExternalAddress 'byte_map_base' could be converted to a rip-relative ++ // displacement and done in a single instruction given favorable mapping and a ++ // smarter version of as_Address. However, 'ExternalAddress' generates a relocation ++ // entry and that entry is not properly handled by the relocation code. ++ AddressLiteral cardtable((address)byte_map_base, relocInfo::none); ++ Address index(noreg, obj, Address::times_1); ++ card_addr = __ as_Address(ArrayAddress(cardtable, index), rscratch4); ++ } ++ int dirty = CardTable::dirty_card_val(); ++ if (UseCondCardMark) { ++ Label L_already_dirty; ++ //if (ct->scanned_concurrently()) {//according to aarch64 ++ __ memb(); ++ //} ++ __ cmpb(card_addr, dirty); ++ __ jcc(Assembler::equal, L_already_dirty); ++// __ movw(temp, dirty); ++// __ stb(temp, card_addr); ++ __ stb(R0, card_addr); ++ __ bind(L_already_dirty); ++ } else { ++// __ movw(temp, dirty); ++// __ stb(temp, card_addr); ++ if (ct->scanned_concurrently()) { ++ __ memb(); ++ } ++ __ stb(R0, card_addr); ++ } ++} ++ ++void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2) {SCOPEMARK_NAME(CardTableBarrierSetAssembler::oop_store_at, masm) ++ 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; ++ ++ bool needs_post_barrier = val != noreg && in_heap; ++ ++ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg); ++ if (needs_post_barrier) { ++ // flatten object address if needed ++ if (!precise || (dst.index() == noreg && dst.disp() == 0)) { ++ store_check(masm, dst.base(), dst); ++ } else { ++ __ lea(tmp1, dst); ++ store_check(masm, tmp1, dst); ++ } ++ } ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/shared/cardTableBarrierSetAssembler_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,42 @@ ++/* ++ * 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_SW64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SW64_HPP ++#define CPU_SW64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SW64_HPP ++ ++#include "asm/macroAssembler.hpp" ++#include "gc/shared/modRefBarrierSetAssembler.hpp" ++ ++class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler { ++protected: ++ void store_check(MacroAssembler* masm, Register obj, Address dst); ++ ++ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, ++ Register start, Register count, Register tmp); ++ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2); ++ ++}; ++ ++#endif // #ifndef CPU_SW64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,83 @@ ++/* ++ * 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/modRefBarrierSetAssembler.hpp" ++ ++#define __ masm-> ++ ++void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Register src, Register dst, Register count) {SCOPEMARK_NAME(ModRefBarrierSetAssembler::arraycopy_prologue, masm) ++ bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; ++ bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0; ++ bool obj_int = type == T_OBJECT && UseCompressedOops; ++// ShouldNotReachHere(); ++ //use T11 is very special, related to stubGenerator_sw64::array_copy* TODO:refactor jzy ++ if (type == T_OBJECT || type == T_ARRAY) { ++ if (!checkcast) { ++ if (!obj_int) { ++ // Save count for barrier ++ __ movl(T11, count); ++ } else if (disjoint) { ++ // Save dst in r11 in the disjoint case ++ __ movl(T11, dst); ++ } ++ } ++ 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) {SCOPEMARK_NAME(ModRefBarrierSetAssembler::arraycopy_epilogue, masm) ++ bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; ++ bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0; ++ bool obj_int = type == T_OBJECT && UseCompressedOops; ++ Register tmp = V0; ++// ShouldNotReachHere(); ++ if (type == T_OBJECT || type == T_ARRAY) { ++ if (!checkcast) { ++ if (!obj_int) { ++ // Save count for barrier ++ count = T11; ++ } else if (disjoint) { ++ // Use the saved dst in the disjoint case ++ dst = T11; ++ } ++ } else { ++ assert_different_registers(src, dst, count, rscratch1);//need this? jzy ++ tmp = rscratch1; ++ } ++ gen_write_ref_array_post_barrier(masm, decorators, dst, count, tmp); ++ } ++} ++ ++void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2) { ++ if (type == T_OBJECT || type == T_ARRAY) { ++ oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2); ++ } else { ++ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); ++ } ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/gc/shared/modRefBarrierSetAssembler_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,54 @@ ++/* ++ * 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_SW64_GC_SHARED_MODREFBARRIERSETASSEMBLER_SW64_HPP ++#define CPU_SW64_GC_SHARED_MODREFBARRIERSETASSEMBLER_SW64_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 start, Register count, Register tmp) {} ++ ++ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2) = 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 start, Register count, Register tmp); ++ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, ++ Address dst, Register val, Register tmp1, Register tmp2); ++}; ++ ++#endif // CPU_SW64_GC_SHARED_MODREFBARRIERSETASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/globalDefinitions_sw64.hpp afu11u/src/hotspot/cpu/sw64/globalDefinitions_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/globalDefinitions_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/globalDefinitions_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * 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_SW64_VM_GLOBALDEFINITIONS_SW64_HPP ++#define CPU_SW64_VM_GLOBALDEFINITIONS_SW64_HPP ++// Size of SW 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 = false; ++ ++ ++// true if x is a power of 2, false otherwise ++inline bool is_power_of_2(intptr_t x) ; ++ ++inline intptr_t mask_bits (intptr_t x, intptr_t m); ++ ++// returns integer round-up to the nearest multiple of s (s must be a power of two) ++inline intptr_t round_to(intptr_t x, uintx s) { ++ #ifdef ASSERT ++ if (!is_power_of_2(s)) fatal("s must be a power of 2"); ++ #endif ++ const uintx m = s - 1; ++ return mask_bits(x + m, ~m); ++} ++ ++#define SUPPORTS_NATIVE_CX8 ++ ++#define SUPPORT_RESERVED_STACK_AREA ++ ++#endif // CPU_SW64_VM_GLOBALDEFINITIONS_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/globals_sw64.hpp afu11u/src/hotspot/cpu/sw64/globals_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/globals_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/globals_sw64.hpp 2025-05-09 10:06:54.192292504 +0800 +@@ -0,0 +1,193 @@ ++/* ++ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_GLOBALS_SW64_HPP ++#define CPU_SW64_VM_GLOBALS_SW64_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) ++ ++define_pd_global(bool, ConvertSleepToYield, true); ++define_pd_global(bool, ShareVtableStubs, true); ++define_pd_global(bool, CountInterpCalls, true); ++define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this ++ ++define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks ++define_pd_global(bool, TrapBasedNullChecks, false); ++define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast ++ ++define_pd_global(uintx, CodeCacheSegmentSize, 64 TIERED_ONLY(+64)); // Tiered compilation has large code-entry alignment. ++define_pd_global(intx, CodeEntryAlignment, 16); ++define_pd_global(intx, OptoLoopAlignment, 16); ++define_pd_global(intx, InlineFrequencyCount, 100); ++ ++#define DEFAULT_STACK_YELLOW_PAGES (2) ++#define DEFAULT_STACK_RED_PAGES (1) ++// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the ++// stack if compiled for unix and LP64. To pass stack overflow tests we need ++// 20 shadow pages. ++#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5)) ++#define DEFAULT_STACK_RESERVED_PAGES (1) ++ ++#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, StackShadowPages, 3 DEBUG_ONLY(+1)); ++define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); ++ ++define_pd_global(uintx, TLABSize, 0); ++define_pd_global(uintx, NewSize, 1024 * K); ++define_pd_global(intx, PreInflateSpin, 10); ++ ++define_pd_global(intx, PrefetchCopyIntervalInBytes, -1); ++define_pd_global(intx, PrefetchScanIntervalInBytes, -1); ++define_pd_global(intx, PrefetchFieldsAhead, -1); ++ ++define_pd_global(bool, RewriteBytecodes, true); ++define_pd_global(bool, RewriteFrequentPairs, true); ++define_pd_global(bool, UseMembar, true); ++ ++////define_pd_global(bool, PreserveFramePointer, false); ++ ++// GC Ergo Flags ++define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread ++ ++define_pd_global(uintx, TypeProfileLevel, 111); ++ ++define_pd_global(bool, PreserveFramePointer, false); ++// Only c2 cares about this at the moment ++define_pd_global(intx, AllocatePrefetchStyle, 2); ++define_pd_global(intx, AllocatePrefetchDistance, -1); ++define_pd_global(bool, CompactStrings, true); ++ ++// Clear short arrays bigger than one word in an arch-specific way ++define_pd_global(intx, InitArrayShortSize, 4096 * BytesPerLong); ++define_pd_global(intx, InlineSmallCode, 4000); ++ ++define_pd_global(bool, ThreadLocalHandshakes, false); ++ ++////#if defined(COMPILER1) || defined(COMPILER2) ++////define_pd_global(intx, InlineSmallCode, 1000); ++////#endif ++ ++#define ARCH_FLAGS(develop, \ ++ product, \ ++ diagnostic, \ ++ experimental, \ ++ notproduct, \ ++ range, \ ++ constraint, \ ++ writeable) \ ++ product(bool, UseSW8A, false, \ ++ "Use SW8A on Shenwei CPUs") \ ++ product(bool, UseAddpi, false, \ ++ "Use addpi of SW8A's instructions") \ ++ product(bool, UseCAS, false, \ ++ "Use CASx of SW8A's instructions") \ ++ product(bool, UseWmemb, false, \ ++ "Use wmemb on SW8A CPU") \ ++ product(bool, NearCpool, true, \ ++ "constant pool is close to instructions") \ ++ product(bool, TraceSignalHandling, false, \ ++ "Trace signal handling") \ ++ product(bool, UseBarriersForVolatile, false, \ ++ "Use memory barriers to implement volatile accesses") \ ++ product(bool, UseNeon, false, \ ++ "Use Neon for CRC32 computation") \ ++ product(bool, UseCRC32, false, \ ++ "Use CRC32 instructions for CRC32 computation") \ ++ product(bool, UseSIMDForMemoryOps, false, \ ++ "Use SIMD instructions in generated memory move code") \ ++ product(bool, UseSIMDForArrayEquals, true, \ ++ "Use SIMD instructions in generated array equals code") \ ++ product(bool, UseSimpleArrayEquals, false, \ ++ "Use simpliest and shortest implementation for array equals") \ ++ product(bool, AvoidUnalignedAccesses, false, \ ++ "Avoid generating unaligned memory accesses") \ ++ product(bool, UseLSE, false, \ ++ "Use LSE instructions") \ ++ product(bool, UseBlockZeroing, true, \ ++ "Use DC ZVA for block zeroing") \ ++ product(intx, BlockZeroingLowLimit, 256, \ ++ "Minimum size in bytes when block zeroing will be used") \ ++ range(1, max_jint) \ ++ product(bool, TraceTraps, false, "Trace all traps the signal handler")\ ++ product(int, SoftwarePrefetchHintDistance, -1, \ ++ "Use prfm hint with specified distance in compiled code." \ ++ "Value -1 means off.") \ ++ range(-1, 4096) \ ++ product(bool, UseSW6B, false, \ ++ "Use SW6B on Shenwei CPUs") \ ++ \ ++ product(bool, UseSimdForward, false, \ ++ "arraycopy disjoint stubs with SIMD instructions") \ ++ product(bool, UseSimdBackward, false, \ ++ "arraycopy conjoint stubs with SIMD instructions") \ ++ product(bool, UseSimdLongOop, false, \ ++ "conjoint oop copy with SIMD instructions") \ ++ /* product(bool, UseCodeCacheAllocOpt, true, */ \ ++ /* "Allocate code cache within 32-bit memory address space") */ \ ++ \ ++ product(bool, UseCountLeadingZerosInstruction, true, \ ++ "Use count leading zeros instruction") \ ++ \ ++ product(bool, UseCountTrailingZerosInstruction, false, \ ++ "Use count trailing zeros instruction") \ ++ \ ++ product(bool, FastIntDiv, false, \ ++ "make Integer division faster") \ ++ \ ++ product(bool, FastLongDiv, false, \ ++ "make Long division faster") \ ++ \ ++ product(bool, FastIntRem, false, \ ++ "make Integer remainder faster") \ ++ \ ++ product(bool, FastLongRem, false, \ ++ "make Long remainder faster") \ ++ \ ++ product(bool, SafePatch, true, \ ++ "use double li48 to make patch operations safer") \ ++ \ ++ product(bool, UseNecessaryMembar, true, \ ++ "It is necessary to add memb instruction on sw platform") \ ++ \ ++ product(bool, FRegisterConflict, true, \ ++ "When FRegisterConflict is true, prevent source and destination FloatRegisters from being the same. " \ ++ "When FRegisterConflict is false, ignore the conflict") \ ++ product(bool, UseSetfpec, false, \ ++ "true for 9906, false for 9916") \ ++ product(bool, UseGetLongIntrinsic, false, \ ++ "Use Unsafe.getLong intrinsic") ++ ++#endif // CPU_SW64_VM_GLOBALS_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/icache_sw64.cpp afu11u/src/hotspot/cpu/sw64/icache_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/icache_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/icache_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,96 @@ ++/* ++ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.hpp" ++#include "runtime/icache.hpp" ++ ++#define __ _masm-> ++extern void sw64TestHook(); ++ ++void ICache::initialize() { ++ sw64TestHook(); ++} ++ ++void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) { ++ StubCodeMark mark(this, "ICache", "flush_icache_stub"); ++ ++ Register rax = V0; ++ address start = __ pc(); ++ ++ const Register addr = c_rarg0; ++ const Register lines = c_rarg1; ++ const Register magic = c_rarg2; ++ ++ Label flush_line, done; ++ ++ __ jcc(Assembler::zero, done, lines); ++ ++ // Force ordering wrt cflush. ++ // Other fence and sync instructions won't do the job. ++ __ memb(); ++ ++ __ bind(flush_line); ++ __ clflush(Address(addr, 0)); ++ __ addptr(addr, ICache::line_size, addr); ++ __ decrementw(lines); ++ __ jcc(Assembler::notZero, flush_line, lines); ++ ++ __ memb(); ++ ++ __ bind(done); ++ ++ __ movl(rax, magic); // Handshake with caller to make sure it happened! ++ __ ret_sw(); ++ ++ // Must be set here so StubCodeMark destructor can call the flush stub. ++ *flush_icache_stub = (ICache::flush_icache_stub_t)start; ++} ++ ++void ICache::call_flush_stub(address start, int lines) { ++ //in fact, the current os implementation simply flush all ICACHE&DCACHE ++// sysmips(3, 0, 0, 0); ++// __asm__ __volatile__ ("ldi $0,266"); ++// __asm__ __volatile__ ("sys_call 0x83"); ++} ++ ++void ICache::invalidate_word(address addr) { ++ //cacheflush(addr, 4, ICACHE); ++ ++// sysmips(3, 0, 0, 0); ++// __asm__ __volatile__ ("ldi $0,266"); ++// __asm__ __volatile__ ("sys_call 0x83"); ++} ++ ++void ICache::invalidate_range(address start, int nbytes) { ++// sysmips(3, 0, 0, 0); ++// __asm__ __volatile__ ("ldi $0,266"); ++// __asm__ __volatile__ ("sys_call 0x83"); ++} ++ ++void ICache::invalidate_all() { ++// __asm__ __volatile__ ("ldi $0,266"); ++// __asm__ __volatile__ ("sys_call 0x83"); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/icache_sw64.hpp afu11u/src/hotspot/cpu/sw64/icache_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/icache_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/icache_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_ICACHE_SW64_HPP ++#define CPU_SW64_VM_ICACHE_SW64_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 = 0, // Size of the icache flush stub in bytes ++ line_size = 32, // flush instruction affects a dword ++ log2_line_size = 5 // log2(line_size) ++ }; ++ static void initialize(); ++ ++ static void call_flush_stub(address start, int lines); ++ ++ static void invalidate_word(address addr); ++ ++ static void invalidate_range(address start, int nbytes); ++ ++ static void invalidate_all(); ++ ++}; ++ ++#endif // CPU_SW64_VM_ICACHE_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/icBuffer_sw64.cpp afu11u/src/hotspot/cpu/sw64/icBuffer_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/icBuffer_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/icBuffer_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "code/icBuffer.hpp" ++#include "gc/shared/collectedHeap.inline.hpp" ++#include "interpreter/bytecodes.hpp" ++#include "memory/resourceArea.hpp" ++#include "nativeInst_sw64.hpp" ++#include "oops/oop.inline.hpp" ++ ++int InlineCacheBuffer::ic_stub_code_size() { ++ return NativeMovConstReg::instruction_size + NativeJump::instruction_size; ++} ++ ++ ++ ++void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) {//Unimplemented(); ++ ResourceMark rm; ++ CodeBuffer code(code_begin, ic_stub_code_size()); ++ MacroAssembler* masm = new MacroAssembler(&code); ++ // note: even though the code contains an embedded value, we do not need reloc info ++ // because ++ // (1) the value is old (i.e., doesn't matter for scavenges) ++ // (2) these ICStubs are removed *before* a GC happens, so the roots disappear ++ // assert(cached_value == NULL || cached_oop->is_perm(), "must be perm oop"); ++ ++ // TODO:confirm jzy ++ // 1. need flush? ++ // 2. need relocate? ++ #define __ masm-> ++ __ prepare_patch_li48(V0, (long)cached_value); //sw64.ad #frame ++ ++ __ patchable_jump(entry_point); ++ __ flush(); ++#undef __ ++} ++ ++ ++address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { ++ NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object ++ address jmp = move->next_instruction_address(); ++ NativeInstruction* ni = nativeInstruction_at(jmp); ++ if (ni->is_jump()) { ++ NativeJump* jump = nativeJump_at(jmp); ++ return jump->jump_destination(); ++ } else { ++ fatal("no a ic buffer entry"); ++ return NULL; ++ } ++} ++ ++ ++void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { ++ // creation also verifies the object ++ NativeMovConstReg* move = nativeMovConstReg_at(code_begin); ++ // Verifies the jump ++ address jmp = move->next_instruction_address(); ++ NativeInstruction* ni = nativeInstruction_at(jmp); ++ if (ni->is_jump()) { ++ NativeJump* jump = nativeJump_at(jmp); ++ } else { ++ fatal("no a ic buffer entry"); ++ } ++ void* o = (void*)move->data(); ++ return o; ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/interp_masm_sw64.cpp afu11u/src/hotspot/cpu/sw64/interp_masm_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/interp_masm_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/interp_masm_sw64.cpp 2025-05-09 10:06:54.192292504 +0800 +@@ -0,0 +1,1909 @@ ++/* ++ * 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 "interp_masm_sw64.hpp" ++#include "interpreter/interpreter.hpp" ++#include "interpreter/interpreterRuntime.hpp" ++#include "logging/log.hpp" ++#include "oops/arrayOop.hpp" ++#include "oops/markOop.hpp" ++#include "oops/methodData.hpp" ++#include "oops/method.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 "assembler_sw64.hpp" ++ ++// Implementation of InterpreterMacroAssembler ++ ++void InterpreterMacroAssembler::jump_to_entry(address entry) { ++ assert(entry, "Entry must have been generated by now"); ++ jump(RuntimeAddress(entry)); ++} ++ ++void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { ++ Label update, next, none; ++ ++ verify_oop(obj); ++ ++ jcc(Assembler::notZero, update, obj); ++ ldptr(AT, mdo_addr); ++ orptr(AT, TypeEntries::null_seen, AT); ++ stptr(AT, mdo_addr); ++ jmp(next); ++ ++ bind(update); ++ load_klass(obj, obj); ++ ++ ldptr(AT, mdo_addr); ++ xorptr(obj, AT, obj); ++ testptr(obj, TypeEntries::type_klass_mask); ++ jcc(Assembler::zero, next); // klass seen before, nothing to ++ // do. The unknown bit may have been ++ // set already but no need to check. ++ ++ testptr(obj, TypeEntries::type_unknown); ++ jcc(Assembler::notZero, next); // already unknown. Nothing to do anymore. ++ ++ ldptr(AT, mdo_addr); ++ jcc(Assembler::zero, none, AT); ++ cmpptr(AT, TypeEntries::null_seen); ++ jcc(Assembler::equal, none); ++ // There is a chance that the checks above (re-reading profiling ++ // data from memory) fail if another thread has just set the ++ // profiling to this obj's klass ++ xorptr(obj, AT, obj); ++ testptr(obj, TypeEntries::type_klass_mask); ++ jcc(Assembler::zero, next); ++ ++ // different than before. Cannot keep accurate profile. ++ orptr(AT, TypeEntries::type_unknown, AT); ++ stptr(AT, mdo_addr); ++ jmp(next); ++ ++ bind(none); ++ // first time here. Set profile type. ++ stptr(obj, mdo_addr); ++ ++ bind(next); ++} ++ ++void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { ++ if (!ProfileInterpreter) { ++ return; ++ } ++ ++ if (MethodData::profile_arguments() || MethodData::profile_return()) { ++ Label profile_continue; ++ ++ test_method_data_pointer(mdp, profile_continue); ++ ++ int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); ++ ++ cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); ++ jcc(Assembler::notEqual, profile_continue); ++ ++ if (MethodData::profile_arguments()) { ++ Label done; ++ int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); ++ addptr(mdp, off_to_args, mdp); ++ ++ 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 ++ ldptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); ++ subw(tmp, i*TypeStackSlotEntries::per_arg_count(), tmp); ++ cmpw(tmp, TypeStackSlotEntries::per_arg_count()); ++ jcc(Assembler::less, done); ++ } ++ ldptr(tmp, Address(callee, Method::const_offset())); ++ ldhu(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); ++ // 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 ++ ldptr(AT, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); ++ subw(tmp, AT, tmp); ++ subw(tmp, 1, tmp); ++ Address arg_addr = argument_address(tmp); ++ ldptr(tmp, arg_addr); ++ ++ Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); ++ profile_obj_type(tmp, mdo_arg_addr); ++ ++ int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); ++ addptr(mdp, to_add, mdp); ++ off_to_args += to_add; ++ } ++ ++ if (MethodData::profile_return()) { ++ ldptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); ++ subw(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count(), tmp); ++ } ++ ++ bind(done); ++ ++ if (MethodData::profile_return()) { ++ // We're right after the type profile for the last ++ // argument. tmp 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"); ++ slll(tmp, exact_log2(DataLayout::cell_size), tmp); ++ //addw(tmp, 0, tmp); ++ addptr(mdp, tmp, mdp); ++ } ++ stptr(mdp, Address(rfp, frame::interpreter_frame_mdp_offset * wordSize)); ++ } else { ++ assert(MethodData::profile_return(), "either profile call args or call ret"); ++ update_mdp_by_constant(mdp, 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 mdp, Register ret, Register tmp) { ++ assert_different_registers(mdp, ret, tmp, _bcp_register); ++ if (ProfileInterpreter && MethodData::profile_return()) { ++ Label profile_continue, done; ++ ++ test_method_data_pointer(mdp, 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; ++ cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic); ++ jcc(Assembler::equal, do_profile); ++ cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle); ++ jcc(Assembler::equal, do_profile); ++ get_method(tmp); ++ cmph(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm); ++ jcc(Assembler::notEqual, profile_continue); ++ ++ bind(do_profile); ++ } ++ ++ Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); ++ movl(tmp, ret); ++ profile_obj_type(tmp, mdo_ret_addr); ++ ++ bind(profile_continue); ++ } ++} ++ ++void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) { ++ if (ProfileInterpreter && MethodData::profile_parameters()) { ++ Label profile_continue, done; ++ ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // Load the offset of the area within the MDO used for ++ // parameters. If it's negative we're not profiling any parameters ++ ldws(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); ++ jcc(Assembler::negative, profile_continue, tmp1); ++ ++ // 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 ++ addptr(mdp, tmp1, mdp); ++ ldptr(tmp1, Address(mdp, ArrayData::array_len_offset())); ++ decrementl(tmp1, TypeStackSlotEntries::per_arg_count()); ++ ++ Label loop; ++ bind(loop); ++ ++ int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); ++ int type_base = in_bytes(ParametersTypeData::type_offset(0)); ++ Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size); ++ Address arg_off(mdp, tmp1, per_arg_scale, off_base); ++ Address arg_type(mdp, tmp1, per_arg_scale, type_base); ++ ++ // load offset on the stack from the slot for this parameter ++ ldptr(tmp2, arg_off); ++ negptr(tmp2); ++ // read the parameter from the local area ++ ldptr(tmp2, Address(rlocals, tmp2, Interpreter::stackElementScale())); ++ ++ // profile the parameter ++ profile_obj_type(tmp2, arg_type); ++ ++ // go to next parameter ++ decrementl(tmp1, TypeStackSlotEntries::per_arg_count()); ++ jcc(Assembler::positive, loop, tmp1); ++ ++ bind(profile_continue); ++ } ++} ++ ++void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, ++ int number_of_arguments) {SCOPEMARK_NAME(InterpreterMacroAssembler::call_VM_leaf_base, this) ++ // interpreter specific ++ // ++ // Note: No need to save/restore bcp & locals (r13 & r14) pointer ++ // since these are callee saved registers and no blocking/ ++ // GC can happen in leaf calls. ++ // Further Note: DO NOT save/restore bcp/locals. If a caller has ++ // already saved them so that it can use BCP/LVP as temporaries ++ // then a save/restore here will DESTROY the copy the caller ++ // saved! There used to be a save_bcp() that only happened in ++ // the ASSERT path (no restore_bcp). Which caused bizarre failures ++ // when jvm built with ASSERTs. ++#ifdef ASSERT ++ { ++ Label L; ++ cmpptr(Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); ++ jcc(Assembler::equal, L); ++ stop("InterpreterMacroAssembler::call_VM_leaf_base:" ++ " last_sp != NULL"); ++ bind(L); ++ } ++#endif ++ // super call ++ MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); ++ // interpreter specific ++ // LP64: Used to ASSERT that BCP/LVP were equal to frame's bcp/locals ++ // but since they may not have been saved (and we don't want to ++ // save them here (see note above) the assert is invalid. ++} ++ ++void InterpreterMacroAssembler::call_VM_base(Register oop_result, ++ Register java_thread, ++ Register last_java_sp, ++ address entry_point, ++ int number_of_arguments, ++ bool check_exceptions) {SCOPEMARK_NAME(InterpreterMacroAssembler::call_VM_base, this) ++ // interpreter specific ++ // ++ // Note: Could avoid restoring locals ptr (callee saved) - however doesn't ++ // really make a difference for these runtime calls, since they are ++ // slow anyway. Btw., bcp must be saved/restored since it may change ++ // due to GC. ++ save_bcp(); ++#ifdef ASSERT ++ { ++ Label L; ++ cmpptr(Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); ++ jcc(Assembler::equal, L); ++ stop("InterpreterMacroAssembler::call_VM_base:" ++ " last_sp != NULL"); ++ bind(L); ++ } ++#endif /* ASSERT */ ++ // super call ++ MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, ++ entry_point, number_of_arguments, ++ check_exceptions); ++ // interpreter specific ++ restore_bcp(); ++ restore_locals(); ++} ++ ++void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { ++ if (JvmtiExport::can_pop_frame()) { ++ Label L; ++ // 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. ++ // This method is only called just after the call into the vm in ++ // call_VM_base, so the arg registers are available. ++ Register pop_cond = c_rarg0; ++ ldw(pop_cond, Address(java_thread, JavaThread::popframe_condition_offset())); ++ testw(pop_cond, JavaThread::popframe_pending_bit); ++ jcc(Assembler::zero, L); ++ testw(pop_cond, JavaThread::popframe_processing_bit); ++ jcc(Assembler::notZero, L); ++ // Call Interpreter::remove_activation_preserving_args_entry() to get the ++ // address of the same-named entrypoint in the generated interpreter code. ++ call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); ++ jmp(V0); ++ bind(L); ++ } ++} ++ ++void InterpreterMacroAssembler::load_earlyret_value(TosState state) { ++ const Register rcx = T11; ++ const Register rax = V0; ++ Register thread = rthread; ++ ldptr(rcx, Address(thread, JavaThread::jvmti_thread_state_offset())); ++ const Address tos_addr(rcx, JvmtiThreadState::earlyret_tos_offset()); ++ const Address oop_addr(rcx, JvmtiThreadState::earlyret_oop_offset()); ++ const Address val_addr(rcx, JvmtiThreadState::earlyret_value_offset()); ++ switch (state) { ++ case atos: ldptr(rax, oop_addr); ++ stptr(R0, oop_addr); ++ verify_oop(rax, state); break; ++ case ltos: ldptr(rax, val_addr); break; ++ case btos: // fall through ++ case ztos: // fall through ++ case ctos: // fall through ++ case stos: // fall through ++ case itos: ldws(rax, val_addr); break; ++ case ftos: load_float(FSF, val_addr); break; ++ case dtos: load_double(FSF, val_addr); break; ++ case vtos: /* nothing to do */ break; ++ default : ShouldNotReachHere(); ++ } ++ // Clean up tos value in the thread object ++ movw(AT, (int) ilgl); ++ stw(AT, tos_addr); ++ stptr(R0, val_addr); ++} ++ ++ ++void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { ++ if (JvmtiExport::can_force_early_return()) { ++ Label L; ++ Register tmp = c_rarg0; ++ ++ ldptr(tmp, Address(rthread, JavaThread::jvmti_thread_state_offset())); ++ testptr(tmp, tmp); ++ jcc(Assembler::zero, 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. ++ ldwu(tmp, Address(tmp, JvmtiThreadState::earlyret_state_offset())); ++ cmpw(tmp, JvmtiThreadState::earlyret_pending); ++ jcc(Assembler::notEqual, L); ++ ++ // Call Interpreter::remove_activation_early_entry() to get the address of the ++ // same-named entrypoint in the generated interpreter code. ++ ldptr(tmp, Address(rthread, JavaThread::jvmti_thread_state_offset())); ++ ldws(tmp, Address(tmp, JvmtiThreadState::earlyret_tos_offset())); ++ call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), tmp); ++ jmp(V0); ++ bind(L); ++ } ++} ++ ++void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, ++ int bcp_offset) { ++ assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); ++ ldbu(AT, bcp_offset, rbcp); ++ ldbu(reg, bcp_offset + 1, rbcp); ++ slll(AT, 8, AT); ++ bis(reg, AT, reg); ++} ++ ++void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, ++ int bcp_offset, ++ size_t index_size) {SCOPEMARK_NAME(get_cache_index_at_bcp, this) ++ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); ++ if (index_size == sizeof(u2)) { ++ ldhu_unaligned(index, Address(rbcp, bcp_offset)); ++ } else if (index_size == sizeof(u4)) { ++ ldw(index, Address(rbcp, bcp_offset)); ++ // Check if the secondary index definition is still ~x, otherwise ++ // we have to change the following assembler code to calculate the ++ // plain index. ++ assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); ++ notw(index, index); ++ } else if (index_size == sizeof(u1)) { ++ ldbu(index, Address(rbcp, bcp_offset)); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, ++ Register index, ++ int bcp_offset, ++ size_t index_size) {SCOPEMARK_NAME(get_cache_and_index_at_bcp, this) ++ assert_different_registers(cache, index); ++ get_cache_index_at_bcp(index, bcp_offset, index_size); ++ ldptr(cache, Address(rfp, frame::interpreter_frame_cache_offset * wordSize)); ++ assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); ++ // convert from field index to ConstantPoolCacheEntry index ++ assert(exact_log2(in_words(ConstantPoolCacheEntry::size())) == 2, "else change next line"); ++ slll(index, 2, index); ++} ++ ++void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, ++ Register index, ++ Register bytecode, ++ int byte_no, ++ int bcp_offset, ++ size_t index_size) {SCOPEMARK_NAME(get_cache_and_index_and_bytecode_at_bcp, this) ++ get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); ++ // We use a 32-bit load here since the layout of 64-bit words on ++ // little-endian machines allow us that. ++ ldwu(bytecode, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); ++ 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"); ++ srll(bytecode, shift_count, bytecode); ++ assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); ++ andw(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(cache != tmp, "must use different register"); ++ get_cache_index_at_bcp(tmp, bcp_offset, index_size); ++ assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); ++ // convert from field index to ConstantPoolCacheEntry index ++ // and from word offset to byte offset ++ assert(exact_log2(in_bytes(ConstantPoolCacheEntry::size_in_bytes())) == 2 + LogBytesPerWord, "else change next line"); ++ slll(tmp, 2 + LogBytesPerWord, tmp); ++ ldptr(cache, Address(rfp, frame::interpreter_frame_cache_offset * wordSize)); ++ // skip past the header ++ addptr(cache, in_bytes(ConstantPoolCache::base_offset()), cache); ++ addptr(cache, 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); ++ ++ get_constant_pool(result); ++ // load pointer for resolved_references[] objArray ++ ldptr(result, Address(result, ConstantPool::cache_offset_in_bytes())); ++ ldptr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes())); ++ resolve_oop_handle(result, tmp); ++ load_heap_oop(result, Address(result, index, ++ UseCompressedOops ? Address::times_4 : Address::times_ptr, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT)), tmp); ++} ++ ++// load cpool->resolved_klass_at(index) ++void InterpreterMacroAssembler::load_resolved_klass_at_index(Register cpool, ++ Register index, Register klass) { ++ ldhu(index, Address(cpool, index, Address::times_ptr, sizeof(ConstantPool))); ++ memb(); ++ Register resolved_klasses = cpool; ++ ldptr(resolved_klasses, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes())); ++ memb(); ++ ldptr(klass, Address(resolved_klasses, index, Address::times_ptr, Array::base_offset_in_bytes())); ++} ++ ++// Generate a subtype check: branch to ok_is_subtype if sub_klass is a ++// subtype of super_klass. ++// ++// Args: ++// FSR: superklass ++// Rsub_klass: subklass ++// ++// Kills: ++// T0, T1 ++void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, ++ Label& ok_is_subtype) {SCOPEMARK_NAME(gen_subtype_check, this) ++ Register rcx = c_rarg4; ++ Register rdi = T0; ++ Register rax = FSR; ++ assert(Rsub_klass != FSR, "FSR holds superklass"); ++ assert(Rsub_klass != rlocals, "s1 holds locals"); ++ assert(Rsub_klass != rbcp, "s0 holds bcp"); ++ assert(Rsub_klass != rcx, "T1 holds 2ndary super array length"); ++ assert(Rsub_klass != rdi, "T0 holds 2ndary super array scan ptr"); ++ ++ // Profile the not-null value's klass. ++ profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi ++ ++// Do the check. ++ check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx ++ ++// Profile the failure of the check. ++ profile_typecheck_failed(rcx); // blows rcx ++} ++ ++// Java Expression Stack ++ ++void InterpreterMacroAssembler::pop_ptr(Register r) { ++ assert(r != esp, "current not consider esp"); ++ if(UseSW8A) { ++ ldl_a(r, Interpreter::stackElementSize, esp); ++ } else { ++ ldptr(r, Address(esp, 0)); ++ addl(esp, Interpreter::stackElementSize, esp); ++ } ++} ++ ++void InterpreterMacroAssembler::push_ptr(Register r) { ++ assert(r != esp, "current not consider esp"); ++ subl(esp, Interpreter::stackElementSize, esp); ++ stptr(r, Address(esp, 0)); ++} ++ ++void InterpreterMacroAssembler::push_i(Register r) { ++ assert(r != esp, "current not consider esp"); ++ // For compatibility reason, don't change to sw. ++ movw(r, r);//clear high 32-bits zero ++ subl(esp, Interpreter::stackElementSize, esp); ++ stl(r, Address(esp, 0)); ++} ++ ++void InterpreterMacroAssembler::push_f(FloatRegister r) { ++ subl(esp, Interpreter::stackElementSize, esp); ++ fsts(r, Address(esp, 0)); ++} ++ ++void InterpreterMacroAssembler::pop_f(FloatRegister r) { ++ if(UseSW8A) { ++ flds_a(r, Interpreter::stackElementSize, esp); ++ } else { ++ flds(r, Address(esp, 0)); ++ addl(esp, Interpreter::stackElementSize, esp); ++ } ++} ++ ++void InterpreterMacroAssembler::push_d(FloatRegister r) { ++ subl(esp, 2 * Interpreter::stackElementSize, esp); ++ fstd(r, Address(esp, 0)); ++} ++ ++void InterpreterMacroAssembler::pop_d(FloatRegister r) { ++ if(UseSW8A) { ++ fldd_a(r, 2 * Interpreter::stackElementSize, esp); ++ } else { ++ fldd(r, Address(esp, 0)); ++ addl(esp, 2 * Interpreter::stackElementSize, esp); ++ } ++} ++ ++void InterpreterMacroAssembler::pop_i(Register r) { ++ assert(r != esp, "current not consider esp"); ++ if(UseSW8A) { ++ ldw_a(r, Interpreter::stackElementSize, esp); ++ } else { ++ ldws(r, Address(esp, 0)); ++ addl(esp, Interpreter::stackElementSize, esp); ++ } ++} ++ ++void InterpreterMacroAssembler::pop_l(Register r) { ++ assert(r != esp, "current not consider esp"); ++ if(UseSW8A) { ++ ldl_a(r, 2 * Interpreter::stackElementSize, esp); ++ } else { ++ ldptr(r, Address(esp, 0)); ++ addl(esp, 2 * Interpreter::stackElementSize, esp); ++ } ++} ++ ++void InterpreterMacroAssembler::push_l(Register r) { ++ assert(r != esp, "current not consider esp"); ++ subl(esp, 2 * Interpreter::stackElementSize, esp); ++ stptr(R0, Address(esp, Interpreter::stackElementSize)); ++ stptr(r, Address(esp, 0)); ++} ++ ++void InterpreterMacroAssembler::pop(TosState state) { ++ switch (state) { ++ case atos: pop_ptr(); break; ++ case btos: ++ case ztos: ++ case ctos: ++ case stos: ++ 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(); ++ } ++ verify_oop(FSR, state); ++} ++ ++//FSR=V0,SSR=T4 ++void InterpreterMacroAssembler::push(TosState state) { ++ verify_oop(FSR, state); ++ switch (state) { ++ case atos: push_ptr(); break; ++ case btos: ++ case ztos: ++ case ctos: ++ case stos: ++ 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(); ++ } ++} ++ ++// Helpers for swap and dup ++void InterpreterMacroAssembler::load_ptr(int n, Register val) { ++ ldptr(val, Address(esp, Interpreter::expr_offset_in_bytes(n))); ++} ++ ++void InterpreterMacroAssembler::store_ptr(int n, Register val) { ++ stptr(val, Address(esp, Interpreter::expr_offset_in_bytes(n))); ++} ++ ++void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {SCOPEMARK_NAME(prepare_to_jump_from_interpreted, this) ++ // set sender sp ++ movl(rsender, esp); ++ // record last_sp ++ stptr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++} ++ ++ ++// Jump to from_interpreted entry of a call unless single stepping is possible ++// in this thread in which case we must call the i2i entry ++void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {SCOPEMARK_NAME(jump_from_interpreted, this) ++ prepare_to_jump_from_interpreted(); ++ ++ if (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. ++ // interp_only is an int, on little endian it is sufficient to test the byte only ++ // Is a cmpl faster? ++ ldbu(AT, Address(rthread, JavaThread::interp_only_mode_offset())); ++ jcc(Assembler::zero, run_compiled_code, AT); ++ jmp(Address(method, Method::interpreter_entry_offset())); ++ bind(run_compiled_code); ++ } ++ ++ jmp(Address(method, Method::from_interpreted_offset())); ++} ++ ++// The following two routines provide a hook so that an implementation ++// can schedule the dispatch in two parts. sw64 does not do this. ++void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { ++ // Nothing sw64 specific to be done here ++} ++ ++void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { ++ dispatch_next(state, step); ++} ++ ++void InterpreterMacroAssembler::dispatch_base(TosState state, ++ address* table, ++ bool verifyoop, ++ bool generate_poll) { ++ // it's a convention that the bytecode to dispatch to in rnext ++ if (VerifyActivationFrameSize) { ++ Label L; ++ subptr(rfp, esp, rscratch1); ++ int32_t min_frame_size = ++ (frame::link_offset - frame::interpreter_frame_initial_sp_offset) * ++ wordSize; ++ cmpptr(rscratch1, (int32_t)min_frame_size); ++ jcc(Assembler::greaterEqual, L); ++ stop("broken stack frame"); ++ bind(L); ++ } ++ if (verifyoop) { ++ verify_oop(FSR, state); ++ } ++ ++ address* const safepoint_table = Interpreter::safept_table(state); ++ Label no_safepoint, dispatch; ++ if (SafepointMechanism::uses_thread_local_poll() && table != safepoint_table && generate_poll) { ++ NOT_PRODUCT(block_comment("Thread-local Safepoint poll")); ++ testb(Address(rthread, Thread::polling_page_offset()), SafepointMechanism::poll_bit()); ++ ++ jcc(Assembler::zero, no_safepoint); ++ lea(rscratch1, ExternalAddress((address)safepoint_table)); ++ jmp(dispatch); ++ } ++ ++ bind(no_safepoint); ++ lea(rscratch1, ExternalAddress((address)table)); ++ bind(dispatch); ++ jmp(Address(rscratch1, rnext, Address::times_8)); //set rnext like dispatch_next ++} ++ ++void InterpreterMacroAssembler::dispatch_only(TosState state, bool generate_poll) { ++ dispatch_base(state, Interpreter::dispatch_table(state), true, generate_poll); ++} ++ ++void InterpreterMacroAssembler::dispatch_only_normal(TosState state) { ++ dispatch_base(state, Interpreter::normal_table(state)); ++} ++ ++void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) { ++ dispatch_base(state, Interpreter::normal_table(state), false); ++} ++ ++ ++void InterpreterMacroAssembler::dispatch_next(TosState state, int step, bool generate_poll) {SCOPEMARK_NAME(InterpreterMacroAssembler::dispatch_next, this) ++ // load next bytecode (load before advancing rbcp to prevent AGI) ++ load_unsigned_byte(rnext, Address(rbcp, step));//use rnext in dispatch_base ++ // advance rbcp ++ incrementl(rbcp, step); ++ dispatch_base(state, Interpreter::dispatch_table(state), true, generate_poll); ++} ++ ++void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { ++ // load current bytecode ++ load_unsigned_byte(rnext, Address(rbcp, 0)); ++ dispatch_base(state, table); ++} ++ ++void InterpreterMacroAssembler::narrow(Register result) { ++ ++ const Register rcx = T9; ++ // Get method->_constMethod->_result_type ++ ldptr(rcx, Address(rfp, frame::interpreter_frame_method_offset * wordSize)); ++ ldptr(rcx, Address(rcx, Method::const_offset())); ++ load_unsigned_byte(rcx, Address(rcx, ConstMethod::result_type_offset())); ++ ++ Label done, notBool, notByte, notChar; ++ ++ // common case first ++ cmpw(rcx, T_INT); ++ jcc(Assembler::equal, done); ++ ++ // mask integer result to narrower return type. ++ cmpw(rcx, T_BOOLEAN); ++ jcc(Assembler::notEqual, notBool); ++ andw(result, 0x1, result); ++ jmp(done); ++ ++ bind(notBool); ++ cmpw(rcx, T_BYTE); ++ jcc(Assembler::notEqual, notByte); ++ sextb(result, result); //TODO jzy 64-bits? 32-bits? ++ jmp(done); ++ ++ bind(notByte); ++ cmpw(rcx, T_CHAR); ++ jcc(Assembler::notEqual, notChar); ++ zapnot(result, 0x3, result); ++ jmp(done); ++ ++ bind(notChar); ++ // cmpw(rcx, T_SHORT); // all that's left ++ // jcc(Assembler::notEqual, done); ++ sexth(result, result); ++ ++ // Nothing to do for T_INT ++ 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, ++ Register ret_addr, ++ bool throw_monitor_exception, ++ bool install_monitor_exception, ++ bool notify_jvmdi) {SCOPEMARK_NAME(remove_activation, this) ++ // Note: Registers V0, T4 and f0, f1 may be in use for the ++ // result check if synchronized method ++ Label unlocked, unlock, no_unlock; ++ ++ const Register rbx = T2; ++ const Register rcx = T3; ++ const Register robj = c_rarg1; ++ const Register rmon = c_rarg1; ++ ++ // get the value of _do_not_unlock_if_synchronized into rdx ++ const Address do_not_unlock_if_synchronized(rthread, ++ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); ++ ldbu(rbx, do_not_unlock_if_synchronized); ++ stb(R0, do_not_unlock_if_synchronized); // reset the flag ++ ++ // get method access flags ++ ldptr(rcx, Address(rfp, frame::interpreter_frame_method_offset * wordSize)); ++ ldw(rcx, Address(rcx, Method::access_flags_offset())); ++ testw(rcx, JVM_ACC_SYNCHRONIZED); ++ jcc(Assembler::zero, unlocked); ++ ++ // Don't unlock anything if the _do_not_unlock_if_synchronized flag ++ // is set. ++ jcc(Assembler::notZero, no_unlock, rbx); ++ ++ // unlock monitor ++ push(state); // save result ++ ++ // 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. ++ const Address monitor(rfp, frame::interpreter_frame_initial_sp_offset * ++ wordSize - (int) sizeof(BasicObjectLock)); ++ // We use c_rarg1 so that if we go slow path it will be the correct ++ // register for unlock_object to pass to VM directly ++ lea(robj, monitor); // address of first monitor ++ ++ ldptr(FSR, Address(robj, BasicObjectLock::obj_offset_in_bytes())); ++ jcc(Assembler::notZero, unlock, FSR); ++ ++ pop(state); ++ if (throw_monitor_exception) { ++ // Entry already unlocked, need to throw exception ++ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_illegal_monitor_state_exception)); ++ should_not_reach_here("throw_illegal_monitor_state_exception"); ++ } else { ++ // Monitor already unlocked during a stack unroll. If requested, ++ // install an illegal_monitor_state_exception. Continue with ++ // stack unrolling. ++ if (install_monitor_exception) { ++ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::new_illegal_monitor_state_exception)); ++ } ++ jmp(unlocked); ++ } ++ ++ bind(unlock); ++ unlock_object(robj); ++ pop(state); ++ ++ // Check that for block-structured locking (i.e., that all locked ++ // objects has been unlocked) ++ bind(unlocked); ++ ++ // FSR, rdx: Might contain return value ++ ++ // Check that all monitors are unlocked ++ { ++ Label loop, exception, entry, restart; ++ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; ++ const Address monitor_block_top( ++ rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); ++ const Address monitor_block_bot( ++ rfp, frame::interpreter_frame_initial_sp_offset * wordSize); ++ ++ bind(restart); ++ // We use c_rarg1 so that if we go slow path it will be the correct ++ // register for unlock_object to pass to VM directly ++ ldptr(rmon, monitor_block_top); // points to current entry, starting ++ // with top-most entry ++ lea(rbx, monitor_block_bot); // points to word before bottom of ++ // monitor block ++ jmp(entry); ++ ++ // Entry already locked, need to throw exception ++ bind(exception); ++ ++ if (throw_monitor_exception) { ++ // Throw exception ++ MacroAssembler::call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime:: ++ throw_illegal_monitor_state_exception)); ++ should_not_reach_here("892 throw_illegal_monitor_state_exception"); ++ } else { ++ // Stack unrolling. Unlock object and install illegal_monitor_exception. ++ // Unlock does not block, so don't have to worry about the frame. ++ // We don't have to preserve c_rarg1 since we are going to throw an exception. ++ ++ push(state); ++ movl(robj, rmon); // nop if robj and rmon are the same ++ unlock_object(robj); ++ pop(state); ++ ++ if (install_monitor_exception) { ++ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime:: ++ new_illegal_monitor_state_exception)); ++ } ++ ++ jmp(restart); ++ } ++ ++ bind(loop); ++ // check if current entry is used ++ ldptr(rcc, Address(rmon, BasicObjectLock::obj_offset_in_bytes())); ++ jcc(Assembler::notZero, exception); ++ ++ addptr(rmon, entry_size, rmon); // otherwise advance to next entry ++ bind(entry); ++ cmpptr(rmon, rbx); // check if bottom reached ++ jcc(Assembler::notEqual, loop); // if not at bottom then check this entry ++ } ++ ++ bind(no_unlock); ++ ++ // jvmti support ++ if (notify_jvmdi) { ++ notify_method_exit(state, NotifyJVMTI); // preserve TOSCA ++ } else { ++ notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA ++ } ++ ++ // remove activation ++ // get sender sp ++ ldptr(rbx, ++ Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); ++ if (StackReservedPages > 0) { ++ // testing if reserved zone needs to be re-enabled ++ Label no_reserved_zone_enabling; ++ ++ ldwu(AT, Address(rthread, JavaThread::stack_guard_state_offset())); ++ cmpw(AT, JavaThread::stack_guard_enabled); ++ jcc(Assembler::equal, no_reserved_zone_enabling); ++ ++ ldptr(AT, Address(rthread, JavaThread::reserved_stack_activation_offset())); ++ cmpptr(rbx, AT); ++ jcc(Assembler::lessEqual, no_reserved_zone_enabling); ++ ++ call_VM_leaf( ++ CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); ++ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_delayed_StackOverflowError)); ++ should_not_reach_here("throw_delayed_StackOverflowError"); ++ ++ bind(no_reserved_zone_enabling); ++ } ++ leave(); // remove frame anchor ++ movl(ret_addr, RA); // get return address TODO:jzy ++ movl(esp, rbx); // set sp to sender sp ++} ++ ++void InterpreterMacroAssembler::get_method_counters(Register method, ++ Register mcs, Label& skip) { ++ Label has_counters; ++ ldptr(mcs, Address(method, Method::method_counters_offset())); ++ testptr(mcs, mcs); ++ jcc(Assembler::notZero, has_counters); ++ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::build_method_counters), method); ++ ldptr(mcs, Address(method,Method::method_counters_offset())); ++ testptr(mcs, mcs); ++ jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory ++ bind(has_counters); ++} ++ ++// Lock object ++// ++// Args: ++// rdx, c_rarg1: BasicObjectLock to be used for locking ++// ++// Kills: ++// rax, rbx ++void InterpreterMacroAssembler::lock_object(Register lock_reg) { ++ assert(lock_reg == c_rarg1, ++ "The argument is only for looks. It must be c_rarg1"); ++ ++ const Register rax = T2; ++ const Register rbx = T1; ++ ++ if (UseHeavyMonitors) { ++ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), ++ lock_reg); ++ } else { ++ Label done; ++ ++ const Register swap_reg = rax; // Must use rax for cmpxchg instruction ++ const Register tmp_reg = rbx; // Will be passed to biased_locking_enter to avoid a ++ // problematic case where tmp_reg = no_reg. ++ const Register obj_reg = c_rarg3; // Will contain the oop ++ ++ const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); ++ const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); ++ const int mark_offset = lock_offset + ++ BasicLock::displaced_header_offset_in_bytes(); ++ ++ Label slow_case; ++ ++ // Load object pointer into obj_reg ++ ldptr(obj_reg, Address(lock_reg, obj_offset)); ++ ++ if (UseBiasedLocking) { ++ biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp_reg, false, done, &slow_case); ++ } ++ ++ // Load immediate 1 into swap_reg %rax ++ ldi(swap_reg, (int32_t)1, R0); ++ ++ // Load (object->mark() | 1) into swap_reg %rax ++ ldptr(AT, Address(obj_reg, oopDesc::mark_offset_in_bytes())); ++ orptr(swap_reg, AT, swap_reg); ++ ++ // Save (object->mark() | 1) into BasicLock's displaced header ++ stptr(swap_reg, Address(lock_reg, mark_offset)); ++ ++ assert(lock_offset == 0, ++ "displaced header must be first word in BasicObjectLock"); ++ ++ cmpxchg(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()), swap_reg);// ++ ++ if (PrintBiasedLockingStatistics) { ++ Label L; ++ jcc(Assembler::failed, L, AT); ++ atomic_inc32((address)BiasedLocking::fast_path_entry_count_addr(), 1, tmp_reg, rscratch1); ++ jmp(done); ++ bind(L); ++ } else { ++ jcc(Assembler::success, done, AT); ++ } ++ ++ const int zero_bits = 7;// yj todo: 7 or 3?? 7 means lsb 3 bits must be same, while 3 mean 2 bits ++ ++ // Test if the oopMark is an obvious stack pointer, i.e., ++ // 1) (mark & zero_bits) == 0, and ++ // 2) esp <= mark < mark + os::pagesize() ++ // ++ // These 3 tests can be done by evaluating the following ++ // expression: ((mark - esp) & (zero_bits - os::vm_page_size())), ++ // assuming both stack pointer and pagesize have their ++ // least significant bits clear. ++ // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg ++ subptr(swap_reg, esp, swap_reg); ++ andptr(swap_reg, zero_bits - os::vm_page_size(), swap_reg); ++ ++ // Save the test result, for recursive case, the result is zero ++ stptr(swap_reg, Address(lock_reg, mark_offset)); ++ ++ if (PrintBiasedLockingStatistics) { ++ Label L; ++ jcc(Assembler::notZero, L, swap_reg); ++ atomic_inc32((address)BiasedLocking::fast_path_entry_count_addr(), 1, tmp_reg, rscratch1); ++ jmp(done); ++ bind(L); ++ } else { ++ jcc(Assembler::zero, done, swap_reg); ++ } ++ ++ bind(slow_case); ++ ++ // Call the runtime routine for 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. Throws an IllegalMonitorException if object is ++// not locked by current thread. ++// ++// Args: ++// c_rarg1: BasicObjectLock for lock ++// ++// Kills: ++// rax ++// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) ++// rscratch1, rscratch2 (scratch regs) ++void InterpreterMacroAssembler::unlock_object(Register lock_reg) { ++ assert(lock_reg == c_rarg1, ++ "The argument is only for looks. It must be c_rarg1"); ++ ++ if (UseHeavyMonitors) { ++ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), ++ lock_reg); ++ } else { ++ Label done; ++ ++ const Register swap_reg = T2; ++ const Register header_reg = c_rarg2; // Will contain the old oopMark ++ const Register obj_reg = c_rarg3; // Will contain the oop ++ ++ save_bcp(); // Save in case of exception ++ ++ // Convert from BasicObjectLock structure to object and BasicLock structure ++ // Store the BasicLock address into %T2 ++ lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes())); ++ ++ // Load oop into obj_reg(%c_rarg3) ++ ldptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); ++ ++ // Free entry ++ stptr(R0, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); ++ ++ if (UseBiasedLocking) { ++ biased_locking_exit(obj_reg, header_reg, done); ++ } ++ ++ // Load the old header from BasicLock structure ++ ldptr(header_reg, Address(swap_reg, ++ BasicLock::displaced_header_offset_in_bytes())); ++ ++ // Test for recursion ++ testptr(header_reg, header_reg); ++ ++ // zero for recursive case ++ jcc(Assembler::zero, done); ++ ++ // Atomic swap back the old header ++ cmpxchg(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()), swap_reg); ++ ++ // zero for recursive case ++ jcc(Assembler::success, done); ++ ++ // Call the runtime routine for slow case. ++ stptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); // restore obj ++ ++ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), ++ lock_reg); ++ ++ bind(done); ++ ++ restore_bcp(); ++ } ++} ++ ++void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, ++ Label& zero_continue) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ ldptr(mdp, Address(rfp, frame::interpreter_frame_mdp_offset * wordSize)); ++ jcc(Assembler::zero, zero_continue, mdp); ++} ++ ++// Set the method data pointer for the current bcp. ++void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ Label set_mdp; ++ const Register rax = V0;//TODO:why not save? jzy ++ const Register rbx = T9; ++// V0 and T0 will be used as two temporary registers. ++ stl(rax, (-1) * wordSize, esp); ++ stl(rbx, (-2) * wordSize, esp); ++ subl(esp, 2 * wordSize, esp); ++ ++ get_method(rbx); ++ // Test MDO to avoid the call if it is NULL. ++ ldptr(rax, Address(rbx, in_bytes(Method::method_data_offset()))); ++ testptr(rax, rax); ++ jcc(Assembler::zero, set_mdp); ++ // rbx: method ++ // _bcp_register: bcp ++ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, _bcp_register); ++ // rax: mdi ++ // mdo is guaranteed to be non-zero here, we checked for it before the call. ++ get_method(rbx); ++ ldptr(rbx, Address(rbx, in_bytes(Method::method_data_offset()))); ++ addptr(rbx, in_bytes(MethodData::data_offset()), rbx); ++ addptr(rax, rbx, rax); ++ bind(set_mdp); ++ stptr(rax, Address(rfp, frame::interpreter_frame_mdp_offset * wordSize)); //TODO check? lsp ++ addl(esp, 2 * wordSize, esp); ++ ldl(rax, (-1) * wordSize, esp); ++ ldl(rbx, (-2) * wordSize, esp); ++} ++//TODO:why not save c_rarg0 c_rarg1 ++void InterpreterMacroAssembler::verify_method_data_pointer() { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++#ifdef ASSERT ++ Label verify_continue; ++ push(rax); ++ push(rbx); ++ Register arg3_reg = c_rarg3; ++ Register arg2_reg = c_rarg2; ++ push(arg3_reg); ++ push(arg2_reg); ++ test_method_data_pointer(arg3_reg, verify_continue); // If mdp is zero, continue ++ get_method(rbx); ++ ++ // If the mdp is valid, it will point to a DataLayout header which is ++ // consistent with the bcp. The converse is highly probable also. ++ load_unsigned_short(arg2_reg, ++ Address(arg3_reg, in_bytes(DataLayout::bci_offset()))); ++ addptr(arg2_reg, Address(rbx, Method::const_offset())); ++ lea(arg2_reg, Address(arg2_reg, ConstMethod::codes_offset())); ++ cmpptr(arg2_reg, _bcp_register); ++ jcc(Assembler::equal, verify_continue); ++ // rbx: method ++ // _bcp_register: bcp ++ // c_rarg3: mdp ++ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), ++ rbx, _bcp_register, arg3_reg); ++ bind(verify_continue); ++ pop(arg2_reg); ++ pop(arg3_reg); ++ pop(rbx); ++ pop(rax); ++#endif // ASSERT ++} ++ ++ ++void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, ++ int constant, ++ Register value) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ Address data(mdp_in, constant); ++ stptr(value, data); ++} ++ ++ ++void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, ++ int constant, ++ bool decrement) { ++ // Counter address ++ Address data(mdp_in, constant); ++ ++ increment_mdp_data_at(data, decrement); ++} ++ ++void InterpreterMacroAssembler::increment_mdp_data_at(Address data, ++ bool decrement) { ++ //TODO check lsp??? ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ // %%% this does 64bit counters at best it is wasting space ++ // at worst it is a rare bug when counters overflow ++ ++ if (decrement) { ++ // Decrement the register. ++ ldptr(rscratch4, data); ++ ldi(rscratch4, (int32_t) -DataLayout::counter_increment, rscratch4); ++ // If the decrement causes the counter to overflow, stay negative ++ Label L; ++ jcc(Assembler::greaterEqual, L, rscratch4); ++ stptr(rscratch4, data); ++ bind(L); ++ } else { ++ assert(DataLayout::counter_increment == 1, ++ "flow-free idiom only works with 1"); ++ ldptr(rscratch4, data); ++ // Increment the register. ++ ldi(rscratch1, DataLayout::counter_increment, rscratch4); ++ // If the increment causes the counter to overflow, pull back by 1. ++ Label L; ++ cmpult(rscratch1, rscratch4, rcc); ++ bne_l(rcc, L); ++ stptr(rscratch1, data); ++ bind(L); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, ++ Register reg, ++ int constant, ++ bool decrement) {SCOPEMARK_NAME(InterpreterMacroAssembler::increment_mdp_data_at, this) ++ assert_different_registers(mdp_in, reg, rscratch1, rscratch4); ++ Address data(mdp_in, reg, Address::times_1, constant); ++ ++ increment_mdp_data_at(data, decrement); ++} ++ ++void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, ++ int flag_byte_constant) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ int header_offset = in_bytes(DataLayout::flags_offset()); ++ int header_bits = flag_byte_constant; ++ // Set the flag ++ ldbu(rscratch4, Address(mdp_in, header_offset)); ++ bis(rscratch4, header_bits, rscratch4); ++ stb(rscratch4, Address(mdp_in, header_offset)); ++} ++ ++ ++ ++void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, ++ int offset, ++ Register value, ++ Register test_value_out, ++ Label& not_equal_continue) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ if (test_value_out == noreg) { ++ cmpptr(value, Address(mdp_in, offset)); ++ } else { ++ // Put the test value into a register, so caller can use it: ++ ldptr(test_value_out, Address(mdp_in, offset)); ++ cmpptr(test_value_out, value); ++ } ++ jcc(Assembler::notEqual, not_equal_continue); ++} ++ ++ ++void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, ++ int offset_of_disp) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ Address disp_address(mdp_in, offset_of_disp); ++ addptr(mdp_in, disp_address); ++ stptr(mdp_in, Address(rfp, frame::interpreter_frame_mdp_offset * wordSize)); ++} ++ ++ ++void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, ++ Register reg, ++ int offset_of_disp) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ Address disp_address(mdp_in, reg, Address::times_1, offset_of_disp); ++ addptr(mdp_in, disp_address); ++ stptr(mdp_in, Address(rfp, frame::interpreter_frame_mdp_offset * wordSize)); ++} ++ ++ ++void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, ++ int constant) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ addptr(mdp_in, constant, mdp_in); ++ stptr(mdp_in, Address(rfp, frame::interpreter_frame_mdp_offset * wordSize)); ++} ++ ++ ++void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { ++ assert(ProfileInterpreter, "must be profiling interpreter"); ++ push(return_bci); // save/restore across call_VM ++ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), ++ return_bci); ++ pop(return_bci); ++} ++ ++ ++void InterpreterMacroAssembler::profile_taken_branch(Register mdp, ++ Register bumped_count) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ // Otherwise, assign to mdp ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // We are taking a branch. Increment the taken count. ++ // We inline increment_mdp_data_at to return bumped_count in a register ++ //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); ++ Address data(mdp, in_bytes(JumpData::taken_offset())); ++ ldptr(rscratch4, data); ++ assert(DataLayout::counter_increment == 1, ++ "flow-free idiom only works with 1"); ++ // yj: we learn aarch64 here to test overflow ++ Label L; ++ ldi(bumped_count, DataLayout::counter_increment, rscratch4); ++ cmpult(bumped_count, rscratch4, rcc); ++ bne_l(rcc, L); ++ stptr(bumped_count, data); ++ bind(L); ++// stptr(bumped_count, in_bytes(JumpData::taken_offset()), mdp); // Store back out ++ // The method data pointer needs to be updated to reflect the new target. ++ update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // We are taking a branch. Increment the not taken count. ++ increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); ++ ++ // The method data pointer needs to be updated to correspond to ++ // the next bytecode ++ update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); ++ bind(profile_continue); ++ } ++} ++ ++void InterpreterMacroAssembler::profile_call(Register mdp) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // We are making a call. Increment the count. ++ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); ++ ++ // The method data pointer needs to be updated to reflect the new target. ++ update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_final_call(Register mdp) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // We are making a call. Increment the count. ++ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); ++ ++ // The method data pointer needs to be updated to reflect the new target. ++ update_mdp_by_constant(mdp, ++ in_bytes(VirtualCallData:: ++ virtual_call_data_size())); ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_virtual_call(Register receiver, ++ Register mdp, ++ Register reg2, ++ bool receiver_can_be_null) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ Label skip_receiver_profile; ++ if (receiver_can_be_null) { ++ Label not_null; ++ jcc(Assembler::notZero, not_null, receiver); ++ // We are making a call. Increment the count for null receiver. ++ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); ++ jmp(skip_receiver_profile); ++ bind(not_null); ++ } ++ ++ // Record the receiver type. ++ record_klass_in_profile(receiver, mdp, reg2, true); ++ bind(skip_receiver_profile); ++ ++ // The method data pointer needs to be updated to reflect the new target. ++#if INCLUDE_JVMCI ++ if (MethodProfileWidth == 0) { ++ update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); ++ } ++#else // INCLUDE_JVMCI ++ update_mdp_by_constant(mdp, ++ in_bytes(VirtualCallData:: ++ virtual_call_data_size())); ++#endif // INCLUDE_JVMCI ++ bind(profile_continue); ++ } ++} ++ ++#if INCLUDE_JVMCI ++void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) { ++ assert_different_registers(method, mdp, reg2); ++ if (ProfileInterpreter && MethodProfileWidth > 0) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ Label done; ++ record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth, ++ &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); ++ bind(done); ++ ++ update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); ++ bind(profile_continue); ++ } ++} ++#endif // INCLUDE_JVMCI ++ ++// This routine creates a state machine for updating the multi-row ++// type profile at a virtual call site (or other type-sensitive bytecode). ++// The machine visits each row (of receiver/count) until the receiver type ++// is found, or until it runs out of rows. At the same time, it remembers ++// the location of the first empty row. (An empty row records null for its ++// receiver, and can be allocated for a newly-observed receiver type.) ++// Because there are two degrees of freedom in the state, a simple linear ++// search will not work; it must be a decision tree. Hence this helper ++// function is recursive, to generate the required tree structured code. ++// It's the interpreter, so we are trading off code space for speed. ++// See below for example code. ++void InterpreterMacroAssembler::record_klass_in_profile_helper( ++ Register receiver, Register mdp, ++ Register reg2, int start_row, ++ Label& done, bool is_virtual_call) { ++ if (TypeProfileWidth == 0) { ++ if (is_virtual_call) { ++ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); ++ } ++#if INCLUDE_JVMCI ++ else if (EnableJVMCI) { ++ increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset())); ++ } ++#endif // INCLUDE_JVMCI ++ } 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 // INCLUDE_JVMCI ++ ++ record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, ++ &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); ++ } ++} ++ ++void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, ++ Register reg2, 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(mdp, item_offset, item, ++ (test_for_null_also ? reg2 : noreg), ++ next_test); ++ // (Reg2 now contains the item from the CallData.) ++ ++ // The item is item[n]. Increment count[n]. ++ int count_offset = in_bytes(item_count_offset_fn(row)); ++ increment_mdp_data_at(mdp, count_offset); ++ jmp(done); ++ bind(next_test); ++ ++ if (test_for_null_also) { ++ Label found_null; ++ // Failed the equality check on item[n]... Test for null. ++ testptr(reg2, reg2); ++ if (start_row == last_row) { ++ // The only thing left to do is handle the null case. ++ if (non_profiled_offset >= 0) { ++ jcc(Assembler::zero, found_null); ++ // 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(mdp, non_profiled_offset); ++ jmp(done); ++ bind(found_null); ++ } else { ++ jcc(Assembler::notZero, done); ++ } ++ break; ++ } ++ // Since null is rare, make it be the branch-taken case. ++ jcc(Assembler::zero, found_null); ++ ++ // Put all the "Case 3" tests here. ++ record_item_in_profile_helper(item, mdp, reg2, 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(mdp, item_offset, item); ++ int count_offset = in_bytes(item_count_offset_fn(start_row)); ++ movw(reg2, DataLayout::counter_increment); ++ set_mdp_data_at(mdp, count_offset, reg2); ++ if (start_row > 0) { ++ jmp(done); ++ } ++} ++ ++// Example state machine code for three profile rows: ++// // main copy of decision tree, rooted at row[1] ++// if (row[0].rec == rec) { row[0].incr(); goto done; } ++// if (row[0].rec != NULL) { ++// // inner copy of decision tree, rooted at row[1] ++// if (row[1].rec == rec) { row[1].incr(); goto done; } ++// if (row[1].rec != NULL) { ++// // degenerate decision tree, rooted at row[2] ++// if (row[2].rec == rec) { row[2].incr(); goto done; } ++// if (row[2].rec != NULL) { count.incr(); goto done; } // overflow ++// row[2].init(rec); goto done; ++// } else { ++// // remember row[1] is empty ++// if (row[2].rec == rec) { row[2].incr(); goto done; } ++// row[1].init(rec); goto done; ++// } ++// } else { ++// // remember row[0] is empty ++// if (row[1].rec == rec) { row[1].incr(); goto done; } ++// if (row[2].rec == rec) { row[2].incr(); goto done; } ++// row[0].init(rec); goto done; ++// } ++// done: ++ ++void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, ++ Register mdp, Register reg2, ++ bool is_virtual_call) { ++ assert(ProfileInterpreter, "must be profiling"); ++ Label done; ++ ++ record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); ++ ++ bind (done); ++} ++ ++void InterpreterMacroAssembler::profile_ret(Register return_bci, ++ Register mdp) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ uint row; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // Update the total ret count. ++ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); ++ ++ for (row = 0; row < RetData::row_limit(); row++) { ++ Label next_test; ++ ++ // See if return_bci is equal to bci[n]: ++ test_mdp_data_at(mdp, ++ in_bytes(RetData::bci_offset(row)), ++ return_bci, noreg, ++ next_test); ++ ++ // return_bci is equal to bci[n]. Increment the count. ++ increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); ++ ++ // The method data pointer needs to be updated to reflect the new target. ++ update_mdp_by_offset(mdp, ++ in_bytes(RetData::bci_displacement_offset(row))); ++ jmp(profile_continue); ++ bind(next_test); ++ } ++ ++ update_mdp_for_ret(return_bci); ++ ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_null_seen(Register mdp) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); ++ ++ // The method data pointer needs to be updated. ++ int mdp_delta = in_bytes(BitData::bit_data_size()); ++ if (TypeProfileCasts) { ++ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); ++ } ++ update_mdp_by_constant(mdp, mdp_delta); ++ ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { ++ if (ProfileInterpreter && TypeProfileCasts) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ int count_offset = in_bytes(CounterData::count_offset()); ++ // Back up the address, since we have already bumped the mdp. ++ count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); ++ ++ // *Decrement* the counter. We expect to see zero or small negatives. ++ increment_mdp_data_at(mdp, count_offset, true); ++ ++ bind (profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // The method data pointer needs to be updated. ++ int mdp_delta = in_bytes(BitData::bit_data_size()); ++ if (TypeProfileCasts) { ++ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); ++ ++ // Record the object type. ++ record_klass_in_profile(klass, mdp, reg2, false); ++ } ++ update_mdp_by_constant(mdp, mdp_delta); ++ ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_switch_default(Register mdp) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // Update the default case count ++ increment_mdp_data_at(mdp, ++ in_bytes(MultiBranchData::default_count_offset())); ++ ++ // The method data pointer needs to be updated. ++ update_mdp_by_offset(mdp, ++ in_bytes(MultiBranchData:: ++ default_displacement_offset())); ++ ++ bind(profile_continue); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::profile_switch_case(Register index, ++ Register mdp, ++ Register reg2) { ++ if (ProfileInterpreter) { ++ Label profile_continue; ++ ++ // If no method data exists, go to profile_continue. ++ test_method_data_pointer(mdp, profile_continue); ++ ++ // Build the base (index * per_case_size_in_bytes()) + ++ // case_array_offset_in_bytes() ++ movw(reg2, in_bytes(MultiBranchData::per_case_size())); ++ mull(index, reg2, index); ++ addptr(index, in_bytes(MultiBranchData::case_array_offset()), index); ++ ++ // Update the case count ++ increment_mdp_data_at(mdp, ++ index, ++ in_bytes(MultiBranchData::relative_count_offset())); ++ ++ // The method data pointer needs to be updated. ++ update_mdp_by_offset(mdp, ++ index, ++ in_bytes(MultiBranchData:: ++ relative_displacement_offset())); ++ ++ bind(profile_continue); ++ } ++} ++ ++ ++ ++void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { ++ if (state == atos) { ++ MacroAssembler::verify_oop(reg); ++ } ++} ++ ++void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { ; } ++ ++// Jump if ((*counter_addr += increment) & mask) satisfies the condition. ++void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, ++ int increment, Address mask, ++ Register scratch, bool preloaded, ++ Condition cond, Label* where) { ++ assert_different_registers(scratch, rcc); ++ if (!preloaded) { ++ ldwu(scratch, counter_addr); ++ } ++ incrementw(scratch, increment); ++ stw(scratch, counter_addr); ++ ldwu(rcc, mask); ++ andw(scratch, rcc, scratch); ++ if (where != NULL) { ++ jcc(cond, *where, scratch); ++ } ++} ++ ++void InterpreterMacroAssembler::notify_method_entry() {SCOPEMARK_NAME(notify_method_entry, this) ++ // Whenever JVMTI is interp_only_mode, method entry/exit events are sent 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. ++ Register rdx = rscratch4; ++ Register rarg = c_rarg1; ++ if (JvmtiExport::can_post_interpreter_events()) { ++ Label L; ++ get_thread(rthread); ++ ldw(rdx, Address(rthread, JavaThread::interp_only_mode_offset())); ++ jcc(Assembler::zero, L, rdx); ++ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::post_method_entry)); ++ bind(L); ++ } ++ ++ { ++ SkipIfEqual skip_if(this, &DTraceMethodProbes, 0); ++ get_method(rarg); ++ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), ++ rthread, rarg); ++ } ++ ++ // RedefineClasses() tracing support for obsolete method entry ++ if (log_is_enabled(Trace, redefine, class, obsolete)) { ++ NOT_LP64(get_thread(rthread);) ++ get_method(rarg); ++ call_VM_leaf( ++ CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), ++ rthread, rarg); ++ } ++} ++ ++ ++void InterpreterMacroAssembler::notify_method_exit( ++ TosState state, NotifyMethodExitMode mode) {SCOPEMARK_NAME(notify_method_exit, this) ++ // Whenever JVMTI is interp_only_mode, method entry/exit events are sent 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. ++ Register rdx = rscratch4; ++ Register rarg = c_rarg1; ++ if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { ++ Label L; ++ // Note: frame::interpreter_frame_result has a dependency on how the ++ // method result is saved across the call to post_method_exit. If this ++ // is changed then the interpreter_frame_result implementation will ++ // need to be updated too. ++ ++ // template interpreter will leave the result on the top of the stack. ++ push(state); ++ ldw(rdx, Address(rthread, JavaThread::interp_only_mode_offset())); ++ jcc(Assembler::zero, L, rdx); ++ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); ++ bind(L); ++ pop(state); ++ } ++ ++ { ++ SkipIfEqual skip(this, &DTraceMethodProbes, false); ++ push(state); ++ get_thread(rthread); ++ get_method(rarg); ++ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), ++ rthread, rarg); ++ pop(state); ++ } ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/interp_masm_sw64.hpp afu11u/src/hotspot/cpu/sw64/interp_masm_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/interp_masm_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/interp_masm_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,293 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * 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_SW64_VM_INTERP_MASM_SW64_64_HPP ++#define CPU_SW64_VM_INTERP_MASM_SW64_64_HPP ++ ++#include "asm/macroAssembler.hpp" ++#include "interpreter/invocationCounter.hpp" ++#include "runtime/frame.hpp" ++ ++// This file specializes the assember with interpreter-specific macros ++ ++typedef ByteSize (*OffsetFunction)(uint); ++ ++class InterpreterMacroAssembler: public MacroAssembler { ++ protected: ++ ++ // Interpreter specific version of call_VM_base ++ using MacroAssembler::call_VM_leaf_base; ++ ++ // Interpreter specific version of call_VM_base ++ virtual void call_VM_leaf_base(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_exceptions); ++ ++ // base routine for all dispatches ++ void dispatch_base(TosState state, address* table, bool verifyoop = true, bool generate_poll = false); ++ ++ public: ++ InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), ++ _locals_register(rlocals), ++ _bcp_register(rbcp) {} ++ ++ void jump_to_entry(address entry); ++ ++ virtual void check_and_handle_popframe(Register java_thread); ++ virtual void check_and_handle_earlyret(Register java_thread); ++ ++ void load_earlyret_value(TosState state); ++ ++ // Interpreter-specific registers ++ void save_bcp() {assert(_bcp_register == rbcp, "_bcp_register should rbcp"); ++ stptr(_bcp_register, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize)); ++ } ++ ++ void restore_bcp() {assert(_bcp_register == rbcp, "_bcp_register should rbcp"); ++ ldptr(_bcp_register, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize)); ++ } ++ ++ void restore_locals() {assert(_locals_register == rlocals, "_locals_register should rlocals"); ++ ldptr(_locals_register, Address(rfp, frame::interpreter_frame_locals_offset * wordSize)); ++ } ++ ++ // Helpers for runtime call arguments/results ++ void get_method(Register reg) { ++ ldptr(reg, Address(rfp, frame::interpreter_frame_method_offset * wordSize)); ++ } ++ ++ void get_const(Register reg) { ++ get_method(reg); ++ ldptr(reg, Address(reg, Method::const_offset())); ++ } ++ ++ void get_constant_pool(Register reg) { ++ get_const(reg); ++ ldptr(reg, Address(reg, ConstMethod::constants_offset())); ++ } ++ ++ void get_constant_pool_cache(Register reg) { ++ get_constant_pool(reg); ++ ldptr(reg, Address(reg, ConstantPool::cache_offset_in_bytes())); ++ } ++ ++ void get_cpool_and_tags(Register cpool, Register tags) { ++ get_constant_pool(cpool); ++ ldptr(tags, Address(cpool, ConstantPool::tags_offset_in_bytes())); ++ } ++ ++ void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); ++ void get_cache_and_index_at_bcp(Register cache, ++ Register index, ++ int bcp_offset, ++ size_t index_size = sizeof(u2)); ++ void get_cache_and_index_and_bytecode_at_bcp(Register cache, ++ Register index, ++ 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)); ++ void get_cache_index_at_bcp(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 = rscratch2); ++ ++ // load cpool->resolved_klass_at(index) ++ void load_resolved_klass_at_index(Register cpool, // the constant pool (corrupted on return) ++ Register index, // the constant pool index (corrupted on return) ++ Register klass); // contains the Klass on return ++ ++ void pop_ptr(Register r = FSR); ++ void pop_i(Register r = FSR); ++ void push_ptr(Register r = FSR); ++ void push_i(Register r = FSR); ++ ++ ++ void push_f(FloatRegister r = FSF); ++ void pop_f(FloatRegister r = FSF); ++ void pop_d(FloatRegister r = FSF); ++ void push_d(FloatRegister r = FSF); ++ ++ void pop_l(Register r = FSR); ++ void push_l(Register r = FSR); ++ ++ void pop(Register r) { ((MacroAssembler*)this)->pop(r); } ++ void push(Register r) { ((MacroAssembler*)this)->push(r); } ++ void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); } ++ ++ void pop(TosState state); // transition vtos -> state ++ void push(TosState state); // transition state -> vtos ++ ++// void pop(RegSet regs, Register stack) { ((MacroAssembler*)this)->pop(regs, stack); } ++// void push(RegSet regs, Register stack) { ((MacroAssembler*)this)->push(regs, stack); } ++ ++ void empty_expression_stack() { ++ ldptr(esp, Address(rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize)); ++ // NULL last_sp until next java call ++ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ } ++ ++ // Helpers for swap and dup ++ void load_ptr(int n, Register val); ++ void store_ptr(int n, Register val); ++ ++ // Generate a subtype check: branch to ok_is_subtype if sub_klass is ++ // a subtype of super_klass. ++ void gen_subtype_check( Register sub_klass, Label &ok_is_subtype ); ++ ++ // Dispatching ++ void dispatch_prolog(TosState state, int step = 0); ++ void dispatch_epilog(TosState state, int step = 0); ++ // dispatch via rbx (assume rbx is loaded already) ++ void dispatch_only(TosState state, bool generate_poll = false); ++ // dispatch normal table via rbx (assume rbx is loaded already) ++ void dispatch_only_normal(TosState state); ++ void dispatch_only_noverify(TosState state); ++ // load rbx from [_bcp_register + step] and dispatch via rbx ++ void dispatch_next(TosState state, int step = 0, bool generate_poll = false); ++ // load rbx from [_bcp_register] and dispatch via rbx and table ++ void dispatch_via (TosState state, address* table); ++ ++ // jump to an invoked target ++ void prepare_to_jump_from_interpreted(); ++ void jump_from_interpreted(Register method, Register temp); ++ ++ // narrow int return value ++ void narrow(Register result); ++ ++ // Returning from interpreted functions ++ // ++ // Removes the current activation (incl. unlocking of monitors) ++ // and sets up the return address. This code is also used for ++ // exception unwindwing. In that case, we do not want to throw ++ // IllegalMonitorStateExceptions, since that might get us into an ++ // infinite rethrow exception loop. ++ // Additionally this code is used for popFrame and earlyReturn. ++ // In popFrame case we want to skip throwing an exception, ++ // installing an exception, and notifying jvmdi. ++ // In earlyReturn case we only want to skip throwing an exception ++ // and installing an exception. ++ void remove_activation(TosState state, Register ret_addr, ++ bool throw_monitor_exception = true, ++ bool install_monitor_exception = true, ++ bool notify_jvmdi = true); ++ void get_method_counters(Register method, Register mcs, Label& skip); ++ ++ // Object locking ++ void lock_object (Register lock_reg); ++ void unlock_object(Register lock_reg); ++ ++ // Interpreter profiling operations ++ void set_method_data_pointer_for_bcp(); ++ void test_method_data_pointer(Register mdp, Label& zero_continue); ++ void verify_method_data_pointer(); ++ ++ void set_mdp_data_at(Register mdp_in, int constant, Register value); ++ void increment_mdp_data_at(Address data, bool decrement = false); ++ void increment_mdp_data_at(Register mdp_in, int constant, ++ bool decrement = false); ++ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, ++ bool decrement = false); ++ void increment_mask_and_jump(Address counter_addr, ++ int increment, Address mask, ++ Register scratch, bool preloaded, ++ Condition cond, Label* where); ++ void set_mdp_flag_at(Register mdp_in, int flag_constant); ++ void test_mdp_data_at(Register mdp_in, int offset, Register value, ++ Register test_value_out, ++ Label& not_equal_continue); ++ ++ void record_klass_in_profile(Register receiver, Register mdp, ++ Register reg2, bool is_virtual_call); ++ void record_klass_in_profile_helper(Register receiver, Register mdp, ++ Register reg2, int start_row, ++ Label& done, bool is_virtual_call); ++ void record_item_in_profile_helper(Register item, Register mdp, ++ Register reg2, 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(Register mdp_in, int offset_of_offset); ++ void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); ++ void update_mdp_by_constant(Register mdp_in, int constant); ++ void update_mdp_for_ret(Register return_bci); ++ ++ void profile_taken_branch(Register mdp, Register bumped_count); ++ void profile_not_taken_branch(Register mdp); ++ void profile_call(Register mdp); ++ void profile_final_call(Register mdp); ++ void profile_virtual_call(Register receiver, Register mdp, ++ Register scratch2, ++ bool receiver_can_be_null = false); ++ void profile_called_method(Register method, Register mdp, Register reg2) NOT_JVMCI_RETURN; ++ void profile_ret(Register return_bci, Register mdp); ++ void profile_null_seen(Register mdp); ++ void profile_typecheck(Register mdp, Register klass, Register scratch); ++ void profile_typecheck_failed(Register mdp); ++ void profile_switch_default(Register mdp); ++ void profile_switch_case(Register index_in_scratch, Register mdp, ++ Register scratch2); ++ ++ // Debugging ++ // only if +VerifyOops && state == atos ++ void verify_oop(Register reg, TosState state = atos); ++ // only if +VerifyFPU && (state == ftos || state == dtos) ++ void verify_FPU(int stack_depth, TosState state = ftos); ++ ++ typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; ++ ++ // support for jvmti/dtrace ++ void notify_method_entry(); ++ void notify_method_exit(TosState state, NotifyMethodExitMode mode); ++ ++ void get_2_byte_integer_at_bcp(Register reg, Register tmp, int offset); ++ void get_4_byte_integer_at_bcp(Register reg, Register tmp, int offset); ++ ++ private: ++ ++ Register _locals_register; // register that contains the pointer to the locals ++ Register _bcp_register; // register that contains the bcp ++ ++ public: ++ void profile_obj_type(Register obj, const Address& mdo_addr); ++ void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); ++ void profile_return_type(Register mdp, Register ret, Register tmp); ++ void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); ++ ++}; ++ ++#endif // CPU_SW64_VM_INTERP_MASM_SW64_64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/interpreterRT_sw64.cpp afu11u/src/hotspot/cpu/sw64/interpreterRT_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/interpreterRT_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/interpreterRT_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,324 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "interpreter/interp_masm.hpp" ++#include "interpreter/interpreter.hpp" ++#include "interpreter/interpreterRuntime.hpp" ++#include "memory/allocation.inline.hpp" ++#include "memory/universe.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-> ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++// Implementation of SignatureHandlerGenerator ++ ++InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator(const methodHandle& method, CodeBuffer* buffer) : ++ NativeSignatureIterator(method) { ++ _masm = new MacroAssembler(buffer); ++ _num_args = (method->is_static() ? 1 : 0); ++ _stack_offset = 0; // don't overwrite return address ++ _floatreg_start_index = FloatRegisterImpl::float_arg_base + 1; //because a0(16) must be env in JNI, so float parameter register should start 17. same reason in generator_slow_signature ++} ++ ++Register InterpreterRuntime::SignatureHandlerGenerator::from() { return rlocals; } ++Register InterpreterRuntime::SignatureHandlerGenerator::to() { return esp; } ++Register InterpreterRuntime::SignatureHandlerGenerator::temp() { return rscratch1; } ++ ++void InterpreterRuntime::SignatureHandlerGenerator::pass_int() { ++ const Address src(from(), Interpreter::local_offset_in_bytes(offset())); ++ switch (_num_args) { ++ case 0: ++ __ ldws(c_rarg1, src); ++ _num_args++; ++ break; ++ case 1: ++ __ ldws(c_rarg2, src); ++ _num_args++; ++ break; ++ case 2: ++ __ ldws(c_rarg3, src); ++ _num_args++; ++ break; ++ case 3: ++ __ ldws(c_rarg4, src); ++ _num_args++; ++ break; ++ case 4: ++ __ ldws(c_rarg5, src); ++ _num_args++; ++ break; ++ default: ++ __ ldws(V0, src); ++ __ stw(V0, Address(to(), _stack_offset)); ++ _stack_offset += wordSize; ++ break; ++ } ++} ++ ++void InterpreterRuntime::SignatureHandlerGenerator::pass_long() { ++ const Address src(from(), Interpreter::local_offset_in_bytes(offset() + 1)); ++ ++ switch (_num_args) { ++ case 0: ++ __ ldptr(c_rarg1, src); ++ _num_args++; ++ break; ++ case 1: ++ __ ldptr(c_rarg2, src); ++ _num_args++; ++ break; ++ case 2: ++ __ ldptr(c_rarg3, src); ++ _num_args++; ++ break; ++ case 3: ++ __ ldptr(c_rarg4, src); ++ _num_args++; ++ break; ++ case 4: ++ __ ldptr(c_rarg5, src); ++ _num_args++; ++ break; ++ default: ++ __ ldptr(V0, src); ++ __ stptr(V0, Address(to(), _stack_offset)); ++ _stack_offset += wordSize; ++ break; ++ } ++} ++ ++void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { ++ const Address src(from(), Interpreter::local_offset_in_bytes(offset())); ++ ++ if (_num_args < Argument::n_float_register_parameters_c-1) { ++ __ flds(as_FloatRegister(_floatreg_start_index + _num_args), src); ++ _num_args++; ++ } else { ++ __ ldws(V0, src); ++ __ stw(V0, Address(to(), _stack_offset)); ++ _stack_offset += wordSize; ++ } ++} ++ ++void InterpreterRuntime::SignatureHandlerGenerator::pass_double() { ++ const Address src(from(), Interpreter::local_offset_in_bytes(offset() + 1)); ++ ++ if (_num_args < Argument::n_float_register_parameters_c-1) { ++ __ fldd(as_FloatRegister(_floatreg_start_index + _num_args), src); ++ _num_args++; ++ } else { ++ __ ldptr(V0, src); ++ __ stptr(V0, Address(to(), _stack_offset)); ++ _stack_offset += wordSize; ++ } ++} ++ ++void InterpreterRuntime::SignatureHandlerGenerator::pass_object() { ++ const Address src(from(), Interpreter::local_offset_in_bytes(offset())); ++ Register rax = V0; ++ ++ switch (_num_args) { ++ case 0: ++ assert(offset() == 0, "argument register 1 can only be (non-null) receiver"); ++ __ lea(c_rarg1, src); ++ _num_args++; ++ break; ++ case 1: ++ __ lea(rax, src); ++ __ movl(c_rarg2, R0); ++ __ cmpptr(src, R0); ++ __ cmove(Assembler::notEqual, c_rarg2, rax, c_rarg2); ++ _num_args++; ++ break; ++ case 2: ++ __ lea(rax, src); ++ __ movl(c_rarg3, R0); ++ __ cmpptr(src, R0); ++ __ cmove(Assembler::notEqual, c_rarg3, rax, c_rarg3); ++ _num_args++; ++ break; ++ case 3: ++ __ lea(rax, src); ++ __ movl(c_rarg4, R0); ++ __ cmpptr(src, R0); ++ __ cmove(Assembler::notEqual, c_rarg4, rax, c_rarg4); ++ _num_args++; ++ break; ++ case 4: ++ __ lea(rax, src); ++ __ movl(c_rarg5, R0); ++ __ cmpptr(src, R0); ++ __ cmove(Assembler::notEqual, c_rarg5, rax, c_rarg5); ++ _num_args++; ++ break; ++ default: ++ __ lea(rax, src); ++ __ movl(temp(), R0); ++ __ cmpptr(src, R0); ++ __ cmove(Assembler::notEqual, temp(), rax, temp()); ++ __ stptr(temp(), Address(to(), _stack_offset)); ++ _stack_offset += wordSize; ++ break; ++ } ++} ++ ++void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) { ++ // generate code to handle arguments ++ iterate(fingerprint); ++ ++ // return result handler ++ __ lea(V0, ExternalAddress(Interpreter::result_handler(method()->result_type()))); ++ // return ++ __ ret_sw(); ++ ++ __ flush(); ++} ++ ++ ++// Implementation of SignatureHandlerLibrary ++ ++void SignatureHandlerLibrary::pd_set_handler(address handler) {} ++ ++ ++class SlowSignatureHandler ++ : public NativeSignatureIterator { ++ private: ++ address _from; ++ intptr_t* _to; ++ intptr_t* _reg_args; ++ intptr_t* _fp_identifiers; ++ unsigned int _num_args; ++ ++ virtual void pass_int() ++ { ++ jint from_obj = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); ++ _from -= Interpreter::stackElementSize; ++ ++ if (_num_args < Argument::n_int_register_parameters_c-1) { ++ *_reg_args++ = from_obj; ++ _num_args++; ++ } else { ++ *_to++ = from_obj; ++ } ++ } ++ ++ virtual void pass_long() ++ { ++ intptr_t from_obj = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); ++ _from -= 2*Interpreter::stackElementSize; ++ ++ if (_num_args < Argument::n_int_register_parameters_c-1) { ++ *_reg_args++ = from_obj; ++ _num_args++; ++ } else { ++ *_to++ = from_obj; ++ } ++ } ++ ++ virtual void pass_object() ++ { ++ intptr_t *from_addr = (intptr_t*)(_from + Interpreter::local_offset_in_bytes(0)); ++ _from -= Interpreter::stackElementSize; ++ if (_num_args < Argument::n_int_register_parameters_c-1) { ++ *_reg_args++ = (*from_addr == 0) ? NULL : (intptr_t) from_addr; ++ _num_args++; ++ } else { ++ *_to++ = (*from_addr == 0) ? NULL : (intptr_t) from_addr; ++ } ++ } ++ ++ virtual void pass_float() ++ { ++ jint from_obj = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); ++ _from -= Interpreter::stackElementSize; ++ ++ if (_num_args < Argument::n_float_register_parameters_c-1) { ++ assert((_num_args*2) < BitsPerWord, "_num_args*2 is out of range"); ++ *_reg_args++ = from_obj; ++ *_fp_identifiers |= ((intptr_t)0x01 << (_num_args*2)); // mark as float ++ _num_args++; ++ } else { ++ *_to++ = from_obj; ++ } ++ } ++ ++ virtual void pass_double() ++ { ++ intptr_t from_obj = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); ++ _from -= 2*Interpreter::stackElementSize; ++ ++ if (_num_args < Argument::n_float_register_parameters_c-1) { ++ assert((_num_args*2) < BitsPerWord, "_num_args*2 is out of range"); ++ *_reg_args++ = from_obj; ++ *_fp_identifiers |= ((intptr_t)0x3 << (_num_args*2)); // mark as double ++ _num_args++; ++ } else { ++ *_to++ = from_obj; ++ } ++ } ++ ++ public: ++ SlowSignatureHandler(const methodHandle& method, address from, intptr_t* to) ++ : NativeSignatureIterator(method) ++ { ++ _from = from; ++ _to = to; ++ ++ _reg_args = to - (method->is_static() ? 6 : 7); ++ _fp_identifiers = to - 2; ++ *(int*) _fp_identifiers = 0; ++ _num_args = (method->is_static() ? 1 : 0); ++ } ++}; ++ ++ ++IRT_ENTRY(address, ++ InterpreterRuntime::slow_signature_handler(JavaThread* thread, ++ Method* method, ++ intptr_t* from, ++ intptr_t* to)) ++ methodHandle m(thread, (Method*)method); ++ assert(m->is_native(), "sanity check"); ++ ++ // handle arguments ++ SlowSignatureHandler(m, (address)from, to).iterate((uint64_t)CONST64(-1));//sw doesn't need to modify 'to' position ++ ++ // return result handler ++ return Interpreter::result_handler(m->result_type()); ++IRT_END +diff -uNr openjdk/src/hotspot/cpu/sw64/interpreterRT_sw64.hpp afu11u/src/hotspot/cpu/sw64/interpreterRT_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/interpreterRT_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/interpreterRT_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_INTERPRETERRT_SW64_HPP ++#define CPU_SW64_VM_INTERPRETERRT_SW64_HPP ++ ++// This is included in the middle of class Interpreter. ++// Do not include files here. ++ ++// native method calls ++ ++class SignatureHandlerGenerator: public NativeSignatureIterator { ++ private: ++ MacroAssembler* _masm; ++ unsigned int _num_args; ++ int _stack_offset; ++ int _floatreg_start_index; //because a0(16) must be env in JNI, so float parameter register should start 17. same reason in generator_slow_signature ++ ++ void pass_int(); ++ void pass_long(); ++ void pass_float(); ++ void pass_double(); ++ void pass_object(); ++ ++ public: ++ // Creation ++ SignatureHandlerGenerator(const methodHandle& method, CodeBuffer* buffer); ++ ++ // Code generation ++ void generate(uint64_t fingerprint); ++ ++ // Code generation support ++ static Register from(); ++ static Register to(); ++ static Register temp(); ++}; ++ ++#endif // CPU_SW64_VM_INTERPRETERRT_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/javaFrameAnchor_sw64.hpp afu11u/src/hotspot/cpu/sw64/javaFrameAnchor_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/javaFrameAnchor_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/javaFrameAnchor_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_JAVAFRAMEANCHOR_SW64_HPP ++#define CPU_SW64_VM_JAVAFRAMEANCHOR_SW64_HPP ++ ++private: ++ ++ // FP value associated with _last_Java_sp: ++ intptr_t* volatile _last_Java_fp; // pointer is volatile not what it points to ++ ++public: ++ // Each arch must define reset, save, restore ++ // 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; ++ OrderAccess::release(); ++ _last_Java_fp = NULL; ++ _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; ++ OrderAccess::release(); ++ } ++ _last_Java_fp = src->_last_Java_fp; ++ _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; ++ } ++ ++ bool walkable(void) { return _last_Java_sp != NULL && _last_Java_pc != NULL; } ++ void make_walkable(JavaThread* thread); ++ void capture_last_Java_pc(void); ++ ++ intptr_t* last_Java_sp(void) const { return _last_Java_sp; } ++ ++ address last_Java_pc(void) { return _last_Java_pc; } ++ ++private: ++ ++ static ByteSize last_Java_fp_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_fp); } ++ ++public: ++ ++ void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; OrderAccess::release(); } ++ ++ intptr_t* last_Java_fp(void) { return _last_Java_fp; } ++ // Assert (last_Java_sp == NULL || fp == NULL) ++ void set_last_Java_fp(intptr_t* fp) { OrderAccess::release(); _last_Java_fp = fp; } ++ ++#endif // CPU_SW64_VM_JAVAFRAMEANCHOR_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/jniFastGetField_sw64.cpp afu11u/src/hotspot/cpu/sw64/jniFastGetField_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/jniFastGetField_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/jniFastGetField_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,252 @@ ++/* ++ * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.hpp" ++#include "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" ++ ++#define __ masm-> ++ ++#define BUFFER_SIZE 30*wordSize ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++// Instead of issuing a LoadLoad barrier we create an address ++// dependency between loads; this might be more efficient. ++ ++// Common register usage: ++// r0/v0: result ++// c_rarg0: jni env ++// c_rarg1: obj ++// c_rarg2: jfield id ++ ++#define BUFFER_SIZE 30*wordSize ++ ++static const Register rtmp = T1; ++static const Register robj = T2; ++static const Register rcounter = T3; ++static const Register roffset = T4; ++static const Register rcounter_addr = T5; ++ ++address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { ++ const char *name = NULL; ++ 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; ++ case T_LONG: name = "jni_fast_GetLongField"; break; ++ default: ShouldNotReachHere(); ++ } ++ ResourceMark rm; ++ BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); ++ CodeBuffer cbuf(blob); ++ MacroAssembler* masm = new MacroAssembler(&cbuf); ++ address fast_entry = __ pc(); ++ ++ Label slow; ++ ++ ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); ++ __ ldwu (rcounter, counter); ++ __ movl (robj, c_rarg1); ++ __ testb (rcounter, 1); ++ __ jcc (Assembler::notZero, slow); ++ if (os::is_MP()) { ++ __ xorptr(robj, rcounter, robj); ++ __ xorptr(robj, rcounter, robj); // obj, since ++ // robj ^ rcounter ^ rcounter == robj ++ // robj is data dependent on rcounter. ++ } ++ ++ __ movl (roffset, c_rarg2); ++ __ srll(roffset, 2, roffset); // offset ++ ++ // Both robj and rtmp 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 */ c_rarg0, robj, rtmp, slow); ++ DEBUG_ONLY(__ movw(rtmp, 0xDEADC0DE);) ++ ++ Register rax = V0; ++ assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); ++ speculative_load_pclist[count] = __ pc(); ++ switch (type) { ++ case T_BOOLEAN: __ ldbu (rax, Address(robj, roffset, Address::times_1)); break; ++ case T_BYTE: __ ldbu (AT, Address(robj, roffset, Address::times_1));__ sextb(AT, rax); break; ++ case T_CHAR: __ ldhu (rax, Address(robj, roffset, Address::times_1)); break; ++ case T_SHORT: __ ldhu (AT, Address(robj, roffset, Address::times_1));__ sexth(AT, rax); break; ++ case T_INT: __ ldws (rax, Address(robj, roffset, Address::times_1)); break; ++ case T_LONG: __ ldl (rax, Address(robj, roffset, Address::times_1)); break; ++ default: ShouldNotReachHere(); ++ } ++ ++ if (os::is_MP()) { ++ __ lea(rcounter_addr, counter); ++ // ca is data dependent on rax. ++ __ xorptr(rcounter_addr, rax, rcounter_addr); ++ __ xorptr(rcounter_addr, rax, rcounter_addr); ++ __ cmpw (rcounter, Address(rcounter_addr, 0)); ++ } else { ++ __ lea(rcounter_addr, counter); ++ __ cmpw (rcounter, Address(rcounter_addr, 0)); ++ } ++ __ jcc (Assembler::notEqual, slow); ++ ++ __ ret_sw(); ++ ++ slowcase_entry_pclist[count++] = __ pc(); ++ __ bind (slow); ++ address slow_case_addr = NULL; ++ 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; ++ case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; ++ default: break; ++ } ++ // tail call ++ __ jump (ExternalAddress(slow_case_addr)); ++ ++ __ 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() { ++ return generate_fast_get_int_field0(T_LONG); ++} ++ ++address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { ++ const char *name =NULL; ++ 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); ++ CodeBuffer cbuf(blob); ++ MacroAssembler* masm = new MacroAssembler(&cbuf); ++ address fast_entry = __ pc(); ++ ++ Label slow; ++ ++ ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); ++ __ ldwu (rcounter, counter); ++ __ movl (robj, c_rarg1); ++ __ testb (rcounter, 1); ++ __ jcc (Assembler::notZero, slow); ++ if (os::is_MP()) { ++ __ xorptr(robj, rcounter, robj); ++ __ xorptr(robj, rcounter, robj); // obj, since ++ // robj ^ rcounter ^ rcounter == robj ++ // robj is data dependent on rcounter. ++ } ++ ++ // Both robj and rtmp 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 */ c_rarg0, robj, rtmp, slow); ++ DEBUG_ONLY(__ movw(rtmp, 0xDEADC0DE);) ++ ++ __ movl (roffset, c_rarg2); ++ __ srll (roffset, 2, roffset); // offset ++ ++ assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); ++ speculative_load_pclist[count] = __ pc(); ++ switch (type) { ++ case T_FLOAT: __ load_float (FSF, Address(robj, roffset, Address::times_1)); break; ++ case T_DOUBLE: __ load_double(FSF, Address(robj, roffset, Address::times_1)); break; ++ default: ShouldNotReachHere(); ++ } ++ ++ if (os::is_MP()) { ++ __ lea(rcounter_addr, counter); ++ __ fimovd (FSF, V0); ++ // counter address is data dependent on xmm0. ++ __ xorptr(rcounter_addr, V0, rcounter_addr); ++ __ xorptr(rcounter_addr, V0, rcounter_addr); ++ __ cmpw (rcounter, Address(rcounter_addr, 0)); ++ } else { ++ __ lea(rcounter_addr, counter); ++ __ cmpw (rcounter, Address(rcounter_addr, 0)); ++ } ++ __ jcc (Assembler::notEqual, slow); ++ ++ __ ret_sw(); ++ ++ slowcase_entry_pclist[count++] = __ pc(); ++ __ bind (slow); ++ address slow_case_addr = NULL; ++ switch (type) { ++ case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; ++ case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; ++ default: break; ++ } ++ // tail call ++ __ jump (ExternalAddress(slow_case_addr)); ++ ++ __ 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 -uNr openjdk/src/hotspot/cpu/sw64/jniTypes_sw64.hpp afu11u/src/hotspot/cpu/sw64/jniTypes_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/jniTypes_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/jniTypes_sw64.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_JNITYPES_SW64_HPP ++#define CPU_SW64_VM_JNITYPES_SW64_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: ++ ++ // 32bit Helper routines. ++ static inline void put_int2r(jint *from, intptr_t *to) { *(jint *)(to++) = from[1]; ++ *(jint *)(to ) = from[0]; } ++ static inline void put_int2r(jint *from, intptr_t *to, int& pos) { put_int2r(from, 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) { *(intptr_t *)(to + 0 ) = from; } ++ static inline void put_int(jint from, intptr_t *to, int& pos) { *(intptr_t *)(to + pos++) = from; } ++ static inline void put_int(jint *from, intptr_t *to, int& pos) { *(intptr_t *)(to + pos++) = *from; } ++ ++ // Longs are stored in native format in one JavaCallArgument slot at ++ // *(to). ++ // In theory, *(to + 1) is an empty slot. But, for several Java2D testing programs (TestBorderLayout, SwingTest), ++ // *(to+1). ++ static inline void put_long(jlong from, intptr_t *to) { ++ *(jlong*) (to + 1) = from; ++ *(jlong*) (to) = from; ++ } ++ ++ static inline void put_long(jlong from, intptr_t *to, int& pos) { ++ *(jlong*) (to + 1 + pos) = from; ++ *(jlong*) (to + pos) = from; ++ pos += 2; ++ } ++ ++ static inline void put_long(jlong *from, intptr_t *to, int& pos) { ++ *(jlong*) (to + 1 + pos) = *from; ++ *(jlong*) (to + 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; } ++ ++#undef _JNI_SLOT_OFFSET ++#define _JNI_SLOT_OFFSET 0 ++ // Doubles are stored in native word format in one JavaCallArgument ++ // slot at *(to). ++ // In theory, *(to + 1) is an empty slot. But, for several Java2D testing programs (TestBorderLayout, SwingTest), ++ // *(to + 1) must contains a copy of the long value. Otherwise it will corrupts. ++ static inline void put_double(jdouble from, intptr_t *to) { ++ *(jdouble*) (to + 1) = from; ++ *(jdouble*) (to) = from; ++ } ++ ++ static inline void put_double(jdouble from, intptr_t *to, int& pos) { ++ *(jdouble*) (to + 1 + pos) = from; ++ *(jdouble*) (to + pos) = from; ++ pos += 2; ++ } ++ ++ static inline void put_double(jdouble *from, intptr_t *to, int& pos) { ++ *(jdouble*) (to + 1 + pos) = *from; ++ *(jdouble*) (to + pos) = *from; ++ pos += 2; ++ } ++ ++ // The get_xxx routines, on the other hand, actually _do_ fetch ++ // java primitive types from the interpreter stack. ++ // No need to worry about alignment on Intel. ++ static inline jint get_int (intptr_t *from) { return *(jint *) from; } ++ static inline jlong get_long (intptr_t *from) { return *(jlong *) (from + _JNI_SLOT_OFFSET); } ++ 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 + _JNI_SLOT_OFFSET); } ++#undef _JNI_SLOT_OFFSET ++}; ++ ++#endif // CPU_SW64_VM_JNITYPES_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/jvmciCodeInstaller_sw64.cpp afu11u/src/hotspot/cpu/sw64/jvmciCodeInstaller_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/jvmciCodeInstaller_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/jvmciCodeInstaller_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,69 @@ ++/* ++ * 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 "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 "vmreg_sw64.inline.hpp" ++ ++jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { ++ Unimplemented(); ++ return 0; ++} ++ ++void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { ++ Unimplemented(); ++} ++ ++void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { ++ Unimplemented(); ++} ++ ++void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { ++ Unimplemented(); ++} ++ ++void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { ++ Unimplemented(); ++} ++ ++void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, Handle hotspot_method, jint pc_offset, TRAPS) { ++ Unimplemented(); ++} ++ ++void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { ++ Unimplemented(); ++} ++ ++// convert JVMCI register indices (as used in oop maps) to HotSpot registers ++VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { ++ return NULL; ++} ++ ++bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { ++ return false; ++} +\ 文件尾没有换行符 +diff -uNr openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64.cpp afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64.cpp 2025-05-09 10:06:54.192292504 +0800 +@@ -0,0 +1,5176 @@ ++/* ++ * 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 "jvm.h" ++#include "asm/assembler.hpp" ++#include "asm/assembler.inline.hpp" ++#include "compiler/disassembler.hpp" ++#include "gc/shared/barrierSet.hpp" ++#include "gc/shared/barrierSetAssembler.hpp" ++#include "gc/shared/collectedHeap.inline.hpp" ++#include "interpreter/interpreter.hpp" ++#include "memory/resourceArea.hpp" ++#include "memory/universe.hpp" ++#include "oops/accessDecorators.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/objectMonitor.hpp" ++#include "runtime/os.hpp" ++#include "runtime/safepoint.hpp" ++#include "runtime/safepointMechanism.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "runtime/thread.hpp" ++#include "utilities/macros.hpp" ++#include "utilities/globalDefinitions_gcc.hpp" ++//#include "crc32c.h" ++#ifdef COMPILER2 ++#include "opto/intrinsicnode.hpp" ++#endif ++ ++#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 ":") ++ ++static Assembler::Condition reverse[] = { ++ Assembler::noOverflow /* overflow = 0x0 */ , ++ Assembler::overflow /* noOverflow = 0x1 */ , ++ Assembler::aboveEqual /* carrySet = 0x2, below = 0x2 */ , ++ Assembler::below /* aboveEqual = 0x3, carryClear = 0x3 */ , ++ Assembler::notZero /* zero = 0x4, equal = 0x4 */ , ++ Assembler::zero /* notZero = 0x5, notEqual = 0x5 */ , ++ Assembler::above /* belowEqual = 0x6 */ , ++ Assembler::belowEqual /* above = 0x7 */ , ++ Assembler::positive /* negative = 0x8 */ , ++ Assembler::negative /* positive = 0x9 */ , ++ Assembler::failed /* success = 0xa */ , ++ Assembler::success /* failed = 0xb */ , ++ Assembler::greaterEqual /* less = 0xc */ , ++ Assembler::less /* greaterEqual = 0xd */ , ++ Assembler::greater /* lessEqual = 0xe */ , ++ Assembler::lessEqual /* greater = 0xf, */ ++}; ++ ++Address MacroAssembler::as_Address(ArrayAddress adr, Register base_reg) { ++ AddressLiteral base = adr.base(); ++ lea(base_reg, base); ++ Address index = adr.index(); ++ assert(index._disp == 0, "must not have disp"); // maybe it can? ++ Address array(base_reg, index._index, index._scale, index._disp); ++ return array; ++} ++ ++void MacroAssembler::call_VM_leaf_base(address entry_point, ++ int number_of_arguments) {SCOPEMARK_NAME(MacroAssembler::call_VM_base, this) ++ Label E, L; ++ ++ testptr(esp, 0xf, rcc); ++ jcc(Assembler::zero, L, rcc); ++ ++ subptr(esp, 8, esp); ++ call(RuntimeAddress(entry_point)); ++ addptr(esp, 8, esp); ++ jmp(E); ++ ++ bind(L); ++ call(RuntimeAddress(entry_point)); ++ bind(E); ++} ++ ++void MacroAssembler::call_VM_leaf_base(address entry_point, ++ int number_of_arguments, ++ Label *retaddr, Register rscratch) {SCOPEMARK_NAME(MacroAssembler::call_VM_base-label, this) ++ /*Label E, L, exit; ++ ++ testptr(esp, 0xf, rcc); ++ jcc(Assembler::zero, L, rcc); ++ ++ mov_immediate64(rscratch1, 0xf7f7f7f7); ++ push(rscratch1); ++ jmp(E); ++ ++ bind(L); ++ //TODO:assert(esp[0] != 0xf7f7f7f7) jzy ++ ++ bind(E); ++ call(RuntimeAddress(entry_point)); ++ if (retaddr) ++ bind(*retaddr); ++ mov_immediate64(rscratch1, 0xf7f7f7f7); ++ ldl(rscratch2, esp, 0); ++ cmpl(rscratch1, rscratch2); ++ jcc(Assembler::notEqual, exit); ++ addptr(esp, 8, esp); ++ bind(exit);*/ ++ ++ //TODO:different from x86, stack not aligned is OK? jzy ++ call(RuntimeAddress(entry_point), retaddr, rscratch); ++} ++ ++int MacroAssembler::corrected_idivq(Register result, Register ra, Register rb, ++ bool want_remainder, Register scratch) ++{ ++ ShouldNotReachHere(); ++ int idivq_offset = offset(); ++ ++ return idivq_offset; ++} ++ ++void MacroAssembler::decrementw(ExternalAddress dst, int value, Register tmp1, Register tmp2){ ++ incrementw(dst, -value, tmp1, tmp2); ++} ++ ++void MacroAssembler::decrementw(Address dst, int value, Register tmp) ++{ ++ incrementw(dst, -value, tmp); ++} ++ ++void MacroAssembler::decrementw(Register reg, int value) ++{ ++ decrementl(reg, value); ++ zapnot(reg, 0xf, reg); ++} ++ ++void MacroAssembler::decrementl(ExternalAddress dst, int value , Register tmp1, Register tmp2){ ++ incrementl(dst, -value, tmp1, tmp2); ++} ++ ++void MacroAssembler::decrementl(Address dst, int value, Register tmp){ ++ incrementl(dst, -value, tmp); ++} ++ ++void MacroAssembler::decrementl(Register reg, int value) { ++ incrementl(reg, -value); ++} ++ ++/** ++ * x86 ++ * @param dst ++ * @param value ++ * @param tmp1 ++ * @param tmp2 ++ */ ++void MacroAssembler::incrementw(AddressLiteral dst, int value, Register tmp1, Register tmp2) { ++ assert_different_registers(tmp1, tmp2); ++ if (!value) return; ++ ++ lea(tmp1, dst); ++ ldws(tmp2, Address(tmp1, 0)); ++ if(is_simm16(value)) { ++ ldi(tmp2, value, tmp2); ++ } else { ++ ShouldNotReachHere(); ++ } ++ stw(tmp2, Address(tmp1, 0)); ++} ++ ++/** ++ * x86 ++ * @param dst ++ * @param value ++ * @param tmp_not_rcc ++ */ ++void MacroAssembler::incrementw(Address dst, int value, Register tmp_not_rcc) { ++ if (!value) return; ++ ldws(tmp_not_rcc, dst); ++ if(is_simm16(value)) { ++ ldi(tmp_not_rcc, value, tmp_not_rcc); ++ } else { ++ ShouldNotReachHere(); ++ } ++ stw(tmp_not_rcc, dst); ++} ++ ++/** ++ * x86 ++ * @param reg ++ * @param value ++ */ ++void MacroAssembler::incrementw(Register reg, int value) { ++ incrementl(reg, value); ++ zapnot(reg, 0xf, reg); ++} ++ ++void MacroAssembler::incrementl(ExternalAddress dst, int value, Register tmp1, Register tmp2){ ++ assert_different_registers(tmp1, tmp2); ++ if (!value) return; ++ mov_immediate64(tmp1, (intptr_t)dst.target(), dst.rspec()); ++ ldptr(tmp2, Address(tmp1, 0)); //ldwu ++ if (is_simm16(value)) { ++ ldi(tmp2, value, tmp2); ++ } else { ++ ShouldNotReachHere(); ++ } ++ stptr(tmp2, Address(tmp1, 0)); ++} ++ ++void MacroAssembler::incrementl(Address dst, int value, Register tmp){ ++ if (!value) return; ++ ldptr(tmp, dst); ++ if(is_simm16(value)) { ++ ldi(tmp, value, tmp); ++ } else { ++ ShouldNotReachHere(); ++// mov_immediate32(AT, value); ++// addl(tmp, AT, tmp); ++ } ++ stptr(tmp, dst); ++} ++ ++void MacroAssembler::incrementl(Register reg, int value) { ++ if (!value) return; ++ if (is_simm16(value)) { ++ ldi(reg, value, reg); ++ } else { ++ ShouldNotReachHere(); ++// mov_immediate32(AT, value); ++// addl(reg, AT, reg); ++ } ++} ++ ++// 32bit can do a case table jump in one instruction but we no longer allow the base ++// to be installed in the Address class ++void MacroAssembler::jump(ArrayAddress entry, Register tmp1, Register tmp2) { ++ assert_different_registers(tmp1, tmp2); ++ lea(tmp1, entry.base()); ++ Address dispatch = entry.index(); ++ assert(dispatch._base == noreg, "must be"); ++ dispatch._base = tmp1; ++ jmp(dispatch, tmp2); ++} ++ ++/** ++ * x86 ++ * lea(Register rd, Address addr) ++ * sw64 ++ * lea(Register rd, Address addr) ++ * note ++ * No diffrence. No temp reg is needed and rd can be same with addr._base or addr._index ++ */ ++void MacroAssembler::lea(Register rd, Address addr) { ++ ldi(rd, addr); ++} ++ ++void MacroAssembler::lea(Register rd, AddressLiteral addr) { ++ mov_immediate64(rd, (intptr_t)addr.target(), addr.rspec()); ++} ++ ++void MacroAssembler::lea(Address dst, AddressLiteral addr, Register tmp_not_rcc) { ++ assert_different_registers(tmp_not_rcc, rcc); ++ lea(tmp_not_rcc, addr); ++ stl(tmp_not_rcc, dst, rcc); ++} ++ ++//todo scw ++void MacroAssembler::leave() { ++ addptr(rfp, 2 * wordSize, esp); ++ ldl(RA, - 1 * wordSize, esp); ++ ldl(rfp, - 2 * wordSize, esp); ++} ++ ++// Move an oop into a register. immediate is true if we want ++// immediate instrcutions, i.e. we are not going to patch this ++// instruction while the code is being executed by another thread. In ++// that case we can use move immediates rather than the constant pool. ++void MacroAssembler::movoop(Register dst, jobject obj, bool immediate) { ++ ShouldNotReachHere(); ++} ++ ++// Move a metadata address into a register. ++void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { ++ int oop_index; ++ if (obj) { ++ oop_index = oop_recorder()->find_index(obj); ++ } else { ++ oop_index = oop_recorder()->allocate_metadata_index(obj); ++ } ++ RelocationHolder rspec = metadata_Relocation::spec(oop_index); ++ relocate(rspec); ++ prepare_patch_li48(dst, (long)(obj)); ++} ++ ++void MacroAssembler::reset_last_Java_frame(bool clear_fp) { ++ Register thread = rthread; ++ // we must set sp to zero to clear frame ++ std(R0, Address(thread, JavaThread::last_Java_sp_offset())); ++ // must clear fp, so that compiled frames are not confused; it is ++ // possible that we need it only for debugging ++ if (clear_fp) { ++ std(R0, Address(thread, JavaThread::last_Java_fp_offset())); ++ } ++ ++ // Always clear the pc because it could have been set by make_walkable() ++ std(R0, Address(thread, JavaThread::last_Java_pc_offset())); ++} ++ ++/*void MacroAssembler::set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ address last_java_pc) {ShouldNotReachHere(); ++ // determine last_java_sp register ++ if (!last_java_sp->is_valid()) { ++ last_java_sp = esp; ++ } ++ ++ Register thread = rthread; ++ // last_java_fp is optional ++ if (last_java_fp->is_valid()) { ++ std(last_java_fp, Address(thread, JavaThread::last_Java_fp_offset())); ++ } ++ ++ // last_java_pc is optional ++ if (last_java_pc != NULL) { ++ relocate(relocInfo::internal_word_type); ++// movptr(AT, (long)last_java_pc); ++ sd(AT, thread, in_bytes(JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset())); ++ } ++ ++ std(last_java_sp, Address(thread, JavaThread::last_Java_sp_offset())); ++}*/ ++void MacroAssembler::set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ address last_java_pc, Register scratch) { ++ // determine last_java_sp register ++ if (!last_java_sp->is_valid()) { ++ last_java_sp = esp; ++ } ++ ++ Register thread = rthread; ++ // last_java_fp is optional ++ if (last_java_fp->is_valid()) { ++ stptr(last_java_fp, Address(thread, JavaThread::last_Java_fp_offset()), scratch); ++ } ++ ++ // last_java_pc is optional ++ if (last_java_pc != NULL) { ++ relocate(relocInfo::internal_word_type); ++ prepare_patch_li48(scratch, (long)last_java_pc); ++ stptr(scratch, Address(rthread, ++ JavaThread::frame_anchor_offset() ++ + JavaFrameAnchor::last_Java_pc_offset())); ++ } ++ ++ stptr(last_java_sp, Address(thread, JavaThread::last_Java_sp_offset()), scratch); ++ ++} ++//TODO:delete we don't need this edition jzy ++/*void MacroAssembler::set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ Register last_java_pc, ++ Register scratch) { ++ // determine last_java_sp register ++ if (!last_java_sp->is_valid()) { ++ last_java_sp = esp; ++ } ++ ++ Register thread = rthread; ++ // last_java_fp is optional ++ if (last_java_fp->is_valid()) { ++ stptr(last_java_fp, Address(thread, JavaThread::last_Java_fp_offset()), scratch); ++ } ++ ++ // last_java_pc is optional ++ if (last_java_pc->is_valid()) {Unimplemented(); ++ stptr(last_java_pc, Address(rthread, ++ JavaThread::frame_anchor_offset() ++ + JavaFrameAnchor::last_Java_pc_offset()), scratch); ++ } ++ ++ stptr(last_java_sp, Address(thread, JavaThread::last_Java_sp_offset()), scratch); ++}*/ ++ ++ ++void MacroAssembler::set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ Label &L, ++ Register scratch, Register scratch2) {BLOCK_COMMENT("MacroAssembler::set_last_Java_frame enter"); ++ //br scratch,0; ++ //add scratch,0,scratch; this instruction need patch TODO:check jzy ++ assert_different_registers(scratch, scratch2); ++ int offset = 0; ++ if(UseAddpi){ ++ if (L.is_bound()) { ++ assert(false, "TODO:should check jzy"); ++ offset = (target(L) - pc()/*add instruction*/) >> 2; ++ } else { ++ L.add_patch_at(code(), locator()); ++ } ++ addpi(offset, scratch);//immediate need special flag when patch? jzy ++ ++ }else { ++ br(scratch, 0); ++ if (L.is_bound()) { ++ assert(false, "TODO:should check jzy"); ++ offset = (target(L) - pc()/*add instruction*/) >> 2; ++ } else { ++ L.add_patch_at(code(), locator()); ++ } ++ ldi(scratch, offset, scratch);//immediate need special flag when patch? jzy ++ } ++ stptr(scratch, Address(rthread, ++ JavaThread::frame_anchor_offset() ++ + JavaFrameAnchor::last_Java_pc_offset()), scratch2); ++ ++ set_last_Java_frame(last_java_sp, last_java_fp, NULL, scratch); BLOCK_COMMENT("MacroAssembler::set_last_Java_frame leave"); ++} ++ ++static void pass_arg0(MacroAssembler* masm, Register arg) { ++ if (c_rarg0 != arg ) { ++ masm->movl(c_rarg0, arg); ++ } ++} ++ ++static void pass_arg1(MacroAssembler* masm, Register arg) { ++ if (c_rarg1 != arg ) { ++ masm->movl(c_rarg1, arg); ++ } ++} ++ ++static void pass_arg2(MacroAssembler* masm, Register arg) { ++ if (c_rarg2 != arg ) { ++ masm->movl(c_rarg2, arg); ++ } ++} ++ ++void MacroAssembler::stop(const char* msg) {SCOPEMARK_NAME(MacroAssembler::stop, this); ++ if (ShowMessageBoxOnError) { ++ address rip = pc(); ++ // pusha(); // get regs on stack ++ lea(c_rarg1, InternalAddress(rip)); ++ } ++ lea(c_rarg0, ExternalAddress((address) msg)); ++// movq(c_rarg2, rsp); // pass pointer to regs array ++// andq(rsp, -16); // align stack as required by ABI ++ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); ++ brk(17); ++} ++ ++void MacroAssembler::debug_stop(const char* msg) {block_comment("debug_stop { "); ++ ldi(rscratch1_GP, 0); ++ beq(rscratch1_GP, -1);block_comment("debug_stop } "); ++} ++ ++void MacroAssembler::warn(const char* msg) { ++ warning("warning: %s", msg); ++} ++ ++void MacroAssembler::align(int modulus) { ++ while (offset() % modulus != 0) nop(); ++} ++ ++// tmp_reg1 and tmp_reg2 should be saved outside of atomic_inc32 (caller saved). ++void MacroAssembler::atomic_inc32(address counter_addr, int inc, Register tmp_reg1, Register tmp_reg2) { ++ Label again; ++ SizedScope sc(this, 64); ++ if(UseSW8A) { ++ mov(tmp_reg1, counter_addr); ++ bind(again); ++ lldw(tmp_reg2, 0, tmp_reg1); ++ addl(tmp_reg2, inc, tmp_reg2); ++ move(AT, tmp_reg2); ++ lstw(AT, 0, tmp_reg1); ++ beq_l(AT, again); ++ } else { ++ mov(tmp_reg1, counter_addr); ++ bind(again); ++ lldw(tmp_reg2, 0, tmp_reg1); ++ ldi(GP, 1, R0); ++ wr_f(GP); ++ addl(tmp_reg2, inc, tmp_reg2); ++ move(AT, tmp_reg2); ++ align(8); // must align ++ lstw(AT, 0, tmp_reg1); ++ rd_f(AT); ++ beq_l(AT, again); ++ } ++} ++ ++void MacroAssembler::atomic_incw(Register counter_addr, Register tmp, Register tmp2) { ++ ShouldNotReachHere(); ++} ++ ++// Writes to stack successive pages until offset reached to check for ++// stack overflow + shadow pages. This clobbers tmp. ++void MacroAssembler::bang_stack_size(Register size, Register tmp) {SCOPEMARK_NAME(bang_stack_size, this) ++ assert_different_registers(tmp, size, rscratch4); ++ movl(tmp, esp); ++ // Bang stack for total size given plus shadow page size. ++ // Bang one page at a time because large size can bang beyond yellow and ++ // red zones. ++ Label loop; ++ bind(loop); ++ mov_immediate64(rscratch4, (-os::vm_page_size())); ++ stw(size, Address(tmp, rscratch4)); ++ //mov_immediate64(rscratch4, os::vm_page_size()); ++ addptr(tmp, rscratch4, tmp); ++ addptr(size, rscratch4, size); ++ jcc(Assembler::greater, loop, size); ++ ++ // 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 including all pages in the shadow zone. ++ for (int i = 1; i < ((int)JavaThread::stack_shadow_zone_size() / os::vm_page_size()); i++) { ++ // this could be any sized move but this is can be a debugging crumb ++ // so the bigger the better. ++ mov_immediate64(rscratch4, (-i*os::vm_page_size())); ++ stptr(size, Address(tmp, rscratch4)); ++ } ++} ++ ++void MacroAssembler::reserved_stack_check() { ++ // testing if reserved zone needs to be enabled ++ Label no_reserved_zone_enabling; ++ Register thread = rthread; ++ ++ cmpptr(esp, Address(thread, JavaThread::reserved_stack_activation_offset())); ++ jcc(Assembler::below, no_reserved_zone_enabling); ++ ++ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread); ++ jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); ++ should_not_reach_here("throw_delayed_StackOverflowError_entry"); ++ ++ bind(no_reserved_zone_enabling); ++} ++ ++int MacroAssembler::biased_locking_enter(Register lock_reg, ++ Register obj_reg, ++ Register swap_reg, ++ Register tmp_reg, ++ bool swap_reg_contains_mark, ++ Label& done, ++ Label* slow_case, ++ BiasedLockingCounters* counters) { ++ assert(UseBiasedLocking, "why call this otherwise?"); ++ assert(tmp_reg != noreg, "tmp_reg must be supplied"); ++ assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg); ++ assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout"); ++ Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes()); ++ ++ if (PrintBiasedLockingStatistics && counters == NULL) { ++ counters = BiasedLocking::counters(); ++ } ++ // 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 ++ // First check to see whether biasing is even enabled for this object ++ Label cas_label; ++ int null_check_offset = -1; ++ if (!swap_reg_contains_mark) { ++ null_check_offset = offset(); ++ ldptr(swap_reg, mark_addr); ++ } ++ bis(R0, swap_reg, tmp_reg); ++ andptr(tmp_reg, markOopDesc::biased_lock_mask_in_place, tmp_reg); ++ cmpptr(tmp_reg, markOopDesc::biased_lock_pattern); ++ jcc(Assembler::notEqual, cas_label); ++ // The bias pattern is present in the object's header. Need to check ++ // whether the bias owner and the epoch are both still current. ++ if (swap_reg_contains_mark) { ++ null_check_offset = offset(); ++ } ++ load_prototype_header(tmp_reg, obj_reg); ++ orptr(tmp_reg, rthread, tmp_reg); ++ xorptr(swap_reg, tmp_reg, tmp_reg); ++ Register header_reg = tmp_reg; ++ andptr(header_reg, ~((int) markOopDesc::age_mask_in_place), header_reg); ++ move(rcc, header_reg); ++ if (counters != NULL) { ++ Label L; ++ jcc(Assembler::notZero, L, header_reg); ++ atomic_inc32((address)counters->biased_lock_entry_count_addr(), 1, rscratch1, rscratch2); ++ jmp(done); ++ bind(L); ++ } else { ++ jcc(Assembler::equal, done, header_reg); ++ } ++ ++ Label try_revoke_bias; ++ Label try_rebias; ++ ++ // 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. ++ testptr(header_reg, markOopDesc::biased_lock_mask_in_place); ++ jcc(Assembler::notZero, 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. ++ testptr(header_reg, markOopDesc::epoch_mask_in_place); ++ jcc(Assembler::notZero, 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. ++ andptr(swap_reg, ++ markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place, ++ swap_reg); ++ bis(R0, swap_reg, tmp_reg); ++ orptr(tmp_reg, rthread, tmp_reg); ++ cmpxchg(tmp_reg, mark_addr, swap_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. ++ if (slow_case != NULL) { ++ jcc(Assembler::failed, *slow_case); ++ } ++ if (counters != NULL) { ++ Label L; ++ jcc(Assembler::success, L); ++ atomic_inc32((address)counters->anonymously_biased_lock_entry_count_addr(), 1, rscratch1, rscratch2); ++ BIND(L); ++ } ++ jmp(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_prototype_header(tmp_reg, obj_reg); ++ orptr(tmp_reg, rthread, tmp_reg); ++ cmpxchg(tmp_reg, mark_addr, swap_reg); ++ // If the biasing toward our thread failed, then another thread ++ // succeeded in biasing it toward itself and we need to revoke that ++ // bias. The revocation will occur in the runtime in the slow case. ++ if (slow_case != NULL) { ++ jcc(Assembler::failed, *slow_case); ++ } ++ if (counters != NULL) { ++ Label L; ++ jcc(Assembler::success, L); ++ atomic_inc32((address) counters->rebiased_lock_entry_count_addr(), 1, rscratch1, rscratch2); ++ BIND(L); ++ } ++ jmp(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_prototype_header(tmp_reg, obj_reg); ++ cmpxchg(tmp_reg, mark_addr, swap_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. ++ jcc(Assembler::failed, cas_label, AT); ++ if (counters != NULL) { ++ atomic_inc32((address) counters->revoked_lock_entry_count_addr(), 1, rscratch1, rscratch2); ++ } ++ ++ bind(cas_label); ++ ++ return null_check_offset; ++} ++ ++void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) { ++ assert(UseBiasedLocking, "why call this otherwise?"); ++ ++ // 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. ++ ldl(temp_reg, oopDesc::mark_offset_in_bytes(), obj_reg); ++ andi(temp_reg, markOopDesc::biased_lock_mask_in_place, temp_reg); ++ addiu(R0, markOopDesc::biased_lock_pattern, AT); ++ cmpptr(AT, temp_reg); ++ jcc(Assembler::equal, done); ++} ++#ifdef COMPILER2 ++// tmp_reg1 and tmp_reg2 should be saved outside of atomic_inc32 (caller saved). ++void MacroAssembler::atomic_incw(AddressLiteral counter_addr, int inc, Register tmp_reg1) { ++ Label again; ++ assert_different_registers(tmp_reg1, rscratch1_GP, rscratch2_AT); ++ assert(Assembler::operand_valid_for_simple_type_instruction_immediate(inc), "exceed limit"); ++ Register tmp_reg2 = rscratch2_AT;//TODO:check we donot need tmp_reg2 jzy ++ SizedScope sc(this, 64); ++ if(UseSW8A) { ++ mov_immediate64(tmp_reg1, (intptr_t) counter_addr.target(), counter_addr.rspec()); ++ bind(again); ++ lldw(tmp_reg2, 0, tmp_reg1); ++ addl(tmp_reg2, inc, tmp_reg2); ++ move(rscratch2_AT, tmp_reg2); ++ lstw(rscratch2_AT, 0, tmp_reg1); ++ beq_l(rscratch2_AT, again); ++ } else { ++ mov_immediate64(tmp_reg1, (intptr_t) counter_addr.target(), counter_addr.rspec()); ++ bind(again); ++ lldw(tmp_reg2, 0, tmp_reg1); ++ ldi(rscratch1_GP, 1, R0); ++ wr_f(rscratch1_GP); ++ addl(tmp_reg2, inc, tmp_reg2); ++ move(rscratch2_AT, tmp_reg2); ++ align(8); // must align ++ lstw(rscratch2_AT, 0, tmp_reg1); ++ rd_f(rscratch2_AT); ++ beq_l(rscratch2_AT, again); ++ } ++} ++// Fast_Lock and Fast_Unlock used by C2 ++ ++// Because the transitions from emitted code to the runtime ++// monitorenter/exit helper stubs are so slow it's critical that ++// we inline both the stack-locking fast-path and the inflated fast path. ++// ++// See also: cmpFastLock and cmpFastUnlock. ++// ++// What follows is a specialized inline transliteration of the code ++// in slow_enter() and slow_exit(). If we're concerned about I$ bloat ++// another option would be to emit TrySlowEnter and TrySlowExit methods ++// at startup-time. These methods would accept arguments as ++// (rax,=Obj, rbx=Self, rcx=box, rdx=Scratch) and return success-failure ++// indications in the icc.ZFlag. Fast_Lock and Fast_Unlock would simply ++// marshal the arguments and emit calls to TrySlowEnter and TrySlowExit. ++// In practice, however, the # of lock sites is bounded and is usually small. ++// Besides the call overhead, TrySlowEnter and TrySlowExit might suffer ++// if the processor uses simple bimodal branch predictors keyed by EIP ++// Since the helper routines would be called from multiple synchronization ++// sites. ++// ++// An even better approach would be write "MonitorEnter()" and "MonitorExit()" ++// in java - using j.u.c and unsafe - and just bind the lock and unlock sites ++// to those specialized methods. That'd give us a mostly platform-independent ++// implementation that the JITs could optimize and inline at their pleasure. ++// Done correctly, the only time we'd need to cross to native could would be ++// to park() or unpark() threads. We'd also need a few more unsafe operators ++// to (a) prevent compiler-JIT reordering of non-volatile accesses, and ++// (b) explicit barriers or fence operations. ++// ++// TODO: ++// ++// * Arrange for C2 to pass "Self" into Fast_Lock and Fast_Unlock in one of the registers (scr). ++// This avoids manifesting the Self pointer in the Fast_Lock and Fast_Unlock terminals. ++// Given TLAB allocation, Self is usually manifested in a register, so passing it into ++// the lock operators would typically be faster than reifying Self. ++// ++// * Ideally I'd define the primitives as: ++// fast_lock (nax Obj, nax box, EAX tmp, nax scr) where box, tmp and scr are KILLED. ++// fast_unlock (nax Obj, EAX box, nax tmp) where box and tmp are KILLED ++// Unfortunately ADLC bugs prevent us from expressing the ideal form. ++// Instead, we're stuck with a rather awkward and brittle register assignments below. ++// Furthermore the register assignments are overconstrained, possibly resulting in ++// sub-optimal code near the synchronization site. ++// ++// * Eliminate the sp-proximity tests and just use "== Self" tests instead. ++// Alternately, use a better sp-proximity test. ++// ++// * Currently ObjectMonitor._Owner can hold either an sp value or a (THREAD *) value. ++// Either one is sufficient to uniquely identify a thread. ++// TODO: eliminate use of sp in _owner and use get_thread(tr) instead. ++// ++// * Intrinsify notify() and notifyAll() for the common cases where the ++// object is locked by the calling thread but the waitlist is empty. ++// avoid the expensive JNI call to JVM_Notify() and JVM_NotifyAll(). ++// ++// * use jccb and jmpb instead of jcc and jmp to improve code density. ++// But beware of excessive branch density on AMD Opterons. ++// ++// * Both Fast_Lock and Fast_Unlock set the ICC.ZF to indicate success ++// or failure of the fast-path. If the fast-path fails then we pass ++// control to the slow-path, typically in C. In Fast_Lock and ++// Fast_Unlock we often branch to DONE_LABEL, just to find that C2 ++// will emit a conditional branch immediately after the node. ++// So we have branches to branches and lots of ICC.ZF games. ++// Instead, it might be better to have C2 pass a "FailureLabel" ++// into Fast_Lock and Fast_Unlock. In the case of success, control ++// will drop through the node. ICC.ZF is undefined at exit. ++// In the case of failure, the node will branch directly to the ++// FailureLabel ++ ++ ++// obj: object to lock ++// box: on-stack box address (displaced header location) - KILLED ++// rax,: tmp -- KILLED ++// scr: tmp -- KILLED ++void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, ++ Register scrReg, Register cx1Reg, Register cx2Reg, ++ BiasedLockingCounters* counters, ++ Metadata* method_data, ++ bool use_rtm, bool profile_rtm) { ++ // Ensure the register assignments are disjoint ++ assert(tmpReg == V0, ""); ++ use_rtm = false; ++ profile_rtm = false; ++ ++ if (use_rtm) {//TODO:sw doesnot need this, we should delete this code jzy ++ assert_different_registers(objReg, boxReg, tmpReg, scrReg, cx1Reg, cx2Reg); ++ } else { ++ assert(cx1Reg == noreg, ""); ++ assert(cx2Reg == noreg, ""); ++ assert_different_registers(objReg, boxReg, tmpReg, scrReg); ++ } ++ ++ if (counters != NULL) { ++ atomic_incw(ExternalAddress((address)counters->total_entry_count_addr()), 1, rscratch3);//TODO:swjdk8 use OK? jzy ++ } ++ if (EmitSync & 1) { ++ // set box->dhw = markOopDesc::unused_mark() ++ // Force all sync thru slow-path: slow_enter() and slow_exit() ++ mov_immediate32s(rscratch3, (int32_t)intptr_t(markOopDesc::unused_mark())); ++ stl(rscratch3, Address(boxReg, 0)); ++ cmpptr (esp, R0); ++ } else { ++ // Possible cases that we'll encounter in fast_lock ++ // ------------------------------------------------ ++ // * Inflated ++ // -- unlocked ++ // -- Locked ++ // = by self ++ // = by other ++ // * biased ++ // -- by Self ++ // -- by other ++ // * neutral ++ // * stack-locked ++ // -- by self ++ // = sp-proximity test hits ++ // = sp-proximity test generates false-negative ++ // -- by other ++ // ++ ++ Label IsInflated, DONE_LABEL; ++ ++ // it's stack-locked, biased or neutral ++ // TODO: optimize away redundant LDs of obj->mark and improve the markword triage ++ // order to reduce the number of conditional branches in the most common cases. ++ // Beware -- there's a subtle invariant that fetch of the markword ++ // at [FETCH], below, will never observe a biased encoding (*101b). ++ // If this invariant is not held we risk exclusion (safety) failure. ++ if (UseBiasedLocking && !UseOptoBiasInlining) { ++ biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, counters); ++ } ++ ++ ldptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // [FETCH] ++ testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased ++ jcc(Assembler::notZero, IsInflated); ++ ++ // Attempt stack-locking ... ++ orptr (tmpReg, markOopDesc::unlocked_value, tmpReg); ++ stptr(tmpReg, Address(boxReg, 0)); // Anticipate successful CAS ++ if (os::is_MP()) { ++ memb(); ++ } ++ cmpxchg(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes()), tmpReg); // Updates tmpReg ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, rscratch2_AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++ ++ if (counters != NULL) { ++ Label skip; ++ jcc(Assembler::notZero, skip);//failed ++ atomic_incw(ExternalAddress((address)counters->fast_path_entry_count_addr()), 1, rscratch3); ++ bind(skip); ++ } ++ jcc(Assembler::zero, DONE_LABEL); // Success ++ ++ // Recursive locking. ++ // The object is stack-locked: markword contains stack pointer to BasicLock. ++ // Locked by current thread if difference with current SP is less than one page. ++ subptr(tmpReg, esp, tmpReg); ++ // Next instruction set ZFlag == 1 (Success) if difference is less then one page. ++ mov_immediate32s(rscratch3, (int32_t)(7 - os::vm_page_size() )); ++ andptr(tmpReg, rscratch3, tmpReg);//TODO:which value? jzy ++ move(rcc, tmpReg); ++ stptr(tmpReg, Address(boxReg, 0)); ++ if (counters != NULL) { ++ Label skip; ++ jcc(Assembler::notEqual, skip); ++ atomic_incw(ExternalAddress((address)counters->fast_path_entry_count_addr()), 1, rscratch3); ++ bind(skip); ++ } ++ jmp(DONE_LABEL); ++ ++ bind(IsInflated); ++ // The object is inflated. tmpReg contains pointer to ObjectMonitor* + markOopDesc::monitor_value ++ ++ // It's inflated ++ movl(scrReg, tmpReg); ++ movl(tmpReg, R0); ++ ++ if (os::is_MP()) { ++ memb(); ++ } ++ cmpxchg(rthread, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), tmpReg); ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++ // Unconditionally set box->_displaced_header = markOopDesc::unused_mark(). ++ // Without cast to int32_t movptr will destroy r10 which is typically obj. ++ mov_immediate32s(rscratch3, (int32_t)intptr_t(markOopDesc::unused_mark())); ++ stl(rscratch3, Address(boxReg, 0)); ++ // Intentional fall-through into DONE_LABEL ... ++ // Propagate ICC.ZF from CAS above into DONE_LABEL. ++ ++ // DONE_LABEL is a hot target - we'd really like to place it at the ++ // start of cache line by padding with NOPs. ++ // See the AMD and Intel software optimization manuals for the ++ // most efficient "long" NOP encodings. ++ // Unfortunately none of our alignment mechanisms suffice. ++ bind(DONE_LABEL); ++ ++ // At DONE_LABEL the icc ZFlag is set as follows ... ++ // Fast_Unlock uses the same protocol. ++ // ZFlag == 1 -> Success ++ // ZFlag == 0 -> Failure - force control through the slow-path ++ } ++} ++ ++// obj: object to unlock ++// box: box address (displaced header location), killed. Must be EAX. ++// tmp: killed, cannot be obj nor box. ++// ++// Some commentary on balanced locking: ++// ++// Fast_Lock and Fast_Unlock are emitted only for provably balanced lock sites. ++// Methods that don't have provably balanced locking are forced to run in the ++// interpreter - such methods won't be compiled to use fast_lock and fast_unlock. ++// The interpreter provides two properties: ++// I1: At return-time the interpreter automatically and quietly unlocks any ++// objects acquired the current activation (frame). Recall that the ++// interpreter maintains an on-stack list of locks currently held by ++// a frame. ++// I2: If a method attempts to unlock an object that is not held by the ++// the frame the interpreter throws IMSX. ++// ++// Lets say A(), which has provably balanced locking, acquires O and then calls B(). ++// B() doesn't have provably balanced locking so it runs in the interpreter. ++// Control returns to A() and A() unlocks O. By I1 and I2, above, we know that O ++// is still locked by A(). ++// ++// The only other source of unbalanced locking would be JNI. The "Java Native Interface: ++// Programmer's Guide and Specification" claims that an object locked by jni_monitorenter ++// should not be unlocked by "normal" java-level locking and vice-versa. The specification ++// doesn't specify what will occur if a program engages in such mixed-mode locking, however. ++// Arguably given that the spec legislates the JNI case as undefined our implementation ++// could reasonably *avoid* checking owner in Fast_Unlock(). ++// In the interest of performance we elide m->Owner==Self check in unlock. ++// A perfectly viable alternative is to elide the owner check except when ++// Xcheck:jni is enabled. ++ ++void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg, bool use_rtm) {SCOPEMARK_NAME(MacroAssembler::fast_unlock, this) ++ assert(boxReg == V0, ""); ++ assert_different_registers(objReg, boxReg, tmpReg); ++ ++ if (EmitSync & 4) { ++ // Disable - inhibit all inlining. Force control through the slow-path ++ cmpptr (esp, 0); ++ } else { ++ Label DONE_LABEL, Stacked, CheckSucc; ++ ++ // Critically, the biased locking test must have precedence over ++ // and appear before the (box->dhw == 0) recursive stack-lock test. ++ if (UseBiasedLocking && !UseOptoBiasInlining) { ++ biased_locking_exit(objReg, tmpReg, DONE_LABEL); ++ } ++ ++ cmpptr(Address(boxReg, 0), R0); // Examine the displaced header ++ jcc (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock ++ ldptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Examine the object's markword ++ testptr(tmpReg, markOopDesc::monitor_value); // Inflated? ++ jcc (Assembler::zero, Stacked); ++ ++ // Despite our balanced locking property we still check that m->_owner == Self ++ // as java routines or native JNI code called by this thread might ++ // have released the lock. ++ // Refer to the comments in synchronizer.cpp for how we might encode extra ++ // state in _succ so we can avoid fetching EntryList|cxq. ++ // ++ // I'd like to add more cases in fast_lock() and fast_unlock() -- ++ // such as recursive enter and exit -- but we have to be wary of ++ // I$ bloat, T$ effects and BP$ effects. ++ // ++ // If there's no contention try a 1-0 exit. That is, exit without ++ // a costly MEMBAR or CAS. See synchronizer.cpp for details on how ++ // we detect and recover from the race that the 1-0 exit admits. ++ // ++ // Conceptually Fast_Unlock() must execute a STST|LDST "release" barrier ++ // before it STs null into _owner, releasing the lock. Updates ++ // to data protected by the critical section must be visible before ++ // we drop the lock (and thus before any other thread could acquire ++ // the lock and observe the fields protected by the lock). ++ // IA32's memory-model is SPO, so STs are ordered with respect to ++ // each other and there's no need for an explicit barrier (fence). ++ // See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html. ++#ifndef _LP64 ++ ++#else // _LP64 ++ // It's inflated ++ if (EmitSync & 1024) { ++ // Emit code to check that _owner == Self ++ // We could fold the _owner test into subsequent code more efficiently ++ // than using a stand-alone check, but since _owner checking is off by ++ // default we don't bother. We also might consider predicating the ++ // _owner==Self check on Xcheck:jni or running on a debug build. ++ ldptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); ++ xorptr(boxReg, rthread, boxReg); ++ } else { ++ movl(boxReg, R0); ++ } ++ ldptr(rscratch3, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); ++ orptr(boxReg, rscratch3, rcc);//result should put in rcc ++ jcc (Assembler::notZero, DONE_LABEL); ++ ldptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); ++ ldptr(rscratch3, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); ++ orptr(boxReg, rscratch3, rcc);//result should put in rcc ++ jcc (Assembler::notZero, CheckSucc); ++ stptr(R0, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); ++ jmp (DONE_LABEL); ++ ++ if ((EmitSync & 65536) == 0) {block_comment(";;EmitSync & 65536"); ++ // Try to avoid passing control into the slow_path ... ++ Label LSuccess, LGoSlowPath ; ++ bind (CheckSucc); ++ ++ // The following optional optimization can be elided if necessary ++ // Effectively: if (succ == null) goto SlowPath ++ // The code reduces the window for a race, however, ++ // and thus benefits performance. ++ cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), R0); ++ jcc (Assembler::zero, LGoSlowPath); ++ ++ movl(boxReg, R0); ++ if ((EmitSync & 16) && os::is_MP()) { ++ xchgptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); ++ } else { ++ stptr(R0, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); ++ if (os::is_MP()) { ++ // Memory barrier/fence ++ // Dekker pivot point -- fulcrum : ST Owner; MEMBAR; LD Succ ++ // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. ++ // This is faster on Nehalem and AMD Shanghai/Barcelona. ++ // See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences ++ // We might also restructure (ST Owner=0;barrier;LD _Succ) to ++ // (mov box,0; xchgq box, &m->Owner; LD _succ) . ++ //lock(); addl(Address(rsp, 0), 0); ++ memb();//TODO:how to resolve this ? jzy ++ } ++ } ++ cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), R0); ++ jcc (Assembler::notZero, LSuccess); ++ ++ // Rare inopportune interleaving - race. ++ // The successor vanished in the small window above. ++ // The lock is contended -- (cxq|EntryList) != null -- and there's no apparent successor. ++ // We need to ensure progress and succession. ++ // Try to reacquire the lock. ++ // If that fails then the new owner is responsible for succession and this ++ // thread needs to take no further action and can exit via the fast path (success). ++ // If the re-acquire succeeds then pass control into the slow path. ++ // As implemented, this latter mode is horrible because we generated more ++ // coherence traffic on the lock *and* artifically extended the critical section ++ // length while by virtue of passing control into the slow path. ++ ++ // box is really RAX -- the following CMPXCHG depends on that binding ++ // cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R) ++ if (os::is_MP()) { memb(); } ++ cmpxchg(rthread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), boxReg); ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++ // There's no successor so we tried to regrab the lock. ++ // If that didn't work, then another thread grabbed the ++ // lock so we're done (and exit was a success). ++ jcc (Assembler::notEqual, LSuccess); ++ // Intentional fall-through into slow-path ++ ++ BIND (LGoSlowPath); ++ mov_immediate32u (rcc, 1); // set ICC.ZF=0 to indicate failure ++ jmp (DONE_LABEL); ++ ++ BIND (LSuccess); ++ mov_immediate32u (rcc, 0); // set ICC.ZF=1 to indicate success ++ jmp (DONE_LABEL); ++ } ++ ++ BIND (Stacked); ++ ldptr(tmpReg, Address (boxReg, 0)); // re-fetch ++ if (os::is_MP()) { memb(); } ++ cmpxchg(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes()), boxReg); // Uses RAX which is box ++ assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, rscratch2_AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++ ++ if (EmitSync & 65536) { ++ bind (CheckSucc); ++ } ++#endif ++ BIND(DONE_LABEL); ++ } ++} ++#endif // COMPILER2 ++void MacroAssembler::generate_fill(BasicType t, bool aligned, ++ Register to, Register value, Register count, ++ Register rtmp) { ++ //ShortBranchVerifier sbv(this); //sw need this? jzy ++ assert_different_registers(to, value, count, rtmp); ++ Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte; ++ Label L_fill_2_bytes, L_fill_4_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(); ++ } ++ ++ if (t == T_BYTE) { ++ andw(value, 0xff, value); ++ movl(rtmp, value); ++ slll(rtmp, 8, rtmp); ++ orw(value, rtmp, value); ++ } ++ if (t == T_SHORT) { ++ andw(value, 0xffff, value); ++ } ++ if (t == T_BYTE || t == T_SHORT) { ++ movw(rtmp, value); ++ slll(rtmp, 16, rtmp); ++ orw(value, rtmp, value); ++ } ++ ++ cmpw(count, 2<is_valid()) { ++ java_thread = rthread; ++ } ++ ++ // determine last_java_sp register ++ if (!last_java_sp->is_valid()) { ++ last_java_sp = esp; ++ } ++ ++ // debugging support ++ assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); ++ assert(number_of_arguments <= 4 , "6 - rthread - ?? "); ++ assert(java_thread == rthread , "unexpected register"); ++#ifdef ASSERT ++ // TraceBytecodes does not use r12 but saves it over the call, so don't verify ++ // r12 is the heapbase. ++ if ((UseCompressedOops || UseCompressedClassPointers) && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?"); ++#endif // ASSERT ++ ++ movl(c_rarg0, rthread); ++ ++ // set last Java frame before call ++ assert(last_java_sp != rfp, "can't use ebp/rbp"); ++ ++ // set last Java frame before call ++ address before_call_pc = (address)pc(); ++ set_last_Java_frame(last_java_sp, rfp, before_call_pc, rscratch1); ++// Label l; ++// set_last_Java_frame(last_java_sp, rfp, l, rscratch1); ++ // do the call ++// MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments, &l); ++// call(entry_point, relocInfo::runtime_call_type); ++ call(RuntimeAddress(entry_point)); ++ // reset last Java frame ++ reset_last_Java_frame(java_thread, true); // ++ ++ check_and_handle_popframe(java_thread); ++ check_and_handle_earlyret(java_thread); ++ ++ if (check_exceptions) { ++ // check for pending exceptions (java_thread is set upon return) ++ cmpptr(Address(java_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD); ++ ++ // This used to conditionally jump to forward_exception however it is ++ // possible if we relocate that the branch will not reach. So we must jump ++ // around so we can always reach ++ ++ Label ok; ++ jcc(Assembler::equal, ok); ++ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); ++ bind(ok); ++ } ++ ++ // get oop result if there is one and reset the value in the thread ++ if (oop_result->is_valid()) { ++ get_vm_result(oop_result, java_thread); ++ } ++} ++ ++void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {SCOPEMARK_NAME(MacroAssembler::call_VM_helper, this) ++ bis(R0, esp, V0); ++ call_VM_base(oop_result, noreg, V0, entry_point, number_of_arguments, check_exceptions); ++} ++ ++// Use this method when MacroAssembler version of call_VM_leaf_base() should be called from Interpreter. ++void MacroAssembler::call_VM_leaf0(address entry_point) { ++ MacroAssembler::call_VM_leaf_base(entry_point, 0); ++} ++ ++void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) { ++ call_VM_leaf_base(entry_point, number_of_arguments); ++} ++ ++void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0) { ++ pass_arg0(this, arg_0); ++ call_VM_leaf(entry_point, 1); ++} ++ ++void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1) { ++ assert(arg_0 != c_rarg1, "smashed arg"); ++ pass_arg1(this, arg_1); ++ pass_arg0(this, arg_0); ++ call_VM_leaf(entry_point, 2); ++} ++ ++void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, ++ Register arg_1, Register arg_2) { ++ assert(arg_0 != c_rarg2, "smashed arg"); ++ assert(arg_1 != c_rarg2, "smashed arg"); ++ pass_arg2(this, arg_2); ++ assert(arg_0 != c_rarg1, "smashed arg"); ++ pass_arg1(this, arg_1); ++ pass_arg0(this, arg_0); ++ call_VM_leaf(entry_point, 3); ++} ++ ++void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) { ++ pass_arg0(this, arg_0); ++ MacroAssembler::call_VM_leaf_base(entry_point, 1); ++} ++ ++void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1) { ++ assert(arg_0 != c_rarg1, "smashed arg"); ++ pass_arg1(this, arg_1); ++ pass_arg0(this, arg_0); ++ MacroAssembler::call_VM_leaf_base(entry_point, 2); ++} ++ ++void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) { ++ assert(arg_0 != c_rarg2, "smashed arg"); ++ assert(arg_1 != c_rarg2, "smashed arg"); ++ pass_arg2(this, arg_2); ++ assert(arg_0 != c_rarg1, "smashed arg"); ++ pass_arg1(this, arg_1); ++ pass_arg0(this, arg_0); ++ MacroAssembler::call_VM_leaf_base(entry_point, 3); ++} ++ ++void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) { ++ ld(oop_result, Address(java_thread, JavaThread::vm_result_offset())); ++ std(R0, Address(java_thread, JavaThread::vm_result_offset())); ++ verify_oop(oop_result, "broken oop in call_VM_base"); ++} ++ ++void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) { ++ ld(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset())); ++ std(R0, Address(java_thread, JavaThread::vm_result_2_offset())); ++} ++ ++// these are no-ops overridden by InterpreterMacroAssembler ++ ++void MacroAssembler::check_and_handle_earlyret(Register java_thread) { } ++ ++void MacroAssembler::check_and_handle_popframe(Register java_thread) { } ++ ++void MacroAssembler::cmpb(Register lh, int imm8, Register ccReg) { ++ if (is_uimm8(imm8)) { ++ ldi(ccReg, -imm8, lh); ++ } else { ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::cmpb(Address addr, int imm8, Register ccReg) { ++ ldbu(ccReg, addr); ++ cmpb(ccReg, imm8, ccReg); ++} ++ ++void MacroAssembler::cmpb(AddressLiteral src1, int imm8, Register ccReg) { ++ mov_immediate64(ccReg, (intptr_t)src1.target(), src1.rspec()); ++ ldbu(ccReg, 0, ccReg); ++ cmpb(ccReg, imm8, ccReg); ++} ++ ++void MacroAssembler::cmph(Address addr, int imm16, Register ccReg) { ++ ldhu(ccReg, addr); ++ ldi(ccReg, -imm16, ccReg); ++} ++ ++/** ++ * x86 ++ * Assembler::cmpl(Register dst, int32_t imm32) ++ * sw64 ++ * MacroAssembler::cmpw(Register lh, int rh, Register ccReg=rcc) ++ * note ++ * lh is signed 64bit int in register. ++ * rh is a sign extended 64bit int. ++ */ ++void MacroAssembler::cmpw(Register lh, int rh, Register ccReg) { ++ //if (-(1 << 16-1) <= rh && rh < ( 1 << 16-1)) { ++ if (Assembler::operand_valid_for_storage_type_instruction_immediate(rh)) { ++ ldi(ccReg, -rh, lh); ++ } else { ++ assert_different_registers(lh, ccReg); ++ mov_immediate64(ccReg, rh);// 考虑到rh如果是负数会占满64位, 因此要mov_imm64 ++ subl(lh, ccReg, ccReg); ++ } ++} ++ ++/** ++ * x86 ++ * Assembler::cmpl(Register dst, Register src) ++ * sw64 ++ * MacroAssembler::cmpw(Register lh, Register rh, Register ccReg=rcc) ++ * note ++ * it's a convention that lh and rh are signed extended int in 64bit reg, ++ */ ++void MacroAssembler::cmpw(Register lh, Register rh, Register ccReg) { ++ assert_different_registers(lh, ccReg); ++ assert_different_registers(rh, ccReg); ++ subl(lh, rh, ccReg);// 考虑到lh和rh都是符号扩展到64位的int, 这里用subl肯定不会有下溢或上溢的问题 ++} ++ ++/** ++ * x86 ++ * Assembler::cmpl(Register dst, Address src) ++ * sw64 ++ * MacroAssembler::cmpw(Register lh, Address rh, Register ccReg=rcc) ++ * note ++ * lh holds a signed extended 64bit int. ++ */ ++void MacroAssembler::cmpw(Register lh, Address rh, Register ccReg) { ++ assert_different_registers(lh, ccReg); ++ ldws(ccReg, rh); ++ subl(lh, ccReg, ccReg); ++} ++ ++/** ++ * x86 ++ * Assembler::cmpl(Address dst, int32_t imm32) ++ * sw64 ++ * MacroAssembler::cmpw(Address lh, int32_t imm, Register ccReg=rcc, Register tmp=rscratch1) ++ * note ++ * imm will be treated as a signed extened 64bit int. ++ */ ++void MacroAssembler::cmpw(Address lh, int32_t imm, Register ccReg, Register tmp) { ++ assert_different_registers(ccReg, tmp); ++ ldws(tmp, lh); ++ if (imm == 0) { ++ movl(ccReg, tmp); ++ } else { ++ mov_immediate64(ccReg, imm); ++ subl(tmp, ccReg, ccReg); ++ } ++} ++ ++/** ++ * x86 ++ * to del ++ * @param lh ++ * @param rh ++ * @param ccReg ++ */ ++void MacroAssembler::cmpw(Address lh, Register rh, Register ccReg) { ++ cmpw(rh, lh, ccReg); ++ subl(R0, ccReg, ccReg); ++} ++ ++/** ++ * x86 ++ * ++ * sw64 ++ * MacroAssembler::cmpw(AddressLiteral src1, int32_t imm, Register ccReg=rcc, Register tmp=rscratch1) ++ * note ++ * imm is a sign extended 64bit int. ++ * ccReg and tmp can't be the same reg. ++ */ ++void MacroAssembler::cmpw(AddressLiteral src1, int32_t imm, Register ccReg, Register tmp) { ++ ldws(tmp, src1); ++ cmpw(tmp, imm, ccReg); ++} ++ ++void MacroAssembler::cmpw(AddressLiteral src1, Register rh, Register ccReg) { ++ ldws(ccReg, src1); ++ subl(ccReg, rh, ccReg); ++} ++ ++/** ++ * x86 ++ * ++ * sw64 ++ * ++ * note ++ * compare lh and rh as unsigned word ++ */ ++void MacroAssembler::cmpwu(Register lh, Address rh, Register ccReg) { ++ ldwu(ccReg, rh); ++ movw(lh, lh); //as unsigned int ++ subl(lh, ccReg, ccReg); ++ addw(lh, R0, lh); ++} ++ ++void MacroAssembler::cmpl(Register lh, int rh, Register ccReg) { ++ // yj todo: is ldi ok here? ++ guarantee(-(1 << 16-1) <= rh && rh < ( 1 << 16-1), "rh value out of simm16"); ++ ldi(ccReg, -rh, lh); ++} ++ ++/** ++ * x86 ++ * cmpq(Register dst, Register src) ++ * sw64 ++ * cmpl_raw(Register lh, Register rh, Register ccReg=rcc) ++ * note ++ * 64bit compare and set result into ccReg. ++ * just sub lh to rh, don't consider overflow and underflow of the result, use carefully ++ */ ++void MacroAssembler::cmpl_raw(Register lh, Register rh, Register ccReg) { ++ subl(lh, rh, ccReg); ++} ++ ++// use cmpl_raw ASAP ++void MacroAssembler::cmpq(Register lh, Register rh, Register ccReg) { ++ set_cmp_insn_mark(lh, rh, true); ++ subl(lh, rh, ccReg); ++} ++ ++//similar to cmpl ++void MacroAssembler::cmpUL(Register lh, Register rh, Register ccReg) { ++ assert_different_registers(lh, ccReg); ++ assert_different_registers(rh, ccReg); ++ xorptr(lh, rh, ccReg); //check sign ++ bge(ccReg, 2);// if same sign, just sub ++ selge(rh, 1, rh, ccReg); ++ Assembler::br(R0, 1); ++ subl(lh, rh, ccReg); ++} ++ ++void MacroAssembler::set_cmp_insn_mark(Register lh, Register rh, bool lcmp) { ++ cmp_insn_mark = pc(); ++ cmp_lh = lh; ++ cmp_rh = rh; ++ cmp_long = lcmp; ++} ++ ++void MacroAssembler::clear_cmp_insn_mark() { ++ cmp_insn_mark = NULL; ++ cmp_lh = noreg; ++ cmp_rh = noreg; ++ cmp_long = false; ++} ++ ++bool MacroAssembler::cmp_insn_marked() { ++ return cmp_insn_mark != NULL; ++} ++ ++// beside cmp, there can be test before jcc or nothing, and sub/add can set cc too ++void MacroAssembler::jccb(Condition cc, Label& L) { ++ switch(cc) { ++ case equal: ++// case zero: ++// case carryClear: ++ beq_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case notEqual: ++// case notZero: ++// case carrySet: ++ bne_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case greaterEqual: ++ if (cmp_insn_marked() && cmp_long) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmple(cmp_rh, cmp_lh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ bge_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case notNegative: ++ bge_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case aboveEqual:// unsigned >= ++ if (cmp_insn_marked()) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmpule(cmp_rh, cmp_lh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ bge_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case greater: ++ if (cmp_insn_marked() && cmp_long) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmplt(cmp_rh, cmp_lh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ bgt_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case positive: ++ bgt_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case above:// unsigned > ++ if (cmp_insn_marked()) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmpult(cmp_rh, cmp_lh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ bgt_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case lessEqual: ++ if (cmp_insn_marked() && cmp_long) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmple(cmp_lh, cmp_rh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ ble_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case belowEqual: //unsigned <= ++ if (cmp_insn_marked()) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmpule(cmp_lh, cmp_rh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ ble_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case less: ++ if (cmp_insn_marked() && cmp_long) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmplt(cmp_lh, cmp_rh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ blt_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case below: // unsigned < ++ if (cmp_insn_marked()) { ++ InstructionMark mark(this); ++ code_section()->set_end(cmp_insn_mark); ++ cmpult(cmp_lh, cmp_rh, rcc); ++ code_section()->set_end(inst_mark()); ++ bne_l(rcc, L); ++ } else ++ blt_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ case negative: ++ blt_l(rcc, L); ++ clear_cmp_insn_mark(); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++/** ++ * x86 ++ * cmpq(Register dst, Register src) ++ * sw64 ++ * cmpl(Register lh, Register rh, Register ccReg=rcc) ++ * note ++ * 64bit compare and set result into ccReg. ++ * just sub lh to rh can cause overflow or underflow of the result, so this compare is more complex. ++ */ ++void MacroAssembler::cmpl(Register lh, Register rh, Register ccReg) { ++ assert_different_registers(lh, ccReg); ++ assert_different_registers(rh, ccReg); ++ xorptr(lh, rh, ccReg); //check sign ++ bge(ccReg, 2);// if same sign, just sub ++ selge(lh, 1, lh, ccReg); // if not && lh >= 0, ccReg=1, else ccReg = -1 ++ Assembler::br(R0, 1); ++ subl(lh, rh, ccReg); ++} ++ ++void MacroAssembler::cmpptr(Register lh, Address rh, Register ccReg) { ++ ldptr(ccReg, rh); ++ cmpptr(lh, ccReg, ccReg); ++} ++ ++void MacroAssembler::cmpptr(Address lh, Register rh, Register ccReg) { ++ ldptr(ccReg, lh); ++ cmpptr(ccReg, rh, ccReg); ++} ++ ++void MacroAssembler::cmpptr(Address lh, int32_t rh, Register ccReg) { ++ ldptr(ccReg, lh); ++ cmpl(ccReg, rh, ccReg);//TODO:refactor jzy ++} ++ ++void MacroAssembler::cmpptr(Register lh, int rh, Register ccReg) { ++ guarantee(-(1 << 16-1) <= rh && rh < ( 1 << 16-1), "rh value out of simm16"); ++ ldi(ccReg, -rh, lh); ++} ++ ++/** ++ * x86: ++ * cmpptr(Register src1, Register src2) ++ * sw64: ++ * cmpptr(Register src1, Register src2, Register ccReg=rcc) ++ * note: ++ * Sw64 use `rcc` as default compare result reg. ++ * The result should be consumed by instructions (e.g. `jcc`) ASAP with no interleaving ++ * instructions (e.g. `stx(reg, Address)`) that will clobber rcc by default. ++ * Note that ldx(reg, Address) don't need temp reg. ++ */ ++void MacroAssembler::cmpptr(Register src1, Register src2, Register ccReg) { ++ subl(src1, src2, ccReg); ++} ++ ++/** ++ * x86 ++ * ++ * sw64 ++ * ++ * note ++ * ++ */ ++void MacroAssembler::cmpptr(Register lh, AddressLiteral rh, Register ccReg) { ++ if (rh.is_lval()) { ++ lea(ccReg, rh); ++ cmpptr(lh, ccReg, ccReg); ++ } else { ++ ldptr(ccReg, rh); ++ cmpptr(lh, ccReg, ccReg); ++ } ++} ++ ++/** ++ * x86: ++ * movq/movl/movw(Register ra, Address addr) ++ * sw64: ++ * ldl/ldl_u/ldptr/ldw/ldhu/ldbu(Register ra, Address addr) ++ * note: ++ * SW64 don't need temp reg for the load, and ra can be same with addr._base or addr._index. ++ * ++ * ldl_u will 8-byte align the addr then load 64bit ++ * ldl will load 64bit ++ * ldw will sign extend the 32bit ++ * ldhu will zero extend the 16bit ++ * ldbu will zero extend the 8bit ++ */ ++#define LDFROMADDR_DEF(LDX) \ ++ void MacroAssembler::LDX(Register ra, Address addr) {\ ++ if (addr.getMode() == Address::base_index_scale_disp) {\ ++ addr.setTmp(ra);\ ++ }\ ++ addr.emit(ra, this, op_##LDX);\ ++ } ++ ++ LDINSNLIST(LDFROMADDR_DEF) ++ ++#undef LDFROMADDR_DEF ++ ++/** ++ * x86 ++ * Assembler::movq/movl/movw/movb(Address, addr, Register ra) ++ * sw64 ++ * MacroAssembler::stl/stl_u/stw/sth/stb(Register ra, Address addr, Register _tmp=rcc) ++ * note ++ * ra can't same with rcc, but can be same with addr._base, or addr._index ++ */ ++#define ST2ADDR_DEF(STX) \ ++ void MacroAssembler::STX(Register ra, Address addr, Register _tmp) {\ ++ if (addr.getMode() == Address::base_index_scale_disp) {\ ++ assert_different_registers(ra, _tmp);\ ++ addr.setTmp(_tmp);\ ++ }\ ++ addr.emit(ra, this, op_##STX);\ ++ } ++ ++ STINSNLIST(ST2ADDR_DEF) ++ ++#undef ST2ADDR_DEF ++ ++#define ADDR_DEF(FLOATINSN) \ ++ void MacroAssembler::FLOATINSN(FloatRegister fa, Address addr, Register _tmp) {\ ++ if (addr.getMode() == Address::base_index_scale_disp) {\ ++ addr.setTmp(_tmp);\ ++ }\ ++ addr.emit(fa, this, op_##FLOATINSN);\ ++ } ++ ++ FLOATINSNLIST(ADDR_DEF) ++ ++#undef ADDR_DEF ++ ++void MacroAssembler::cmpoop(Register src1, Register src2, Register ccReg) { ++ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->obj_equals(this, src1, src2, ccReg); ++} ++ ++static void change_cmxchg_result(MacroAssembler* _masm) { ++ _masm->mov_immediate32(rcc, 1); ++ _masm->cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++} ++//todo scw ++// if c_reg == content(dest) { c_reg = dest ; store x_reg to dest;} else { c_reg = dest; } ++void MacroAssembler::cmpxchg(Register x_reg, Address dest, Register c_reg) {SCOPEMARK_NAME(MacroAssembler::cmpxchg, this); ++ assert_different_registers(AT, GP, rscratch3, c_reg, dest.base()); ++ assert_different_registers(AT, GP, rscratch3, x_reg, dest.base()); ++ SizedScope sc(this, 64); ++ Label done, again, nequal; ++ if (UseSW8A) { ++ if(UseCAS) { ++ move(GP, x_reg); ++ if(dest.disp() != 0) { ++ ldi(AT, dest.disp(), dest.base()); ++ casl(c_reg, AT, GP); ++ } else { ++ casl(c_reg, dest.base(), GP); ++ } ++ cmpeq(c_reg, GP, AT); ++ move(c_reg, GP); ++ } else { ++ BIND(again); ++ lldl(AT, dest.disp(), dest.base()); ++ bne_c(AT, c_reg, nequal); ++ ++ move(AT, x_reg); ++ lstl(AT, dest.disp(), dest.base()); ++ beq_l(AT, again); ++ beq_l(R0, done); ++ ++ // not xchged ++ BIND(nequal); ++ memb(); ++ move(c_reg, AT); ++ move(AT, R0); ++ ++ BIND(done); ++ } ++ } else { ++ //subl(esp, 16, esp); ++ //stl(rscratch3, 0, esp); ++ BIND(again); ++ lldl(rscratch3, dest.disp(), dest.base()); ++ cmpeq(rscratch3, c_reg, GP); ++ wr_f(GP); ++ move(AT, x_reg); ++ align(8); ++ lstl(AT, dest.disp(), dest.base()); ++ rd_f(AT); ++ beq_l(GP, nequal); ++ beq_l(AT, again); ++ // not xchged ++ BIND(nequal); ++ //if(rscratch3 != c_reg) bis(R0, rscratch3, c_reg); ++ bis(R0, rscratch3, c_reg); ++ ++ //ldl(rscratch3, 0, esp); ++ //addl(esp, 16, esp); ++ //ornot(R0, AT, rcc); ++ } ++ change_cmxchg_result(this); ++// mov_immediate32(rcc, 1); ++// cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++} ++ ++//todo scw ++// if c_reg == content(dest) { Address(dest) = x_reg ;} else { c_reg = content(dest); } ++void MacroAssembler::cmpxchg32(Register x_reg, Address dest, Register c_reg) { ++ assert_different_registers(AT, GP, rscratch3, c_reg, dest.base()); ++ assert_different_registers(AT, GP, rscratch3, x_reg, dest.base()); ++ SizedScope sc(this, 64); ++ Label done, again, nequal; ++ if (UseSW8A) { ++ if(UseCAS) { ++ move(GP, x_reg); ++ if (dest.disp() != 0) { ++ ldi(AT, dest.disp(), dest.base()); ++ casw(c_reg, AT, GP); ++ } else { ++ casw(c_reg, dest.base(), GP); ++ } ++ cmpeq(c_reg, GP , AT); ++ move(c_reg, GP); ++ } else { ++ BIND(again); ++ lldw(AT, dest.disp(), dest.base()); ++ bne_c(AT, c_reg, nequal); ++ ++ move(AT, x_reg); ++ lstw(AT, dest.disp(), dest.base()); ++ beq_l(AT, again); ++ beq_l(R0, done); ++ ++ // not xchged ++ BIND(nequal); ++ memb(); ++ move(c_reg, AT); ++ move(AT, R0); ++ ++ BIND(done); ++ } ++ } else { ++ //subl(esp, 16, esp); ++ //stl(rscratch3, 0, esp); ++ BIND(again); ++ lldw(rscratch3, dest.disp(), dest.base()); ++ cmpeq(rscratch3, c_reg, GP); ++ wr_f(GP); ++ move(AT, x_reg); ++ align(8); ++ lstw(AT, dest.disp(), dest.base()); ++ rd_f(AT); ++ beq_l(GP, nequal); ++ beq_l(AT, again); ++ // not xchged ++ BIND(nequal); ++ bis(R0, rscratch3, c_reg); ++ ++ //ldl(rscratch3, 0, esp); ++ //addl(esp, 16, esp); ++ //xor_ins(AT, R0, rcc); ++ //ornot(R0, AT, rcc); ++ } ++ change_cmxchg_result(this); ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++} ++ ++void MacroAssembler::fill_to_size(address start, int size) { ++ if (pc() - start > size) should_not_reach_here("size expanded!"); ++ while (pc() - start < size) ++ nop(); ++} ++ ++//If oldval == *dest then store newval into dest ++void MacroAssembler::storeLcon(Register oldval, Address dest, Register newval) { ++ //guarantee((dest.index()->encoding() == sp->encoding()), "impossible encoding storeLCon 1"); ++ //guarantee((dest.disp() == 0), "impossible encoding storeLCon 2"); ++ //guarantee((dest.index()->encoding() == sp->encoding() && dest.disp() == 0), "impossible encoding storeLCon"); ++ SizedScope sc(this, 64); ++ assert_different_registers(AT, GP, oldval, newval, dest.base()); ++ Label again, failure; ++ if(UseSW8A) { ++ if(UseCAS) { ++ move(GP, newval); ++ if(dest.disp() != 0) { ++ ldi(AT, dest.disp(), dest.base()); ++ casl(oldval, AT, GP); ++ } else { ++ casl(oldval, dest.base(), GP); ++ } ++ cmpeq(oldval, GP, AT); ++ } else { ++ BIND(again); ++ lldl(GP, dest.disp(), dest.base()); ++ cmpeq(GP, oldval, AT); ++ beq_l(AT, failure); ++ move(AT, newval); ++ lstl(AT, dest.disp(), dest.base()); ++ beq_l(AT, again); ++ BIND(failure); ++ } ++ } else { ++ BIND(again); ++ lldl(AT, dest.disp(), dest.base()); ++ cmpeq(AT, oldval, GP); ++ wr_f(GP); ++ move(AT, newval); ++ align(8); ++ lstl(AT, dest.disp(), dest.base()); ++ rd_f(AT); ++ beq_l(GP, failure); ++ beq_l(AT, again); ++ BIND(failure); ++ } ++ //xor_ins(AT, R0, rcc);//need it ?? ++ change_cmxchg_result(this); ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++} ++ ++void MacroAssembler::storeIcon(Register oldval, Address dest, Register newval) { ++ //guarantee((dest.index() == sp && dest.disp() == 0), "impossible encoding storeICon"); ++ SizedScope sc(this, 64); ++ assert_different_registers(AT, GP, oldval, newval, dest.base()); ++ Label again, failure; ++ if(UseSW8A) { ++ if(UseCAS) { ++ move(GP, newval); ++ if(dest.disp() != 0) { ++ ldi(AT, dest.disp(), dest.base()); ++ casw(oldval, AT, GP); ++ } else { ++ casw(oldval, dest.base(), GP); ++ } ++ cmpeq(oldval, GP, AT); ++ } else { ++ BIND(again); ++ lldw(GP, dest.disp(), dest.base()); ++ cmpeq(GP, oldval, AT); ++ beq_l(AT, failure); ++ move(AT, newval); ++ lstw(AT, dest.disp(), dest.base()); ++ beq_l(AT, again); ++ BIND(failure); ++ } ++ } else { ++ BIND(again); ++ lldw(AT, dest.disp(), dest.base()); ++ cmpeq(AT, oldval, GP); ++ wr_f(GP); ++ move(AT, newval); ++ align(8); ++ lstw(AT, dest.disp(), dest.base()); ++ rd_f(AT); ++ beq_l(GP, failure); ++ beq_l(AT, again); ++ BIND(failure); ++ } ++ //xor_ins(AT, R0, rcc);// need it? ++ change_cmxchg_result(this); ++ //mov_immediate32(rcc, 1); ++ //cmove(Assembler::success, rcc, R0, rcc, AT); //TODO:refactor we should refactor cmpxchg, not add this instruction jzy ++} ++ ++void MacroAssembler::cmpxchgptr(Register xreg, AddressLiteral adr, Register creg, Register tmp) { ++ assert_different_registers(tmp, AT); ++ lea(tmp, adr); ++ cmpxchg(xreg, Address(tmp, 0), creg); ++} ++void MacroAssembler::xchgptr(Register src1, Register src2) { ++ movl(rscratch2, src1); ++ movl(src1, src2); ++ movl(src2, rscratch2); ++} ++ ++int MacroAssembler::corrected_idivl(Register result, Register ra, Register rb, ++ bool want_remainder, Register scratch) ++{ ++ ShouldNotReachHere(); ++ int idivl_offset = offset(); ++ return idivl_offset; ++} ++ ++void MacroAssembler::enter() { ++ subptr(esp, 16, esp); ++ stl(rfp, 0, esp); ++ stl(RA, 8, esp); ++ movl(rfp, esp); ++} ++ ++void MacroAssembler::load_float(FloatRegister rd, AddressLiteral addr, Register tmp) { ++ mov_immediate64(tmp, (intptr_t)addr.target(), addr.rspec()); ++ flds(rd, 0, tmp); ++} ++ ++void MacroAssembler::load_double(FloatRegister rd, AddressLiteral addr, Register tmp) { ++ mov_immediate64(tmp, (intptr_t)addr.target(), addr.rspec()); ++ fldd(rd, 0, tmp); ++} ++ ++void MacroAssembler::load_float(FloatRegister fa, Address src, Register tmp) { ++ flds(fa, src, tmp); ++} ++ ++void MacroAssembler::load_double(FloatRegister fa, Address src, Register tmp) { ++ fldd(fa, src, tmp); ++} ++ ++void MacroAssembler::store_float(FloatRegister fa, Address src, Register tmp) { ++ fsts(fa, src, tmp); ++} ++ ++void MacroAssembler::store_double(FloatRegister fa, Address src, Register tmp) { ++ fstd(fa, src, tmp); ++} ++ ++void MacroAssembler::jump(AddressLiteral addr, Register tmp) { ++ mov_address64(T12, (intptr_t)addr.target(), addr.rspec()); ++ Assembler::jmp(tmp, T12, 0);// set ra=AT for debug ++} ++ ++void MacroAssembler::jump(RuntimeAddress addr, Register tmp) { ++ mov_address64(T12, (intptr_t)addr.target(), addr.rspec()); ++ Assembler::jmp(tmp, T12, 0);// set ra=AT for debug ++} ++ ++//TODO:check right jzy ++void MacroAssembler::jump_cc(Condition cc, AddressLiteral dst, Register ccReg, Register tmp) { ++ Label skip; ++ jcc(reverse[cc], skip, ccReg); ++ jump(dst, tmp); ++ bind(skip); ++} ++ ++void MacroAssembler::jcc(Condition cc, Label& L, Register ccReg, ConditionLength cl) { ++ if (cl == bitw) { ++ subw(ccReg, 0, ccReg); ++ } ++ switch(cc) { ++// case equal: ++ case zero: ++ beq_l(ccReg, L); ++ break; ++// case notEqual: ++ case notZero: ++ bne_l(ccReg, L); ++ break; ++ case greaterEqual: ++ case aboveEqual: ++ case notNegative: ++ bge_l(ccReg, L); ++ break; ++ case greater: ++ case positive: ++ case above://unsigned> ++ bgt_l(ccReg, L); ++ break; ++ case lessEqual: ++ case belowEqual: //unsigned<= ++ ble_l(ccReg, L); ++ break; ++ case less: ++ case below: ++ case negative: ++ blt_l(ccReg, L); ++ break; ++ case success:// for cas success ++ bne_l(AT, L); ++ break; ++ case failed:// for cas failed ++ beq_l(AT, L); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::cmpws(int cc, Register op1, Register op2, Register ccReg) { ++ switch((Condition)cc) { ++ case equal: ++ cmpeq(op1, op2, ccReg); ++ break; ++ case notEqual: ++ subw(op1, op2, ccReg); ++ break; ++ case greater: ++ cmplt(op2, op1, ccReg); ++ break; ++ case greaterEqual: ++ cmple(op2, op1, ccReg); ++ break; ++ case less: ++ cmplt(op1, op2, ccReg); ++ break; ++ case lessEqual: ++ cmple(op1, op2, ccReg); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::cmpls(int cc, Register op1, Register op2, Register ccReg) { ++ switch((Condition)cc) { ++ case equal: ++ cmpeq(op1, op2, ccReg); ++ break; ++ case notEqual: ++ subl(op1, op2, ccReg); ++ break; ++ case greater: ++ cmplt(op2, op1, ccReg); ++ break; ++ case greaterEqual: ++ cmple(op2, op1, ccReg); ++ break; ++ case less: ++ cmplt(op1, op2, ccReg); ++ break; ++ case lessEqual: ++ cmple(op1, op2, ccReg); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::cmpwu(int cc, Register op1, Register op2, Register ccReg) { ++ switch((Condition)cc) { ++ case equal: ++ cmpeq(op1, op2, ccReg); ++ break; ++ case notEqual: ++ subw(op1, op2, ccReg);//TODO:refactor jzy use subl to replace? ++ break; ++ case above://unsigned> ++ cmpult(op2, op1, ccReg); ++ break; ++ case aboveEqual: ++ cmpule(op2, op1, ccReg); ++ break; ++ case below: ++ cmpult(op1, op2, ccReg); ++ break; ++ case belowEqual: //unsigned<= ++ cmpule(op1, op2, ccReg); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::cmplu(int cc, Register op1, Register op2, Register ccReg) { ++ switch((Condition)cc) { ++ case equal: ++ cmpeq(op1, op2, ccReg); ++ break; ++ case notEqual: ++ subl(op1, op2, ccReg); ++ break; ++ case above://unsigned> ++ cmpult(op2, op1, ccReg); ++ break; ++ case aboveEqual: ++ cmpule(op2, op1, ccReg); ++ break; ++ case below: ++ cmpult(op1, op2, ccReg); ++ break; ++ case belowEqual: //unsigned<= ++ cmpule(op1, op2, ccReg); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::cmpfs(int cc, FloatRegister op1, FloatRegister op2, FloatRegister ccReg, bool is_order) {SCOPEMARK_NAME(MacroAssembler::cmpfs, this); ++ switch((Condition)cc) { ++ case equal: ++ fcmpeq(op1, op2, ccReg); ++ break; ++ case notEqual: ++ fcmpeq(op1, op2, ccReg); ++ fcmpeq(ccReg, fzero, ccReg); ++ break; ++ case greater: ++ c_olt_s(op2, op1); ++ break; ++ case greaterEqual: ++ c_ole_s(op2, op1); ++ break; ++ case less: ++ block_comment("less;;"); ++ if (is_order) { ++ c_olt_s(op1, op2); ++ } else { ++ c_ult_s(op1, op2); ++ } ++ break; ++ case lessEqual: ++ block_comment("lessEqual;;"); ++ if (is_order) { ++ c_ole_s(op1, op2); ++ } else { ++ c_ule_s(op1, op2); ++ } ++ break; ++ } ++} ++ ++void MacroAssembler::cmpfd(int cc, FloatRegister op1, FloatRegister op2, FloatRegister ccReg, bool is_order) {SCOPEMARK_NAME(MacroAssembler::cmpfd, this); ++ switch((Condition)cc) { ++ case equal: ++ fcmpeq(op1, op2, ccReg); ++ break; ++ case notEqual: ++ //TODO:performance jzy ++// mov_immediate64(rscratch3, 1); ++// ifmovd(rscratch3, fscratch1); ++// fcmpeq(op1, op2, ccReg); ++// fseleq(ccReg, fscratch1, fzero, ccReg); ++ fcmpeq(op1, op2, ccReg); ++ fcmpeq(ccReg, fzero, ccReg); ++ break; ++ case greater: ++ c_olt_d(op2, op1); ++ break; ++ case greaterEqual: ++ c_ole_d(op2, op1); ++ break; ++ case less: ++ block_comment("less;;"); ++ if (is_order) { ++ c_olt_d(op1, op2); ++ } else { ++ c_ult_d(op1, op2); ++ } ++ break; ++ case lessEqual: ++ if (is_order) { ++ c_ole_d(op1, op2); ++ } else { ++ c_ule_d(op1, op2); ++ } ++ break; ++ } ++} ++ ++void MacroAssembler::load_unsigned_short(Register dst, Address src) { ++ ldhu(dst, src); ++} ++ ++void MacroAssembler::load_unsigned_byte(Register dst, Address src) { ++ ldbu(dst, src); ++} ++ ++void MacroAssembler::load_signed_short(Register rd, Address addr) { ++ ldhu(rd, addr); ++ sexth(rd, rd); ++} ++ ++void MacroAssembler::load_signed_byte32(Register rd, Address addr, Register tmp) { ++ ldbu(rd, addr); ++ sextb(rd, rd); ++ movw(rd, rd); ++} ++ ++void MacroAssembler::load_signed_byte64(Register rd, Address addr, Register tmp) { ++ ldbu(rd, addr); ++ sextb(rd, rd); ++} ++ ++void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2) { ++ switch (size_in_bytes) { ++ case 8: ld(dst, src); break; ++ case 4: lw(dst, src); break; ++ case 2: if (is_signed) load_signed_short(dst, src); else load_unsigned_short(dst, src); break; ++ case 1: if (is_signed) load_signed_byte32( dst, src); else load_unsigned_byte( dst, src); break; ++ default: ShouldNotReachHere(); ++ } ++} ++ ++void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::null_check(Register reg, int offset) { ++ if (needs_explicit_null_check(offset)) { ++ // provoke OS NULL exception if reg = NULL by ++ // accessing M[reg] w/o changing any registers ++ // NOTE: this is plenty to provoke a segv ++ cmpptr(V0, Address(reg, 0)); ++ } else { ++ // nothing to do, (later) access of M[reg + offset] ++ // will provoke OS NULL exception if reg = NULL ++ } ++} ++ ++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::pop_CPU_state(bool restore_vectors) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::push_CPU_state(bool save_vectors) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::reset_last_Java_frame(Register java_thread, bool clear_fp) { ++ // determine java_thread register ++ if (!java_thread->is_valid()) { ++ java_thread = rthread; ++ } ++ // we must set sp to zero to clear frame ++ stl(R0, in_bytes(JavaThread::last_Java_sp_offset()), java_thread); ++ // must clear fp, so that compiled frames are not confused; it is possible ++ // that we need it only for debugging ++ if(clear_fp) { ++ stl(R0, in_bytes(JavaThread::last_Java_fp_offset()), java_thread); ++ } ++ ++ // Always clear the pc because it could have been set by make_walkable() ++ stl(R0, in_bytes(JavaThread::last_Java_pc_offset()), java_thread); ++} ++ ++void MacroAssembler::round_to(Register reg, int modulus) { ++ addptr(reg, modulus - 1, reg); ++ andptr(reg, -modulus, reg); ++} ++ ++void MacroAssembler::serialize_memory(Register thread, Register tmp) { ++ assert_different_registers(rscratch2_AT, tmp); ++ movwu(tmp, thread); ++ srll(tmp, os::get_serialize_page_shift_count(), tmp); ++ mov_immediate64(rscratch2_AT, (os::vm_page_size() - sizeof(int))); ++ andptr(tmp, rscratch2_AT, tmp); ++ ++ mov_immediate64(rscratch2_AT, (intptr_t)os::get_memory_serialize_page()); ++ addl(rscratch2_AT, tmp, rscratch2_AT); ++ stw(tmp, Address(rscratch2_AT, 0)); ++ //stw(tmp, Address(tmp, (intptr_t)os::get_memory_serialize_page()));//TODO:use intptr_t's transform is OK? jzy ++ ++} ++ ++/*void MacroAssembler::set_last_Java_frame(Register java_thread, ++ Register last_java_sp, ++ Register last_java_fp, ++ address last_java_pc) {ShouldNotReachHere(); ++ // determine java_thread register ++ if (!java_thread->is_valid()) { ++ java_thread = rthread; ++ } ++ // determine last_java_sp register ++ if (!last_java_sp->is_valid()) { ++ last_java_sp = esp; ++ } ++ ++ // last_java_fp is optional ++ if (last_java_fp->is_valid()) { ++ stptr(last_java_fp, Address(java_thread, JavaThread::last_Java_fp_offset())); ++ } ++ ++ if (last_java_pc != NULL) { ++ lea(Address(java_thread, ++ JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset()), ++ InternalAddress(last_java_pc), AT); ++ } else { ++ ShouldNotReachHere(); ++ } ++ stptr(last_java_sp, Address(java_thread, JavaThread::last_Java_sp_offset())); ++}*/ ++ ++void MacroAssembler::testb(Register lh, int imm8, Register ccReg) { ++ if (is_uimm8(imm8)) { ++ and_ins(lh, imm8, ccReg); ++ } else { ++ Unimplemented(); ++ } ++} ++ ++void MacroAssembler::testb(Register lh, Register rh, Register ccReg) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::testb(Address addr, int imm8, Register ccReg) { ++ ldbu(ccReg, addr); ++ if (is_uimm8(imm8)) { ++ and_ins(ccReg, imm8, ccReg); ++ } else { ++ Unimplemented(); ++ } ++} ++ ++/** ++ * x86 ++ * Assembler::testl(Register dst, int32_t imm32) ++ * sw64 ++ * testw(Register lh, int rh, Register ccReg, Register scratch) ++ * note ++ * test 32bit of lh and rh. the msb32 of lh don't cares ++ */ ++void MacroAssembler::testw(Register lh, int rh, Register ccReg, Register scratch) { ++ andw(lh, rh, ccReg, scratch); ++} ++ ++void MacroAssembler::testw(Register lh, Register rh, Register ccReg) { ++ andw(lh, rh, ccReg); ++} ++ ++void MacroAssembler::testl(Register lh, long rh, Register res, Register scratch) { ++ testptr(lh, rh, res, scratch); ++} ++ ++void MacroAssembler::testl(Register lh, Register rh, Register ccReg) { ++ testptr(lh, rh, ccReg); ++} ++ ++void MacroAssembler::testptr(Register lh, long rh, Register res, Register scratch) { ++ andptr(lh, rh, res, scratch); ++} ++ ++void MacroAssembler::testptr(Register lh, Register rh, Register ccReg) { ++ and_ins(lh, rh, ccReg); ++} ++ ++void MacroAssembler::resolve_jobject(Register value, ++ Register thread, ++ Register tmp) {SCOPEMARK_NAME(MacroAssembler::resolve_jobject, this); ++ assert_different_registers(value, thread, tmp); ++ Label done, not_weak; ++ testptr(value, value); ++ jcc(Assembler::zero, done); // Use NULL as-is. ++ testptr(value, JNIHandles::weak_tag_mask); // Test for jweak tag. ++ jcc(Assembler::zero, not_weak); ++ // Resolve jweak. ++ access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, ++ value, Address(value, -JNIHandles::weak_tag_value), tmp, thread); ++ verify_oop(value); ++ jmp(done); ++ bind(not_weak); ++ // Resolve (untagged) jobject. ++ access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, 0), tmp, thread); ++ verify_oop(value); ++ bind(done); ++} ++ ++// Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes. ++void MacroAssembler::tlab_allocate(Register thread, Register obj, ++ Register var_size_in_bytes, ++ int con_size_in_bytes, ++ Register t1, ++ Register t2, ++ Label& slow_case) { ++ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->tlab_allocate(this, thread, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); ++} ++ ++// Defines obj, preserves var_size_in_bytes ++void MacroAssembler::eden_allocate(Register thread, Register obj, ++ Register var_size_in_bytes, ++ int con_size_in_bytes, ++ Register t1, ++ Label& slow_case) {SCOPEMARK_NAME(eden_allocate, this) ++ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->eden_allocate(this, thread, obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); ++} ++ ++// Zero words; len is in bytes ++// Destroys all registers except addr ++// len must be a nonzero multiple of wordSize ++void MacroAssembler::zero_memory(Register addr, Register len, Register t1) { ++ should_not_reach_here("zero_memory"); ++} ++ ++// 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, ++ Label& L_no_such_interface, ++ bool return_method) { ++ assert_different_registers(recv_klass, intf_klass, scan_temp, rcc); ++ assert_different_registers(method_result, intf_klass, scan_temp, rcc); ++ assert(recv_klass != method_result || !return_method, ++ "recv_klass can be destroyed when method isn't needed"); ++ ++ assert(itable_index.is_constant() || itable_index.as_register() == method_result, ++ "caller must use same register for non-constant itable index as for method"); ++ ++ // Compute start of first itableOffsetEntry (which is at the end of the vtable) ++ int vtable_base = in_bytes(Klass::vtable_start_offset()); ++ int itentry_off = itableMethodEntry::method_offset_in_bytes(); ++ int scan_step = itableOffsetEntry::size() * wordSize; ++ int vte_size = vtableEntry::size_in_bytes(); ++ Address::ScaleFactor times_vte_scale = Address::times_ptr; ++ assert(vte_size == wordSize, "else adjust times_vte_scale"); ++ ++ ldws(scan_temp, Address(recv_klass, Klass::vtable_length_offset())); ++ ++ // %%% Could store the aligned, prescaled offset in the klassoop. ++ lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base)); ++ ++ if (return_method) { ++ // Adjust recv_klass by scaled itable_index, so we can free itable_index. ++ assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); ++ lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off)); ++ } ++ ++ // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { ++ // if (scan->interface() == intf) { ++ // result = (klass + scan->offset() + itable_index); ++ // } ++ // } ++ Label search, found_method; ++ ++ for (int peel = 1; peel >= 0; peel--) { ++ ldptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes())); ++ cmpptr(intf_klass, method_result); ++ ++ if (peel) { ++ jcc(Assembler::equal, found_method); ++ } else { ++ jcc(Assembler::notEqual, search); ++ // (invert the test to fall through to found_method...) ++ } ++ ++ if (!peel) break; ++ ++ bind(search); ++ ++ // Check that the previous 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. ++ jcc(Assembler::zero, L_no_such_interface, method_result); ++ addptr(scan_temp, scan_step, scan_temp); ++ } ++ ++ bind(found_method); ++ ++ if (return_method) { ++ // Got a hit. ++ ldws(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes())); ++ ldptr(method_result, Address(recv_klass, scan_temp, Address::times_1)); ++ } ++} ++ ++ ++// virtual method calling ++void MacroAssembler::lookup_virtual_method(Register recv_klass, ++ RegisterOrConstant vtable_index, ++ Register method_result) { ++ const int base = in_bytes(Klass::vtable_start_offset()); ++ assert(vtableEntry::size() * wordSize == wordSize, "else adjust the scaling in the code below"); ++ Address vtable_entry_addr(recv_klass, ++ vtable_index, Address::times_ptr, ++ base + vtableEntry::method_offset_in_bytes()); ++ ldptr(method_result, vtable_entry_addr); ++ } ++ ++ ++void MacroAssembler::check_klass_subtype(Register sub_klass, ++ Register super_klass, ++ Register temp_reg, ++ Label& L_success) { ++ Label L_failure; ++ check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_failure, NULL); ++ check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, noreg, &L_success, NULL); ++ bind(L_failure); ++} ++ ++ ++void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, ++ Register super_klass, ++ Register temp_reg, ++ Label* L_success, ++ Label* L_failure, ++ Label* L_slow_path, ++ RegisterOrConstant super_check_offset) { ++ assert_different_registers(sub_klass, super_klass, temp_reg); ++ bool must_load_sco = (super_check_offset.constant_or_zero() == -1); ++ if (super_check_offset.is_register()) { ++ assert_different_registers(sub_klass, super_klass, ++ super_check_offset.as_register()); ++ } else if (must_load_sco) { ++ assert(temp_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, "at most one NULL in the batch"); ++ ++ int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); ++ int sco_offset = in_bytes(Klass::super_check_offset_offset()); ++ Address super_check_offset_addr(super_klass, sco_offset); ++ ++ // Hacked jcc, which "knows" that L_fallthrough, at least, is in ++ // range of a jccb. If this routine grows larger, reconsider at ++ // least some of these. ++#define local_jcc(assembler_cond, label) \ ++ if (&(label) == &L_fallthrough) jcc(assembler_cond, label); \ ++ else jcc( assembler_cond, label) /*omit semi*/ ++ ++ // Hacked jmp, which may only be used just before L_fallthrough. ++#define final_jmp(label) \ ++ if (&(label) == &L_fallthrough) { /*do nothing*/ } \ ++ else jmp(label) /*omit semi*/ ++ ++ // 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. ++ cmpptr(sub_klass, super_klass); ++ local_jcc(Assembler::equal, *L_success); ++ ++ // Check the supertype display: ++ if (must_load_sco) { ++ // Positive movl does right thing on LP64. ++ ldws(temp_reg, super_check_offset_addr); ++ super_check_offset = RegisterOrConstant(temp_reg); ++ } ++ Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0); ++ cmpptr(super_klass, super_check_addr); // load displayed supertype ++ ++ // 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). ++ ++ if (super_check_offset.is_register()) { ++ local_jcc(Assembler::equal, *L_success); ++ cmpw(super_check_offset.as_register(), sc_offset); ++ if (L_failure == &L_fallthrough) { ++ local_jcc(Assembler::equal, *L_slow_path); ++ } else { ++ local_jcc(Assembler::notEqual, *L_failure); ++ final_jmp(*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) { ++ local_jcc(Assembler::equal, *L_success); ++ } else { ++ local_jcc(Assembler::notEqual, *L_slow_path); ++ final_jmp(*L_success); ++ } ++ } else { ++ // No slow path; it's a fast decision. ++ if (L_failure == &L_fallthrough) { ++ local_jcc(Assembler::equal, *L_success); ++ } else { ++ local_jcc(Assembler::notEqual, *L_failure); ++ final_jmp(*L_success); ++ } ++ } ++ ++ bind(L_fallthrough); ++ ++#undef local_jcc ++#undef final_jmp ++} ++ ++ ++void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, ++ Register super_klass, ++ Register temp_reg, ++ Register temp2_reg, ++ Label* L_success, ++ Label* L_failure, ++ bool set_cond_codes) { ++ if (temp2_reg == noreg) temp2_reg = AT; ++ assert_different_registers(temp_reg, noreg); ++ assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg); ++ ++ const Register rcx = temp2_reg; ++ const Register rdi = temp_reg; ++ ++ 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++; } ++ 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()); ++ Address secondary_supers_addr(sub_klass, ss_offset); ++ Address super_cache_addr( sub_klass, sc_offset); ++ ++ // Do a linear scan of the secondary super-klass chain. ++ // This code is rarely used, so simplicity is a virtue here. ++ // The repne_scan instruction uses fixed registers, which we must spill. ++ // Don't worry too much about pre-existing connections with the input regs. ++ ++#ifndef PRODUCT ++ int* pst_counter = &SharedRuntime::_partial_subtype_ctr; ++ ExternalAddress pst_counter_addr((address) pst_counter); ++ lea(rcx, pst_counter_addr); ++ ldws(rdi, Address(rcx, 0)); ++ addw(rdi, 1, rdi); ++ stw(rdi, Address(rcx, 0)); ++#endif //PRODUCT ++ ++ // We will consult the secondary-super array. ++ ldptr(rdi, secondary_supers_addr); ++ // Load the array length. (Positive movl does right thing on LP64.) ++ ldws(rcx, Address(rdi, Array::length_offset_in_bytes())); ++ // Skip to start of data. ++ addptr(rdi, Array::base_offset_in_bytes(), rdi); ++ ++ // Scan RCX words at [RDI] for an occurrence of super_klass. ++ Label Loop, found; ++ bind(Loop); ++ jcc(Assembler::zero, *L_failure, rcx); ++ cmpptr(Address(rdi, 0), super_klass); ++ jcc(Assembler::equal, found); ++ addptr(rdi, 1 * wordSize, rdi); ++ subw(rcx, 1, rcx); ++ jmp(Loop); ++ ++ bind(found); ++ // Success. Cache the super we found and proceed in triumph. ++ stptr(super_klass, super_cache_addr); ++ if (L_success != &L_fallthrough) { ++ jmp(*L_success); ++ } ++ ++ bind(L_fallthrough); ++} ++ ++ ++void MacroAssembler::verify_oop(Register reg, const char* s) { ++ if (!VerifyOops) return; ++ ++ // Pass register number to verify_oop_subroutine ++ const char * b = NULL; ++ {//name(), s); ++ b = code_string(ss.as_string()); ++ } ++ block_comment("verify_oop {"); ++ const Register rax = V0; ++ //push(rscratch1); // trash by call, sw doesn't trash rscratch1 ++ push(rax); // save rax, ++ push(reg); // pass register argument ++ ExternalAddress buffer((address) b); ++ lea(rax, buffer.addr()); ++ push(rax); ++ // call indirectly to solve generation ordering problem ++ ldptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address())); ++ push(RA); ++ call(rax); ++ pop(RA); ++ addl(esp, 8, esp);//just pop ++ pop(reg); ++ pop(rax); ++ // Caller pops the arguments (oop, message) and restores rax, r10 ++ block_comment("} verify_oop"); ++} ++ ++//todo scw ++RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, ++ Register tmp, ++ int offset) { ++ ShouldNotReachHere(); ++ intptr_t value = *delayed_value_addr; ++ if (value != 0) ++ return RegisterOrConstant(value + offset); ++// Address a(delayed_value_addr); ++ // load indirectly to solve generation ordering problem ++ // movptr(tmp, ExternalAddress((address) delayed_value_addr)); ++ // ld(tmp, a); ++ if (offset != 0) ++ addiu(tmp, offset, tmp); ++ ++ return RegisterOrConstant(tmp); ++} ++ ++ ++Address MacroAssembler::argument_address(RegisterOrConstant arg_slot, ++ int extra_slot_offset) { ++ // cf. TemplateTable::prepare_invoke(), if (load_receiver). ++ int stackElementSize = Interpreter::stackElementSize; ++ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0); ++#ifdef ASSERT ++ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1); ++ assert(offset1 - offset == stackElementSize, "correct arithmetic"); ++#endif ++ Register scale_reg = noreg; ++ Address::ScaleFactor scale_factor = Address::no_scale; ++ if (arg_slot.is_constant()) { ++ offset += arg_slot.as_constant() * stackElementSize; ++ } else { ++ scale_reg = arg_slot.as_register(); ++ scale_factor = Address::times(stackElementSize); ++ } ++ // offset += wordSize; // return PC is on stack // yj todo: we don't push PC on stack?? ++ return Address(esp, scale_reg, scale_factor, offset); ++} ++ ++ ++void MacroAssembler::verify_oop_addr(Address addr, const char* s) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::verify_tlab() { ++#ifdef ASSERT ++ if (UseTLAB && VerifyOops) { ++ Label next, ok; ++ Register thread_reg = rthread; ++ Register t1 = rscratch1; ++ Register t2 = rscratch2; ++ get_thread(thread_reg); ++ //push(t1); ++ ldptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset()))); ++ cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset()))); ++ jcc(Assembler::aboveEqual, next); ++ STOP("assert(top >= start)"); ++ should_not_reach_here("assert(top >= start)"); ++ ++ bind(next); ++ ldptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_end_offset()))); ++ cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset()))); ++ jcc(Assembler::aboveEqual, ok); ++ STOP("assert(top <= end)"); ++ should_not_reach_here("assert(top <= end)"); ++ //pop(t1); ++ bind(ok); ++ } ++#endif ++} ++ ++void MacroAssembler::verify_FPU(int stack_depth, const char* s) { ++ //Unimplemented(); ++} ++ ++// ((OopHandle)result).resolve(); ++void MacroAssembler::resolve_oop_handle(Register result, Register tmp) {//warn("TODO:modify resolve_oop_handle jzy"); ++ assert_different_registers(result, tmp); ++ // OopHandle::resolve is an indirection. ++ access_load_at(T_OBJECT, IN_NATIVE, result, Address(result, 0), tmp, noreg); ++} ++ ++void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) { ++ // get mirror ++ const int mirror_offset = in_bytes(Klass::java_mirror_offset()); ++ ldl(mirror, Address(method, Method::const_offset())); ++ ldl(mirror, Address(mirror, ConstMethod::constants_offset())); ++ ldl(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes())); ++ ldl(mirror, Address(mirror, mirror_offset)); ++ resolve_oop_handle(mirror, tmp); ++} ++ ++void MacroAssembler::load_klass(Register dst, Register src) { ++ if (UseCompressedClassPointers) { ++ ldwu(dst, Address(src, oopDesc::klass_offset_in_bytes())); ++ decode_klass_not_null(dst); ++ } else { ++ ldptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); ++ } ++} ++ ++void MacroAssembler::load_prototype_header(Register dst, Register src) { ++ load_klass(dst, src); ++ ld(dst, Address(dst, Klass::prototype_header_offset())); ++} ++ ++void MacroAssembler::store_klass(Register dst, Register src) { ++ if (UseCompressedClassPointers) { ++ encode_klass_not_null(src); ++ stw(src, oopDesc::klass_offset_in_bytes(), dst); ++ } else { ++ stl(src, oopDesc::klass_offset_in_bytes(), dst); ++ } ++} ++ ++void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, ++ Register dst, Address src, ++ Register tmp1, Register thread_tmp) {SCOPEMARK_NAME(MacroAssembler::access_load_at, this) ++ 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, dst, src, tmp1, thread_tmp); ++ } else { ++ bs->load_at(this, decorators, type, dst, src, tmp1, thread_tmp); ++ } ++} ++ ++void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, ++ Address dst, Register src, ++ Register tmp1, Register thread_tmp) {SCOPEMARK_NAME(MacroAssembler::access_store_at, this) ++ 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, dst, src, tmp1, thread_tmp); ++ } else { ++ bs->store_at(this, decorators, type, dst, src, tmp1, thread_tmp); ++ } ++} ++ ++void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, ++ Register thread_tmp, DecoratorSet decorators) { ++ access_load_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp); ++} ++ ++void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register tmp1, ++ Register thread_tmp, DecoratorSet decorators) { ++ access_load_at(T_OBJECT, IN_HEAP | IS_NOT_NULL | decorators, dst, src, tmp1, thread_tmp); ++} ++ ++void MacroAssembler::store_heap_oop(Address dst, Register src, Register tmp1, ++ Register thread_tmp, DecoratorSet decorators) { ++ access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp); ++} ++ ++// Used for storing NULLs. ++void MacroAssembler::store_heap_oop_null(Address dst) { ++ access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg); ++} ++ ++void MacroAssembler::store_klass_gap(Register dst, Register src) { ++ if (UseCompressedClassPointers) { ++ stw(src, oopDesc::klass_gap_offset_in_bytes(), dst); ++ } ++} ++ ++#ifdef ASSERT ++void MacroAssembler::verify_heapbase(const char* msg) {SCOPEMARK_NAME(MacroAssembler::verify_heapbase, this) ++ assert (UseCompressedOops || UseCompressedClassPointers, "should be compressed"); ++ assert (Universe::heap() != NULL, "java heap should be initialized"); ++ if (CheckCompressedOops) { ++ Label ok; ++// push(1 << rscratch1->encoding(), sp); ++// push(rscratch1); // cmpptr trashes rscratch1 ++ cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr())); ++ jcc(Assembler::equal, ok); ++ STOP(msg); ++ bind(ok); ++// pop(1 << rscratch1->encoding(), sp); ++// pop(rscratch1); ++ } ++} ++#endif ++ ++ ++// Algorithm must match CompressedOops::encode. ++void MacroAssembler::encode_heap_oop(Register dst, Register src) { ++#ifdef ASSERT ++ verify_heapbase("MacroAssembler::encode_heap_oop:heap base corrupted?"); ++#endif ++ verify_oop(src, "broken oop in encode_heap_oop"); ++ if (Universe::narrow_oop_base() == NULL) { ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ srll(src, LogMinObjAlignmentInBytes, dst); ++ } else { ++ if (dst != src) bis(R0, src, dst); ++ } ++ } else { ++ if (dst == src) { ++ seleq(dst, r12_heapbase, dst, dst); ++ subl(dst, r12_heapbase, dst); ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ srll(dst, LogMinObjAlignmentInBytes, dst); ++ } ++ } else { ++ subl(src, r12_heapbase, dst); ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ srll(dst, LogMinObjAlignmentInBytes, dst); ++ } ++ seleq(src, R0, dst, dst); ++ } ++ } ++} ++ ++void MacroAssembler::encode_heap_oop_not_null(Register r) { ++// stop("encode_heap_oop_not_null not check lsp"); ++#ifdef ASSERT ++ verify_heapbase("MacroAssembler::encode_heap_oop_not_null: heap base corrupted?"); ++ if (CheckCompressedOops) { ++ Label ok; ++ testl(r, r); ++ jcc(Assembler::notEqual, ok); ++ STOP("null oop passed to encode_heap_oop_not_null"); ++ bind(ok); ++ } ++#endif ++ verify_oop(r, "broken oop in encode_heap_oop_not_null"); ++ if (Universe::narrow_oop_base() != NULL) { ++ subl(r, r12_heapbase, r); ++ } ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ srll(r, LogMinObjAlignmentInBytes, r); ++ } ++} ++ ++void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { ++// stop("encode_heap_oop_not_null 2 not check lsp"); ++#ifdef ASSERT ++ verify_heapbase("MacroAssembler::encode_heap_oop_not_null2: heap base corrupted?"); ++ if (CheckCompressedOops) { ++ Label ok; ++ testl(src, src); ++ jcc(Assembler::notEqual, ok); ++ STOP("null oop passed to encode_heap_oop_not_null2"); ++ bind(ok); ++ } ++#endif ++ verify_oop(src, "broken oop in encode_heap_oop_not_null2"); ++ if (dst != src) { ++ movl(dst, src); ++ } ++ if (Universe::narrow_oop_base() != NULL) { ++ subl(dst, r12_heapbase, dst); ++ } ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ srll(dst, LogMinObjAlignmentInBytes, dst); ++ } ++} ++ ++void MacroAssembler::decode_heap_oop(Register dst, Register src) { ++#ifdef ASSERT ++ verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?"); ++#endif ++ if (Universe::narrow_oop_base() == NULL) { ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ if (dst != src) nop(); // DON'T DELETE THIS GUY. ++ slll(src, LogMinObjAlignmentInBytes, dst); ++ } else { ++ if (dst != src) bis(R0, src, dst); ++ } ++ } else { ++ if (dst == src) { ++ if (dst != AT) bis(R0, dst, AT); ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ slll(dst, LogMinObjAlignmentInBytes, dst); ++ } ++ addl(dst, r12_heapbase, dst); ++ seleq(AT, R0, dst, dst); ++ } else { ++ if (Universe::narrow_oop_shift() != 0) { ++ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ slll(src, LogMinObjAlignmentInBytes, dst); ++ addl(dst, r12_heapbase, dst); ++ } else { ++ addl(src, r12_heapbase, dst); ++ } ++ seleq(src, R0, dst, dst); ++ } ++ } ++ verify_oop(dst, "broken oop in decode_heap_oop"); ++} ++ ++void MacroAssembler::decode_heap_oop_not_null(Register r) { ++ assert (UseCompressedOops, "should only be used for compressed headers"); ++ assert (Universe::heap() != NULL, "java heap should be initialized"); ++ // Cannot assert, unverified entry point counts instructions (see .ad file) ++ // vtableStubs also counts instructions in pd_code_size_limit. ++ // Also do not verify_oop as this is called by verify_oop. ++ if (Universe::narrow_oop_shift() != 0) { ++ assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ slll(r, LogMinObjAlignmentInBytes, r); ++ if (Universe::narrow_oop_base() != NULL) { ++ addl(r, r12_heapbase, r); ++ } ++ } else { ++ assert (Universe::narrow_oop_base() == NULL, "sanity"); ++ } ++} ++ ++void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { ++// stop("decode_heap_oop_not_null 2 not check lsp"); ++ // Note: it will change flags ++ assert (UseCompressedOops, "should only be used for compressed headers"); ++ assert (Universe::heap() != NULL, "java heap should be initialized"); ++ // Cannot assert, unverified entry point counts instructions (see .ad file) ++ // vtableStubs also counts instructions in pd_code_size_limit. ++ // Also do not verify_oop as this is called by verify_oop. ++ if (Universe::narrow_oop_shift() != 0) { ++ assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); ++ if (LogMinObjAlignmentInBytes == Address::times_8) { ++ lea(dst, Address(r12_heapbase, src, Address::times_8, 0)); ++ } else { ++ if (dst != src) { ++ movl(dst, src); ++ } ++ slll(dst, LogMinObjAlignmentInBytes, dst); ++ if (Universe::narrow_oop_base() != NULL) { ++ addl(dst, r12_heapbase, dst); ++ } ++ } ++ } else { ++ assert (Universe::narrow_oop_base() == NULL, "sanity"); ++ if (dst != src) { ++ movl(dst, src); ++ } ++ } ++} ++ ++void MacroAssembler::encode_klass_not_null(Register r) { ++ if (Universe::narrow_klass_base() != NULL) { ++ assert(r != rscratch3, "Encoding a klass in rcc"); ++ set64(rscratch3, (int64_t)Universe::narrow_klass_base()); ++ subl(r, rscratch3, r); ++ } ++ if (Universe::narrow_klass_shift() != 0) { ++ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); ++ srll(r, LogKlassAlignmentInBytes, r); ++ } ++// if (Universe::narrow_klass_base() != NULL) { ++// reinit_heapbase(); ++// } ++} ++ ++void MacroAssembler::encode_klass_not_null(Register dst, Register src) { ++ if (dst == src) { ++ encode_klass_not_null(src); ++ } else { ++ if (Universe::narrow_klass_base() != NULL) { ++ set64(dst, (int64_t)Universe::narrow_klass_base()); ++ subl(src, dst, dst); ++ } else { ++ movl(dst, src); ++ } ++ if (Universe::narrow_klass_shift() != 0) { ++ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); ++ srll(dst, LogKlassAlignmentInBytes, dst); ++ } ++ } ++} ++ ++// !!! 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) { ++ // Note: it will change flags ++ assert (UseCompressedClassPointers, "should only be used for compressed headers"); ++ assert(r != r12_heapbase, "Decoding a klass in r12"); ++ // Cannot assert, unverified entry point counts instructions (see .ad file) ++ // vtableStubs also counts instructions in pd_code_size_limit. ++ // Also do not verify_oop as this is called by verify_oop. ++ if (Universe::narrow_klass_shift() != 0) { ++ assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); ++ slll(r, LogKlassAlignmentInBytes, r); ++ } ++ if (Universe::narrow_klass_base() != NULL) { ++ set64(r12_heapbase, (int64_t)Universe::narrow_klass_base()); ++ addl(r, r12_heapbase, r); ++ reinit_heapbase(); ++ } ++} ++ ++void MacroAssembler::decode_klass_not_null(Register dst, Register src) { ++ assert (UseCompressedClassPointers, "should only be used for compressed headers"); ++ ++ if (dst == src) { ++ decode_klass_not_null(dst); ++ } else { ++ // Cannot assert, unverified entry point counts instructions (see .ad file) ++ // vtableStubs also counts instructions in pd_code_size_limit. ++ // Also do not verify_oop as this is called by verify_oop. ++ set64(dst, (int64_t)Universe::narrow_klass_base()); ++ if (Universe::narrow_klass_shift() != 0) { ++ assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); ++ assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?"); ++ lea(dst, Address(dst, src, Address::times_8, 0)); ++ } else { ++ addl(dst, src, dst); ++ } ++ } ++} ++ ++void MacroAssembler::emit_data(RelocationHolder const& rspec, int format) { ++ if (rspec.type() != relocInfo::none) { ++#ifdef ASSERT ++ //check_relocation(rspec, format);//sw will be wrong ++#endif ++ if (format == call32_operand){ ++ ShouldNotReachHere(); ++ code_section()->relocate(code_section()->end(), rspec, disp32_operand); ++ } ++ else ++ code_section()->relocate(code_section()->end(), rspec, format); ++ } ++} ++ ++void MacroAssembler::mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec){ ++ emit_data(rspec, narrow_oop_operand); ++ int16_t high = (imm32 - (int16_t)(imm32))>>16; ++ int16_t low = (int16_t)(imm32); ++ ldih(dst, high, R0); ++ ldi(dst, low, dst); ++ // if imm32=0x0000ffff, ldih/ldi will result in 0x10000ffff, so we must zapnot ++ zapnot(dst, 0xf, dst); ++} ++ ++void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { ++ assert (UseCompressedOops, "should only be used for compressed headers"); ++ assert (Universe::heap() != NULL, "java heap should be initialized"); ++ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); ++ int oop_index = oop_recorder()->find_index(obj); ++ RelocationHolder rspec = oop_Relocation::spec(oop_index); ++ mov_narrow_oop(dst, oop_index, rspec); ++ //code_section()->relocate(pc(), rspec); ++ //prepare_patch_li48(dst, oop_index); ++} ++ ++void MacroAssembler::set_narrow_oop(Address dst, jobject obj) { ++ should_not_reach_here("set_narrow_oop"); ++} ++ ++void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj, Register ccReg) { ++ should_not_reach_here("cmp_narrow_oop"); ++} ++ ++void MacroAssembler::cmp_narrow_oop(Address dst, jobject obj, Register ccReg) { ++ should_not_reach_here("cmp_narrow_oop"); ++} ++ ++void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { ++ assert (UseCompressedClassPointers, "should only be used for compressed headers"); ++ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); ++ int klass_index = oop_recorder()->find_index(k); ++ RelocationHolder rspec = metadata_Relocation::spec(klass_index); ++ mov_narrow_oop(dst,Klass::encode_klass(k),rspec); ++ //code_section()->relocate(pc(), rspec); ++ //prepare_patch_li48(dst, Klass::encode_klass(k)); ++} ++ ++void MacroAssembler::set_narrow_klass(Address dst, Klass* k) { ++ should_not_reach_here("set_narrow_klass"); ++} ++ ++void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k, Register ccReg) { ++ should_not_reach_here("cmp_narrow_klass"); ++} ++ ++void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k, Register ccReg) { ++ should_not_reach_here("cmp_narrow_klass"); ++} ++ ++void MacroAssembler::reinit_heapbase() { ++ if (UseCompressedOops || UseCompressedClassPointers) { ++ if (Universe::heap() != NULL) { ++ if (Universe::narrow_oop_base() == NULL) { ++ movl(r12_heapbase, R0); ++ } else { ++ mov_immediate64(r12_heapbase, (int64_t)Universe::narrow_ptrs_base()); ++ } ++ } else { ++ ldptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr())); ++ } ++ } ++} ++ ++// Search for str1 in str2 and return index or -1 ++void MacroAssembler::string_indexof(Register str2, Register str1, ++ Register cnt2, Register cnt1, ++ Register tmp1, Register tmp2, ++ Register tmp3, Register tmp4, ++ Register tmp5, Register tmp6, ++ int icnt1, Register result, int ae) { ++ should_not_reach_here("string_indexof"); ++} ++ ++void MacroAssembler::string_indexof_char(Register str1, Register cnt1, ++ Register ch, Register result, ++ Register tmp1, Register tmp2, Register tmp3) ++{ ++ should_not_reach_here("string_indexof_char"); ++} ++ ++// Compare strings. ++void MacroAssembler::string_compare(Register str1, Register str2, ++ Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2, ++ FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3, int ae) { ++ should_not_reach_here("string_compare"); ++} ++ ++// This method checks if provided byte array contains byte with highest bit set. ++void MacroAssembler::has_negatives(Register ary1, Register len, Register result) { ++ // a1: byte array ++ // a2: len ++ // v0: result ++ //ShortBranchVerifier sbv(this); ++ Register tmp1 = rscratch3; ++ assert_different_registers(ary1, len, result, tmp1); ++ //assert_different_registers(vec1, vec2); ++ Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE; ++ ++ // len == 0 ++ //testl(len, len); ++ jcc(Assembler::zero, FALSE_LABEL, len); ++ ++ movwu(result, len); // copy ++ ++ // Compare 4-byte vectors ++ andw(len, 0xfffffffc, len); // vector count (in bytes) ++ jcc(Assembler::zero, COMPARE_CHAR, len); ++ ++ lea(ary1, Address(ary1, len, Address::times_1)); ++ negptr(len); ++ ++ bind(COMPARE_VECTORS); ++ ldwu(tmp1, Address(ary1, len, Address::times_1)); ++ andw(tmp1, 0x80808080, tmp1); ++ jcc(Assembler::notZero, TRUE_LABEL, tmp1); ++ addptr(len, 4, len); ++ jcc(Assembler::notZero, COMPARE_VECTORS, len); ++ ++ // Compare trailing char (final 2 bytes), if any ++ bind(COMPARE_CHAR); ++ testl(result, 0x2); // tail char ++ jcc(Assembler::zero, COMPARE_BYTE); ++ load_unsigned_short(tmp1, Address(ary1, 0)); ++ andw(tmp1, 0x00008080, tmp1); ++ jcc(Assembler::notZero, TRUE_LABEL, tmp1); ++ subptr(result, 2, result); ++ lea(ary1, Address(ary1, 2)); ++ ++ bind(COMPARE_BYTE); ++ testw(result, 0x1); // tail byte ++ jcc(Assembler::zero, FALSE_LABEL); ++ load_unsigned_byte(tmp1, Address(ary1, 0)); ++ andw(tmp1, 0x00000080, tmp1); ++ jcc(Assembler::notEqual, TRUE_LABEL, tmp1); ++ jmp(FALSE_LABEL); ++ ++ bind(TRUE_LABEL); ++ mov_immediate32u(result, 1); // return true ++ jmp(DONE); ++ ++ bind(FALSE_LABEL); ++ mov_immediate32u(result, 0); // return false ++ ++ // That's it ++ bind(DONE); ++} ++ ++void MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, ++ Register tmp4, Register tmp5, Register result, ++ Register cnt1, int elem_size) { ++ should_not_reach_here("arrays_equals not implement"); ++} ++ ++// Intrinsic for sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray and ++// java/lang/StringUTF16.compress. ++void MacroAssembler::encode_iso_array(Register src, Register dst, ++ Register len, Register result, ++ FloatRegister Vtmp1, FloatRegister Vtmp2, ++ FloatRegister Vtmp3, FloatRegister Vtmp4) ++{ ++ should_not_reach_here("encode_iso_array not implement"); ++} ++ ++/** ++ * Helpers for multiply_to_len(). ++ */ ++void MacroAssembler::add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, ++ Register src1, Register src2) { ++ ShouldNotReachHere(); ++} ++ ++/** ++ * Multiply 64 bit by 64 bit first loop. ++ */ ++void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, ++ Register y, Register y_idx, Register z, ++ Register carry, Register product, ++ Register idx, Register kdx) { ++ ShouldNotReachHere(); ++} ++ ++/** ++ * Multiply 128 bit by 128. Unrolled inner loop. ++ * ++ */ ++void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, ++ Register carry, Register carry2, ++ Register idx, Register jdx, ++ Register yz_idx1, Register yz_idx2, ++ Register tmp, Register tmp3, Register tmp4, ++ Register tmp6, Register product_hi) { ++ ShouldNotReachHere(); ++} ++ ++/** ++ * Code for BigInteger::multiplyToLen() instrinsic. ++ * ++ * i0: x ++ * i1: xlen ++ * i2: y ++ * i3: ylen ++ * i4: z ++ * i5: zlen ++ * i10: tmp1 ++ * i11: tmp2 ++ * i12: tmp3 ++ * i13: tmp4 ++ * i14: tmp5 ++ * i15: tmp6 ++ * i16: tmp7 ++ * ++ */ ++void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, ++ Register z, Register zlen, ++ Register tmp1, Register tmp2, Register tmp3, Register tmp4, ++ Register tmp5, Register tmp6, Register product_hi) { ++ ShouldNotReachHere(); ++} ++ ++// Code for BigInteger::mulAdd instrinsic ++// out = i0 ++// in = i1 ++// offset = i2 (already out.length-offset) ++// len = i3 ++// k = i4 ++// ++// pseudo code from java implementation: ++// carry = 0; ++// offset = out.length-offset - 1; ++// for (int j=len-1; j >= 0; j--) { ++// product = (in[j] & LONG_MASK) * kLong + (out[offset] & LONG_MASK) + carry; ++// out[offset--] = (int)product; ++// carry = product >>> 32; ++// } ++// return (int)carry; ++void MacroAssembler::mul_add(Register out, Register in, Register offset, ++ Register len, Register k) { ++ ShouldNotReachHere(); ++} ++ ++/** ++ * Emits code to update CRC-32 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) { ++ xorr(val, crc, val); ++ and_ins(val, 0xFF, val); ++ srll(crc, 8, crc); // unsigned shift ++// zapnot(crc, 0xF, crc); ++ ++ dsll(AT, val, Address::times_4); ++ addl(table, AT, AT); ++ ldw(AT, 0, AT); ++ zapnot(AT, 0xF, AT); ++ xorr(crc, AT, crc); ++} ++ ++/** ++ * @param crc register containing existing CRC (32-bit) ++ * @param buf register pointing to input byte buffer (byte*) ++ * @param len register containing number of bytes ++ * @param table register that will contain address of CRC table ++ * @param tmp scratch register ++ */ ++void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, ++ Register table0, Register table1, Register table2, Register table3, ++ Register tmp, Register tmp2, Register tmp3) { ++ ShouldNotReachHere(); ++} ++ ++// Compress char[] array to byte[]. ++void MacroAssembler::char_array_compress(Register src, Register dst, Register len, ++ FloatRegister tmp1Reg, FloatRegister tmp2Reg, ++ FloatRegister tmp3Reg, FloatRegister tmp4Reg, ++ Register result) { ++ should_not_reach_here("char_array_compress"); ++} ++ ++// Inflate byte[] array to char[]. ++void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len, ++ FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3, ++ Register tmp4) { ++ should_not_reach_here("byte_array_inflate"); ++} ++ ++SkipIfEqual::SkipIfEqual( ++ MacroAssembler* masm, const bool* flag_addr, bool value) { ++ _masm = masm; ++ _masm->mov(AT, (address)flag_addr); ++ _masm->ldbu(AT, 0, AT); ++ _masm->addiu(AT, -value, AT); ++ _masm->beq_l(AT,_label); ++} ++ ++SkipIfEqual::~SkipIfEqual() { ++ _masm->bind(_label); ++} ++ ++// get_thread() can be called anywhere inside generated code so we ++// need to save whatever non-callee save context might get clobbered ++// by the call to JavaThread::sw64_get_thread_helper() or, indeed, ++// the call setup code. ++// ++// sw64_get_thread_helper() clobbers only i0, i1, and flags. ++// ++void MacroAssembler::get_thread(Register thread) { ++ pushad(thread); ++ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, Thread::current), 0); ++ ++ int off;//depending on the sd sequence in pushad(); ++ ++ /* ++ * in [assembler_sw64.cpp] pushad(), F12 is inserted between A7 and T0. ++ * Therefore, the offsets before A7 need to be adjusted by 8 bytes. ++ * ++ * NOTE: I have tried removing the push action of F12 from pushad(), but failed. ++ * Maybe other modules in Hotspot depend on this special layout. ++ */ ++ move(thread, V0); ++ popad(thread); ++} ++ ++//--------------------------------------------------------------------------------------------------------------- ++ ++Register temp_regs[] = {T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, A0, A1, A2, A3, A4, A5, GP, V0, AT}; ++void MacroAssembler::saveTRegisters(){ ++ int i, index; ++ ++ // Fixed-point registers ++ int len = sizeof(temp_regs) / sizeof(temp_regs[0]); ++ ++ addiu(esp, -1 * len * wordSize, esp); ++ for (i = 0, index = len - 1; i < len; i++) { ++ stl(temp_regs[i], index * wordSize, esp); ++ index--; //index not equal i ++ } ++ ++} ++ ++void MacroAssembler::restoreTRegisters(){ ++ int i, index; ++ /* Fixed-point registers */ ++ int len = sizeof(temp_regs) / sizeof(temp_regs[0]); ++ for (i = len-1, index = 0; i >= 0; i--) { ++ ldl(temp_regs[i], index * wordSize, esp); ++ index++; ++ } ++ addiu(esp, index * wordSize, esp); ++} ++ ++Register caller_saved_registers[] = {V0, T0, T1, T2, T3, T4, T5, T6, T7, rfp, A0, A1, A2, A3, A4, A5, T8, T9, T10, T11, RA, T12, AT, GP}; ++ ++// In SW64, F0~23 are all caller-saved registers ++FloatRegister caller_saved_fpu_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}; ++ ++//We preserve all caller-saved register ++void MacroAssembler::pushad(Register skip){ ++ int i, index; ++ ++ // Fixed-point registers ++ int len = sizeof(caller_saved_registers) / sizeof(caller_saved_registers[0]); ++ //int stack_len = skip == noreg ? len : (len-1); ++ ++ for (i = 0, index = 1; i < len; i++) { ++ if (skip != caller_saved_registers[i]) { ++ stl(caller_saved_registers[i], -1 * index * wordSize, esp); ++ index++; //index not equal i ++ } ++ } ++ addiu(esp, -1 * (index-1) * wordSize, esp); ++ ++ /* Floating-point registers */ ++ len = sizeof(caller_saved_fpu_registers) / sizeof(caller_saved_fpu_registers[0]); ++ addiu(esp, -1 * len * wordSize, esp); ++ for (i = 0; i < len; i++) { ++ fstd(caller_saved_fpu_registers[i], (len - i - 1) * wordSize, esp); ++ } ++}; ++ ++void MacroAssembler::popad(Register skip){ ++ int i, index; ++ ++ /* Floating-point registers */ ++ int len = sizeof(caller_saved_fpu_registers) / sizeof(caller_saved_fpu_registers[0]); ++ for (i = 0; i < len; i++) { ++ fldd(caller_saved_fpu_registers[i], (len - i - 1) * wordSize, esp); ++ } ++ addiu(esp, len * wordSize, esp); ++ ++ /* Fixed-point registers */ ++ len = sizeof(caller_saved_registers) / sizeof(caller_saved_registers[0]); ++ for (i = len-1, index = 0; i >= 0; i--) { ++ if (skip != caller_saved_registers[i]) { ++ ldl(caller_saved_registers[i], index * wordSize, esp); ++ index++; ++ } ++ } ++ addiu(esp, index * wordSize, esp); ++}; ++ ++ ++ ++void MacroAssembler::notw(Register rd, Register rs) { ++ ornot(R0, rs, rd); ++// zapnot(rd, 0xf, rd); ++} ++ ++/** ++ * x86 ++ * Assembler::movl(Register dst, Address src) ++ * sw64 ++ * MacroAssembler::ldws(Register rd, Address addr) ++ * note ++ * load 32bit into reg. ++ * for x86 the reg can be viewed just as 32bit, they don't care the msb32 since their instructions can operate 32bit directly. ++ * for sw64 the msb32 cares and ldws sign extend into msb32. ++ * it's recommend to use ldws to substitue movl when transplanting, except for the ocassions mentioned in ldwu ++ */ ++void MacroAssembler::ldws(Register rd, Address addr) { ++ ldw(rd, addr); ++} ++ ++/** ++ * x86 ++ * Assembler::movl(Register dst, Address src) ++ * sw64 ++ * MacroAssembler::ldwu(Register rd, Address addr) ++ * note ++ * load 32bit into reg. ++ * for x86 the reg can be viewed just as 32bit, they don't care the msb32 since their instructions can operate 32bit directly. ++ * for sw64 the msb32 cares and ldwu zero the msb32. ++ * if rd is loaded as a flag, a status, a mode, following by a test, a and, we must use ldwu ++ */ ++void MacroAssembler::ldwu(Register rd, Address addr) { ++ ldw(rd, addr); ++ zapnot(rd, 0xf, rd); ++} ++ ++void MacroAssembler::ldptr(Register rd, Address addr, Register tmp) { ++ ldl(rd, addr); ++} ++ ++/** ++ * x86 ++ * MacroAssembler::movptr(Address dst, Register src) ++ * sw64 ++ * MacroAssembler::stptr(Register rd, Address addr, Register tmp=rcc) ++ * note ++ * rd can't be same with tmp ++ */ ++void MacroAssembler::stptr(Register rd, Address addr, Register tmp) { ++ assert_different_registers(rd, tmp); ++ stl(rd, addr, tmp); ++} ++ ++void MacroAssembler::addptr(Register rd, Address addr) { ++ assert_different_registers(rd, rcc); ++ ldptr(rcc, addr); ++ addptr(rd, rcc, rd); ++} ++ ++/** ++ * x86 ++ * no corresponding ++ * sw64 ++ * MacroAssembler::ldws(Register rd, AddressLiteral addr) ++ * note ++ * use ldws ASAP ++ */ ++void MacroAssembler::ldws(Register rd, AddressLiteral addr) { ++ mov_immediate64(rd, (intptr_t)addr.target(), addr.rspec()); ++ ldw(rd, 0, rd); ++} ++ ++/** ++ * x86 ++ * Assembler:: ++ * sw64 ++ * MacroAssembler::ldwu(Register rd, AddressLiteral addr) ++ * note ++ * use when load a flag/status/mode ++ */ ++void MacroAssembler::ldwu(Register rd, AddressLiteral addr) { ++ ldws(rd, addr); ++ zapnot(rd, 0xf, rd); ++} ++ ++/** ++ * x86 ++ * movptr ++ * sw64 ++ * ldptr ++ * note ++ * same ++ */ ++void MacroAssembler::ldptr(Register rd, AddressLiteral addr) { ++ mov_immediate64(rd, (intptr_t)addr.target(), addr.rspec()); ++ ldl(rd, 0, rd); ++} ++ ++/** ++ * x86 ++ * jmp ++ * sw64 ++ * jmp(Address rd, Register tmp=T12) ++ * note ++ * sw use t12 as jump target, especially when jump into runtime ++ */ ++void MacroAssembler::jmp(Address rd, Register tmp) { ++ ldl(T12, rd); ++ Assembler::jmp(tmp, T12, 0);// set ra=AT for debug ++} ++ ++/** ++ * x86 ++ * jmp ++ * sw64 ++ * jmp(Register rd, Register tmp=T12); ++ * note ++ * sw use AT as link reg for debug ++ */ ++void MacroAssembler::jmp(Register rd, Register tmp) { ++ assert_different_registers(rd, tmp); ++ if (rd != T12) ++ movl(T12, rd); ++ Assembler::jmp(tmp, T12, 0);// set ra=tmp for debug ++} ++ ++void MacroAssembler::jmp(Label& lbl) { ++ beq_l(R0, lbl); ++} ++ ++/** ++ * x86 ++ * Assembler::movzwl(Register dst, Address src) ++ * sw64 ++ * MacroAssembler::ldhu_unaligned(Register rd, Address addr, Register tmp=rcc) ++ * note ++ * load and zero-extend a 16bit into a reg. ++ * movzwl and ldhu_unaligned are all little endian, so maybe have to swap in some occasion. ++ * x86 zero-extends a 16bit into 32bit, sw64 zero-extends 16bit into a 64bit reg. ++ * tmp can't be same with rd. ++ */ ++void MacroAssembler::ldhu_unaligned(Register rd, Address addr, Register tmp) { ++ assert_different_registers(rd, tmp); ++ lea(tmp, addr); ++ Assembler::ldbu(rd, 1, tmp); ++ slll(rd, 8, rd); ++ Assembler::ldbu(tmp, 0, tmp); ++ bis(tmp, rd, rd); ++} ++ ++/** ++ * x86 ++ * Assembler::movzwl(Register dst, Address src) ++ * sw64 ++ * MacroAssembler::ldhu_unaligned_be(Register rd, Address addr, Register tmp=rcc) ++ * note ++ * load and zero-extend a 16bit into a reg. ++ * movzwl is little endian, so have to bswapl after movzwl. ++ * ldhu_unaligned_be is big endian, so don't have to swap. ++ * x86 zero-extend a 16bit into 32bit, we zero-extend into a 64bit reg. ++ * tmp can't be same with rd. ++ */ ++void MacroAssembler::ldhu_unaligned_be(Register rd, Address addr, Register tmp) { ++// Assembler::ldhu(rd, addr);// unaligned exception may occur here ++ assert_different_registers(rd, tmp); ++ lea(tmp, addr); ++ Assembler::ldbu(rd, 1, tmp); ++ Assembler::ldbu(tmp, 0, tmp); ++ slll(tmp, 8, tmp); ++ bis(tmp, rd, rd); ++} ++ ++void MacroAssembler::cmove(Condition cc, Register dst, Register src1, Register src2, Register ccReg) { ++ switch(cc) { ++// case equal: ++ case zero: ++ seleq(ccReg, src1, src2, dst); ++ break; ++// case notEqual: ++ case notZero: ++ selne(ccReg, src1, src2, dst); ++ break; ++ case greaterEqual: ++ case aboveEqual: ++ selge(ccReg, src1, src2, dst); ++ break; ++ case greater: ++ case positive: ++ selgt(ccReg, src1, src2, dst); ++ break; ++ case lessEqual: ++ selle(ccReg, src1, src2, dst); ++ break; ++ case less: ++ case below: ++ sellt(ccReg, src1, src2, dst); ++ break; ++ ++ case success: ++ selne(ccReg, src1, src2, dst); ++ break; ++ ++ case failed: ++ ShouldNotReachHere(); ++ break; ++ default: ++ Unimplemented(); ++ } ++} ++ ++// Patch any kind of instruction; there may be several instructions. ++// Return the total length (in bytes) of the instructions. ++int MacroAssembler::pd_patch_instruction_size(address branch, address target) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++int MacroAssembler::patch_oop(address insn_addr, address o) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++void MacroAssembler::prepare_patch_li48(Register rd, long imm) { ++ assert_not_delayed(); ++ assert(is_simm16(imm >> 32), "Not a 48-bit address"); ++ ++ int16_t msb_l, lsb_h, lsb_l; ++ NativeInstruction::imm48_split(imm, msb_l, lsb_h, lsb_l); ++ block_comment(";;li48 {"); ++ ldi(rd, msb_l, R0); ++ slll(rd, 32, rd); ++ ldih(rd, lsb_h, rd); ++ ldi(rd, lsb_l, rd); ++ char buf[50]; ++ sprintf(buf, "0x%lx }", imm); ++ block_comment(buf); ++} ++ ++address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++//without check, maybe fixed ++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; ++ if (sw2_arith_op(inst) == op_addpi) { ++ m = ins_mask(25, 13); ++ v = wdisp2(dest_pos, 4, 25, 13); ++ return inst & ~m | v; ++ } ++ switch (sw2_op(inst)) { ++ default: ShouldNotReachHere(); ++ case op_ret: ++ case op_jmp: ++ case op_call: m = wdisp(word_aligned_ones, 0, 16); v = wdisp( dest_pos, inst_pos+4, 16); break; ++ case op_br: ++ case op_bsr: ++ case op_beq: ++ case op_bne: ++ case op_blt: ++ case op_ble: ++ case op_bgt: ++ case op_bge: ++ case op_blbc: ++ case op_blbs: ++ case op_fbeq: ++ case op_fbne: ++ case op_fblt: ++ case op_fble: ++ case op_fbgt: ++ case op_fbge: m = wdisp(word_aligned_ones, 0, 21); v = wdisp( dest_pos, inst_pos+4, 21); break; ++ case op_ldi: m = simm(-1, 16); v = simm(dest_pos-inst_pos, 16); break; ++ // case op_addpi: m = ins_mask(25, 13); v = wdisp2(dest_pos, inst_pos + 4, 25, 13); ++ } ++ ++ return inst & ~m | v; ++} ++ ++// used registers : T0, T1 ++void MacroAssembler::verify_oop_subroutine() { ++ // RA: ra ++ // A0: char* error message ++ // A1: oop object to verify ++ ++ Label exit, error; ++ // increment counter ++ mov(T0, (long)StubRoutines::verify_oop_count_addr()); ++ ldw(AT, 0, T0); ++ addiu(AT, 1, AT); ++ stw(AT, 0, T0); ++ ++ // make sure object is 'reasonable' ++ beq_l(A1, exit); // if obj is NULL it is ok ++ ++ // Check if the oop is in the right area of memory ++ //const int oop_mask = Universe::verify_oop_mask(); ++ //const int oop_bits = Universe::verify_oop_bits(); ++ const uintptr_t oop_mask = Universe::verify_oop_mask(); ++ const uintptr_t oop_bits = Universe::verify_oop_bits(); ++ if (Assembler::is_simm8(oop_mask)) { ++ and_ins(A1, oop_mask, T0); ++ } else { ++ mov(AT, oop_mask); ++ and_ins(A1, AT, T0); ++ } ++ if (Assembler::is_simm8(oop_bits)) { ++ cmpeq(T0, oop_bits, AT); ++ beq(AT, offset(target(error))); ++ } else { ++ mov(AT, oop_bits); ++ bne_c(T0, AT, error); ++ } ++ ++ // make sure klass is 'reasonable' ++ //add for compressedoops ++ reinit_heapbase(); ++ //add for compressedoops ++ load_klass(T0, A1); ++ beq_l(T0, error); // if klass is NULL it is broken ++ // return if everything seems ok ++ BIND(exit); ++ ++ ret_sw(); ++ ++ // handle errors ++ BIND(error); ++ pushad(); ++ call_patch(CAST_FROM_FN_PTR(address, MacroAssembler::debug), relocInfo::runtime_call_type); ++ popad(); ++ ret_sw(); ++} ++ ++// MacroAssembler protected routines needed to implement ++// public methods ++ ++//void MacroAssembler::mov(Register r, Address dest) { ++// code_section()->relocate(pc(), dest.rspec()); ++// u_int64_t imm64 = (u_int64_t)dest.target(); ++//// movptr(r, imm64); ++//} ++ ++// Move a constant pointer into r. In Sw64 mode the virtual ++// address space is 48 bits in size, so we only need three ++// instructions to create a patchable instruction sequence that can ++// reach anywhere. ++//void MacroAssembler::movptr(Register r, long imm64) { ++// assert_not_delayed(); ++// assert(is_simm16(imm64 >> 32), "Not a 48-bit address"); ++// ++// int16_t msb_l, lsb_h, lsb_l; ++// imm48_split(imm64, msb_l, lsb_h, lsb_l); ++// ldi(r, msb_l, R0); ++// slll(r, 32, r); ++// ldih(r, lsb_h, r); ++// ldi(r, lsb_l, r); ++//} ++ ++// must get argument(a double) in F16/F17 ++//void MacroAssembler::trigfunc(char trig, bool preserve_cpu_regs, int num_fpu_regs_in_use) { ++//We need to preseve the register which maybe modified during the Call ++void MacroAssembler::trigfunc(char trig, int num_fpu_regs_in_use) { ++//save all modified register here ++//FIXME, in the disassembly of tirgfunc, only used V0,T4,T12, SP,RA,so we ony save V0,T4,T12 ++ pushad(); ++//we should preserve the stack space before we call ++ addiu(esp, -wordSize * 2, esp); ++ switch (trig){ ++ case 's' : ++ call_patch( CAST_FROM_FN_PTR(address, SharedRuntime::dsin), relocInfo::runtime_call_type ); ++ break; ++ case 'c': ++ call_patch( CAST_FROM_FN_PTR(address, SharedRuntime::dcos), relocInfo::runtime_call_type ); ++ break; ++ case 't': ++ call_patch( CAST_FROM_FN_PTR(address, SharedRuntime::dtan), relocInfo::runtime_call_type ); ++ break; ++ default:assert (false, "bad intrinsic"); ++ break; ++ } ++ addiu(esp, wordSize * 2, esp); ++ popad(); ++} ++ ++/** ++ * x86 ++ * Assembler::movl(Address dst, int32_t imm32) ++ * sw64 ++ * MacroAssembler::stw(int src, Address dst, Register tmp=rcc) ++ * note ++ * store a imm32 to a Address. only support base_plus_disp type Address. tmp can be any reg. ++ */ ++void MacroAssembler::stw(int imm32, Address dst, Register tmp) { ++ if (dst.getMode() == Address::base_plus_disp) { ++ mov_immediate32(tmp, imm32); ++ stw(tmp, dst); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++void MacroAssembler::mov_immediate64(Register dst, u_int64_t imm64) { ++// int32_t lsb32 = (int32_t) (imm64); ++// int32_t msb32 = (int32_t) ((imm64 - lsb32) >> 32); ++// int16_t msb_h = (msb32-(int16_t)msb32) >> 16; ++// int16_t msb_l = (int16_t)msb32; ++// int16_t lsb_h = (lsb32-(int16_t)lsb32) >> 16; ++// int16_t lsb_l = (int16_t)lsb32; ++// block_comment(";;imm64 {"); ++// if(msb_h == 0) { ++// ldi(dst, msb_l, R0); ++// } else { ++// ldih(dst, msb_h, R0); ++// if(msb_l != 0) ++// ldi(dst, msb_l, dst); ++// } ++// slll(dst, 32, dst); ++// if( ((int)lsb_h == -32768) && (lsb_l < 0) ) { ++// ldih(dst, 0x4000, dst);// yj todo ++// ldih(dst, 0x4000, dst); ++// ldi(dst, lsb_l, dst); ++// } else { ++// ldih(dst, lsb_h, dst); ++// ldi(dst, lsb_l, dst); ++// } ++// char buf[50]; ++// sprintf(buf, "0x%lx }", imm64); ++// block_comment(buf); ++ int32_t lo = (int32_t) (imm64); ++ int32_t hi = (int32_t) ((imm64 - lo) >> 32); ++ ++ int16_t lo_h16 = (lo - (int16_t)(lo))>>16; ++ int16_t lo_l16 = (int16_t)(lo); ++ int16_t hi_h16 = (hi - (int16_t)(hi))>>16; ++ int16_t hi_l16 = (int16_t)(hi); ++ block_comment(";;imm64 {"); ++ if ( is_simm16(imm64) ) { ++ ldi(dst, imm64, R0); ++ } else if ( hi != 0 ) { ++ if ( is_simm16(hi) ) { ++ ldi(dst, hi, R0); ++ } else { ++ ldih(dst, hi_h16, R0); ++ if (hi_l16 != 0) ++ ldi(dst, hi_l16, dst); ++ } ++ slll(dst, 32, dst); ++ if ( lo != 0 ) { ++ if ( ((int)lo_h16 == -32768) && ((int)lo_l16 < 0)) { ++ // original val was in range 0x7FFF8000..0x7FFFFFFF ++ ldih(dst, 0x4000, dst); ++ ldih(dst, 0x4000, dst); ++ if (lo_l16 != 0) ++ ldi(dst, lo_l16, dst); ++ } else { ++ ldih(dst, lo_h16, dst); ++ if (lo_l16 != 0) ++ ldi(dst, lo_l16, dst); ++ } ++ } ++ } else if ( (hi == 0) && (lo != 0) ) { ++ if ( ((int)lo_h16 == -32768) && ((int)lo_l16 < 0)) { ++ // original val was in range 0x7FFF8000..0x7FFFFFFF ++ /* ldih(d, lo_h16, R0); ++ * ldi(d, lo_l16, d); ++ * addw(d, 0, d); */ ++ ldih(dst, 0x4000, R0); ++ ldih(dst, 0x4000, dst); ++ if (lo_l16 != 0) ++ ldi(dst, lo_l16, dst); ++ } else { ++ ldih(dst, lo_h16, R0); ++ if (lo_l16 != 0) ++ ldi(dst, lo_l16, dst); ++ } ++ } else { ++ tty->print_cr("value = 0x%lx", imm64); ++ guarantee(false, "Not supported yet in set64!"); ++ } ++ char buf[50]; ++ sprintf(buf, "0x%lx }", imm64); ++ block_comment(buf); ++} ++ ++/** ++ * x86 ++ * Assembler::mov_literal64(Register, long, RelocationHolder const&) ++ * sw64 ++ * MacroAssembler::mov_immediate64(Register dst, u_int64_t imm64, RelocationHolder const& rspec, int format ++ * note ++ * x86's imm64 is just following the opcode, while sw64 is split and embeded in the ldi/sll/ldih/ldi seq. ++ * x86's imm64 format is set when mov_literal64 invoke emit_data64. sw's formate is set here. ++ */ ++void MacroAssembler::mov_immediate64(Register dst, u_int64_t imm64, RelocationHolder const& rspec, int format) { ++ InstructionMark im(this); ++ assert(inst_mark() != NULL, "must be inside InstructionMark"); ++ // Do not use AbstractAssembler::relocate, which is not intended for ++ // embedded words. Instead, relocate to the enclosing instruction. ++ code_section()->relocate(inst_mark(), rspec, format); ++#ifdef ASSERT ++ check_relocation(rspec, format); ++#endif ++ ++ assert(imm64 <= ((intptr_t(1) << 48) - 1), "imm64 is too large"); ++ prepare_patch_li48(dst, imm64); ++} ++ ++void MacroAssembler::mov_address64(Register dst, u_int64_t imm64, RelocationHolder const &rspec, int format) { ++ InstructionMark im(this); ++ assert(inst_mark() != NULL, "must be inside InstructionMark"); ++ // Do not use AbstractAssembler::relocate, which is not intended for ++ // embedded words. Instead, relocate to the enclosing instruction. ++ code_section()->relocate(inst_mark(), rspec, format); ++#ifdef ASSERT ++ check_relocation(rspec, format); ++#endif ++ if (SafePatch) { ++ if (offset() % 8 == 0) { ++ nop(); ++ br(T12, 2); ++ emit_int64((long) imm64); ++ ldl(T12, 0, T12); ++ } else { ++ br(T12, 2); ++ emit_int64((long) imm64); ++ ldl(T12, 0, T12); ++ nop(); ++ } ++ } else { ++ assert(imm64 <= ((intptr_t(1) << 48) - 1), "imm64 is too large"); ++ prepare_patch_li48(dst, imm64); ++ } ++} ++// zero extend imm32 into dst ++void MacroAssembler::mov_immediate32(Register dst, int imm32) { ++ if (imm32>=0 && imm32 < (1<<15)) { ++ // if imm32=0x0000ffff, ldi will result in 0xf..fffff since it's sign extened ++ // so imm32 must less then 1<<15, not 1<<16 ++ ldi(dst, imm32, R0); ++ } else { ++ int16_t high = (imm32 - (int16_t)(imm32))>>16; ++ int16_t low = (int16_t)(imm32); ++ ldih(dst, high, R0); ++ ldi(dst, low, dst); ++ // if imm32=0x0000ffff, ldih/ldi will result in 0x10000ffff, so we must zapnot ++ zapnot(dst, 0xf, dst); ++ } ++} ++ ++// zero extend imm32 into dst ++void MacroAssembler::mov_immediate32u(Register dst, int imm32) { ++ if (imm32>=0 && imm32 < (1<<15)) { ++ // if imm32=0x0000ffff, ldi will result in 0xf..fffff since it's sign extened ++ // so imm32 must less then 1<<15, not 1<<16 ++ ldi(dst, imm32, R0); ++ } else { ++ int16_t high = (imm32 - (int16_t)(imm32))>>16; ++ int16_t low = (int16_t)(imm32); ++ ldih(dst, high, R0); ++ ldi(dst, low, dst); ++ // if imm32=0x7fffffff, high=0x8000, low=0xffff ldih/ldi will result in 0xffffffff 7fffffff, so we must zapnot ++// if( ((int)high == (-32768)) && (low < 0) ) //TODO CHECK lsp: if((imm32<0) || (((int)high == (-32768)) && (low < 0))) ++ zapnot(dst, 0xf, dst); ++ } ++} ++// signed extend imm32 into dst ++void MacroAssembler::mov_immediate32s(Register dst, int imm32) { ++// if (imm32>=0 && imm32 < (1<<15)) { ++// // if imm32=0x0000ffff, ldi will result in 0xf..fffff since it's sign extened ++// // so imm32 must less then 1<<15, not 1<<16 ++// ldi(dst, imm32, R0); ++// } else { ++// int16_t high = (imm32 - (int16_t)(imm32))>>16; ++// int16_t low = (int16_t)(imm32); ++// ldih(dst, high, R0); ++// ldi(dst, low, dst); ++// // if imm32=0x7fffffff, high=0x8000,low=0xffff ldih/ldi will result in 0xffffffff 7fffffff, so we must addw ++// if( ((int)high == (-32768)) && (low < 0) ) ++// addw(dst, R0, dst); ++// } ++ assert(is_simm(imm32, 32), "imm should be simm32 in MacroAssembler::li32"); ++ int16_t high = (imm32 - (int16_t)(imm32))>>16; ++ int16_t low = (int16_t)(imm32); ++ if(is_simm16(imm32)){ ++ ldi(dst, imm32, R0); ++ } else { ++ ldih(dst, high, R0); ++ ldi(dst, low, dst); ++ if( ((int)high == (-32768)) && (low < 0) ) ++ addw(dst, R0, dst); ++ } ++} ++ ++void MacroAssembler::hswap(Register reg) { ++ if (UseSW8A) { ++ revbh(reg, reg); ++ sexth(reg, reg); ++ } else { ++ srll(reg, 8, AT); ++ slll(reg, 24, reg); ++ addw(reg, 0, reg); ++ sral(reg, 16, reg); ++ or_ins(reg, AT, reg); ++ } ++} ++ ++void MacroAssembler::huswap(Register reg) { ++ if (UseSW8A) { ++ revbh(reg, reg); ++ } else { ++ srll(reg, 8, AT); ++ slll(reg, 8, reg); ++ zapnot(reg, 0x2, reg); ++ or_ins(reg, AT, reg); ++ } ++} ++ ++// something funny to do this will only one more register AT ++// 32 bits ++void MacroAssembler::swap(Register reg) { ++ if (UseSW8A) { ++ revbw(reg, reg); ++ } else { ++ assert_different_registers(reg, AT); ++ zapnot(reg, 0xf, reg); ++ srll(reg, 8, AT); ++ slll(reg, 24, reg); ++ or_ins(reg, AT, reg); ++ srll(AT, 16, AT); ++ xor_ins(AT, reg, AT); ++ and_ins(AT, 0xff, AT); ++ xor_ins(reg, AT, reg); ++ slll(AT, 16, AT); ++ xor_ins(reg, AT, reg); ++ addw(reg, 0x0, reg); ++ } ++} ++ ++void MacroAssembler::bswapw(Register reg) { ++ swap(reg); ++} ++ ++void MacroAssembler::boundary_test(FloatRegister ft, Register res){ ++ Register tmp1 = AT; ++ Register tmp2 = GP; ++ fimovd(ft,tmp1); ++ slll(tmp1, 0x1, tmp2); ++ srll(tmp2, 53, tmp2); ++ ldi(tmp1, 2047, R0); ++ subl(tmp2, tmp1, res); ++} ++ ++void MacroAssembler::set64(Register d, long value) { ++ // yj todo: check and merge with mov_immediate64 ++ assert_not_delayed(); ++ ++ int32_t lo = (int32_t) (value); ++ int32_t hi = (int32_t) ((value - lo) >> 32); ++ ++ int16_t lo_h16 = (lo - (int16_t)(lo))>>16; ++ int16_t lo_l16 = (int16_t)(lo); ++ int16_t hi_h16 = (hi - (int16_t)(hi))>>16; ++ int16_t hi_l16 = (int16_t)(hi); ++ ++ if ( is_simm16(value) ) { ++ ldi(d, value, R0); ++ } else if ( hi != 0 ) { ++ if ( is_simm16(hi) ) { ++ ldi(d, hi, R0); ++ } else { ++ ldih(d, hi_h16, R0); ++ if (hi_l16 != 0) ++ ldi(d, hi_l16, d); ++ } ++ slll(d, 32, d); ++ if ( lo != 0 ) { ++ if ( ((int)lo_h16 == -32768) && ((int)lo_l16 < 0)) { ++ // original val was in range 0x7FFF8000..0x7FFFFFFF ++ ldih(d, 0x4000, d); ++ ldih(d, 0x4000, d); ++ if (lo_l16 != 0) ++ ldi(d, lo_l16, d); ++ } else { ++ ldih(d, lo_h16, d); ++ if (lo_l16 != 0) ++ ldi(d, lo_l16, d); ++ } ++ } ++ } else if ( (hi == 0) && (lo != 0) ) { ++ if ( ((int)lo_h16 == -32768) && ((int)lo_l16 < 0)) { ++ // original val was in range 0x7FFF8000..0x7FFFFFFF ++ /* ldih(d, lo_h16, R0); ++ * ldi(d, lo_l16, d); ++ * addw(d, 0, d); */ ++ ldih(d, 0x4000, R0); ++ ldih(d, 0x4000, d); ++ if (lo_l16 != 0) ++ ldi(d, lo_l16, d); ++ } else { ++ ldih(d, lo_h16, R0); ++ if (lo_l16 != 0) ++ ldi(d, lo_l16, d); ++ } ++ } else { ++ tty->print_cr("value = 0x%lx", value); ++ guarantee(false, "Not supported yet in set64!"); ++ } ++} ++ ++void MacroAssembler::push(int32_t imm32) { ++ assert(imm32==NULL_WORD, "we don't support imm other than 0"); ++ subl(esp, 8, esp); ++ stl(R0, 0, esp); ++} ++ ++void MacroAssembler::push(Register src) { ++ subl(esp, 8, esp); ++ stl(src, 0, esp); ++} ++ ++void MacroAssembler::pop(Register dst) { ++ if(UseSW8A) { ++ ldl_a(dst, 8 ,esp); ++ } else { ++ ldl(dst, 0, esp); ++ addl(esp, 8, esp); ++ } ++} ++ ++void MacroAssembler::push2(Register reg1, Register reg2) { ++ addiu(esp, -16, esp); ++ stl(reg2, 0, esp); ++ stl(reg1, 8, esp); ++} ++ ++void MacroAssembler::pusha() { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::popa() { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::add(Register Rd, Register Rn, RegisterOrConstant increment) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::sub(Register Rd, Register Rn, RegisterOrConstant decrement) { ++ ShouldNotReachHere(); ++} ++ ++// this simulates the behaviour of the x86 cmpxchg instruction using a ++// load linked/store conditional pair. we use the acquire/release ++// versions of these instructions so that we flush pending writes as ++// per Java semantics. ++ ++// n.b the x86 version assumes the old value to be compared against is ++// in rax and updates rax with the value located in memory if the ++// cmpxchg fails. we supply a register for the old value explicitly ++ ++// the sw64 load linked/store conditional instructions do not ++// accept an offset. so, unlike x86, we must provide a plain register ++// to identify the memory word to be compared/exchanged rather than a ++// register+offset Address. ++ ++void MacroAssembler::cmpxchgptr(Register oldv, Register newv, Register addr, Register tmp, ++ Label &succeed, Label *fail) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::cmpxchg_obj_header(Register oldv, Register newv, Register obj, Register tmp, ++ Label &succeed, Label *fail) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::cmpxchgw(Register oldv, Register newv, Register addr, Register tmp, ++ Label &succeed, Label *fail) { ++ ShouldNotReachHere(); ++} ++ ++#ifndef PRODUCT ++extern "C" void findpc(intptr_t x); ++#endif ++ ++void MacroAssembler::debug(char* msg) { ++ if ( ShowMessageBoxOnError ) { ++ JavaThreadState saved_state = JavaThread::current()->thread_state(); ++ JavaThread::current()->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(); ++ } ++ ++ } ++ 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::debug64(char* msg, int64_t pc, int64_t regs[]) ++{ ++ //::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); ++ if ( ShowMessageBoxOnError ) { ++ JavaThreadState saved_state = JavaThread::current()->thread_state(); ++ JavaThread::current()->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(); ++ } ++ ++ } ++ 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::push_call_clobbered_registers() { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::pop_call_clobbered_registers() { ++ ShouldNotReachHere(); ++} ++ ++Address MacroAssembler::spill_address(int size, int offset, Register tmp) ++{ ++ ShouldNotReachHere(); ++ Register base = sp; ++ return Address(base, offset); ++} ++ ++// Checks whether offset is aligned. ++// Returns true if it is, else false. ++bool MacroAssembler::merge_alignment_check(Register base, ++ size_t size, ++ long cur_offset, ++ long prev_offset) const { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++// Checks whether current and previous loads/stores can be merged. ++// Returns true if it can be merged, else false. ++bool MacroAssembler::ldst_can_merge(Register rt, ++ const Address &adr, ++ size_t cur_size_in_bytes, ++ bool is_store) const { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++// Merge current load/store with previous load/store into ldp/stp. ++void MacroAssembler::merge_ldst(Register rt, ++ const Address &adr, ++ size_t cur_size_in_bytes, ++ bool is_store) { ++ ShouldNotReachHere(); ++} ++ ++/** ++ * Emits code to update CRC-32 with a 32-bit value according to tables 0 to 3 ++ * ++ * @param [in,out]crc Register containing the crc. ++ * @param [in]v Register containing the 32-bit to fold into the CRC. ++ * @param [in]table0 Register containing table 0 of crc constants. ++ * @param [in]table1 Register containing table 1 of crc constants. ++ * @param [in]table2 Register containing table 2 of crc constants. ++ * @param [in]table3 Register containing table 3 of crc constants. ++ * ++ * uint32_t crc; ++ * v = crc ^ v ++ * crc = table3[v&0xff]^table2[(v>>8)&0xff]^table1[(v>>16)&0xff]^table0[v>>24] ++ * ++ */ ++void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp, ++ Register table0, Register table1, Register table2, Register table3, ++ bool upper) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::kernel_crc32_using_crc32(Register crc, Register buf, ++ Register len, Register tmp0, Register tmp1, Register tmp2, ++ Register tmp3) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::kernel_crc32c_using_crc32c(Register crc, Register buf, ++ Register len, Register tmp0, Register tmp1, Register tmp2, ++ Register tmp3) { ++ ShouldNotReachHere(); ++} ++ ++/** ++ * @param crc register containing existing CRC (32-bit) ++ * @param buf register pointing to input byte buffer (byte*) ++ * @param len register containing number of bytes ++ * @param table register that will contain address of CRC table ++ * @param tmp scratch register ++ */ ++void MacroAssembler::kernel_crc32c(Register crc, Register buf, Register len, ++ Register table0, Register table1, Register table2, Register table3, ++ Register tmp, Register tmp2, Register tmp3) { ++ kernel_crc32c_using_crc32c(crc, buf, len, table0, table1, table2, table3); ++} ++ ++void MacroAssembler::cmp_klass(Register oop, Register trial_klass, Register tmp) { ++ ShouldNotReachHere(); ++} ++ ++Address MacroAssembler::allocate_metadata_address(Metadata* obj) { ++ ShouldNotReachHere(); ++ int index = oop_recorder()->allocate_metadata_index(obj); ++ RelocationHolder rspec = metadata_Relocation::spec(index); ++ return Address(); ++} ++ ++Address MacroAssembler::constant_oop_address(jobject obj) { ++ ShouldNotReachHere(); ++ int oop_index = oop_recorder()->find_index(obj); ++ return Address(); ++} ++ ++// Move the address of the polling page into dest. ++void MacroAssembler::get_polling_page(Register dest, address page, relocInfo::relocType rtype) { ++ should_not_reach_here("get_polling_page"); ++} ++ ++// Move the address of the polling page into r, then read the polling ++// page. ++address MacroAssembler::read_polling_page(Register r, address page, relocInfo::relocType rtype) { ++ get_polling_page(r, page, rtype); ++ return read_polling_page(r, rtype); ++} ++ ++// Read the polling page. The address of the polling page must ++// already be in r. ++address MacroAssembler::read_polling_page(Register r, relocInfo::relocType rtype) { ++ should_not_reach_here("read_polling_page"); ++ return 0; ++} ++ ++void MacroAssembler::adrp(Register reg1, const Address &dest, unsigned long &byte_offset) { ++ should_not_reach_here("adrp"); ++} ++ ++void MacroAssembler::load_byte_map_base(Register reg) { ++ should_not_reach_here("load_byte_map_base"); ++} ++ ++void MacroAssembler::build_frame(int framesize) { ++ should_not_reach_here("build_frame"); ++} ++ ++void MacroAssembler::remove_frame(int framesize) { ++ should_not_reach_here("remove_frame"); ++} ++ ++typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); ++ ++typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); ++typedef void (MacroAssembler::* uxt_insn)(Register Rd, Register Rn); ++ ++// Compare Strings ++ ++// For Strings we're passed the address of the first characters in a1 ++// and a2 and the length in cnt1. ++// elem_size is the element size in bytes: either 1 or 2. ++// There are two implementations. For arrays >= 8 bytes, all ++// comparisons (including the final one, which may overlap) are ++// performed 8 bytes at a time. For strings < 8 bytes, we compare a ++// halfword, then a short, and then a byte. ++ ++void MacroAssembler::string_equals(Register a1, Register a2, ++ Register result, Register cnt1, int elem_size) ++{ ++ should_not_reach_here("string_equals"); ++} ++ ++ ++// The size of the blocks erased by the zero_blocks stub. We must ++// handle anything smaller than this ourselves in zero_words(). ++const int MacroAssembler::zero_words_block_size = 8; ++ ++// zero_words() is used by C2 ClearArray patterns. It is as small as ++// possible, handling small word counts locally and delegating ++// anything larger to the zero_blocks stub. It is expanded many times ++// in compiled code, so it is important to keep it short. ++ ++// ptr: Address of a buffer to be zeroed. ++// cnt: Count in HeapWords. ++// ++// ptr, cnt, rscratch1, and rscratch2 are clobbered. ++void MacroAssembler::zero_words(Register ptr, Register cnt) ++{ ++ should_not_reach_here("zero_words"); ++} ++ ++// base: Address of a buffer to be zeroed, 8 bytes aligned. ++// cnt: Immediate count in HeapWords. ++#define SmallArraySize (18 * BytesPerLong) ++void MacroAssembler::zero_words(Register base, u_int64_t cnt) ++{ ++ should_not_reach_here("zero_words"); ++} ++ ++////// Zero blocks of memory by using DC ZVA. ++////// ++////// Aligns the base address first sufficently for DC ZVA, then uses ++////// DC ZVA repeatedly for every full block. cnt is the size to be ++////// zeroed in HeapWords. Returns the count of words left to be zeroed ++////// in cnt. ++////// ++////// NOTE: This is intended to be used in the zero_blocks() stub. If ++////// you want to use it elsewhere, note that cnt must be >= 2*zva_length. ++////void MacroAssembler::zero_dcache_blocks(Register base, Register cnt) { ++//// Register tmp = rscratch1; ++//// Register tmp2 = rscratch2; ++//// int zva_length = VM_Version::zva_length(); ++//// Label initial_table_end, loop_zva; ++//// Label fini; ++//// ++//// // Base must be 16 byte aligned. If not just return and let caller handle it ++//// tst(base, 0x0f); ++//// br(Assembler::NE, fini); ++//// // Align base with ZVA length. ++//// neg(tmp, base); ++//// andr(tmp, tmp, zva_length - 1); ++//// ++//// // tmp: the number of bytes to be filled to align the base with ZVA length. ++//// add(base, base, tmp); ++//// sub(cnt, cnt, tmp, Assembler::ASR, 3); ++//// adr(tmp2, initial_table_end); ++//// sub(tmp2, tmp2, tmp, Assembler::LSR, 2); ++//// br(tmp2); ++//// ++//// for (int i = -zva_length + 16; i < 0; i += 16) ++//// stp(zr, zr, Address(base, i)); ++//// BIND(initial_table_end); ++//// ++//// sub(cnt, cnt, zva_length >> 3); ++//// BIND(loop_zva); ++//// dc(Assembler::ZVA, base); ++//// subs(cnt, cnt, zva_length >> 3); ++//// add(base, base, zva_length); ++//// br(Assembler::GE, loop_zva); ++//// add(cnt, cnt, zva_length >> 3); // count not zeroed by DC ZVA ++//// BIND(fini); ++////} ++ ++// base: Address of a buffer to be filled, 8 bytes aligned. ++// cnt: Count in 8-byte unit. ++// value: Value to be filled with. ++// base will point to the end of the buffer after filling. ++void MacroAssembler::fill_words(Register base, Register cnt, Register value) ++{ ++ should_not_reach_here("fill_words"); ++} ++ ++void MacroAssembler::safepoint_poll(Label& slow_path, Register thread_reg, Register temp_reg) {SCOPEMARK_NAME(safepoint_poll, this); ++ if (SafepointMechanism::uses_thread_local_poll()) { ++ assert(thread_reg == rthread, "should be"); ++ testb(Address(thread_reg, Thread::polling_page_offset()), SafepointMechanism::poll_bit(), temp_reg); ++ jcc(Assembler::notZero, slow_path, temp_reg); // handshake bit set implies poll ++ } else { ++ cmpw(ExternalAddress(SafepointSynchronize::address_of_state()), ++ SafepointSynchronize::_not_synchronized, temp_reg); ++ jcc(Assembler::notEqual, slow_path, temp_reg); ++ } ++} ++ ++// Just like safepoint_poll, but use an acquiring load for thread- ++// local polling. ++// ++// We need an acquire here to ensure that any subsequent load of the ++// global SafepointSynchronize::_state flag is ordered after this load ++// of the local Thread::_polling page. We don't want this poll to ++// return false (i.e. not safepointing) and a later poll of the global ++// SafepointSynchronize::_state spuriously to return true. ++// ++// This is to avoid a race when we're in a native->Java transition ++// racing the code which wakes up from a safepoint. ++// ++void MacroAssembler::safepoint_poll_acquire(Label& slow_path) { ++ should_not_reach_here("safepoint_poll_acquire"); ++} ++ ++void MacroAssembler::far_call(Address entry, CodeBuffer *cbuf, Register tmp) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) { ++ ShouldNotReachHere(); ++} ++ ++void MacroAssembler::jr(address entry) { ++ patchable_jump(entry); ++} ++ ++void MacroAssembler::jr(address entry, relocInfo::relocType rtype) { ++ switch (rtype) { ++ case relocInfo::runtime_call_type: ++ case relocInfo::none: ++ jr(entry); ++ break; ++ default: ++ { ++ InstructionMark im(this); ++ relocate(rtype); ++ patchable_jump(entry); ++ } ++ break; ++ } ++} ++ ++void MacroAssembler::patchable_jump(address target) { ++ if (reachable_from_cache(target)) { ++ nop(); ++ nop(); ++ nop(); ++ nop(); ++ beq_a(R0, target); ++ } else { ++ if (SafePatch) { ++ if (offset() % 8 == 0) { ++ nop(); ++ br(T12, 2); ++ emit_int64((long) target); ++ ldl(T12, 0, T12); ++ } else { ++ br(T12, 2); ++ emit_int64((long) target); ++ ldl(T12, 0, T12); ++ nop(); ++ } ++ } else { ++ prepare_patch_li48(T12, (long) target); ++ } ++ jmp(T12); ++ } ++} ++ ++void MacroAssembler::call_patch(address entry) { ++// c/c++ code assume T12 is entry point, so we just always move entry to t12 ++// maybe there is some more graceful method to handle this. FIXME ++// For more info, see class NativeCall. ++ patchable_call(entry); ++} ++ ++void MacroAssembler::call_patch(address entry, relocInfo::relocType rtype) { ++ switch (rtype) { ++// case relocInfo::runtime_call_type: ++// patchable_call_setfpec1(entry); ++// break; ++ case relocInfo::none: ++ call_patch(entry); ++ break; ++ default: ++ { ++ InstructionMark im(this); ++ relocate(rtype); ++ call_patch(entry); ++ } ++ break; ++ } ++} ++ ++void MacroAssembler::patchable_call(address target, Label *retAddr, Register tmp) { ++ if (reachable_from_cache(target)) { ++ nop(); ++ nop(); ++ nop(); ++ nop(); ++ bsr(RA, (int) (long) target); ++ } else { ++ if (SafePatch) { ++ if (offset() % 8 == 0) { ++ nop(); ++ br(T12, 2); ++ emit_int64((long) target); ++ ldl(T12, 0, T12); ++ } else { ++ br(T12, 2); ++ emit_int64((long) target); ++ ldl(T12, 0, T12); ++ nop(); ++ } ++ } else { ++ prepare_patch_li48(tmp, (long) target); ++ if (tmp != T12) { ++ movl(T12, tmp); ++ } ++ } ++ Assembler::call(RA, T12, 0); ++ if (retAddr) ++ bind(*retAddr); ++ if (UseSetfpec) ++ setfpec1(); ++ } ++} ++ ++//void MacroAssembler::patchable_call_setfpec1(address target) { ++// if (reachable_from_cache(target)) { ++// nop(); ++// nop(); ++// nop(); ++// nop(); ++// bsr(RA, (int)(long)target); ++// } else { ++//// movptr(T12, (long)target); ++// //jalr_setfpec1(T12); ++// jmp(T12, rscratch1); ++// } ++//} ++ ++// Maybe emit a call via a trampoline. If the code cache is small ++// trampolines won't be emitted. ++ ++address MacroAssembler::trampoline_call(Address entry, CodeBuffer *cbuf) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++ ++// Emit a trampoline stub for a call to a target which is too far away. ++// ++// code sequences: ++// ++// call-site: ++// branch-and-link to or ++// ++// Related trampoline stub for this call site in the stub section: ++// load the call target from the constant pool ++// branch (LR still points to the call site above) ++ ++address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, ++ address dest) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++void MacroAssembler::emit_static_call_stub() { ++ ShouldNotReachHere(); ++} ++ ++// These two are taken from x86, but they look generally useful ++ ++// scans count pointer sized words at [addr] for occurence of value, ++// generic ++void MacroAssembler::repne_scan(Register addr, Register value, Register count, ++ Register scratch) { ++ ShouldNotReachHere(); ++} ++ ++// scans count 4 byte words at [addr] for occurence of value, ++// generic ++void MacroAssembler::repne_scanw(Register addr, Register value, Register count, ++ Register scratch) { ++ ShouldNotReachHere(); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64.hpp afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64.hpp 2025-05-09 10:06:54.192292504 +0800 +@@ -0,0 +1,2166 @@ ++/* ++ * 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. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_MACROASSEMBLER_SW64_HPP ++#define CPU_SW64_VM_MACROASSEMBLER_SW64_HPP ++ ++#include "asm/assembler.hpp" ++#ifdef PRODUCT ++#define SCOPEMARK /* nothing */ ++#define SCOPEMARK_NAME(name, masm) /* nothing */ ++#else ++#define SCOPEMARK \ ++char line[200]; sprintf(line,"%s:%d",__FILE__, __LINE__);\ ++ScopeMark scopeMark(_masm, line); ++ ++#define SCOPEMARK2 \ ++char line[200]; sprintf(line,"%s:%d",__FILE__, __LINE__);\ ++ScopeMark scopeMark(this, line); ++ ++#define SCOPEMARK_NAME(name, masm) \ ++char line[200]; sprintf(line,"%s:%d",__FILE__, __LINE__);\ ++ScopeMark scopeMark(masm, line, #name); ++ ++#endif ++ ++// MacroAssembler extends Assembler by frequently used macros. ++// ++// Instructions for which a 'better' code sequence exists depending ++// on arguments should also go in here. ++ ++class MacroAssembler: public Assembler { ++ friend class LIR_Assembler; ++ ++ public: ++ using Assembler::offset; ++ ++ // 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( ++ address entry_point, // the entry point ++ int number_of_arguments // the number of arguments to pop after the call ++ ); ++ ++ //TODO:refactor use this edition to deal with label ++ virtual void call_VM_leaf_base( ++ address entry_point, // the entry point ++ int number_of_arguments, // the number of arguments to pop after the call ++ Label *retaddr, ++ Register rscratch = T12 ++ ); ++ ++ protected: ++ // 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). ++ // ++ // If no java_thread register is specified (noreg) than rthread will be used instead. call_VM_base ++ // returns the register which contains the thread upon return. If a thread register has been ++ // specified, the return value will correspond to that register. If no last_java_sp is specified ++ // (noreg) than rsp will be used instead. ++ virtual void call_VM_base( // returns the register containing the thread upon return ++ Register oop_result, // where an oop-result ends up if any; use noreg otherwise ++ Register java_thread, // 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 the call ++ bool check_exceptions // whether to check for pending exceptions after return ++ ); ++ ++ void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true); ++ ++ public: ++ MacroAssembler(CodeBuffer* code) : Assembler(code) {} ++ ++ // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code. ++ // The implementation is only non-empty for the InterpreterMacroAssembler, ++ // as only the interpreter handles PopFrame and ForceEarlyReturn requests. ++ virtual void check_and_handle_popframe(Register java_thread); ++ virtual void check_and_handle_earlyret(Register java_thread); ++ ++ //jzy ++ Address as_Address(ArrayAddress adr, Register base_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). ++ ++ virtual void null_check(Register reg, int offset = -1); ++ static bool needs_explicit_null_check(intptr_t offset); ++ ++ // Required platform-specific helpers for Label::patch_instructions. ++ // They _shadow_ the declarations in AbstractAssembler, which are undefined. ++ static int pd_patch_instruction_size(address branch, address target); ++ static void pd_patch_instruction_aarch(address branch, address target) { ++ pd_patch_instruction_size(branch, target); ++ } ++ static address pd_call_destination(address branch) { ++ ShouldNotReachHere(); ++ return 0; ++ } ++ int patched_branch(int dest_pos, int inst, int inst_pos); ++ void pd_patch_instruction(address branch, address target) { ++ jint& stub_inst = *(jint*) branch; ++ stub_inst = patched_branch(target - branch, stub_inst, 0); ++ } ++ ++#ifndef PRODUCT ++ static void pd_print_patched_instruction(address branch); ++#endif ++ ++ static int patch_oop(address insn_addr, address o); ++ static int patch_narrow_klass(address insn_addr, narrowKlass n); ++ ++ //void li64(Register rd, long imm); ++ //prepare target address for patcher(li48) ++ void prepare_patch_li48(Register rd, long imm); ++ ++ address emit_trampoline_stub(int insts_call_instruction_offset, address target); ++ void emit_static_call_stub(); ++ ++ void load_unsigned_byte(Register dst, Address src); ++ void load_unsigned_short(Register dst, Address src); ++ ++ void load_signed_byte32(Register rd, Address addr, Register tmp=rcc); ++ void load_signed_byte64(Register rd, Address addr, Register tmp=rcc); ++ void load_signed_short(Register rd, Address addr); ++ ++ // Support for sign-extension (hi:lo = extend_sign(lo)) ++ void extend_sign(Register hi, Register lo); ++ ++ // Load and store values by size and signed-ness ++ void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg); ++ void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg); ++ ++ // Support for inc/dec with optimal instruction selection depending on value ++ ++ // x86_64 aliases an unqualified register/address increment and ++ // decrement to call incrementq and decrementq but also supports ++ // explicitly sized calls to incrementq/decrementq or ++ // incrementl/decrementl ++ ++ // for sw64 the proper convention would be to use ++ // increment/decrement for 64 bit operatons and ++ // incrementw/decrementw for 32 bit operations. so when porting ++ // x86_64 code we can leave calls to increment/decrement as is, ++ // replace incrementq/decrementq with increment/decrement and ++ // replace incrementl/decrementl with incrementw/decrementw. ++ ++ // n.b. increment/decrement calls with an Address destination will ++ // need to use a scratch register to load the value to be ++ // incremented. increment/decrement calls which add or subtract a ++ // constant value greater than 2^12 will need to use a 2nd scratch ++ // register to hold the constant. so, a register increment/decrement ++ // may trash rscratch2 and an address increment/decrement trash ++ // rscratch and rscratch2 ++ ++ void decrement(Register reg, int value = 1){decrementl(reg, value);} ++ void increment(Register reg, int value = 1){incrementl(reg, value);} ++ ++ void decrementw(ExternalAddress dst, int value = 1, Register tmp1 = rscratch1, Register tmp2 = rscratch2); ++ void decrementw(Address dst, int value = 1, Register tmp = rcc); ++ void decrementw(Register reg, int value = 1); ++ ++ void decrementl(ExternalAddress dst, int value = 1, Register tmp1 = rscratch1, Register tmp2 = rscratch2); ++ void decrementl(Address dst, int value = 1, Register tmp = rcc); ++ void decrementl(Register reg, int value = 1); ++ ++ void incrementw(AddressLiteral dst, int value = 1, Register tmp1 = rscratch1, Register tmp2 = rscratch2); ++ void incrementw(Address dst, int value = 1, Register tmp_not_rcc=rscratch1); ++ void incrementw(Register reg, int value = 1); ++ ++ void incrementl(ExternalAddress dst, int value = 1, Register tmp1 = rscratch1, Register tmp2 = rscratch2); ++ void incrementl(Address dst, int value = 1, Register tmp = rcc); ++ void incrementl(Register reg, int value = 1); ++ ++ ++ // Alignment ++ void align(int modulus); ++ ++ // Stack frame creation/removal ++ void enter(); ++ void leave(); ++ ++ // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information) ++ // The pointer will be loaded into the thread register. ++ void get_thread(Register thread); ++ ++ ++ // Support for VM calls ++ // ++ // 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. ++ ++ ++ void call_VM(Register oop_result, ++ address entry_point, ++ 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); ++ ++ // Overloadings with last_Java_sp ++ 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 get_vm_result (Register oop_result, Register thread); ++ void get_vm_result_2(Register metadata_result, Register thread); ++ ++// // These always tightly bind to MacroAssembler::call_VM_base ++// // bypassing the virtual implementation ++// void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true); ++// void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true); ++// void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true); ++// void super_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 super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4, bool check_exceptions = true); ++ ++ void call_VM_leaf0(address entry_point); ++ void call_VM_leaf(address entry_point, ++ int number_of_arguments = 0); ++ void call_VM_leaf(address entry_point, ++ Register arg_1); ++ void call_VM_leaf(address entry_point, ++ Register arg_1, Register arg_2); ++ void call_VM_leaf(address entry_point, ++ Register arg_1, Register arg_2, Register arg_3); ++ ++ // These always tightly bind to MacroAssembler::call_VM_leaf_base ++ // bypassing the virtual implementation ++ void super_call_VM_leaf(address entry_point); ++ void super_call_VM_leaf(address entry_point, Register arg_1); ++ void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2); ++ void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3); ++ void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4); ++ ++ // last Java Frame (fills frame anchor) ++// void set_last_Java_frame(Register thread, ++// Register last_java_sp, ++// Register last_java_fp, ++// address last_java_pc); ++ ++ // thread in the default location ++// void set_last_Java_frame(Register last_java_sp, ++// Register last_java_fp, ++// address last_java_pc); ++ ++ void set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ address last_java_pc, ++ Register scratch); ++ ++ void set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ Label &last_java_pc, ++ Register scratch, Register scratch2=rscratch2_AT); ++ ++ /*void set_last_Java_frame(Register last_java_sp, ++ Register last_java_fp, ++ Register last_java_pc, ++ Register scratch);*/ ++ ++ void reset_last_Java_frame(Register thread, bool clear_fp); ++ ++//// void reset_last_Java_frame(Register thread); ++ ++ // thread in the default location (rthread) ++ void reset_last_Java_frame(bool clear_fp); ++ ++ // Stores ++//// void store_check(Register obj); // store check for obj - register is destroyed afterwards ++//// void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) ++ ++ void resolve_jobject(Register value, Register thread, Register tmp); ++ ++ // C 'boolean' to Java boolean: x == 0 ? 0 : 1 ++ void c2bool(Register x); ++ ++ // oop manipulations ++ void load_klass(Register dst, Register src); ++ void store_klass(Register dst, Register src); ++ ++ void access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src, ++ Register tmp1, Register tmp_thread); ++ ++ void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src, ++ Register tmp1, Register tmp_thread); ++ ++ void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, ++ Register thread_tmp = noreg, DecoratorSet decorators = 0); ++ void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, ++ Register thread_tmp = noreg, DecoratorSet decorators = 0); ++ void store_heap_oop(Address dst, Register src, Register tmp1 = noreg, ++ Register tmp_thread = noreg, DecoratorSet decorators = 0); ++ ++ // currently unimplemented ++ // Used for storing NULL. All other oop constants should be ++ // stored using routines that take a jobject. ++ void store_heap_oop_null(Address dst); ++ ++ void load_prototype_header(Register dst, Register src); ++ ++ void store_klass_gap(Register dst, Register src); ++ ++ // This dummy is to prevent a call to store_heap_oop from ++ // converting a zero (like NULL) into a Register by giving ++ // the compiler two choices it can't resolve ++ ++//// void store_heap_oop(Address dst, void* dummy); ++ ++ void encode_heap_oop(Register dst, Register src); ++ void encode_heap_oop(Register r) { encode_heap_oop(r, r); } ++ void decode_heap_oop(Register dst, Register src); ++ 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 dst, Register src); ++ void decode_heap_oop_not_null(Register dst, Register src); ++ ++ void emit_data(RelocationHolder const& rspec, int format); ++ void mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec); ++ ++ void set_narrow_oop(Register dst, jobject obj); ++ void set_narrow_oop(Address dst, jobject obj); ++ void cmp_narrow_oop(Register dst, jobject obj, Register ccReg=rcc); ++ void cmp_narrow_oop(Address dst, jobject obj, Register ccReg=rcc); ++ ++ void encode_klass_not_null(Register r); ++ void decode_klass_not_null(Register r); ++ void encode_klass_not_null(Register dst, Register src); ++ void decode_klass_not_null(Register dst, Register src); ++ void set_narrow_klass(Register dst, Klass* k); ++ void set_narrow_klass(Address dst, Klass* k); ++ void cmp_narrow_klass(Register dst, Klass* k, Register ccReg=rcc); ++ void cmp_narrow_klass(Address dst, Klass* k, Register ccReg=rcc); ++ ++ // if heap base register is used - reinit it with the correct value ++ void reinit_heapbase(); ++ ++ DEBUG_ONLY(void verify_heapbase(const char* msg);) ++ ++ void push_CPU_state(bool save_vectors = false); ++ void pop_CPU_state(bool restore_vectors = false) ; ++ ++ // Round up to a power of two ++ void round_to(Register reg, int modulus); ++ ++ // allocation ++ void eden_allocate( ++ Register thread, // Current thread ++ 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 tlab_allocate( ++ Register thread, // Current thread ++ 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 zero_memory(Register addr, Register len, Register t1); ++ ++ // interface method calling ++ void lookup_interface_method(Register recv_klass, ++ Register intf_klass, ++ RegisterOrConstant itable_index, ++ Register method_result, ++ Register scan_temp, ++ Label& no_such_interface, ++ bool return_method = true); ++ ++ // virtual method calling ++ // n.b. x86 allows RegisterOrConstant for vtable_index ++ 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. ++ void check_klass_subtype_fast_path(Register sub_klass, ++ Register super_klass, ++ Register temp_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 and temp2_reg can be noreg, if no temps are available. ++ // Updates the sub's secondary super cache as necessary. ++ // If set_cond_codes, condition codes will be Z on success, NZ on failure. ++ void check_klass_subtype_slow_path(Register sub_klass, ++ Register super_klass, ++ Register temp_reg, ++ Register temp2_reg, ++ Label* L_success, ++ Label* L_failure, ++ bool set_cond_codes = false); ++ ++ // Simplified, combined version, good for typical uses. ++ // Falls through on failure. ++ void check_klass_subtype(Register sub_klass, ++ Register super_klass, ++ Register temp_reg, ++ Label& L_success); ++ ++ Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0); ++ ++ ++ // Debugging ++ ++ // only if +VerifyOops ++ void verify_oop(Register reg, const char* s = "broken oop"); ++ void verify_oop_addr(Address addr, const char * s = "broken oop addr"); ++ ++// 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_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__) ++ ++ // only if +VerifyFPU ++ void verify_FPU(int stack_depth, const char* s = "illegal FPU state"); ++ ++ // prints msg, dumps registers and stops execution ++ void stop(const char* msg); ++ //use for sw debug, need to refactor, like int3 in x86 platform jzy ++ void debug_stop(const char* msg); ++ ++ void int3() { ++ call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint))); ++ } ++// // prints msg and continues ++ void warn(const char* msg); ++ ++ static void debug(char* msg); ++ static void debug64(char* msg, int64_t pc, int64_t regs[]); ++ ++// void untested() { stop("untested"); } ++// ++ void unimplemented(const char* what = ""); ++ ++ void should_not_reach_here(const char* what="should_not_reach_here") { stop(what); } ++ ++ // Stack overflow checking ++ void bang_stack_with_offset(int offset) { ++ // stack grows down, caller passes positive offset ++ assert(offset > 0, "must bang with negative offset"); ++ if (offset <= 32768) { ++ stw(R0, -offset, esp); ++ } else { ++ mov_immediate64(rscratch2, offset); ++ subl(esp, rscratch2, rscratch2); ++ stw(R0, 0, rscratch2); ++ } ++ } ++ ++ // Writes to stack successive pages until offset reached to check for ++ // stack overflow + shadow pages. Also, clobbers tmp ++ void bang_stack_size(Register size, Register tmp); ++ ++ // 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); ++ ++ // Support for serializing memory accesses between threads ++ void serialize_memory(Register thread, Register tmp); ++ ++ void safepoint_poll(Label& slow_path, Register thread_reg, Register temp_reg); ++ void safepoint_poll_acquire(Label& slow_path); ++ ++ void verify_tlab(); ++ ++ // Biased locking support ++ // lock_reg and obj_reg must be loaded up with the appropriate values. ++ // swap_reg is killed. ++ // tmp_reg must be supplied and must not be rscratch1 or rscratch2 ++ // Optional slow case is for implementations (interpreter and C1) which branch to ++ // slow case directly. Leaves condition codes set for C2's Fast_Lock node. ++ // Returns offset of first potentially-faulting instruction for null ++ // check info (currently consumed only by C1). If ++ // swap_reg_contains_mark is true then returns -1 as it is assumed ++ // the calling code has already passed any potential faults. ++ int biased_locking_enter(Register lock_reg, Register obj_reg, ++ Register swap_reg, Register tmp_reg, ++ bool swap_reg_contains_mark, ++ Label& done, Label* slow_case = NULL, ++ BiasedLockingCounters* counters = NULL); ++ void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done); ++ #ifdef COMPILER2 ++ void atomic_incw(AddressLiteral counter_addr, int inc, Register tmp_reg1); ++ // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. ++ // See full desription in macroAssembler_x86.cpp. ++ void fast_lock(Register obj, Register box, Register tmp, ++ Register scr, Register cx1, Register cx2, ++ BiasedLockingCounters* counters, ++ Metadata* method_data, ++ bool use_rtm, bool profile_rtm); ++ void fast_unlock(Register obj, Register box, Register tmp, bool use_rtm); ++#endif ++ // Fill primitive arrays ++ void generate_fill(BasicType t, bool aligned, ++ Register to, Register value, Register count, ++ Register rtmp); ++ ++// gpr load store instructions ++ ++#define LDINSNLIST(FUNC) \ ++ FUNC(ldbu)\ ++ FUNC(ldhu)\ ++ FUNC(ldw)\ ++ FUNC(ldl)\ ++ FUNC(ldl_u)\ ++ FUNC(ldi) ++ ++#define LDFROMADDR_DEC(LDX) \ ++ using Assembler::LDX; \ ++ void LDX(Register ra, Address addr); ++ ++ LDINSNLIST(LDFROMADDR_DEC) ++ ++#undef LDFROMADDR_DEC ++ ++#define STINSNLIST(FUNC) \ ++ FUNC(stb)\ ++ FUNC(sth)\ ++ FUNC(stw)\ ++ FUNC(stl)\ ++ FUNC(stl_u) ++ ++#define ST2ADDR_DEC(STX) \ ++ using Assembler::STX; \ ++ void STX(Register ra, Address addr, Register tmp=rcc); ++ ++ STINSNLIST(ST2ADDR_DEC) ++ ++#undef ST2ADDR_DEC ++ ++ void stw(int, Address, Register tmp = rcc); ++ void stptr(Register rd, Address addr, Register tmp=rcc); ++ void ldhu_unaligned(Register rd, Address addr, Register tmp=rcc); ++ void ldhu_unaligned_be(Register rd, Address addr, Register tmp=rcc); ++ void ldwu(Register rd, Address addr); ++ void ldws(Register rd, Address addr); ++ void ldwu(Register rd, AddressLiteral addr); ++ void ldws(Register rd, AddressLiteral addr); ++ void ldptr(Register rd, Address addr, Register tmp=rcc); ++ void ldptr(Register rd, AddressLiteral addr); ++ ++ ++// float register load store instructions ++ ++#define FLOATINSNLIST(FUNC) \ ++ FUNC(flds)\ ++ FUNC(fldd)\ ++ FUNC(fsts)\ ++ FUNC(fstd) ++ ++#define ADDR_DEC(FLOATINSN) \ ++ using Assembler::FLOATINSN; \ ++ void FLOATINSN(FloatRegister ra, Address addr, Register tmp=rcc); ++ ++ FLOATINSNLIST(ADDR_DEC) ++ ++#undef ADDR_DEC ++ ++ void load_float(FloatRegister ra, Address src, Register tmp=rcc); ++ void load_float(FloatRegister rd, AddressLiteral addr, Register tmp=rcc); ++ void load_double(FloatRegister ra, Address src, Register tmp=rcc); ++ void load_double(FloatRegister rd, AddressLiteral addr, Register tmp=rcc); ++ void store_float(FloatRegister ra, Address src, Register tmp=rcc); ++ void store_double(FloatRegister ra, Address src, Register tmp=rcc); ++ ++ void lea(Register rd, Address src); ++ void lea(Register rd, AddressLiteral addr); ++ void lea(Address dst, AddressLiteral adr, Register tmp_not_rcc); ++ ++// arithmathic instrunctions ++ ++/** ++ * x86 ++ * Assembler::andl/orl/xorl(Register dst, int32_t imm32) ++ * sw64 ++ * MacroAssembler::andw/orw/xorw(Register lh, int rh, Register res, Register scratch=rcc) ++ * note ++ * we will clear the msb32 of res, so the msb32 of lh is no matter. ++ */ ++#define LOGICINSNLIST(FUNC) \ ++ FUNC(andw, and_ins)\ ++ FUNC(orw, bis)\ ++ FUNC(xorw, xor_ins) ++ ++#define ARITHINSNLIST(FUNC) \ ++ FUNC(addwu, addw)\ ++ FUNC(subwu, subw)\ ++ FUNC(mulwu, mulw) ++ ++ /* I introduce scratch reg in NAMEw since it's possible that lh and res could be the same reg */ ++#define EXPAND_W(NAME, INSN) \ ++ void NAME(Register lh, int rh, Register res, Register scratch=rcc){\ ++ assert_different_registers(lh, scratch);\ ++ if (rh >=0 && rh < (1<<8)) {\ ++ INSN(lh, rh, res);\ ++ }\ ++ else if (rh >=0 && rh < (1<<15)) {\ ++ ldi(scratch, rh, R0);\ ++ INSN(lh, scratch, res);\ ++ } else {\ ++ mov_immediate32(scratch, rh);\ ++ INSN(lh, scratch, res);\ ++ } \ ++ }\ ++ void NAME(Register lh, Register rh, Register res){INSN(lh, rh, res); zapnot(res, 0xf, res); } ++ ++ LOGICINSNLIST(EXPAND_W) ++ ARITHINSNLIST(EXPAND_W) ++ ++#undef EXPAND_W ++ ++#undef LOGICINSNLIST ++#undef ARITHINSNLIST ++ ++ ++#define LOGICINSNLIST(FUNC) \ ++ FUNC(andptr, and_ins)\ ++ FUNC(orptr, bis)\ ++ FUNC(xorptr, xor_ins) ++ ++#define ARITHINSNLIST(FUNC) \ ++ FUNC(addptr, addl)\ ++ FUNC(subptr, subl) ++ ++ /* I introduce scratch reg in NAMEptr since it's possible that lh and res could be the same reg */ ++#define EXPAND_PTR(NAME, INSN) \ ++ void NAME(Register lh, long rh, Register res, Register scratch=rcc){\ ++ assert_different_registers(lh, scratch);\ ++ if (rh >=0 && rh < (1<<8))\ ++ INSN(lh, rh, res);\ ++ else if (rh >=0 && rh < (1<<15)) {\ ++ ldi(scratch, rh, R0);\ ++ INSN(lh, scratch, res);\ ++ } else {\ ++ mov_immediate64(scratch, rh);\ ++ INSN(lh, scratch, res);\ ++ }\ ++ }\ ++ void NAME(Register lh, Register rh, Register res){INSN(lh, rh, res);} ++ ++ LOGICINSNLIST(EXPAND_PTR) ++ ARITHINSNLIST(EXPAND_PTR) ++ ++#undef EXPAND_PTR ++ ++ void notl (Register res) { ornot(R0, res, res); } ++ void notptr(Register res) { notl(res); } ++ void addptr(Register rd, Address addr); ++ void notw(Register rd, Register rs); ++ void negptr(Register rs) { subl(R0, rs, rs); } ++ ++// compare instructions ++ ++ void cmpoop(Register lh, Register rh, Register ccReg=rcc); ++ ++ void cmpb(Register lh, int rh, Register ccReg=rcc); ++ void cmpb(Address addr, int imm8, Register ccReg=rcc); ++ void cmpb(AddressLiteral src1, int imm8, Register ccReg=rcc); ++ ++ void cmph(Address addr, int imm16, Register ccReg=rcc); ++ ++ void cmpw(Register lh, int rh, Register ccReg=rcc); ++ void cmpw(Register lh, Register rh, Register ccReg=rcc); ++ void cmpw(Register lh, Address rh, Register ccReg=rcc); ++ void cmpw(Address lh, Register rh, Register ccReg=rcc); ++ void cmpw(Address lh, int32_t imm, Register ccReg=rcc, Register tmp=rscratch1); ++ void cmpw(AddressLiteral src1, int32_t imm, Register ccReg=rcc, Register tmp=rscratch1); ++ void cmpw(AddressLiteral src1, Register rh, Register ccReg=rcc); ++ void cmpwu(Register lh, Address rh, Register ccReg=rcc); ++ void cmpws(int cc, Register op1, Register op2, Register ccReg=rcc); ++ void cmpls(int cc, Register op1, Register op2, Register ccReg=rcc); ++ void cmpwu(int cc, Register op1, Register op2, Register ccReg=rcc); ++ void cmplu(int cc, Register op1, Register op2, Register ccReg=rcc); ++ void cmpfs(int cc, FloatRegister op1, FloatRegister op2, FloatRegister ccReg=FcmpRES, bool is_order = false); ++ void cmpfd(int cc, FloatRegister op1, FloatRegister op2, FloatRegister ccReg=FcmpRES, bool is_order = false); ++ void cmpfcc(int cc, FloatRegister op1, FloatRegister op2); ++ void cmpdcc(int cc, FloatRegister op1, FloatRegister op2); ++ ++ void cmpl(Register lh, int rh, Register ccReg=rcc); ++ void cmpl(Register lh, Register rh, Register ccReg=rcc); ++ void cmpl_raw(Register lh, Register rh, Register ccReg=rcc); ++ void cmpq(Register lh, Register rh, Register ccReg=rcc); ++ void cmpUL(Register lh, Register rh, Register ccReg); ++ ++ address cmp_insn_mark = NULL; ++ Register cmp_lh ; ++ Register cmp_rh; ++ bool cmp_long; ++ void set_cmp_insn_mark(Register lh, Register rh, bool lcmp=false); ++ void clear_cmp_insn_mark(); ++ bool cmp_insn_marked(); ++ void jccb(Condition cc, Label& L); ++ ++ void cmpptr(Register lh, int rh, Register ccReg=rcc); ++ void cmpptr(Register lh, Register rh, Register ccReg=rcc); ++ void cmpptr(Register lh, Address rh, Register ccReg=rcc); ++ void cmpptr(Address lh, Register rh, Register ccReg=rcc); ++ void cmpptr(Address lh, int32_t rh, Register ccReg=rcc); ++ void cmpptr(Register lh, AddressLiteral rh, Register ccReg=rcc); ++ ++ void cmpxchgptr(Register xreg, AddressLiteral adr, Register creg, Register tmp); ++ ++ void jump(AddressLiteral addr, Register tmp=AT); //scw tmp=T12 ++ void jump(RuntimeAddress addr, Register tmp=AT); //scw tmp=T12 ++ void jump(ArrayAddress entry, Register tmp1, Register tmp2); ++ void jump_cc(Condition cc, AddressLiteral dst, Register ccReg=rcc, Register tmp=rscratch1); ++ ++ void call(Register entry, Label *retAddr = NULL); ++ void call(Register entry, address& retAddr); ++ void call(AddressLiteral addr, Label *retAddr = NULL, Register tmp=T12); //scw tmp=T12 ++ void call(RuntimeAddress addr, Label *retAddr = NULL, Register tmp=T12); //scw tmp=T12 ++ ++ void jmp(Label& lbl); ++ void jmp(Address rd, Register tmp=AT); ++ void jmp(Register rd, Register tmp=AT); ++ ++ void jcc(Condition cc, Label& L, Register ccReg=rcc, ConditionLength cl = bitl); ++// void jccb(Condition cc, Label& L, Register ccReg=rcc); ++ ++ // Helper functions for statistics gathering. ++ // Unconditional atomic increment. ++ void atomic_incw(Register counter_addr, Register tmp, Register tmp2); ++ ++ void testb(Address addr, int imm8, Register ccReg=rcc); ++ void testb(Register lh, int rh, Register res=rcc); ++ void testb(Register lh, Register rh, Register res=rcc); ++ void testw(Register lh, int rh, Register res=rcc, Register scratch=rcc); ++ void testw(Register lh, Register rh, Register res=rcc); ++ void testl(Register lh, long rh, Register res=rcc, Register scratch=rcc); ++ void testl(Register lh, Register rh, Register ccReg=rcc); ++ void testptr(Register lh, long rh, Register res=rcc, Register scratch=rcc); ++ void testptr(Register lh, Register rh, Register ccReg=rcc); ++ ++ void inline fmovs(FloatRegister dst, FloatRegister src) { ++ fcpys(src, src, dst); ++ } ++ void inline fmovd(FloatRegister dst, FloatRegister src) { ++ fcpys(src, src, dst); ++ } ++ ++ // swap the two byte of the low 16-bit halfword ++ // this directive will use AT, be sure the high 16-bit of reg is zero ++ void hswap(Register reg); ++ void huswap(Register reg); ++ ++ // convert big endian integer to little endian integer ++ void swap(Register reg); ++ void bswapw(Register reg); ++ ++ /** ++ * if c_reg == *dest then *dest <= x_reg, ++ * else c_reg <= *dest. ++ * The AT indicate if xchg occurred, 1 for xchged, else 0 ++ * @param x_reg ++ * @param dest ++ * @param c_reg ++ */ ++ void cmpxchg(Register x_reg, Address dest, Register c_reg); ++ void cmpxchg32(Register x_reg, Address dest, Register c_reg); ++ void fill_to_size(address start, int size); ++ ++ /** ++ * if oldval == *dest then *dest <= newval ++ * @param oldval ++ * @param dest ++ * @param newval ++ */ ++ void storeLcon(Register oldval, Address dest, Register newval); ++ void storeIcon(Register oldval, Address dest, Register newval); ++ void boundary_test(FloatRegister ft, Register res); ++ ++ // test if x is within signed immediate range for nbits ++ static bool is_uimm(intptr_t x, int nbits) { return intptr_t(0) <= x && x < ( intptr_t(1) << nbits ); } ++ // test if 0 <= x <= 255 ++ static bool is_uimm8(intptr_t x) { return is_uimm(x, 8); } ++ ++ // Various forms of CAS ++ ++ void cmpxchg_obj_header(Register oldv, Register newv, Register obj, Register tmp, ++ Label &suceed, Label *fail); ++ void cmpxchgptr(Register oldv, Register newv, Register addr, Register tmp, ++ Label &suceed, Label *fail); ++ ++ void cmpxchgw(Register oldv, Register newv, Register addr, Register tmp, ++ Label &suceed, Label *fail); ++ ++ void atomic_add(Register prev, RegisterOrConstant incr, Register addr); ++ void atomic_addw(Register prev, RegisterOrConstant incr, Register addr); ++ void atomic_addal(Register prev, RegisterOrConstant incr, Register addr); ++ void atomic_addalw(Register prev, RegisterOrConstant incr, Register addr); ++ ++ void atomic_xchg(Register prev, Register newv, Register addr); ++ void atomic_xchgw(Register prev, Register newv, Register addr); ++ void atomic_xchgal(Register prev, Register newv, Register addr); ++ void atomic_xchgalw(Register prev, Register newv, Register addr); ++ ++public: ++ // Calls ++ ++ address trampoline_call(Address entry, CodeBuffer *cbuf = NULL); ++ ++ static bool far_branches() { ++ ShouldNotReachHere(); ++ return 0; ++ } ++ ++ // Jumps that can reach anywhere in the code cache. ++ // Trashes tmp. ++ void far_call(Address entry, CodeBuffer *cbuf = NULL, Register tmp = rscratch1); ++ void far_jump(Address entry, CodeBuffer *cbuf = NULL, Register tmp = rscratch1); ++ ++ static int far_branch_size() { ++ ShouldNotReachHere(); ++ return 0; ++ } ++ ++ // Emit the CompiledIC call idiom ++ void ic_call(address entry, jint method_index = 0); ++ ++public: ++ ++ // Data ++ ++ // dst = src1 if rcc match cc, else dst = src2 ++ void cmove(Condition cc, Register dst, Register src1, Register src2, Register ccReg=rcc); ++ ++ void mov_metadata(Register dst, Metadata* obj); ++ Address allocate_metadata_address(Metadata* obj); ++ Address constant_oop_address(jobject obj); ++ ++ void movoop(Register dst, jobject obj, bool immediate = false); ++ ++ // CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic. ++ void kernel_crc32(Register crc, Register buf, Register len, ++ Register table0, Register table1, Register table2, Register table3, ++ Register tmp, Register tmp2, Register tmp3); ++ // CRC32 code for java.util.zip.CRC32C::updateBytes() instrinsic. ++ void kernel_crc32c(Register crc, Register buf, Register len, ++ Register table0, Register table1, Register table2, Register table3, ++ Register tmp, Register tmp2, Register tmp3); ++ ++ // Stack push and pop individual 64 bit registers ++ void push(Register src); ++ void push(int32_t imm32); ++ void pop(Register dst); ++ void push2(Register reg1, Register reg2); ++ void push (FloatRegister reg) { subl(esp, 8, esp); fstd(reg, 0, esp); } ++ void pop (FloatRegister reg) { if(UseSW8A) {fldd_a(reg, 8, esp);} else {fldd(reg, 0, esp); addl(esp, 8, esp); }} ++ ++ // push all registers onto the stack ++ void pusha(); ++ void popa(); ++ ++ void pushptr(Address src, Register tmp = rcc) { ldptr(rcc, src); push(rcc);} ++ void repne_scan(Register addr, Register value, Register count, ++ Register scratch); ++ void repne_scanw(Register addr, Register value, Register count, ++ Register scratch); ++ ++ void add(Register Rd, Register Rn, RegisterOrConstant increment); ++ void sub(Register Rd, Register Rn, RegisterOrConstant decrement); ++ ++ void adrp(Register reg1, const Address &dest, unsigned long &byte_offset); ++ ++ void tableswitch(Register index, jint lowbound, jint highbound, ++ Label &jumptable, Label &jumptable_end, int stride = 1) { ++ ShouldNotReachHere(); ++ } ++ ++ // Form an address from base + offset in Rd. Rd may or may not ++ // actually be used: you must use the Address that is returned. It ++ // is up to you to ensure that the shift provided matches the size ++ // of your data. ++ Address form_address(Register Rd, Register base, long byte_offset, int shift); ++ ++ // Return true iff an address is within the 48-bit Sw64 address ++ // space. ++ bool is_valid_Sw64_address(address a) { ++ return ((uint64_t)a >> 48) == 0; ++ } ++ ++ // Load the base of the cardtable byte map into reg. ++ void load_byte_map_base(Register reg); ++ ++ // Prolog generator routines to support switch between x86 code and ++ // generated ARM code ++ ++ // routine to generate an x86 prolog for a stub function which ++ // bootstraps into the generated ARM code which directly follows the ++ // stub ++ // ++ ++public: ++ ++ address read_polling_page(Register r, address page, relocInfo::relocType rtype); ++ address read_polling_page(Register r, relocInfo::relocType rtype); ++ void get_polling_page(Register dest, address page, relocInfo::relocType rtype); ++ ++ // CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic. ++ void update_byte_crc32(Register crc, Register val, Register table); ++ void update_word_crc32(Register crc, Register v, Register tmp, ++ Register table0, Register table1, Register table2, Register table3, ++ bool upper = false); ++ ++ void string_compare(Register str1, Register str2, ++ Register cnt1, Register cnt2, Register result, ++ Register tmp1, Register tmp2, FloatRegister vtmp1, ++ FloatRegister vtmp2, FloatRegister vtmp3, int ae); ++ ++ void has_negatives(Register ary1, Register len, Register result); ++ ++ void arrays_equals(Register a1, Register a2, Register result, Register cnt1, ++ Register tmp1, Register tmp2, Register tmp3, int elem_size); ++ ++ void string_equals(Register a1, Register a2, Register result, Register cnt1, ++ int elem_size); ++ ++ void fill_words(Register base, Register cnt, Register value); ++ void zero_words(Register base, u_int64_t cnt); ++ void zero_words(Register ptr, Register cnt); ++//// void zero_dcache_blocks(Register base, Register cnt); ++ ++ static const int zero_words_block_size; ++ ++ void byte_array_inflate(Register src, Register dst, Register len, ++ FloatRegister vtmp1, FloatRegister vtmp2, ++ FloatRegister vtmp3, Register tmp4); ++ ++ void char_array_compress(Register src, Register dst, Register len, ++ FloatRegister tmp1Reg, FloatRegister tmp2Reg, ++ FloatRegister tmp3Reg, FloatRegister tmp4Reg, ++ Register result); ++ ++ void encode_iso_array(Register src, Register dst, ++ Register len, Register result, ++ FloatRegister Vtmp1, FloatRegister Vtmp2, ++ FloatRegister Vtmp3, FloatRegister Vtmp4); ++ void string_indexof(Register str1, Register str2, ++ Register cnt1, Register cnt2, ++ Register tmp1, Register tmp2, ++ Register tmp3, Register tmp4, ++ Register tmp5, Register tmp6, ++ int int_cnt1, Register result, int ae); ++ void string_indexof_char(Register str1, Register cnt1, ++ Register ch, Register result, ++ Register tmp1, Register tmp2, Register tmp3); ++ void fast_log(FloatRegister vtmp0, FloatRegister vtmp1, FloatRegister vtmp2, ++ FloatRegister vtmp3, FloatRegister vtmp4, FloatRegister vtmp5, ++ FloatRegister tmpC1, FloatRegister tmpC2, FloatRegister tmpC3, ++ FloatRegister tmpC4, Register tmp1, Register tmp2, ++ Register tmp3, Register tmp4, Register tmp5); ++ void generate_dsin_dcos(bool isCos, address npio2_hw, address two_over_pi, ++ address pio2, address dsin_coef, address dcos_coef); ++ private: ++ // begin trigonometric functions support block ++ void generate__ieee754_rem_pio2(address npio2_hw, address two_over_pi, address pio2); ++ void generate__kernel_rem_pio2(address two_over_pi, address pio2); ++ void generate_kernel_sin(FloatRegister x, bool iyIsOne, address dsin_coef); ++ void generate_kernel_cos(FloatRegister x, address dcos_coef); ++ // end trigonometric functions support block ++ void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, ++ Register src1, Register src2); ++ void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2) { ++ add2_with_carry(dest_hi, dest_hi, dest_lo, src1, src2); ++ } ++ void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, ++ Register y, Register y_idx, Register z, ++ Register carry, Register product, ++ Register idx, Register kdx); ++ void multiply_128_x_128_loop(Register y, Register z, ++ Register carry, Register carry2, ++ Register idx, Register jdx, ++ Register yz_idx1, Register yz_idx2, ++ Register tmp, Register tmp3, Register tmp4, ++ Register tmp7, Register product_hi); ++ void kernel_crc32_using_crc32(Register crc, Register buf, ++ Register len, Register tmp0, Register tmp1, Register tmp2, ++ Register tmp3); ++ void kernel_crc32c_using_crc32c(Register crc, Register buf, ++ Register len, Register tmp0, Register tmp1, Register tmp2, ++ Register tmp3); ++public: ++ void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, ++ Register zlen, Register tmp1, Register tmp2, Register tmp3, ++ Register tmp4, Register tmp5, Register tmp6, Register tmp7); ++ void mul_add(Register out, Register in, Register offs, Register len, Register k); ++ // ISB may be needed because of a safepoint ++ void maybe_isb() { ShouldNotReachHere();} ++ ++private: ++ // Returns an address on the stack which is reachable with a ldr/str of size ++ // Uses rscratch2 if the address is not directly reachable ++ Address spill_address(int size, int offset, Register tmp=rscratch2); ++ ++ bool merge_alignment_check(Register base, size_t size, long cur_offset, long prev_offset) const; ++ ++ // Check whether two loads/stores can be merged into ldp/stp. ++ bool ldst_can_merge(Register rx, const Address &adr, size_t cur_size_in_bytes, bool is_store) const; ++ ++ // Merge current load/store with previous load/store into ldp/stp. ++ void merge_ldst(Register rx, const Address &adr, size_t cur_size_in_bytes, bool is_store); ++ ++ // Try to merge two loads/stores into ldp/stp. If success, returns true else false. ++ bool try_merge_ldst(Register rt, const Address &adr, size_t cur_size_in_bytes, bool is_store); ++ ++public: ++ ++ // True if an XOR can be used to expand narrow klass references. ++ bool use_XOR_for_compressed_class_base; ++ ++ ++// void andw(Register lh, int rh, Register res, Register scratch=rcc); ++// void andw(Register lh, Register rh, Register res); ++// void andptr(Register lh, long rh, Register res, Register scratch=rcc); ++// void andptr(Register lh, Register rh, Register res); ++ ++ ++ void addiu32(Register rs, int imm, Register rt, Register cc = GP) { ++ if (imm >= 0 && is_uimm8(imm)) { ++ addw(rs, imm, rt); ++ } else if (imm < 0 && is_uimm8(-imm)) { ++ subw(rs, -imm, rt); ++ } else { ++ ldi(cc, imm, R0); ++ addw(rs, cc, rt); ++ } ++ } ++ ++ void addiu(Register rs, int imm, Register rt, Register cc = GP) { ++ if (imm >= 0 && is_uimm8(imm)) { ++ addl(rs, imm, rt); ++ } else if (imm < 0 && is_uimm8(-imm)) { ++ subl(rs, -imm, rt); ++ } else { ++ ldi(cc, imm, R0); ++ addl(rs, cc, rt); ++ } ++ } ++ ++ void ori(Register rs, int imm, Register rt, Register cc = GP) { ++ if (is_uimm8(imm)) { ++ bis(rs, imm, rt); ++ } else { ++ ldi(cc, imm, R0); ++ bis(rs, cc, rt); ++ } ++ } ++ ++ void andi(Register rs, int imm, Register rt, Register cc = GP) { ++ if (is_uimm8(imm)) { ++ and_ins(rs, imm, rt); ++ } else { ++ ldi(cc, imm, R0); ++ and_ins(rs, cc, rt); ++ } ++ } ++ ++ void idiv_sw(Register rs, Register rt, Register rd){ ++ if(rt == R0){ ++ ShouldNotReachHere(); ++ }else{ ++ FloatRegister fsrc1 = f22; ++ FloatRegister fsrc2 = f23; ++ FloatRegister fdest = f24; ++ ifmovd(rs, fsrc1); ++ ifmovd(rt, fsrc2); ++ fcvtld(fsrc1, fsrc1); ++ fcvtld(fsrc2, fsrc2); ++ fdivd(fsrc1, fsrc2, fdest); ++ fcvtdl_z(fdest, fdest); ++ fcvtlw(fdest, fsrc1); ++ fimovs(fsrc1, rd); ++ } ++ } ++ ++ void irem_sw(Register rs, Register rt, Register rd){ ++ if(rt == R0){ ++ ShouldNotReachHere(); ++ }else{ ++ FloatRegister fsrc1 = f22; ++ FloatRegister fsrc2 = f23; ++ FloatRegister fdest = f24; ++ Register tem1 = rscratch3; ++ Register tem2 = rscratch4; ++ ifmovd(rs, fsrc1); ++ ifmovd(rt, fsrc2); ++ fcvtld(fsrc1, fsrc1); ++ fcvtld(fsrc2, fsrc2); ++ fdivd(fsrc1, fsrc2, fdest); ++ fcvtdl_z(fdest, fdest); ++ fimovd(fdest, tem1); ++ mulw(tem1, rt, tem2); ++ subw(rs, tem2, rd); ++ } ++ } ++ ++ void ldiv_sw(Register rs, Register rt, Register rd){ ++ if(rt == R0){ ++ ShouldNotReachHere(); ++ }else{ ++ FloatRegister fsrc1 = f23; ++ FloatRegister fsrc2 = f24; ++ FloatRegister fdest = f25; ++ ifmovd(rs, fsrc1); ++ ifmovd(rt, fsrc2); ++ fcvtld(fsrc1, fsrc1); ++ fcvtld(fsrc2, fsrc2); ++ fdivd(fsrc1, fsrc2, fdest); ++ fcvtdl_z(fdest, fdest); ++ fimovd(fdest, rd); ++ } ++ } ++ ++ void lrem_sw(Register rs, Register rt, Register rd){ ++ if(rt == R0){ ++ ShouldNotReachHere(); ++ }else{ ++ FloatRegister fsrc1 = f23; ++ FloatRegister fsrc2 = f24; ++ FloatRegister fdest = f25; ++ Register tem1 = rscratch3; ++ Register tem2 = rscratch4; ++ ifmovd(rs, fsrc1); ++ ifmovd(rt, fsrc2); ++ fcvtld(fsrc1, fsrc1); ++ fcvtld(fsrc2, fsrc2); ++ fdivd(fsrc1, fsrc2, fdest); ++ fcvtdl_z(fdest, fdest); ++ fimovd(fdest, tem1); ++ mull(tem1, rt, tem2); ++ subl(rs, tem2, rd); ++ } ++ } ++ void corrected_idivw(Register ra, Register rb, Register rc) { ++ Label special_case, done; ++ Register tem1 = GP; ++ ++ if(rb == R0) { ++ ShouldNotReachHere(); ++ } else { ++ // load -1 in register ++ ldi(tem1, -1, R0); ++ ++ // check for special case, e.g. rb = -1 ++ cmpeq(tem1, rb, tem1); ++ bne_l(tem1, special_case); ++ ++ // handle normal case ++ divw(ra, rb, rc); ++ beq_l(R0, done); ++ ++ // handle special case ++ bind(special_case); ++ subw(R0, ra, rc); ++ ++ // normal and special case exit ++ bind(done); ++ } ++ } ++ ++ void corrected_idivl(Register ra, Register rb, Register rc) { ++ Label special_case, done; ++ Register tem1 = GP; ++ ++ if (rb == R0) { ++ ShouldNotReachHere(); ++ } else { ++ // load -1 in register ++ ldi(tem1, -1, R0); ++ ++ // check for special case, e.g. rb = -1l ++ cmpeq(tem1, rb, tem1); ++ bne_l(tem1, special_case); ++ ++ // handle normal case ++ divl(ra, rb, rc); ++ beq_l(R0, done); ++ ++ // handle special case ++ bind(special_case); ++ subl(R0, ra, rc); ++ ++ // normal and special case exit ++ bind(done); ++ } ++ } ++ void add_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fadds(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fadds(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fadds(fs, f28, fd); ++ }else{ ++ fadds(fs, ft, fd); ++ } ++ } else ++ fadds(fs, ft, fd); ++ } ++ ++ void sub_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fsubs(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fsubs(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fsubs(fs, f28, fd); ++ }else{ ++ fsubs(fs, ft, fd); ++ } ++ } else ++ fsubs(fs, ft, fd); ++ } ++ ++ void mul_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fmuls(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fmuls(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fmuls(fs, f28, fd); ++ }else{ ++ fmuls(fs, ft, fd); ++ } ++ } else ++ fmuls(fs, ft, fd); ++ } ++ ++ void div_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fdivs(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fdivs(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fdivs(fs, f28, fd); ++ }else{ ++ fdivs(fs, ft, fd); ++ } ++ } else ++ fdivs(fs, ft, fd); ++ } ++ ++ void add_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ faddd(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ faddd(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ faddd(fs, f28, fd); ++ }else{ ++ faddd(fs, ft, fd); ++ } ++ } else ++ faddd(fs, ft, fd); ++ } ++ ++ void sub_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fsubd(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fsubd(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fsubd(fs, f28, fd); ++ }else{ ++ fsubd(fs, ft, fd); ++ } ++ } else ++ fsubd(fs, ft, fd); ++ } ++ ++ void mul_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fmuld(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fmuld(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fmuld(fs, f28, fd); ++ }else{ ++ fmuld(fs, ft, fd); ++ } ++ } else ++ fmuld(fs, ft, fd); ++ } ++ ++ void div_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(ft, f28); ++ if (fs == ft && ft == fd){ ++ fdivd(fs, ft, f28); ++ fcpys(f28, f28, fd); ++ }else if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fdivd(f28, ft, fd); ++ }else if (ft == fd){ ++ fcpys(ft, ft, f28); ++ fdivd(fs, f28, fd); ++ }else{ ++ fdivd(fs, ft, fd); ++ } ++ } else ++ fdivd(fs, ft, fd); ++ } ++ ++ void sqrt_s(FloatRegister fd, FloatRegister fs) { ++ if (FRegisterConflict) { ++ if(fs == fd){ ++ mov_s(f28, fs); ++ fsqrts(f28, fd); ++ } else ++ fsqrts(fs, fd); ++ } else ++ fsqrts(fs, fd); ++ } ++ ++ void sqrt_d(FloatRegister fd, FloatRegister fs) { ++ if (FRegisterConflict) { ++ if (fs == fd) { ++ mov_d(f28, fs); ++ fsqrtd(f28,fd); ++ } else ++ fsqrtd(fs, fd); ++ } else ++ fsqrtd(fs, fd); ++ } ++ ++ void cvt_s_l(FloatRegister fd, FloatRegister fs) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(fd, f28); ++ if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fcvtls(f28, fd); ++ }else{ ++ fcvtls(fs, fd); ++ } ++ } else ++ fcvtls(fs, fd); ++ } ++ ++ void cvt_d_l(FloatRegister fd, FloatRegister fs) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(fd, f28); ++ if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fcvtld(f28, fd); ++ }else{ ++ fcvtld(fs, fd); ++ } ++ } else ++ fcvtld(fs, fd); ++ } ++ ++ void cvt_d_s(FloatRegister fd, FloatRegister fs) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(fd, f28); ++ if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fcvtsd(f28, fd); ++ }else{ ++ fcvtsd(fs, fd); ++ } ++ } else ++ fcvtsd(fs, fd); ++ } ++ ++ void cvt_s_d(FloatRegister fd, FloatRegister fs) { ++ if (FRegisterConflict) { ++ assert_different_registers(fs, f28); ++ assert_different_registers(fd, f28); ++ if (fs == fd){ ++ fcpys(fs, fs, f28); ++ fcvtds(f28, fd); ++ } else ++ fcvtds(fs, fd); ++ } else ++ fcvtds(fs, fd); ++ } ++ ++ void c_un_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ } ++ void c_eq_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpeq(fs, ft, FcmpRES); ++ } ++ void c_ueq_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ fbne(FcmpRES, 1); ++ fcmpeq(fs, ft, FcmpRES); ++ } ++ ++ // fs < ft FcmpRES = 2.0 ++ // fs/ft nan FcmpRES = 2.0 ++ void c_ult_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ fbne(FcmpRES, 1); ++ fcmplt(fs, ft, FcmpRES); ++// fcmple(ft, fs, FcmpRES); ++// fcmpeq(FcmpRES, fzero, FcmpRES); ++ } ++ ++ void c_olt_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, f28, FcmpRES); ++ assert_different_registers(ft, f28, FcmpRES); ++// fcmpun(fs, ft, f28); ++// fcmpeq(f28, f31, FcmpRES); ++// fbeq(FcmpRES, 1); ++ fcmplt(fs, ft, FcmpRES); ++ } ++ ++ void c_ult_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ fbne(FcmpRES, 1); ++ fcmplt(fs, ft, FcmpRES); ++// fcmple(ft, fs, FcmpRES); ++// fcmpeq(FcmpRES, fzero, FcmpRES); ++ } ++ ++ void c_olt_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, f28, FcmpRES); ++ assert_different_registers(ft, f28, FcmpRES); ++// fcmpun(fs, ft, f28); ++// fcmpeq(f28, f31, FcmpRES); ++// fbeq(FcmpRES, 1); ++ fcmplt(fs, ft, FcmpRES); ++ } ++ ++ void c_ole_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, f28, FcmpRES); ++ assert_different_registers(ft, f28, FcmpRES); ++// fcmpun(fs, ft, f28); ++// fcmpeq(f28, f31, FcmpRES); ++// fbeq(FcmpRES, 1); ++ fcmple(fs, ft, FcmpRES); ++ } ++ ++ void c_ule_s (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ fbne(FcmpRES, 1); ++ fcmple(fs, ft, FcmpRES); ++// fcmplt(ft, fs, FcmpRES); ++// fcmpeq(FcmpRES, fzero, FcmpRES); ++ } ++ ++ void c_un_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ } ++ void c_eq_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpeq(fs, ft, FcmpRES); ++ } ++ void c_ueq_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ fbne(FcmpRES, 1); ++ fcmpeq(fs, ft, FcmpRES); ++ } ++ ++ void c_ole_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, f28, FcmpRES); ++ assert_different_registers(ft, f28, FcmpRES); ++// fcmpun(fs, ft, f28); ++// fcmpeq(f28, f31, FcmpRES); ++// fbeq(FcmpRES, 1); ++ fcmple(fs, ft, FcmpRES); ++ } ++ ++ void c_ule_d (FloatRegister fs, FloatRegister ft) { ++ assert_different_registers(fs, FcmpRES); ++ assert_different_registers(ft, FcmpRES); ++ fcmpun(fs, ft, FcmpRES); ++ fbne(FcmpRES, 1); ++ fcmple(fs, ft, FcmpRES); ++// fcmplt(ft, fs, FcmpRES); ++// fcmpeq(FcmpRES, fzero, FcmpRES); ++ } ++ ++ // Frame creation and destruction shared between JITs. ++ void build_frame(int framesize); ++ void remove_frame(int framesize); ++ ++public: ++// void mov(Register dst, Address a); ++ void mov_immediate64(Register dst, u_int64_t imm64, RelocationHolder const& rspec, int format = 0); ++ void mov_address64(Register dst, u_int64_t imm64, RelocationHolder const& rspec, int format = 0); ++ void mov_immediate64(Register dst, u_int64_t imm64); ++ void mov_immediate32(Register dst, int imm32); ++ void mov_immediate32u(Register dst, int imm32); ++ void mov_immediate32s(Register dst, int imm32); ++ void set64(Register d, long value); ++ void push_RA_call(Register entry, Register tmp=T12) { ++ if (entry != tmp) movl(tmp, entry); ++ ++ br(RA, 0); ++ addl(RA, 4 * BytesPerInt, RA); ++ subl(rsp, wordSize, rsp); ++ stl(RA, 0, rsp); ++ Assembler::call(RA, tmp, (int)0); ++ addl(rsp, wordSize, rsp); ++ if(UseSetfpec) ++ setfpec1(); ++ } ++ ++ static void imm48_split(long imm48, int16_t &msb_l, int16_t &lsb_h, int16_t &lsb_l) { ++ int32_t lsb32 = (int32_t) ((intptr_t) imm48); ++ int32_t msb32 = (int32_t) (((intptr_t) imm48 - lsb32) >> 32); ++ ++ msb_l = (int16_t) msb32; ++ lsb_h = (lsb32 - (int16_t) lsb32) >> 16; ++ lsb_l = (int16_t) lsb32; ++ guarantee((msb_l >= 0x0 && msb_l < 0x7fff) || (msb_l == 0x7fff && lsb32 >= 0x0 && lsb32 < 0x7fff8000), "wrong number in li48 "); ++ if (lsb32 >= 0x7fff8000) ++ msb_l = msb_l + 1; ++ } ++ ++// void push(RegSet regs, Register stack) { if (regs.bits()) push(regs.bits(), stack); } ++// void pop(RegSet regs, Register stack) { if (regs.bits()) pop(regs.bits(), stack); } ++ ++ // Push and pop everything that might be clobbered by a native ++ // runtime call except rscratch1 and rscratch2. (They are always ++ // scratch, so we don't have to protect them.) Only save the lower ++ // 64 bits of each vector register. ++ void push_call_clobbered_registers(); ++ void pop_call_clobbered_registers(); ++ ++ // Helper functions for statistics gathering. ++ void atomic_inc32(address counter_addr, int inc, Register tmp_reg1, Register tmp_reg2); ++ ++ // now mov instructions for loading absolute addresses and 32 or ++ // 64 bit integers ++ ++ inline void mov(Register dst, address addr) ++ { ++ mov_immediate64(dst, (u_int64_t)addr); ++ } ++ ++ inline void mov(Register dst, u_int64_t imm64) ++ { ++ mov_immediate64(dst, imm64); ++ } ++ ++ inline void movws(Register dst, u_int32_t imm32) ++ { ++ mov_immediate32(dst, imm32); ++ movws(dst, dst); ++ } ++ ++ /** ++ * x86 ++ * movslq(Register dst, Register src) ++ * sw64 ++ * movws(Register dst, Register src) ++ * note ++ * sign extend 32bit to 64bit ++ */ ++ inline void movws(Register dst, Register src) ++ { ++ addw(src, R0, dst); ++ } ++ ++ inline void movws(Register dst, Address src) ++ { ShouldNotReachHere(); ++ ldw(dst, src); ++ } ++ ++ inline void movl(Register dst, u_int64_t imm64) ++ { ++ mov_immediate64(dst, imm64); ++ } ++ ++ inline void movws(Register dst, int32_t imm32) ++ { ++ mov_immediate32s(dst, imm32); ++ } ++ ++ inline void movwu(Register dst, u_int32_t imm32) ++ { ++ mov_immediate32u(dst, imm32); ++ } ++ ++ inline void movw(Register dst, u_int32_t imm32) ++ { ++ mov_immediate32(dst, imm32); ++ } ++ ++ inline void movw(Register dst, Register src) ++ { ++ zapnot(src, 0xf, dst); ++ } ++ ++ inline void movwu(Register dst, Register src) ++ { ++ zapnot(src, 0xf, dst); ++ } ++ ++ inline void movw(Register dst, ExternalAddress addr, Register tmp=rcc) ++ { ++ mov_immediate64(tmp, (intptr_t)addr.target(), addr.rspec()); ++ zapnot(tmp, 0xf, dst); ++ } ++ ++ inline void movw(ExternalAddress addr, Register src, Register tmp=rcc) ++ { ++ mov_immediate64(tmp, (intptr_t)addr.target(), addr.rspec()); ++ stw(src, Address(tmp, 0)); ++ } ++ ++ inline void mov(Register dst, long l) ++ { ++ mov(dst, (u_int64_t)l); ++ } ++ ++ inline void mov(Register dst, int i) ++ { ++ mov(dst, (long)i); ++ } ++ ++ void mov(Register dst, RegisterOrConstant src) { ++ ShouldNotReachHere(); ++ } ++ ++ ++public: ++ ++ // Can we reach target using jal/j from anywhere ++ // in the code cache (because code can be relocated)? ++ bool reachable_from_cache(address target) { ++ return false; ++ } ++ // Argument ops ++ inline void store_int_argument(Register s, Argument &a) {ShouldNotReachHere(); ++ if(a.is_Register()) { ++ move(a.as_Register(), s); ++ } else { ++ sw(s, a.as_caller_address()); ++ } ++ } ++ ++ void sign_extend_short(Register reg) { sexth(reg, reg); } ++ void sign_extend_byte (Register reg) { sextb(reg, reg); } ++ ++ void trigfunc(char trig, int num_fpu_regs_in_use = 1); ++ ++ void subu32(Register rd, Register rs, Register rt) { subw(rs, rt, rd); } ++ void dsub (Register rd, Register rs, Register rt) { subl(rs, rt, rd); } ++ void addu32(Register rd, Register rs, Register rt) { addw(rs, rt, rd); } ++ void daddu (Register rd, Register rs, Register rt) { addl(rs, rt, rd); } ++ void dadd (Register rd, Register rs, Register rt) { addl(rs, rt, rd); } ++ //move should replace with movl jzy ++ void move(Register rd, Register rs) { movl(rd, rs); } ++ void movl(Register rd, Register rs) { if (rs != rd) bis(R0, rs, rd); } ++ void stbool(bool boolconst, Address dst, Register tmp = rscratch1) { ++ ldi(tmp, (int) boolconst, R0); ++ if(sizeof(bool) == 1) ++ stb(tmp, dst); ++ else if(sizeof(bool) == 2) ++ sth(tmp, dst); ++ else if(sizeof(bool) == 4) ++ stw(tmp, dst); ++ else ++ ShouldNotReachHere(); ++ } ++ ++ void mov_s(FloatRegister fd, FloatRegister fs) { fcpys(fs, fs, fd); } ++ void mov_d(FloatRegister fd, FloatRegister fs) { fcpys(fs, fs, fd); } ++ void abs_d(FloatRegister fd, FloatRegister fs) { fcpys(f31, fs, fd); } ++ ++ void brk (int code) { sys_call(0x80); } ++ ++ void dsll(Register rd, Register rt , int sa) { slll(rt, sa, rd); } ++ void dsrl(Register rd, Register rt , int sa) { srll(rt, sa, rd); } ++ void sll (Register rt, int sa, Register rd) { slll(rt, sa&0x1f, rd); addw(rd, 0, rd); } ++ void sllv(Register rd, Register rt, Register rs, Register cc = GP) { and_ins(rs, 0x1f, cc); slll(rt, cc, rd); addw(rd, 0, rd); } ++ void sra (Register rd, Register rt, int sa) { addw(rt, 0, rd); sral(rt, sa&0x1f, rd); } ++ void srav(Register rd, Register rt, Register rs, Register cc = GP) { and_ins(rs, 0x1f, cc); addw(rt, 0, rd); sral(rd, cc, rd); } ++ void srlv(Register rd, Register rt, Register rs, Register cc = GP) { and_ins(rs, 0x1f, cc); zapnot(rt, 0xf, rd); srll(rd, cc, rd); addw(rd, 0x0, rd); } ++ ++ void lbu (Register rt, Address src) { ldbu(rt, src.disp(), src.base()); } ++// void lb (Register rt, Address src) { lb(rt, src.disp(), src.base()); } ++// void lb (Register rt, int off, Register base) { ldbu(rt, off, base); sextb(rt, rt); } ++// void lh (Register rt, Address src) { ldh(rt, src.disp(), src.base()); } ++// void ldh (Register rt, int off, Register base) { ldhu(rt, Address(base, off)); sexth(rt, rt); } ++ void lhu (Register rt, Address src) { ldhu(rt, src); } ++// void lhu (Register rt, Register base, int off) { ldhu(rt, Address(base, off)); } ++ void lw (Register rt, Address src) { ldw(rt, src.disp(), src.base()); } ++// void ldwu(Register rt, int off, Register base) { ldw(rt, off, base); zapnot(rt, 0xF, rt); } ++ void ld (Register rt, Address src) { ldl(rt, src.disp(), src.base()); } ++ void sb (Register rt, Address dst) { stb(rt, dst.disp(), dst.base()); } ++ void sb (Register rt, Register base, int off) { stb(rt, off, base); } ++ ++ // ld_ptr will perform lw for 32 bit VMs and ld for 64 bit VMs ++ inline void ld_ptr(Register rt, Address a){ ++ ldl(rt, a.disp(), a.base()); ++ } ++ inline void st_ptr(Register rt, Address a){ ++ stl(rt, a.disp(), a.base()); ++ } ++ ++// void lwc1(FloatRegister rt, Address src) { lwc1(rt, src.base(), src.disp()); } ++// void lwc1(FloatRegister ft, Register base, int off) { flds(ft, off, base); } ++// void ldc1(FloatRegister rt, Address src) { ldc1(rt, src.base(), src.disp()); } ++// void ldc1(FloatRegister ft, Register base, int off) { fldd(ft, off, base); } ++ void lw (Register rt, Register base, int off) { ldw(rt, off, base); } ++ void ld (Register rt, Register base, int off) { ldl(rt, off, base); } ++// void swc1(FloatRegister ft, Register base, int off) { fsts(ft, off, base); } ++// void sdc1(FloatRegister ft, Register base, int off) { fstd(ft, off, base); } ++ void sw (Register rt, Register base, int off) { stw(rt, off, base); } ++ void sd (Register rt, Register base, int off) { stl(rt, off, base); } ++ ++// void fflds(FloatRegister rt, Address src) { flds(rt, src.disp(), src.base()); } ++// void ffldd(FloatRegister rt, Address src) { fldd(rt, src.disp(), src.base()); } ++// void ffsts(FloatRegister rt, Address dst) { fsts(rt, dst.disp(), dst.base()); } ++// void ffstd(FloatRegister rt, Address dst) { fstd(rt, dst.disp(), dst.base()); } ++ ++ void sw(Register rt, Address dst) { ++ Register src = rt; ++ Register base = dst.base(); ++ int disp = dst.disp(); ++ ++ if( Assembler::is_simm16(disp) ) { ++ stw(src, disp, base); ++ } else { ++ mov_immediate32(AT, disp); ++ addl(base, AT, AT); ++ stw(src, 0, AT); ++ } ++ } ++ ++ void std(Register rt, Address dst) { ++ Register src = rt; ++ Register base = dst.base(); ++ int disp = dst.disp(); ++ ++ if(is_simm16(disp)) { ++ stl(src, disp, base); ++ } else { ++ mov_immediate32(AT, disp); ++ addl(base, AT, AT); ++ stl(src, 0, AT); ++ } ++ } ++ ++ void empty_FPU_stack(){/*need implemented*/}; ++ ++ inline void store_ptr_argument(Register s, Argument &a) {ShouldNotReachHere(); ++ if(a.is_Register()) { ++ move(a.as_Register(), s); ++ } else { ++ st_ptr(s, a.as_caller_address()); ++ } ++ } ++ ++ inline void store_float_argument(FloatRegister s, Argument &a) {ShouldNotReachHere(); ++ if(a.is_Register()) { ++ fcpys(s, s, a.as_FloatRegister()); ++ } else { ++ fsts(s, a.as_caller_address()); ++ } ++ } ++ ++ inline void store_double_argument(FloatRegister s, Argument &a) {ShouldNotReachHere(); ++ if(a.is_Register()) { ++ fcpys(s, s, a.as_FloatRegister()); ++ } else { ++ fstd(s, a.as_caller_address()); ++ } ++ } ++ ++ void load( int width, Register ra, int mdisp, Register rb ){ ++ if(width == 0) ldbu( ra, mdisp, rb ); ++ else if(width == 1) ldhu( ra, mdisp, rb ); ++ else if(width == 2) ldw( ra, mdisp, rb ); ++ else ldl( ra, mdisp, rb ); ++ } ++ ++ void store( int width, Register ra, int mdisp, Register rb ){ ++ if(width == 0) stb( ra, mdisp, rb ); ++ else if(width == 1) sth( ra, mdisp, rb ); ++ else if(width == 2) stw( ra, mdisp, rb ); ++ else stl( ra, mdisp, rb ); ++ } ++ ++ //get the offset field of jump/branch instruction ++ //for condition branch instruction the disp is 21 bits ++ int offset(address entry) { ++ assert(is_simm21((entry - pc() - 4) / 4), "change this code"); ++ if (!is_simm21((entry - pc() - 4) / 4)) { ++ tty->print_cr("!!! is_simm16: %x", (unsigned int)((entry - pc() - 4) / 4)); ++ } ++ return (entry - pc() - 4) / 4; ++ } ++ ++ /** ++ * oop_maps->add_gc_map use offset to compute map ++ * but sw should put setfpec1 after call where will call gcc's code in, ++ * so sw should not use default offset method ++ * ++ * lbl is label which use to calculate return address ++ * offset is codebuffer's offset. ++ */ ++ int offset(Label &lbl, address start) { ++ assert(lbl.is_bound(), "need bound"); ++ int off = lbl.loc_pos() - (start - code_section()->start()); ++ return off; ++ } ++ ++ ++ void beq_a (Register a, address entry) { beq(a, offset(entry)); } ++ void beq_l (Register a, Label& L) { beq(a, offset(target(L))); } ++ void beq_c (Register rs, Register rt, Label& L, Register cc = GP) { ++ if ( rt == R0 ) { ++ beq(rs, offset(target(L))); ++ } else if (rs == R0) { ++ beq(rt, offset(target(L))); ++ } else { ++ cmpeq(rs, rt, cc); ++ bne(cc, offset(target(L))); ++ } ++ } ++ void bne_l (Register a, Label& L) { bne(a, offset(target(L))); } ++ void bne_c (Register rs, Register rt, Label& L, Register cc = GP) { ++ if ( rt == R0 ) { ++ bne(rs, offset(target(L))); ++ } else if (rs == R0) { ++ bne(rt, offset(target(L))); ++ } else { ++ cmpeq(rs, rt, cc); ++ beq(cc, offset(target(L))); ++ } ++ } ++ ++ void bgtz(Register rs, address entry) { bgt(rs, offset(entry)); } ++ void blez(Register rs, address entry) { ble(rs, offset(entry)); } ++ ++ void bge_l( Register a, Label& L ) { bge( a, offset(target(L))); } ++ void bgt_l( Register a, Label& L ) { bgt( a, offset(target(L))); } ++ void ble_l( Register a, Label& L ) { ble( a, offset(target(L))); } ++ void blt_l( Register a, Label& L ) { blt( a, offset(target(L))); } ++ void sltu (Register rd, Register rs, Register rt) { cmpult(rs, rt, rd); } ++ void slti(Register rt, Register rs, int imm, Register cc = GP) { ldi(cc, imm, R0); cmplt(rs, cc, rt); } ++ ++ void ffbeq(FloatRegister rs, Label& L) { fbeq(rs, offset(target(L))); } ++ void ffbne(FloatRegister rs, Label& L) { fbne(rs, offset(target(L))); } ++ ++ //we need 2 fun to save and resotre general register ++ void pushad(Register skip = noreg); ++ void popad(Register skip = noreg); ++ void saveTRegisters(); ++ void restoreTRegisters(); ++ ++ void ret_sw() { Assembler::ret(R0, RA, 0);} ++ void ret() { Assembler::ret(R0, RA, 0);} ++ ++ //TODO:to implement ++ void xchgptr(Register src1, Address src2) { stop("unimplement xchgptr: jzy"); } ++ void xchgptr(Register src1, Register src2); ++ void xchgw (Register src1, Address src2) { stop("unimplement xchgw: jzy");} ++ ++ void cmpxchgq(Register src1, Address src2) { stop("unimplement cmpxchgq: jzy"); } ++ void cmpxchgw(Register src1, Address src2) { stop("unimplement cmpxchgw: jzy"); } ++ void cmpxchgb(Register src1, Address src2) { stop("unimplement cmpxchgb: jzy"); } ++ void lock() { memb(); } ++ ++ void xaddw (Address src1, Register src2) { stop("unimplement xaddw: jzy");} ++ void xaddptr (Address src1, Register src2) { stop("unimplement xaddptr: jzy");} ++ // Jumps ++ void jr(Register rs) { Assembler::jmp(rscratch2, rs, 0); } ++ void jr(address entry); ++ void jr(address entry, relocInfo::relocType rtype); ++ ++ void patchable_jump(address target); ++ ++ void jalr(Register rd, Register rs) { ShouldNotReachHere(); } ++ void jalr(Register rs) { jalr(RA, rs); } ++ void jalr() { jalr(T12); } ++ ++ void jalr_setfpec1(Register rd, Register rs) { ShouldNotReachHere(); } ++ void jalr_setfpec1(Register rs) { jalr_setfpec1(RA, rs); } ++ ++ // Calls ++ void call_patch(address entry); ++ void call_patch(address entry, relocInfo::relocType rtype); ++ ++ void patchable_call_setfpec1(address target); ++ void patchable_call(address target, Label *retAddr = NULL, Register tmp=T12); ++ ++ inline void xorr ( Register rd, Register rs, Register rt ) { xor_ins(rs, rt, rd); } ++ inline void andnot ( Register ra, Register rb, Register rc ) { bic( ra, rb, rc ); } ++ inline void andnot ( Register ra, int lit, Register rc ) { bic( ra, lit, rc ); } ++ inline void or_ins ( Register ra, Register rb, Register rc ) { bis( ra, rb, rc ); } ++ inline void or_ins ( Register ra, int lit, Register rc ) { bis( ra, lit, rc ); } ++ ++ // Generalized Test Bit And Branch, including a "far" variety which ++ // spans more than 32KiB. ++ void tbr(Condition cond, Register Rt, int bitpos, Label &dest, bool far = false) { ++ ShouldNotReachHere(); ++ } ++ ++ // idiv variant which deals with MINLONG as dividend and -1 as divisor ++ int corrected_idivl(Register result, Register ra, Register rb, ++ bool want_remainder, Register tmp = rscratch1); ++ int corrected_idivq(Register result, Register ra, Register rb, ++ bool want_remainder, Register tmp = rscratch1); ++ ++ static address target_addr_for_insn(address insn_addr, unsigned insn); ++ static address target_addr_for_insn(address insn_addr) { ++ unsigned insn = *(unsigned*)insn_addr; ++ return target_addr_for_insn(insn_addr, insn); ++ } ++ ++ 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 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; ++ } ++ static int ins_mask(int msb, int lsb) { ++ int nbits = msb - lsb + 1; ++ unsigned mask = checked_cast(right_n_bits(nbits)); ++ mask <<= lsb; ++ return mask; ++ } ++ static int wdisp2( intptr_t dst, intptr_t src, int msb, int lsb) { ++ intptr_t xx = dst - src; ++ int nbits = msb - lsb +1; ++ assert_signed_word_disp_range(xx, nbits); ++ int r = (xx >> 2) & (( 1 << nbits ) - 1); ++ assert( inv_wdisp( r, src, nbits ) == dst, "inverse not inverse"); ++ r <<= lsb; ++ return r; ++ } ++ // signed immediate, in low bits, nbits long ++ static int simm(int x, int nbits) { ++ assert_signed_range(x, nbits); ++ return x & (( 1 << nbits ) - 1); ++ } ++ ++ void verify_oop_subroutine(); ++ ++ void cmp_klass(Register oop, Register trial_klass, Register tmp); ++ ++ void resolve_oop_handle(Register result, Register tmp = rscratch1); ++ void load_mirror(Register mirror, Register method, Register tmp = rscratch1); ++}; ++ ++class ScopeMark { ++private: ++ MacroAssembler* _masm; ++ char _begin[300]; ++ char _end[300]; ++public: ++ ++ ScopeMark(MacroAssembler* masm, const char* position, const char* comment = "") : _masm(masm) { ++ if (comment == "") { ++ ::sprintf(_begin, "%s{", position); ++ ::sprintf(_end, "%s}", position); ++ } else { ++ ::sprintf(_begin, "%s %s %s enter", position, "{", comment); ++ ::sprintf(_end, "%s leave }", position); ++ } ++ ++ _masm->block_comment(_begin); ++ } ++ ++ ~ScopeMark() { ++ _masm->block_comment(_end); ++ } ++}; ++ ++class SizedScope { ++private: ++ int _size; ++ MacroAssembler* _masm; ++ address _start; ++public: ++ SizedScope(MacroAssembler* masm, int size) { ++ _masm = masm; ++ _size = size; ++ _start = _masm->pc(); ++ } ++ ~SizedScope() { ++ if (_masm->pc() - _start > _size) Unimplemented(); ++ while (_masm->pc() - _start < _size) _masm->nop(); ++ } ++}; ++ ++#ifdef ASSERT ++inline bool AbstractAssembler::pd_check_instruction_mark() { return true; } ++#endif ++ ++/** ++ * 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 { ++ private: ++ MacroAssembler* _masm; ++ Label _label; ++ ++ public: ++ SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value); ++ ~SkipIfEqual(); ++}; ++ ++struct tableswitch { ++ Register _reg; ++ int _insn_index; jint _first_key; jint _last_key; ++ Label _after; ++ Label _branches; ++}; ++ ++#endif // CPU_SW64_VM_MACROASSEMBLER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64.inline.hpp afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64.inline.hpp +--- openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64.inline.hpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_MACROASSEMBLER_SW64_INLINE_HPP ++#define CPU_SW64_VM_MACROASSEMBLER_SW64_INLINE_HPP ++ ++#include "asm/assembler.hpp" ++ ++#ifndef PRODUCT ++ ++#endif // ndef PRODUCT ++ ++#endif // CPU_SW64_VM_MACROASSEMBLER_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64_log.cpp afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64_log.cpp +--- openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64_log.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64_log.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,262 @@ ++/* Copyright (c) 2018, Cavium. All rights reserved. (By BELLSOFT) ++ * Copyright (c) 2016, Intel Corporation. ++ * Intel Math Library (LIBM) Source Code ++ * ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/assembler.hpp" ++#include "asm/assembler.inline.hpp" ++#include "macroAssembler_sw64.hpp" ++ ++// Algorithm idea is taken from x86 hotspot intrinsic and adapted for AARCH64. ++// ++// For mathematical background please refer to the following literature: ++// ++// Tang, Ping-Tak Peter. ++// Table-driven implementation of the logarithm function ++// in IEEE floating-point arithmetic. ++// ACM Transactions on Mathematical Software (TOMS) 16, no. 4, 1990: 378-400. ++ ++/******************************************************************************/ ++// ALGORITHM DESCRIPTION - LOG() ++// --------------------- ++// ++// x=2^k * mx, mx in [1,2) ++// ++// Get B~1/mx based on the output of frecpe instruction (B0) ++// B = int((B0*2^7+0.5))/2^7 ++// ++// Reduced argument: r=B*mx-1.0 (computed accurately in high and low parts) ++// ++// Result: k*log(2) - log(B) + p(r) if |x-1| >= small value (2^-6) and ++// p(r) is a degree 7 polynomial ++// -log(B) read from data table (high, low parts) ++// Result is formed from high and low parts ++// ++// Special cases: ++// 1. log(NaN) = quiet NaN ++// 2. log(+INF) = that INF ++// 3. log(0) = -INF ++// 4. log(1) = +0 ++// 5. log(x) = NaN if x < -0, including -INF ++// ++/******************************************************************************/ ++ ++// Table with p(r) polynomial coefficients ++// and table representation of logarithm values (hi and low parts) ++__attribute__ ((aligned(64))) juint _L_tbl[] = ++{ ++ // coefficients of p(r) polynomial: ++ // _coeff[] ++ 0x00000000UL, 0xbfd00000UL, // C1_0 = -0.25 ++ 0x92492492UL, 0x3fc24924UL, // C1_1 = 0.14285714285714285 ++ 0x55555555UL, 0x3fd55555UL, // C2_0 = 0.3333333333333333 ++ 0x3d6fb175UL, 0xbfc5555eUL, // C2_1 = -0.16666772842235003 ++ 0x00000000UL, 0xbfe00000UL, // C3_0 = -0.5 ++ 0x9999999aUL, 0x3fc99999UL, // C3_1 = 0.2 ++ // _log2[] ++ 0xfefa3800UL, 0x3fa62e42UL, // C4_0 = 0.043321698784993146 ++ 0x93c76730UL, 0x3ceef357UL, // C4_1 = 3.436201886692732e-15 ++ // _L_tbl[] with logarithm values (hi and low parts) ++ 0xfefa3800UL, 0x3fe62e42UL, 0x93c76730UL, 0x3d2ef357UL, 0xaa241800UL, ++ 0x3fe5ee82UL, 0x0cda46beUL, 0x3d220238UL, 0x5c364800UL, 0x3fe5af40UL, ++ 0xac10c9fbUL, 0x3d2dfa63UL, 0x26bb8c00UL, 0x3fe5707aUL, 0xff3303ddUL, ++ 0x3d09980bUL, 0x26867800UL, 0x3fe5322eUL, 0x5d257531UL, 0x3d05ccc4UL, ++ 0x835a5000UL, 0x3fe4f45aUL, 0x6d93b8fbUL, 0xbd2e6c51UL, 0x6f970c00UL, ++ 0x3fe4b6fdUL, 0xed4c541cUL, 0x3cef7115UL, 0x27e8a400UL, 0x3fe47a15UL, ++ 0xf94d60aaUL, 0xbd22cb6aUL, 0xf2f92400UL, 0x3fe43d9fUL, 0x481051f7UL, ++ 0xbcfd984fUL, 0x2125cc00UL, 0x3fe4019cUL, 0x30f0c74cUL, 0xbd26ce79UL, ++ 0x0c36c000UL, 0x3fe3c608UL, 0x7cfe13c2UL, 0xbd02b736UL, 0x17197800UL, ++ 0x3fe38ae2UL, 0xbb5569a4UL, 0xbd218b7aUL, 0xad9d8c00UL, 0x3fe35028UL, ++ 0x9527e6acUL, 0x3d10b83fUL, 0x44340800UL, 0x3fe315daUL, 0xc5a0ed9cUL, ++ 0xbd274e93UL, 0x57b0e000UL, 0x3fe2dbf5UL, 0x07b9dc11UL, 0xbd17a6e5UL, ++ 0x6d0ec000UL, 0x3fe2a278UL, 0xe797882dUL, 0x3d206d2bUL, 0x1134dc00UL, ++ 0x3fe26962UL, 0x05226250UL, 0xbd0b61f1UL, 0xd8bebc00UL, 0x3fe230b0UL, ++ 0x6e48667bUL, 0x3d12fc06UL, 0x5fc61800UL, 0x3fe1f863UL, 0xc9fe81d3UL, ++ 0xbd2a7242UL, 0x49ae6000UL, 0x3fe1c078UL, 0xed70e667UL, 0x3cccacdeUL, ++ 0x40f23c00UL, 0x3fe188eeUL, 0xf8ab4650UL, 0x3d14cc4eUL, 0xf6f29800UL, ++ 0x3fe151c3UL, 0xa293ae49UL, 0xbd2edd97UL, 0x23c75c00UL, 0x3fe11af8UL, ++ 0xbb9ddcb2UL, 0xbd258647UL, 0x8611cc00UL, 0x3fe0e489UL, 0x07801742UL, ++ 0x3d1c2998UL, 0xe2d05400UL, 0x3fe0ae76UL, 0x887e7e27UL, 0x3d1f486bUL, ++ 0x0533c400UL, 0x3fe078bfUL, 0x41edf5fdUL, 0x3d268122UL, 0xbe760400UL, ++ 0x3fe04360UL, 0xe79539e0UL, 0xbd04c45fUL, 0xe5b20800UL, 0x3fe00e5aUL, ++ 0xb1727b1cUL, 0xbd053ba3UL, 0xaf7a4800UL, 0x3fdfb358UL, 0x3c164935UL, ++ 0x3d0085faUL, 0xee031800UL, 0x3fdf4aa7UL, 0x6f014a8bUL, 0x3d12cde5UL, ++ 0x56b41000UL, 0x3fdee2a1UL, 0x5a470251UL, 0x3d2f27f4UL, 0xc3ddb000UL, ++ 0x3fde7b42UL, 0x5372bd08UL, 0xbd246550UL, 0x1a272800UL, 0x3fde148aUL, ++ 0x07322938UL, 0xbd1326b2UL, 0x484c9800UL, 0x3fddae75UL, 0x60dc616aUL, ++ 0xbd1ea42dUL, 0x46def800UL, 0x3fdd4902UL, 0xe9a767a8UL, 0x3d235bafUL, ++ 0x18064800UL, 0x3fdce42fUL, 0x3ec7a6b0UL, 0xbd0797c3UL, 0xc7455800UL, ++ 0x3fdc7ff9UL, 0xc15249aeUL, 0xbd29b6ddUL, 0x693fa000UL, 0x3fdc1c60UL, ++ 0x7fe8e180UL, 0x3d2cec80UL, 0x1b80e000UL, 0x3fdbb961UL, 0xf40a666dUL, ++ 0x3d27d85bUL, 0x04462800UL, 0x3fdb56faUL, 0x2d841995UL, 0x3d109525UL, ++ 0x5248d000UL, 0x3fdaf529UL, 0x52774458UL, 0xbd217cc5UL, 0x3c8ad800UL, ++ 0x3fda93edUL, 0xbea77a5dUL, 0x3d1e36f2UL, 0x0224f800UL, 0x3fda3344UL, ++ 0x7f9d79f5UL, 0x3d23c645UL, 0xea15f000UL, 0x3fd9d32bUL, 0x10d0c0b0UL, ++ 0xbd26279eUL, 0x43135800UL, 0x3fd973a3UL, 0xa502d9f0UL, 0xbd152313UL, ++ 0x635bf800UL, 0x3fd914a8UL, 0x2ee6307dUL, 0xbd1766b5UL, 0xa88b3000UL, ++ 0x3fd8b639UL, 0xe5e70470UL, 0xbd205ae1UL, 0x776dc800UL, 0x3fd85855UL, ++ 0x3333778aUL, 0x3d2fd56fUL, 0x3bd81800UL, 0x3fd7fafaUL, 0xc812566aUL, ++ 0xbd272090UL, 0x687cf800UL, 0x3fd79e26UL, 0x2efd1778UL, 0x3d29ec7dUL, ++ 0x76c67800UL, 0x3fd741d8UL, 0x49dc60b3UL, 0x3d2d8b09UL, 0xe6af1800UL, ++ 0x3fd6e60eUL, 0x7c222d87UL, 0x3d172165UL, 0x3e9c6800UL, 0x3fd68ac8UL, ++ 0x2756eba0UL, 0x3d20a0d3UL, 0x0b3ab000UL, 0x3fd63003UL, 0xe731ae00UL, ++ 0xbd2db623UL, 0xdf596000UL, 0x3fd5d5bdUL, 0x08a465dcUL, 0xbd0a0b2aUL, ++ 0x53c8d000UL, 0x3fd57bf7UL, 0xee5d40efUL, 0x3d1fadedUL, 0x0738a000UL, ++ 0x3fd522aeUL, 0x8164c759UL, 0x3d2ebe70UL, 0x9e173000UL, 0x3fd4c9e0UL, ++ 0x1b0ad8a4UL, 0xbd2e2089UL, 0xc271c800UL, 0x3fd4718dUL, 0x0967d675UL, ++ 0xbd2f27ceUL, 0x23d5e800UL, 0x3fd419b4UL, 0xec90e09dUL, 0x3d08e436UL, ++ 0x77333000UL, 0x3fd3c252UL, 0xb606bd5cUL, 0x3d183b54UL, 0x76be1000UL, ++ 0x3fd36b67UL, 0xb0f177c8UL, 0x3d116ecdUL, 0xe1d36000UL, 0x3fd314f1UL, ++ 0xd3213cb8UL, 0xbd28e27aUL, 0x7cdc9000UL, 0x3fd2bef0UL, 0x4a5004f4UL, ++ 0x3d2a9cfaUL, 0x1134d800UL, 0x3fd26962UL, 0xdf5bb3b6UL, 0x3d2c93c1UL, ++ 0x6d0eb800UL, 0x3fd21445UL, 0xba46baeaUL, 0x3d0a87deUL, 0x635a6800UL, ++ 0x3fd1bf99UL, 0x5147bdb7UL, 0x3d2ca6edUL, 0xcbacf800UL, 0x3fd16b5cUL, ++ 0xf7a51681UL, 0x3d2b9acdUL, 0x8227e800UL, 0x3fd1178eUL, 0x63a5f01cUL, ++ 0xbd2c210eUL, 0x67616000UL, 0x3fd0c42dUL, 0x163ceae9UL, 0x3d27188bUL, ++ 0x604d5800UL, 0x3fd07138UL, 0x16ed4e91UL, 0x3cf89cdbUL, 0x5626c800UL, ++ 0x3fd01eaeUL, 0x1485e94aUL, 0xbd16f08cUL, 0x6cb3b000UL, 0x3fcf991cUL, ++ 0xca0cdf30UL, 0x3d1bcbecUL, 0xe4dd0000UL, 0x3fcef5adUL, 0x65bb8e11UL, ++ 0xbcca2115UL, 0xffe71000UL, 0x3fce530eUL, 0x6041f430UL, 0x3cc21227UL, ++ 0xb0d49000UL, 0x3fcdb13dUL, 0xf715b035UL, 0xbd2aff2aUL, 0xf2656000UL, ++ 0x3fcd1037UL, 0x75b6f6e4UL, 0xbd084a7eUL, 0xc6f01000UL, 0x3fcc6ffbUL, ++ 0xc5962bd2UL, 0xbcf1ec72UL, 0x383be000UL, 0x3fcbd087UL, 0x595412b6UL, ++ 0xbd2d4bc4UL, 0x575bd000UL, 0x3fcb31d8UL, 0x4eace1aaUL, 0xbd0c358dUL, ++ 0x3c8ae000UL, 0x3fca93edUL, 0x50562169UL, 0xbd287243UL, 0x07089000UL, ++ 0x3fc9f6c4UL, 0x6865817aUL, 0x3d29904dUL, 0xdcf70000UL, 0x3fc95a5aUL, ++ 0x58a0ff6fUL, 0x3d07f228UL, 0xeb390000UL, 0x3fc8beafUL, 0xaae92cd1UL, ++ 0xbd073d54UL, 0x6551a000UL, 0x3fc823c1UL, 0x9a631e83UL, 0x3d1e0ddbUL, ++ 0x85445000UL, 0x3fc7898dUL, 0x70914305UL, 0xbd1c6610UL, 0x8b757000UL, ++ 0x3fc6f012UL, 0xe59c21e1UL, 0xbd25118dUL, 0xbe8c1000UL, 0x3fc6574eUL, ++ 0x2c3c2e78UL, 0x3d19cf8bUL, 0x6b544000UL, 0x3fc5bf40UL, 0xeb68981cUL, ++ 0xbd127023UL, 0xe4a1b000UL, 0x3fc527e5UL, 0xe5697dc7UL, 0x3d2633e8UL, ++ 0x8333b000UL, 0x3fc4913dUL, 0x54fdb678UL, 0x3d258379UL, 0xa5993000UL, ++ 0x3fc3fb45UL, 0x7e6a354dUL, 0xbd2cd1d8UL, 0xb0159000UL, 0x3fc365fcUL, ++ 0x234b7289UL, 0x3cc62fa8UL, 0x0c868000UL, 0x3fc2d161UL, 0xcb81b4a1UL, ++ 0x3d039d6cUL, 0x2a49c000UL, 0x3fc23d71UL, 0x8fd3df5cUL, 0x3d100d23UL, ++ 0x7e23f000UL, 0x3fc1aa2bUL, 0x44389934UL, 0x3d2ca78eUL, 0x8227e000UL, ++ 0x3fc1178eUL, 0xce2d07f2UL, 0x3d21ef78UL, 0xb59e4000UL, 0x3fc08598UL, ++ 0x7009902cUL, 0xbd27e5ddUL, 0x39dbe000UL, 0x3fbfe891UL, 0x4fa10afdUL, ++ 0xbd2534d6UL, 0x830a2000UL, 0x3fbec739UL, 0xafe645e0UL, 0xbd2dc068UL, ++ 0x63844000UL, 0x3fbda727UL, 0x1fa71733UL, 0x3d1a8940UL, 0x01bc4000UL, ++ 0x3fbc8858UL, 0xc65aacd3UL, 0x3d2646d1UL, 0x8dad6000UL, 0x3fbb6ac8UL, ++ 0x2bf768e5UL, 0xbd139080UL, 0x40b1c000UL, 0x3fba4e76UL, 0xb94407c8UL, ++ 0xbd0e42b6UL, 0x5d594000UL, 0x3fb9335eUL, 0x3abd47daUL, 0x3d23115cUL, ++ 0x2f40e000UL, 0x3fb8197eUL, 0xf96ffdf7UL, 0x3d0f80dcUL, 0x0aeac000UL, ++ 0x3fb700d3UL, 0xa99ded32UL, 0x3cec1e8dUL, 0x4d97a000UL, 0x3fb5e95aUL, ++ 0x3c5d1d1eUL, 0xbd2c6906UL, 0x5d208000UL, 0x3fb4d311UL, 0x82f4e1efUL, ++ 0xbcf53a25UL, 0xa7d1e000UL, 0x3fb3bdf5UL, 0xa5db4ed7UL, 0x3d2cc85eUL, ++ 0xa4472000UL, 0x3fb2aa04UL, 0xae9c697dUL, 0xbd20b6e8UL, 0xd1466000UL, ++ 0x3fb1973bUL, 0x560d9e9bUL, 0xbd25325dUL, 0xb59e4000UL, 0x3fb08598UL, ++ 0x7009902cUL, 0xbd17e5ddUL, 0xc006c000UL, 0x3faeea31UL, 0x4fc93b7bUL, ++ 0xbd0e113eUL, 0xcdddc000UL, 0x3faccb73UL, 0x47d82807UL, 0xbd1a68f2UL, ++ 0xd0fb0000UL, 0x3faaaef2UL, 0x353bb42eUL, 0x3d20fc1aUL, 0x149fc000UL, ++ 0x3fa894aaUL, 0xd05a267dUL, 0xbd197995UL, 0xf2d4c000UL, 0x3fa67c94UL, ++ 0xec19afa2UL, 0xbd029efbUL, 0xd42e0000UL, 0x3fa466aeUL, 0x75bdfd28UL, ++ 0xbd2c1673UL, 0x2f8d0000UL, 0x3fa252f3UL, 0xe021b67bUL, 0x3d283e9aUL, ++ 0x89e74000UL, 0x3fa0415dUL, 0x5cf1d753UL, 0x3d0111c0UL, 0xec148000UL, ++ 0x3f9c63d2UL, 0x3f9eb2f3UL, 0x3d2578c6UL, 0x28c90000UL, 0x3f984925UL, ++ 0x325a0c34UL, 0xbd2aa0baUL, 0x25980000UL, 0x3f9432a9UL, 0x928637feUL, ++ 0x3d098139UL, 0x58938000UL, 0x3f902056UL, 0x06e2f7d2UL, 0xbd23dc5bUL, ++ 0xa3890000UL, 0x3f882448UL, 0xda74f640UL, 0xbd275577UL, 0x75890000UL, ++ 0x3f801015UL, 0x999d2be8UL, 0xbd10c76bUL, 0x59580000UL, 0x3f700805UL, ++ 0xcb31c67bUL, 0x3d2166afUL, 0x00000000UL, 0x00000000UL, 0x00000000UL, ++ 0x80000000UL ++}; ++ ++// BEGIN dlog PSEUDO CODE: ++// double dlog(double X) { ++// // p(r) polynomial coefficients initialized from _L_tbl table ++// double C1_0 = _L_tbl[0]; ++// double C1_1 = _L_tbl[1]; ++// double C2_0 = _L_tbl[2]; ++// double C2_1 = _L_tbl[3]; ++// double C3_0 = _L_tbl[4]; ++// double C3_1 = _L_tbl[5]; ++// double C4_0 = _L_tbl[6]; ++// double C4_1 = _L_tbl[7]; ++// // NOTE: operations with coefficients above are mostly vectorized in assembly ++// // Check corner cases first ++// if (X == 1.0d || AS_LONG_BITS(X) + 0x0010000000000000 <= 0x0010000000000000) { ++// // NOTE: AS_LONG_BITS(X) + 0x0010000000000000 <= 0x0010000000000000 means ++// // that X < 0 or X >= 0x7FF0000000000000 (0x7FF* is NaN or INF) ++// if (X < 0 || X is NaN) return NaN; ++// if (X == 1.0d) return 0.0d; ++// if (X == 0.0d) return -INFINITY; ++// if (X is INFINITY) return INFINITY; ++// } ++// // double representation is 2^exponent * mantissa ++// // split X into two multipliers: 2^exponent and 1.0 * mantissa ++// // pseudo function: zeroExponent(X) return value of X with exponent == 0 ++// float vtmp5 = 1/(float)(zeroExponent(X)); // reciprocal estimate ++// // pseudo function: HI16(X) returns high 16 bits of double value ++// int hiWord = HI16(X); ++// double vtmp1 = (double) 0x77F0 << 48 | mantissa(X); ++// hiWord -= 16; ++// if (AS_LONG_BITS(hiWord) > 0x8000) { ++// // SMALL_VALUE branch ++// vtmp0 = vtmp1 = vtmp0 * AS_DOUBLE_BITS(0x47F0000000000000); ++// hiWord = HI16(vtmp1); ++// vtmp0 = AS_DOUBLE_BITS(AS_LONG_BITS(vtmp0) |= 0x3FF0000000000000); ++// vtmp5 = (double) (1/(float)vtmp0); ++// vtmp1 <<= 12; ++// vtmp1 >>= 12; ++// } ++// // MAIN branch ++// double vtmp3 = AS_LONG_BITS(vtmp1) & 0xffffe00000000000; // hi part ++// int intB0 = AS_INT_BITS(vtmp5) + 0x8000; ++// double vtmp0 = AS_DOUBLE_BITS(0xffffe00000000000 & (intB0<<29)); ++// int index = (intB0 >> 16) && 0xFF; ++// double hiTableValue = _L_tbl[8+index]; // vtmp2[0] ++// double lowTableValue = _L_tbl[16+index]; // vtmp2[1] ++// vtmp5 = AS_DOUBLE_BITS(hiWord & 0x7FF0 - 0x3FE0); // 0x3FE = 1023 << 4 ++// vtmp1 -= vtmp3; // low part ++// vtmp3 = vtmp3*vtmp0 - 1.0; ++// hiTableValue += C4_0 * vtmp5; ++// lowTableValue += C4_1 * vtmp5; ++// double r = vtmp1 * vtmp0 + vtmp3; // r = B*mx-1.0, computed in hi and low parts ++// vtmp0 = hiTableValue + r; ++// hiTableValue -= vtmp0; ++// double i2 = r*r; ++// double i3 = i2*r; ++// double p7 = C3_0*i2 + C2_0*i3 + C1_0*i2*i2 + C3_1*i3*i2 + C2_1*i3*i3 ++// + C1_1*i3*i2*i2; // degree 7 polynomial ++// return p7 + (vtmp0 + ((r + hiTableValue) + lowTableValue)); ++// } ++// ++// END dlog PSEUDO CODE ++ ++ ++// Generate log(X). X passed in register f0. Return log(X) into f0. ++// Generator parameters: 10 temporary FPU registers and temporary general ++// purpose registers ++void MacroAssembler::fast_log(FloatRegister vtmp0, FloatRegister vtmp1, ++ FloatRegister vtmp2, FloatRegister vtmp3, ++ FloatRegister vtmp4, FloatRegister vtmp5, ++ FloatRegister C1, FloatRegister C2, ++ FloatRegister C3, FloatRegister C4, ++ Register tmp1, Register tmp2, Register tmp3, ++ Register tmp4, Register tmp5) { ++ ShouldNotReachHere(); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64_trig.cpp afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64_trig.cpp +--- openjdk/src/hotspot/cpu/sw64/macroAssembler_sw64_trig.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/macroAssembler_sw64_trig.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,710 @@ ++/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Cavium. All rights reserved. (By BELLSOFT) ++ * 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 "runtime/stubRoutines.hpp" ++#include "macroAssembler_sw64.hpp" ++ ++// The following code is a optimized version of fdlibm sin/cos implementation ++// (C code is in share/runtime/sharedRuntimeTrig.cpp) adapted for SW64. ++ ++// Please refer to sin/cos approximation via polynomial and ++// trigonometric argument reduction techniques to the following literature: ++// ++// [1] Muller, Jean-Michel, Nicolas Brisebarre, Florent De Dinechin, ++// Claude-Pierre Jeannerod, Vincent Lefevre, Guillaume Melquiond, ++// Nathalie Revol, Damien Stehlé, and Serge Torres: ++// Handbook of floating-point arithmetic. ++// Springer Science & Business Media, 2009. ++// [2] K. C. Ng ++// Argument Reduction for Huge Arguments: Good to the Last Bit ++// July 13, 1992, SunPro ++// ++// HOW TO READ THIS CODE: ++// This code consists of several functions. Each function has following header: ++// 1) Description ++// 2) C-pseudo code with differences from fdlibm marked by comments starting ++// with "NOTE". Check unmodified fdlibm code in ++// share/runtime/SharedRuntimeTrig.cpp ++// 3) Brief textual description of changes between fdlibm and current ++// implementation along with optimization notes (if applicable) ++// 4) Assumptions, input and output ++// 5) (Optional) additional notes about intrinsic implementation ++// Each function is separated in blocks which follow the pseudo-code structure ++// ++// HIGH-LEVEL ALGORITHM DESCRIPTION: ++// - entry point: generate_dsin_dcos(...); ++// - check corner cases: NaN, INF, tiny argument. ++// - check if |x| < Pi/4. Then approximate sin/cos via polynomial (kernel_sin/kernel_cos) ++// -- else proceed to argument reduction routine (__ieee754_rem_pio2) and ++// use reduced argument to get result via kernel_sin/kernel_cos ++// ++// HIGH-LEVEL CHANGES BETWEEN INTRINSICS AND FDLIBM: ++// 1) two_over_pi table fdlibm representation is int[], while intrinsic version ++// has these int values converted to double representation to load converted ++// double values directly (see stubRoutines_aarch4::_two_over_pi) ++// 2) Several loops are unrolled and vectorized: see comments in code after ++// labels: SKIP_F_LOAD, RECOMP_FOR1_CHECK, RECOMP_FOR2 ++// 3) fdlibm npio2_hw table now has "prefix" with constants used in ++// calculation. These constants are loaded from npio2_hw table instead of ++// constructing it in code (see stubRoutines_sw64.cpp) ++// 4) Polynomial coefficients for sin and cos are moved to table sin_coef ++// and cos_coef to use the same optimization as in 3). It allows to load most of ++// required constants via single instruction ++// ++// ++// ++///* __ieee754_rem_pio2(x,y) ++// * ++// * returns the remainder of x rem pi/2 in y[0]+y[1] (i.e. like x div pi/2) ++// * x is input argument, y[] is hi and low parts of reduced argument (x) ++// * uses __kernel_rem_pio2() ++// */ ++// // use tables(see stubRoutines_sw64.cpp): two_over_pi and modified npio2_hw ++// ++// BEGIN __ieee754_rem_pio2 PSEUDO CODE ++// ++//static int __ieee754_rem_pio2(double x, double *y) { ++// double z,w,t,r,fn; ++// double tx[3]; ++// int e0,i,j,nx,n,ix,hx,i0; ++// ++// i0 = ((*(int*)&two24A)>>30)^1; /* high word index */ ++// hx = *(i0+(int*)&x); /* high word of x */ ++// ix = hx&0x7fffffff; ++// if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */ ++// if(hx>0) { ++// z = x - pio2_1; ++// if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ ++// y[0] = z - pio2_1t; ++// y[1] = (z-y[0])-pio2_1t; ++// } else { /* near pi/2, use 33+33+53 bit pi */ ++// z -= pio2_2; ++// y[0] = z - pio2_2t; ++// y[1] = (z-y[0])-pio2_2t; ++// } ++// return 1; ++// } else { /* negative x */ ++// z = x + pio2_1; ++// if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ ++// y[0] = z + pio2_1t; ++// y[1] = (z-y[0])+pio2_1t; ++// } else { /* near pi/2, use 33+33+53 bit pi */ ++// z += pio2_2; ++// y[0] = z + pio2_2t; ++// y[1] = (z-y[0])+pio2_2t; ++// } ++// return -1; ++// } ++// } ++// if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */ ++// t = fabsd(x); ++// n = (int) (t*invpio2+half); ++// fn = (double)n; ++// r = t-fn*pio2_1; ++// w = fn*pio2_1t; /* 1st round good to 85 bit */ ++// // NOTE: y[0] = r-w; is moved from if/else below to be before "if" ++// y[0] = r-w; ++// if(n<32&&ix!=npio2_hw[n-1]) { ++// // y[0] = r-w; /* quick check no cancellation */ // NOTE: moved earlier ++// } else { ++// j = ix>>20; ++// // y[0] = r-w; // NOTE: moved earlier ++// i = j-(((*(i0+(int*)&y[0]))>>20)&0x7ff); ++// if(i>16) { /* 2nd iteration needed, good to 118 */ ++// t = r; ++// w = fn*pio2_2; ++// r = t-w; ++// w = fn*pio2_2t-((t-r)-w); ++// y[0] = r-w; ++// i = j-(((*(i0+(int*)&y[0]))>>20)&0x7ff); ++// if(i>49) { /* 3rd iteration need, 151 bits acc */ ++// t = r; /* will cover all possible cases */ ++// w = fn*pio2_3; ++// r = t-w; ++// w = fn*pio2_3t-((t-r)-w); ++// y[0] = r-w; ++// } ++// } ++// } ++// y[1] = (r-y[0])-w; ++// if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} ++// else return n; ++// } ++// /* ++// * all other (large) arguments ++// */ ++// // NOTE: this check is removed, because it was checked in dsin/dcos ++// // if(ix>=0x7ff00000) { /* x is inf or NaN */ ++// // y[0]=y[1]=x-x; return 0; ++// // } ++// /* set z = scalbn(|x|,ilogb(x)-23) */ ++// *(1-i0+(int*)&z) = *(1-i0+(int*)&x); ++// e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */ ++// *(i0+(int*)&z) = ix - (e0<<20); ++// ++// // NOTE: "for" loop below in unrolled. See comments in asm code ++// for(i=0;i<2;i++) { ++// tx[i] = (double)((int)(z)); ++// z = (z-tx[i])*two24A; ++// } ++// ++// tx[2] = z; ++// nx = 3; ++// ++// // NOTE: while(tx[nx-1]==zeroA) nx--; is unrolled. See comments in asm code ++// while(tx[nx-1]==zeroA) nx--; /* skip zero term */ ++// ++// n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi); ++// if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} ++// return n; ++//} ++// ++// END __ieee754_rem_pio2 PSEUDO CODE ++// ++// Changes between fdlibm and intrinsic for __ieee754_rem_pio2: ++// 1. INF/NaN check for huge argument is removed in comparison with fdlibm ++// code, because this check is already done in dcos/dsin code ++// 2. Most constants are now loaded from table instead of direct initialization ++// 3. Two loops are unrolled ++// Assumptions: ++// 1. Assume |X| >= PI/4 ++// 2. Assume rscratch1 = 0x3fe921fb00000000 (~ PI/4) ++// 3. Assume ix = i3 ++// Input and output: ++// 1. Input: X = i0 ++// 2. Return n in i2, y[0] == y0 == f4, y[1] == y1 == f5 ++// NOTE: general purpose register names match local variable names in C code ++// NOTE: fpu registers are actively reused. See comments in code about their usage ++void MacroAssembler::generate__ieee754_rem_pio2(address npio2_hw, ++ address two_over_pi, address pio2) { ++ ShouldNotReachHere(); ++} ++ ++///* ++// * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) ++// * double x[],y[]; int e0,nx,prec; int ipio2[]; ++// * ++// * __kernel_rem_pio2 return the last three digits of N with ++// * y = x - N*pi/2 ++// * so that |y| < pi/2. ++// * ++// * The method is to compute the integer (mod 8) and fraction parts of ++// * (2/pi)*x without doing the full multiplication. In general we ++// * skip the part of the product that are known to be a huge integer ( ++// * more accurately, = 0 mod 8 ). Thus the number of operations are ++// * independent of the exponent of the input. ++// * ++// * NOTE: 2/pi int representation is converted to double ++// * // (2/pi) is represented by an array of 24-bit integers in ipio2[]. ++// * ++// * Input parameters: ++// * x[] The input value (must be positive) is broken into nx ++// * pieces of 24-bit integers in double precision format. ++// * x[i] will be the i-th 24 bit of x. The scaled exponent ++// * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 ++// * match x's up to 24 bits. ++// * ++// * Example of breaking a double positive z into x[0]+x[1]+x[2]: ++// * e0 = ilogb(z)-23 ++// * z = scalbn(z,-e0) ++// * for i = 0,1,2 ++// * x[i] = floor(z) ++// * z = (z-x[i])*2**24 ++// * ++// * ++// * y[] ouput result in an array of double precision numbers. ++// * The dimension of y[] is: ++// * 24-bit precision 1 ++// * 53-bit precision 2 ++// * 64-bit precision 2 ++// * 113-bit precision 3 ++// * The actual value is the sum of them. Thus for 113-bit ++// * precsion, one may have to do something like: ++// * ++// * long double t,w,r_head, r_tail; ++// * t = (long double)y[2] + (long double)y[1]; ++// * w = (long double)y[0]; ++// * r_head = t+w; ++// * r_tail = w - (r_head - t); ++// * ++// * e0 The exponent of x[0] ++// * ++// * nx dimension of x[] ++// * ++// * prec an interger indicating the precision: ++// * 0 24 bits (single) ++// * 1 53 bits (double) ++// * 2 64 bits (extended) ++// * 3 113 bits (quad) ++// * ++// * NOTE: ipio2[] array below is converted to double representation ++// * //ipio2[] ++// * // integer array, contains the (24*i)-th to (24*i+23)-th ++// * // bit of 2/pi after binary point. The corresponding ++// * // floating value is ++// * ++// * ipio2[i] * 2^(-24(i+1)). ++// * ++// * Here is the description of some local variables: ++// * ++// * jk jk+1 is the initial number of terms of ipio2[] needed ++// * in the computation. The recommended value is 2,3,4, ++// * 6 for single, double, extended,and quad. ++// * ++// * jz local integer variable indicating the number of ++// * terms of ipio2[] used. ++// * ++// * jx nx - 1 ++// * ++// * jv index for pointing to the suitable ipio2[] for the ++// * computation. In general, we want ++// * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 ++// * is an integer. Thus ++// * e0-3-24*jv >= 0 or (e0-3)/24 >= jv ++// * Hence jv = max(0,(e0-3)/24). ++// * ++// * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. ++// * ++// * q[] double array with integral value, representing the ++// * 24-bits chunk of the product of x and 2/pi. ++// * ++// * q0 the corresponding exponent of q[0]. Note that the ++// * exponent for q[i] would be q0-24*i. ++// * ++// * PIo2[] double precision array, obtained by cutting pi/2 ++// * into 24 bits chunks. ++// * ++// * f[] ipio2[] in floating point ++// * ++// * iq[] integer array by breaking up q[] in 24-bits chunk. ++// * ++// * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] ++// * ++// * ih integer. If >0 it indicates q[] is >= 0.5, hence ++// * it also indicates the *sign* of the result. ++// * ++// */ ++// ++// Use PIo2 table(see stubRoutines_sw64.cpp) ++// ++// BEGIN __kernel_rem_pio2 PSEUDO CODE ++// ++//static int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, /* NOTE: converted to double */ const double *ipio2 // const int *ipio2) { ++// int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; ++// double z,fw,f[20],fq[20],q[20]; ++// ++// /* initialize jk*/ ++// // jk = init_jk[prec]; // NOTE: prec==2 for double. jk is always 4. ++// jp = jk; // NOTE: always 4 ++// ++// /* determine jx,jv,q0, note that 3>q0 */ ++// jx = nx-1; ++// jv = (e0-3)/24; if(jv<0) jv=0; ++// q0 = e0-24*(jv+1); ++// ++// /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ ++// j = jv-jx; m = jx+jk; ++// ++// // NOTE: split into two for-loops: one with zeroB and one with ipio2[j]. It ++// // allows the use of wider loads/stores ++// for(i=0;i<=m;i++,j++) f[i] = (j<0)? zeroB : /* NOTE: converted to double */ ipio2[j]; //(double) ipio2[j]; ++// ++// // NOTE: unrolled and vectorized "for". See comments in asm code ++// /* compute q[0],q[1],...q[jk] */ ++// for (i=0;i<=jk;i++) { ++// for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; ++// } ++// ++// jz = jk; ++//recompute: ++// /* distill q[] into iq[] reversingly */ ++// for(i=0,j=jz,z=q[jz];j>0;i++,j--) { ++// fw = (double)((int)(twon24* z)); ++// iq[i] = (int)(z-two24B*fw); ++// z = q[j-1]+fw; ++// } ++// ++// /* compute n */ ++// z = scalbnA(z,q0); /* actual value of z */ ++// z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ ++// n = (int) z; ++// z -= (double)n; ++// ih = 0; ++// if(q0>0) { /* need iq[jz-1] to determine n */ ++// i = (iq[jz-1]>>(24-q0)); n += i; ++// iq[jz-1] -= i<<(24-q0); ++// ih = iq[jz-1]>>(23-q0); ++// } ++// else if(q0==0) ih = iq[jz-1]>>23; ++// else if(z>=0.5) ih=2; ++// ++// if(ih>0) { /* q > 0.5 */ ++// n += 1; carry = 0; ++// for(i=0;i0) { /* rare case: chance is 1 in 12 */ ++// switch(q0) { ++// case 1: ++// iq[jz-1] &= 0x7fffff; break; ++// case 2: ++// iq[jz-1] &= 0x3fffff; break; ++// } ++// } ++// if(ih==2) { ++// z = one - z; ++// if(carry!=0) z -= scalbnA(one,q0); ++// } ++// } ++// ++// /* check if recomputation is needed */ ++// if(z==zeroB) { ++// j = 0; ++// for (i=jz-1;i>=jk;i--) j |= iq[i]; ++// if(j==0) { /* need recomputation */ ++// for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ ++// ++// for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ ++// f[jx+i] = /* NOTE: converted to double */ ipio2[jv+i]; //(double) ipio2[jv+i]; ++// for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; ++// q[i] = fw; ++// } ++// jz += k; ++// goto recompute; ++// } ++// } ++// ++// /* chop off zero terms */ ++// if(z==0.0) { ++// jz -= 1; q0 -= 24; ++// while(iq[jz]==0) { jz--; q0-=24;} ++// } else { /* break z into 24-bit if necessary */ ++// z = scalbnA(z,-q0); ++// if(z>=two24B) { ++// fw = (double)((int)(twon24*z)); ++// iq[jz] = (int)(z-two24B*fw); ++// jz += 1; q0 += 24; ++// iq[jz] = (int) fw; ++// } else iq[jz] = (int) z ; ++// } ++// ++// /* convert integer "bit" chunk to floating-point value */ ++// fw = scalbnA(one,q0); ++// for(i=jz;i>=0;i--) { ++// q[i] = fw*(double)iq[i]; fw*=twon24; ++// } ++// ++// /* compute PIo2[0,...,jp]*q[jz,...,0] */ ++// for(i=jz;i>=0;i--) { ++// for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; ++// fq[jz-i] = fw; ++// } ++// ++// // NOTE: switch below is eliminated, because prec is always 2 for doubles ++// /* compress fq[] into y[] */ ++// //switch(prec) { ++// //case 0: ++// // fw = 0.0; ++// // for (i=jz;i>=0;i--) fw += fq[i]; ++// // y[0] = (ih==0)? fw: -fw; ++// // break; ++// //case 1: ++// //case 2: ++// fw = 0.0; ++// for (i=jz;i>=0;i--) fw += fq[i]; ++// y[0] = (ih==0)? fw: -fw; ++// fw = fq[0]-fw; ++// for (i=1;i<=jz;i++) fw += fq[i]; ++// y[1] = (ih==0)? fw: -fw; ++// // break; ++// //case 3: /* painful */ ++// // for (i=jz;i>0;i--) { ++// // fw = fq[i-1]+fq[i]; ++// // fq[i] += fq[i-1]-fw; ++// // fq[i-1] = fw; ++// // } ++// // for (i=jz;i>1;i--) { ++// // fw = fq[i-1]+fq[i]; ++// // fq[i] += fq[i-1]-fw; ++// // fq[i-1] = fw; ++// // } ++// // for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; ++// // if(ih==0) { ++// // y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; ++// // } else { ++// // y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; ++// // } ++// //} ++// return n&7; ++//} ++// ++// END __kernel_rem_pio2 PSEUDO CODE ++// ++// Changes between fdlibm and intrinsic: ++// 1. One loop is unrolled and vectorized (see comments in code) ++// 2. One loop is split into 2 loops (see comments in code) ++// 3. Non-double code is removed(last switch). Sevaral variables became ++// constants because of that (see comments in code) ++// 4. Use of jx, which is nx-1 instead of nx ++// Assumptions: ++// 1. Assume |X| >= PI/4 ++// Input and output: ++// 1. Input: X = i0, jx == nx - 1 == i6, e0 == rscratch1 ++// 2. Return n in i2, y[0] == y0 == f4, y[1] == y1 == f5 ++// NOTE: general purpose register names match local variable names in C code ++// NOTE: fpu registers are actively reused. See comments in code about their usage ++void MacroAssembler::generate__kernel_rem_pio2(address two_over_pi, address pio2) { ++ ShouldNotReachHere(); ++} ++ ++///* __kernel_sin( x, y, iy) ++// * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854 ++// * Input x is assumed to be bounded by ~pi/4 in magnitude. ++// * Input y is the tail of x. ++// * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). ++// * ++// * Algorithm ++// * 1. Since sin(-x) = -sin(x), we need only to consider positive x. ++// * 2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0. ++// * 3. sin(x) is approximated by a polynomial of degree 13 on ++// * [0,pi/4] ++// * 3 13 ++// * sin(x) ~ x + S1*x + ... + S6*x ++// * where ++// * ++// * |sin(x) 2 4 6 8 10 12 | -58 ++// * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 ++// * | x | ++// * ++// * 4. sin(x+y) = sin(x) + sin'(x')*y ++// * ~ sin(x) + (1-x*x/2)*y ++// * For better accuracy, let ++// * 3 2 2 2 2 ++// * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) ++// * then 3 2 ++// * sin(x) = x + (S1*x + (x *(r-y/2)+y)) ++// */ ++//static const double ++//S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ ++//S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ ++//S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ ++//S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ ++//S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ ++//S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ ++// ++// NOTE: S1..S6 were moved into a table: StubRoutines::sw64::_dsin_coef ++// ++// BEGIN __kernel_sin PSEUDO CODE ++// ++//static double __kernel_sin(double x, double y, bool iy) ++//{ ++// double z,r,v; ++// ++// // NOTE: not needed. moved to dsin/dcos ++// //int ix; ++// //ix = high(x)&0x7fffffff; /* high word of x */ ++// ++// // NOTE: moved to dsin/dcos ++// //if(ix<0x3e400000) /* |x| < 2**-27 */ ++// // {if((int)x==0) return x;} /* generate inexact */ ++// ++// z = x*x; ++// v = z*x; ++// r = S2+z*(S3+z*(S4+z*(S5+z*S6))); ++// if(iy==0) return x+v*(S1+z*r); ++// else return x-((z*(half*y-v*r)-y)-v*S1); ++//} ++// ++// END __kernel_sin PSEUDO CODE ++// ++// Changes between fdlibm and intrinsic: ++// 1. Removed |x| < 2**-27 check, because if was done earlier in dsin/dcos ++// 2. Constants are now loaded from table dsin_coef ++// 3. C code parameter "int iy" was modified to "bool iyIsOne", because ++// iy is always 0 or 1. Also, iyIsOne branch was moved into ++// generation phase instead of taking it during code execution ++// Input ans output: ++// 1. Input for generated function: X argument = x ++// 2. Input for generator: x = register to read argument from, iyIsOne ++// = flag to use low argument low part or not, dsin_coef = coefficients ++// table address ++// 3. Return sin(x) value in f0 ++void MacroAssembler::generate_kernel_sin(FloatRegister x, bool iyIsOne, ++ address dsin_coef) { ++ ShouldNotReachHere(); ++} ++ ++///* ++// * __kernel_cos( x, y ) ++// * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 ++// * Input x is assumed to be bounded by ~pi/4 in magnitude. ++// * Input y is the tail of x. ++// * ++// * Algorithm ++// * 1. Since cos(-x) = cos(x), we need only to consider positive x. ++// * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. ++// * 3. cos(x) is approximated by a polynomial of degree 14 on ++// * [0,pi/4] ++// * 4 14 ++// * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x ++// * where the remez error is ++// * ++// * | 2 4 6 8 10 12 14 | -58 ++// * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 ++// * | | ++// * ++// * 4 6 8 10 12 14 ++// * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then ++// * cos(x) = 1 - x*x/2 + r ++// * since cos(x+y) ~ cos(x) - sin(x)*y ++// * ~ cos(x) - x*y, ++// * a correction term is necessary in cos(x) and hence ++// * cos(x+y) = 1 - (x*x/2 - (r - x*y)) ++// * For better accuracy when x > 0.3, let qx = |x|/4 with ++// * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. ++// * Then ++// * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)). ++// * Note that 1-qx and (x*x/2-qx) is EXACT here, and the ++// * magnitude of the latter is at least a quarter of x*x/2, ++// * thus, reducing the rounding error in the subtraction. ++// */ ++// ++//static const double ++//C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ ++//C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ ++//C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ ++//C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ ++//C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ ++//C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ ++// ++// NOTE: C1..C6 were moved into a table: StubRoutines::sw64::_dcos_coef ++// ++// BEGIN __kernel_cos PSEUDO CODE ++// ++//static double __kernel_cos(double x, double y) ++//{ ++// double a,h,z,r,qx=0; ++// ++// // NOTE: ix is already initialized in dsin/dcos. Reuse value from register ++// //int ix; ++// //ix = high(x)&0x7fffffff; /* ix = |x|'s high word*/ ++// ++// // NOTE: moved to dsin/dcos ++// //if(ix<0x3e400000) { /* if x < 2**27 */ ++// // if(((int)x)==0) return one; /* generate inexact */ ++// //} ++// ++// z = x*x; ++// r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); ++// if(ix < 0x3FD33333) /* if |x| < 0.3 */ ++// return one - (0.5*z - (z*r - x*y)); ++// else { ++// if(ix > 0x3fe90000) { /* x > 0.78125 */ ++// qx = 0.28125; ++// } else { ++// set_high(&qx, ix-0x00200000); /* x/4 */ ++// set_low(&qx, 0); ++// } ++// h = 0.5*z-qx; ++// a = one-qx; ++// return a - (h - (z*r-x*y)); ++// } ++//} ++// ++// END __kernel_cos PSEUDO CODE ++// ++// Changes between fdlibm and intrinsic: ++// 1. Removed |x| < 2**-27 check, because if was done earlier in dsin/dcos ++// 2. Constants are now loaded from table dcos_coef ++// Input and output: ++// 1. Input for generated function: X argument = x ++// 2. Input for generator: x = register to read argument from, dcos_coef ++// = coefficients table address ++// 2. Return cos(x) value in f0 ++void MacroAssembler::generate_kernel_cos(FloatRegister x, address dcos_coef) { ++ ShouldNotReachHere(); ++} ++ ++// generate_dsin_dcos creates stub for dsin and dcos ++// Generation is done via single call because dsin and dcos code is almost the ++// same(see C code below). These functions work as follows: ++// 1) handle corner cases: |x| ~< pi/4, x is NaN or INF, |x| < 2**-27 ++// 2) perform argument reduction if required ++// 3) call kernel_sin or kernel_cos which approximate sin/cos via polynomial ++// ++// BEGIN dsin/dcos PSEUDO CODE ++// ++//dsin_dcos(jdouble x, bool isCos) { ++// double y[2],z=0.0; ++// int n, ix; ++// ++// /* High word of x. */ ++// ix = high(x); ++// ++// /* |x| ~< pi/4 */ ++// ix &= 0x7fffffff; ++// if(ix <= 0x3fe921fb) return isCos ? __kernel_cos : __kernel_sin(x,z,0); ++// ++// /* sin/cos(Inf or NaN) is NaN */ ++// else if (ix>=0x7ff00000) return x-x; ++// else if (ix<0x3e400000) { /* if ix < 2**27 */ ++// if(((int)x)==0) return isCos ? one : x; /* generate inexact */ ++// } ++// /* argument reduction needed */ ++// else { ++// n = __ieee754_rem_pio2(x,y); ++// switch(n&3) { ++// case 0: return isCos ? __kernel_cos(y[0],y[1]) : __kernel_sin(y[0],y[1], true); ++// case 1: return isCos ? -__kernel_sin(y[0],y[1],true) : __kernel_cos(y[0],y[1]); ++// case 2: return isCos ? -__kernel_cos(y[0],y[1]) : -__kernel_sin(y[0],y[1], true); ++// default: ++// return isCos ? __kernel_sin(y[0],y[1],1) : -__kernel_cos(y[0],y[1]); ++// } ++// } ++//} ++// END dsin/dcos PSEUDO CODE ++// ++// Changes between fdlibm and intrinsic: ++// 1. Moved ix < 2**27 from kernel_sin/kernel_cos into dsin/dcos ++// 2. Final switch use equivalent bit checks(tbz/tbnz) ++// Input ans output: ++// 1. Input for generated function: X = i0 ++// 2. Input for generator: isCos = generate sin or cos, npio2_hw = address ++// of npio2_hw table, two_over_pi = address of two_over_pi table, ++// pio2 = address if pio2 table, dsin_coef = address if dsin_coef table, ++// dcos_coef = address of dcos_coef table ++// 3. Return result in f0 ++// NOTE: general purpose register names match local variable names in C code ++void MacroAssembler::generate_dsin_dcos(bool isCos, address npio2_hw, ++ address two_over_pi, address pio2, address dsin_coef, address dcos_coef) { ++ ShouldNotReachHere(); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/methodHandles_sw64.cpp afu11u/src/hotspot/cpu/sw64/methodHandles_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/methodHandles_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/methodHandles_sw64.cpp 2025-05-09 10:05:55.880290534 +0800 +@@ -0,0 +1,616 @@ ++/* ++ * 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.hpp" ++#include "classfile/javaClasses.inline.hpp" ++#include "interpreter/interpreter.hpp" ++#include "interpreter/interpreterRuntime.hpp" ++#include "memory/allocation.inline.hpp" ++#include "prims/methodHandles.hpp" ++#include "runtime/flags/flagSetting.hpp" ++#include "runtime/frame.inline.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 MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg) {SCOPEMARK_NAME(MethodHandles::load_klass_from_Class, _masm) ++ if (VerifyMethodHandles) ++ verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), ++ "MH argument is a Class"); ++ __ ldptr(klass_reg, Address(klass_reg, java_lang_Class::klass_offset_in_bytes())); ++} ++ ++#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, SystemDictionary::WKID klass_id, ++ const char* error_message) {SCOPEMARK_NAME(MethodHandles::verify_klass, _masm) ++ InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id); ++ Klass* klass = SystemDictionary::well_known_klass(klass_id); ++ Register temp = rdi; ++ Register temp2 = noreg; ++ temp2 = rscratch3; // used by MacroAssembler::cmpptr ++ Label L_ok, L_bad; ++ BLOCK_COMMENT("verify_klass {"); ++ __ verify_oop(obj); ++ __ jcc(Assembler::zero, L_bad, obj); ++ __ push(temp); if (temp2 != noreg) __ push(temp2); ++#define UNPUSH { if (temp2 != noreg) __ pop(temp2); __ pop(temp); } ++ __ load_klass(temp, obj); ++ __ cmpptr(temp, ExternalAddress((address) klass_addr)); ++ __ jcc(Assembler::equal, L_ok); ++ int super_check_offset = klass->super_check_offset(); //long-> int may be a problem? need modify? jzy ++ __ ldptr(temp, Address(temp, super_check_offset)); ++ __ cmpptr(temp, ExternalAddress((address) klass_addr)); ++ __ jcc(Assembler::equal, L_ok); ++ UNPUSH; ++ __ BIND(L_bad); ++ __ stop(error_message); ++ __ BIND(L_ok); ++ UNPUSH; ++ BLOCK_COMMENT("} verify_klass"); ++} ++ ++void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {SCOPEMARK_NAME(MethodHandles::verify_ref_kind, _masm) ++ Label L; ++ BLOCK_COMMENT("verify_ref_kind {"); ++ __ ldwu(temp, Address(member_reg, NONZERO(java_lang_invoke_MemberName::flags_offset_in_bytes()))); ++ __ srll(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT, temp); ++ __ andw(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK, temp); ++ __ cmpw(temp, ref_kind); ++ __ jcc(Assembler::equal, 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 temp, ++ bool for_compiler_entry) {SCOPEMARK_NAME(MethodHandles::jump_from_method_handle, _masm) ++ assert(method == rmethod, "interpreter calling convention"); ++ ++ Label L_no_such_method; ++ __ jcc(Assembler::zero, L_no_such_method, rmethod); ++ ++ __ verify_method_ptr(method); ++ ++ 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. ++ //Register rthread = rthread; ++ // interp_only is an int, on little endian it is sufficient to test the byte only ++ // Is a cmpl faster? ++ __ cmpb(Address(rthread, JavaThread::interp_only_mode_offset()), 0); ++ __ jcc(Assembler::zero, run_compiled_code); ++ __ jmp(Address(method, Method::interpreter_entry_offset())); ++ __ BIND(run_compiled_code); ++ } ++ ++ const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : ++ Method::from_interpreted_offset(); ++ __ jmp(Address(method, entry_offset)); ++ ++ __ bind(L_no_such_method); ++ __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); ++} ++ ++void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, ++ Register recv, Register method_temp, ++ Register temp2, ++ 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, rscratch3); ++ assert(recv != noreg, "required register"); ++ assert(method_temp == rmethod, "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(method_temp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())), temp2); ++ __ verify_oop(method_temp); ++ __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())), temp2); ++ __ verify_oop(method_temp); ++ __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())), temp2); ++ __ verify_oop(method_temp); ++ __ access_load_at(T_ADDRESS, IN_HEAP, method_temp, ++ Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())), ++ noreg, noreg); ++ ++ if (VerifyMethodHandles && !for_compiler_entry) { ++ // make sure recv is already on stack ++ __ ldptr(temp2, Address(method_temp, Method::const_offset())); ++ __ load_sized_value(temp2, ++ Address(temp2, ConstMethod::size_of_parameters_offset()), ++ sizeof(u2), /*is_signed*/ false); ++ // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); ++ Label L; ++ __ ldl(rscratch3, __ argument_address(temp2, -1)); ++ __ cmpoop(recv, rscratch3); ++ __ jcc(Assembler::equal, L); ++ __ ldptr(V0, __ argument_address(temp2, -1)); ++ __ stop("receiver not on stack"); ++ __ BIND(L); ++ } ++ ++ jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); ++ BLOCK_COMMENT("} jump_to_lambda_form"); ++} ++ ++ ++// Code generation ++address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm, ++ vmIntrinsics::ID iid) {SCOPEMARK_NAME(MethodHandles::generate_method_handle_interpreter_entry, _masm) ++ 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. ++ __ stop("empty stubs make SG sick"); ++ return NULL; ++ } ++ ++ // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) ++ // rbx: Method* ++ // rdx: argument locator (parameter slot count, added to rsp) ++ // rcx: used as temp to hold mh or receiver ++ // rax, rdi: garbage temps, blown away ++ Register rdx_argp = rdx; // argument list ptr, live on error paths ++ Register rax_temp = rax; ++ Register rcx_mh = rcx; // MH receiver; dies quickly and is recycled ++ Register rbx_method = rbx; // eventual target of this invocation ++ //Register rcx = c_rarg3; ++ // 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 {"); ++ __ movw(rscratch3, (int)iid); ++ __ cmpw(Address(rbx_method, Method::intrinsic_id_offset_in_bytes()), rscratch3); ++ __ jcc(Assembler::equal, 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 rdx_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)) { ++ __ ldptr(rdx_argp, Address(rbx_method, Method::const_offset())); ++ __ load_sized_value(rdx_argp, ++ Address(rdx_argp, ConstMethod::size_of_parameters_offset()), ++ sizeof(u2), /*is_signed*/ false); ++ // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); ++ rdx_first_arg_addr = __ argument_address(rdx_argp, -1); ++ } else { ++ DEBUG_ONLY(rdx_argp = noreg); ++ } ++ ++ if (!is_signature_polymorphic_static(iid)) { ++ __ ldptr(rcx_mh, rdx_first_arg_addr); ++ DEBUG_ONLY(rdx_argp = noreg); ++ } ++ ++ // rdx_first_arg_addr is live! ++ ++ trace_method_handle_interpreter_entry(_masm, iid); ++ ++ if (iid == vmIntrinsics::_invokeBasic) { ++ generate_method_handle_dispatch(_masm, iid, rcx_mh, noreg, not_for_compiler_entry); ++ ++ } else { ++ // Adjust argument list by popping the trailing MemberName argument. ++ Register rcx_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. ++ __ ldptr(rcx_recv = rcx, rdx_first_arg_addr); ++ } ++ DEBUG_ONLY(rdx_argp = noreg); ++ Register rbx_member = rbx_method; // MemberName ptr; incoming method ptr is dead now ++ //TODO:__ stop("check:generate_method_handle_interpreter_entry jzy"); ++ //__ pop(rax_temp); // return address ++ __ pop(rbx_member); // extract last argument ++ //__ push(rax_temp); // re-push return address ++ generate_method_handle_dispatch(_masm, iid, rcx_recv, rbx_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) {SCOPEMARK_NAME(MethodHandles::generate_method_handle_dispatch, _masm) ++ assert(is_signature_polymorphic(iid), "expected invoke iid"); ++ Register rbx_method = rbx; // eventual target of this invocation ++ // temps used in this code are not used in *either* compiled or interpreted calling sequences ++ ++ Register temp1 = rscratch1; ++ Register temp2 = rscratch2; ++ Register temp3 = rax; ++ if (for_compiler_entry) { ++ assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0), "only valid assignment"); ++ assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); ++ assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); ++ assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); ++ } ++ else { ++ assert_different_registers(temp1, temp2, temp3, saved_last_sp_register()); // don't trash lastSP ++ } ++ assert_different_registers(temp1, temp2, temp3, receiver_reg); ++ assert_different_registers(temp1, temp2, temp3, member_reg); ++ ++ if (iid == vmIntrinsics::_invokeBasic) { ++ // indirect through MH.form.vmentry.vmtarget ++ jump_to_lambda_form(_masm, receiver_reg, rbx_method, temp1, 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(java_lang_invoke_MemberName), ++ "MemberName required for invokeVirtual etc."); ++ } ++ //TODO:__ stop("generate_method_handle_dispatch check:jzy"); ++ 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( rbx_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(temp1_recv_klass, receiver_reg); ++ __ 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(temp1_recv_klass, receiver_reg); ++ __ verify_klass_ptr(temp1_recv_klass); ++ } ++ if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { ++ Label L_ok; ++ Register temp2_defc = temp2; ++ __ load_heap_oop(temp2_defc, member_clazz, temp3); ++ load_klass_from_Class(_masm, temp2_defc); ++ __ verify_klass_ptr(temp2_defc); ++ __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, 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 ++ // rsi/r13 - interpreter linkage (if interpreted) ++ // rcx, rdx, rsi, rdi, r8 - 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, temp3); ++ } ++ __ load_heap_oop(rbx_method, member_vmtarget); ++ __ access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg, noreg); ++ break; ++ ++ case vmIntrinsics::_linkToStatic: ++ if (VerifyMethodHandles) { ++ verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); ++ } ++ __ load_heap_oop(rbx_method, member_vmtarget); ++ __ access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg, noreg); ++ 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, temp3); ++ } ++ ++ // pick out the vtable index from the MemberName, and then we can discard it: ++ Register temp2_index = temp2; ++ __ access_load_at(T_ADDRESS, IN_HEAP, temp2_index, member_vmindex, noreg, noreg); ++ ++ if (VerifyMethodHandles) { ++ Label L_index_ok; ++ __ cmpw(temp2_index, 0); ++ __ jcc(Assembler::greaterEqual, 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, rbx_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, temp3); ++ } ++ ++ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ Register temp3_intf = temp3; ++ __ load_heap_oop(temp3_intf, member_clazz); ++ load_klass_from_Class(_masm, temp3_intf); ++ __ verify_klass_ptr(temp3_intf); ++ ++ Register rbx_index = rbx_method; ++ __ access_load_at(T_ADDRESS, IN_HEAP, rbx_index, member_vmindex, noreg, noreg); ++ if (VerifyMethodHandles) { ++ Label L; ++ __ cmpw(rbx_index, 0); ++ __ jcc(Assembler::greaterEqual, 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, temp3_intf, ++ // note: next two args must be the same: ++ rbx_index, rbx_method, ++ temp2, ++ L_incompatible_class_change_error); ++ break; ++ } ++ ++ default: ++ fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); ++ break; ++ } ++ ++ // Live at this point: ++ // rbx_method ++ // rsi/r13 (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(rbx_method); ++ jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry); ++ ++ if (iid == vmIntrinsics::_linkToInterface) { ++ __ bind(L_incompatible_class_change_error); ++ __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); ++ } ++ } ++} ++ ++#ifndef PRODUCT ++void trace_method_handle_stub(const char* adaptername, ++ oop mh, ++ intptr_t* saved_regs, ++ intptr_t* entry_sp) { ++ // called as a leaf from native code: do not block the JVM! ++ bool has_mh = (strstr(adaptername, "/static") == NULL && ++ strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH ++ const char* mh_reg_name = has_mh ? "rcx_mh" : "rcx"; ++ tty->print_cr("MH %s %s=" PTR_FORMAT " sp=" PTR_FORMAT, ++ adaptername, mh_reg_name, ++ p2i(mh), p2i(entry_sp)); ++ ++ if (Verbose) { ++ tty->print_cr("Registers:"); ++ const int saved_regs_count = RegisterImpl::number_of_registers; ++ for (int i = 0; i < saved_regs_count; i++) { ++ Register r = as_Register(i); ++ // The registers are stored in reverse order on the stack (by pusha). ++ tty->print("%3s=" PTR_FORMAT, r->name(), saved_regs[((saved_regs_count - 1) - i)]); ++ if ((i + 1) % 4 == 0) { ++ tty->cr(); ++ } else { ++ tty->print(", "); ++ } ++ } ++ tty->cr(); ++ ++ { ++ // 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 PC on the stack top (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 ++ ++ // Current C frame ++ frame cur_frame = os::current_frame(); ++ ++ // Robust search of trace_calling_frame (independant of inlining). ++ // Assumes saved_regs comes from a pusha in the trace_calling_frame. ++ assert(cur_frame.sp() < saved_regs, "registers not saved on stack ?"); ++ frame trace_calling_frame = os::get_sender_for_C_frame(&cur_frame); ++ while (trace_calling_frame.fp() < saved_regs) { ++ trace_calling_frame = os::get_sender_for_C_frame(&trace_calling_frame); ++ } ++ ++ // safely create a frame and call frame::describe ++ intptr_t *dump_sp = trace_calling_frame.sender_sp(); ++ intptr_t *dump_fp = trace_calling_frame.link(); ++ ++ bool walkable = has_mh; // whether the traced frame shoud be walkable ++ ++ 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, dump_fp); ++ dump_frame.describe(values, 1); ++ } else { ++ // Stack may not be walkable (invalid PC above FP): ++ // Add descriptions without building a Java frame to avoid issues ++ values.describe(-1, dump_fp, "fp for #1 "); ++ values.describe(-1, dump_sp, "sp for #1"); ++ } ++ values.describe(-1, entry_sp, "raw top of stack"); ++ ++ 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(); ++ } ++} ++ } ++} ++ ++// The stub wraps the arguments in a struct on the stack to avoid ++// dealing with the different calling conventions for passing 6 ++// arguments. ++struct MethodHandleStubArguments { ++ const char* adaptername; ++ oopDesc* mh; ++ intptr_t* saved_regs; ++ intptr_t* entry_sp; ++}; ++void trace_method_handle_stub_wrapper(MethodHandleStubArguments* args) { ++ trace_method_handle_stub(args->adaptername, ++ args->mh, ++ args->saved_regs, ++ args->entry_sp); ++} ++ ++void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {SCOPEMARK_NAME(MethodHandles::trace_method_handle, _masm) ++ if (!TraceMethodHandles) return;Unimplemented(); ++ BLOCK_COMMENT(err_msg("trace_method_handle %s {", adaptername)); ++ Register rbx = R0; //? jzy ++ __ stop("check: trace_method_handle jzy"); ++ __ enter(); ++ __ andptr(esp, -16, esp); // align stack if needed for FPU state ++ __ pushad(); ++ __ movl(r12_heapbase, esp); // for retreiving saved_regs ++ // Note: saved_regs must be in the entered frame for the ++ // robust stack walking implemented in trace_method_handle_stub. ++ ++ // save FP result, valid at some call sites (adapter_opt_return_float, ...) ++ __ increment(esp, -2 * wordSize); ++ __ store_double(FSF, Address(esp, 0)); ++ ++ // Incoming state: ++ // rcx: method handle ++ // ++ // To avoid calling convention issues, build a record on the stack ++ // and pass the pointer to that instead. ++ Register rbp = rfp; ++ Register rcx = R0; //? jzy ++ __ push(rbp); // entry_sp (with extra align space) ++ __ push(rbx); // pusha saved_regs ++ __ push(rcx); // mh ++ __ push(rcx); // slot for adaptername ++ __ mov_immediate64(rscratch1, (intptr_t) adaptername); ++ __ stptr(rscratch1, Address(esp, 0)); ++ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub_wrapper), esp); ++ __ increment(esp, sizeof(MethodHandleStubArguments)); ++ ++ __ load_double(FSF, Address(esp, 0)); ++ __ increment(esp, 2 * wordSize); ++ ++ __ popad(); ++ __ leave(); ++ BLOCK_COMMENT("} trace_method_handle"); ++} ++#endif //PRODUCT +diff -uNr openjdk/src/hotspot/cpu/sw64/methodHandles_sw64.hpp afu11u/src/hotspot/cpu/sw64/methodHandles_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/methodHandles_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/methodHandles_sw64.hpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++// Platform-specific definitions for method handles. ++// These definitions are inlined into class MethodHandles. ++ ++// Adapters ++enum /* platform_dependent_constants */ { ++ adapter_code_size = 32000 DEBUG_ONLY(+ 150000) ++}; ++ ++public: ++ ++ static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg); ++ ++ static void verify_klass(MacroAssembler* _masm, ++ Register obj, SystemDictionary::WKID klass_id, ++ const char* error_message = "wrong klass") NOT_DEBUG_RETURN; ++ ++ static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) { ++ verify_klass(_masm, mh_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MethodHandle), ++ "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, ++ bool for_compiler_entry); ++ ++ static void jump_to_lambda_form(MacroAssembler* _masm, ++ Register recv, Register method_temp, ++ Register temp2, ++ bool for_compiler_entry); ++ ++ static Register saved_last_sp_register() { ++ // Should be in sharedRuntime, not here. ++ return i29; ++ } +diff -uNr openjdk/src/hotspot/cpu/sw64/nativeInst_sw64.cpp afu11u/src/hotspot/cpu/sw64/nativeInst_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/nativeInst_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/nativeInst_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,773 @@ ++/* ++ * 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 "jvm.h" ++#include "asm/macroAssembler.hpp" ++#include "classfile/javaClasses.inline.hpp" ++#include "interpreter/interpreter.hpp" ++#include "interpreter/interpreterRuntime.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" ++ ++#include ++ ++#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 ":") ++ ++int NativeCall::instruction_size = 5 * BytesPerInstWord; ++int NativeCall::return_address_offset = 5 * BytesPerInstWord; ++int NativeJump::instruction_size = 5 * BytesPerInstWord; ++int NativeJump::next_instruction_offset = 5 * BytesPerInstWord; ++ ++void NativeInstruction::imm48_split(long imm48, int16_t &msb_l, int16_t &lsb_h, int16_t &lsb_l) { ++ int32_t lsb32 = (int32_t) ((intptr_t) imm48); ++ int32_t msb32 = (int32_t) (((intptr_t) imm48 - lsb32) >> 32); ++ ++ msb_l = (int16_t) msb32; ++ lsb_h = (lsb32 - (int16_t) lsb32) >> 16; ++ lsb_l = (int16_t) lsb32; ++ guarantee((msb_l >= 0x0 && msb_l < 0x7fff) || (msb_l == 0x7fff && lsb32 >= 0x0 && lsb32 < 0x7fff8000), "wrong number in li48 "); ++ if (lsb32 >= 0x7fff8000) ++ msb_l = msb_l + 1; ++} ++ ++//void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg) { ++// if (VerifyMethodHandles) ++// verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), ++// "MH argument is a Class"); ++// __ ldptr(klass_reg, Address(klass_reg, java_lang_Class::klass_offset_in_bytes())); ++//} ++ ++ ++/** ++ * x86 ++ * NativeInstruction::set_ptr_at(data_offset, x) ++ * sw64 ++ * NativeInstruction::set_address(address dest) ++ * note ++ * x86 call/jmp 64bits destination embedded following the opcodes ++ * sw64 call/jmp 48bits destination split in the disp in the ldi/sll/ldih/ldi sequence ++ */ ++void NativeInstruction::set_address(address dest) { ++// Unimplemented(); ++ if (SafePatch) { ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl)) { ++ set_long_at(8, (long) dest); ++ } else if (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi)) { ++ set_long_at(4, (long) dest); ++ } else { ++ tty->print_cr("\nError!\nset_address: 0x%lx", addr_at(0)); ++ Disassembler::decode(addr_at(0) - 10 * 4, addr_at(0) + 10 * 4, tty); ++ fatal("not a call "); ++ } ++ } else { ++ OrderAccess::fence(); ++ int16_t msb_l, lsb_h, lsb_l; ++ NativeInstruction::imm48_split((long) dest, msb_l, lsb_h, lsb_l); ++ /* li48 or li64 */ ++ if (is_op(int_at(0), Assembler::op_ldi) && is_op(int_at(4), Assembler::op_slll_l)) { ++ int first_word = int_at(0); ++ set_int_at(0, 0x13FFFFFF); /* .1: br .1 */ ++ set_int_at(8, (int_at(8) & 0xffff0000) | (lsb_h & 0xffff)); ++ set_int_at(12, (int_at(12) & 0xffff0000) | (lsb_l & 0xffff)); ++ set_int_at(0, (first_word & 0xffff0000) | (msb_l & 0xffff)); ++ ++ // ICache::invalidate_range(addr_at(0), 16); ++ } else if (is_op(int_at(0), Assembler::op_ldih) && is_op(int_at(8), Assembler::op_slll_l)) { ++ Unimplemented(); ++ } else { ++ fatal("not a call "); ++ } ++ } ++} ++ ++void NativeInstruction::set_long_at(int offset, long i) { ++ address addr = addr_at(offset); ++ *(long *) addr = i; ++} ++ ++void NativeInstruction::wrote(int offset) { ++ //ICache::invalidate_word(addr_at(offset)); ++} ++ ++void NativeLoadGot::report_and_fail() const { ++ tty->print_cr("Addr: " INTPTR_FORMAT, p2i(instruction_address())); ++ fatal("not a indirect rip mov to rbx"); ++} ++ ++void NativeLoadGot::verify() const { ++ if (has_rex) { ++ int rex = ubyte_at(0); ++ if (rex != rex_prefix) { ++ report_and_fail(); ++ } ++ } ++ ++ int inst = ubyte_at(rex_size); ++ if (inst != instruction_code) { ++ report_and_fail(); ++ } ++ int modrm = ubyte_at(rex_size + 1); ++ if (modrm != modrm_rbx_code && modrm != modrm_rax_code) { ++ report_and_fail(); ++ } ++} ++ ++intptr_t NativeLoadGot::data() const { ++ Unimplemented(); ++ return *(intptr_t *) got_address(); ++} ++ ++address NativePltCall::destination() const { ++ ShouldNotReachHere(); ++ NativeGotJump* jump = nativeGotJump_at(plt_jump()); ++ return jump->destination(); ++} ++ ++address NativePltCall::plt_entry() const { ++ ShouldNotReachHere(); ++ return return_address() + displacement(); ++ } ++ ++address NativePltCall::plt_jump() const { ++ ShouldNotReachHere(); ++ address entry = plt_entry(); ++ // Virtual PLT code has move instruction first ++ if (((NativeGotJump*)entry)->is_GotJump()) { ++ return entry; ++ } else { ++ return nativeLoadGot_at(entry)->next_instruction_address(); ++ } ++} ++ ++address NativePltCall::plt_load_got() const { ++ ShouldNotReachHere(); ++ address entry = plt_entry(); ++ if (!((NativeGotJump*)entry)->is_GotJump()) { ++ // Virtual PLT code has move instruction first ++ return entry; ++ } else { ++ // Static PLT code has move instruction second (from c2i stub) ++ return nativeGotJump_at(entry)->next_instruction_address(); ++ } ++} ++ ++address NativePltCall::plt_c2i_stub() const { ++ ShouldNotReachHere(); ++ address entry = plt_load_got(); ++ // This method should be called only for static calls which has C2I stub. ++ NativeLoadGot* load = nativeLoadGot_at(entry); ++ return entry; ++} ++ ++address NativePltCall::plt_resolve_call() const { ++ ShouldNotReachHere(); ++ NativeGotJump* jump = nativeGotJump_at(plt_jump()); ++ address entry = jump->next_instruction_address(); ++ if (((NativeGotJump*)entry)->is_GotJump()) { ++ return entry; ++ } else { ++ // c2i stub 2 instructions ++ entry = nativeLoadGot_at(entry)->next_instruction_address(); ++ return nativeGotJump_at(entry)->next_instruction_address(); ++} ++} ++ ++void NativePltCall::reset_to_plt_resolve_call() { ++ set_destination_mt_safe(plt_resolve_call()); ++} ++ ++void NativePltCall::set_destination_mt_safe(address dest) { ++ ShouldNotReachHere(); ++ // rewriting the value in the GOT, it should always be aligned ++ NativeGotJump* jump = nativeGotJump_at(plt_jump()); ++ address* got = (address *) jump->got_address(); ++ *got = dest; ++} ++ ++void NativePltCall::set_stub_to_clean() { ++ ShouldNotReachHere(); ++ NativeLoadGot* method_loader = nativeLoadGot_at(plt_c2i_stub()); ++ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address()); ++ method_loader->set_data(0); ++ jump->set_jump_destination((address)-1); ++} ++ ++void NativePltCall::verify() const { ++ ShouldNotReachHere(); ++ // Make sure code pattern is actually a call rip+off32 instruction. ++ int inst = ubyte_at(0); ++ if (inst != instruction_code) { ++ tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()), ++ inst); ++ fatal("not a call rip+off32"); ++ } ++} ++ ++address NativeGotJump::destination() const { ++ ShouldNotReachHere(); ++ address *got_entry = (address *) got_address(); ++ return *got_entry; ++} ++ ++void NativeGotJump::verify() const { ++ ShouldNotReachHere(); ++ int inst = ubyte_at(0); ++ if (inst != instruction_code) { ++ tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()), ++ inst); ++ fatal("not a indirect rip jump"); ++ } ++} ++ ++void NativeCall::verify() { ++ NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++ NativeInstruction* call = nativeInstruction_at(addr_at(0) + NativeCall::instruction_size - 4); ++ ++ if (mov->is_mov_ptr() && call->is_call_reg()) return; ++ ++ fatal("not a call instruction"); ++} ++ ++address NativeCall::destination() const { ++ if (SafePatch) { ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl)) { ++ return (address) long_at(8); ++ } else if (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi)) { ++ return (address) long_at(4); ++ } else { ++ tty->print_cr("\nError!\ndestination: 0x%lx", addr_at(0)); ++ Disassembler::decode(addr_at(0) - 10 * 4, addr_at(0) + 10 * 4, tty); ++ fatal("not a call "); ++ } ++ } else { ++ NativeMovConstReg *mov = nativeMovConstReg_at(addr_at(0)); ++ return (address) mov->data(); ++ } ++} ++ ++void NativeCall::print() { ++ tty->print_cr(PTR_FORMAT ": call " PTR_FORMAT, ++ p2i(instruction_address()), p2i(destination())); ++} ++ ++// Inserts a native call instruction at a given pc ++void NativeCall::insert(address code_pos, address entry) { ++ NativeCall *call = nativeCall_at(code_pos); ++ CodeBuffer cb(call->addr_at(0), instruction_size); ++ MacroAssembler masm(&cb); ++#define __ masm. ++ if (SafePatch) { ++ if (__ offset() % 8 == 0) { ++ __ nop(); ++ __ br(T12, 2); ++ __ emit_int64((long) entry); ++ __ ldl(T12, 0, T12); ++ } else { ++ __ br(T12, 2); ++ __ emit_int64((long) entry); ++ __ ldl(T12, 0, T12); ++ __ nop(); ++ } ++ } else { ++ __ prepare_patch_li48(T12, (long) entry); ++ } ++ __ call(T12); ++#undef __ ++ ++ // ICache::invalidate_range(call->addr_at(0), instruction_size); ++} ++ ++// MT-safe patching of a call instruction. ++// First patches first word of instruction to two jmp's that jmps to them ++// selfs (spinlock). Then patches the last byte, and then atomicly replaces ++// the jmp's with the first 4 byte of the new instruction. ++void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { ++ Unimplemented(); ++ 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 ++ if (os::is_MP()) { ++ guarantee((intptr_t)instr_addr % BytesPerWord == 0, "must be aligned"); ++ } ++ ++ // First patch dummy jmp in place ++ unsigned char patch[4]; ++ assert(sizeof(patch)==sizeof(jint), "sanity check"); ++ patch[0] = 0xEB; // jmp rel8 ++ patch[1] = 0xFE; // jmp to self ++ patch[2] = 0xEB; ++ patch[3] = 0xFE; ++ ++ // First patch dummy jmp in place ++ *(jint*)instr_addr = *(jint *)patch; ++ ++ // Invalidate. Opteron requires a flush after every write. ++ n_call->wrote(0); ++ ++ // Patch 4th byte ++ instr_addr[4] = code_buffer[4]; ++ ++ n_call->wrote(4); ++ ++ // Patch bytes 0-3 ++ *(jint*)instr_addr = *(jint *)code_buffer; ++ ++ n_call->wrote(0); ++ ++#ifdef ASSERT ++ // verify patching ++ for ( int i = 0; i < instruction_size; i++) { ++ address ptr = (address)((intptr_t)code_buffer + i); ++ int a_byte = (*ptr) & 0xFF; ++ assert(*((address)((intptr_t)instr_addr + i)) == a_byte, "mt safe patching failed"); ++ } ++#endif ++ ++} ++ ++ ++// 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. If the displacement field is aligned ++// we can simply rely on atomicity of 32-bit writes to make sure other threads ++// will see no intermediate states. Otherwise, the first two bytes of the ++// call are guaranteed to be aligned, and can be atomically patched to a ++// self-loop to guard the instruction while we change the other bytes. ++ ++// We cannot rely on locks here, since the free-running threads must run at ++// full speed. ++// ++// Used in the runtime linkage of calls; see class CompiledIC. ++// (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) ++void NativeCall::set_destination_mt_safe(address dest) {//Unimplemented(); ++ set_destination(dest); ++} ++ ++ ++void NativeMovConstReg::verify() { ++ if (is_op(int_at(0), Assembler::op_ldih) && ++ is_op(int_at(4), Assembler::op_ldi) && ++ is_op(int_at(8), Assembler::op_slll_l) && ++ is_op(int_at(12), Assembler::op_ldih) && ++ is_op(int_at(16), Assembler::op_ldi)) { ++ return; ++ } ++ ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_slll_l) && ++ is_op(int_at(8), Assembler::op_ldih) && ++ is_op(int_at(12), Assembler::op_ldi)) { ++ return; ++ } ++ ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl)) { ++ return; ++ } ++ if (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi)) { ++ return; ++ } ++ if (!nativeInstruction_at(addr_at(0))->is_mov_ptr()) { ++ print(); ++ fatal("not a mov reg64, ptr"); ++ } ++} ++ ++ ++void NativeMovConstReg::print() { ++ tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT, ++ p2i(instruction_address()), data()); ++} ++ ++//------------------------------------------------------------------- ++ ++int NativeMovRegMem::instruction_start() const { ++ Unimplemented(); ++ int off = 0; ++ u_char instr_0 = ubyte_at(off); ++ return off; ++} ++ ++int NativeMovRegMem::patch_offset() const { ++ int off = data_offset + instruction_start(); ++ u_char mod_rm = *(u_char*)(instruction_address() + 1); ++ // nnnn(r12|rsp) isn't coded as simple mod/rm since that is ++ // the encoding to use an SIB byte. Which will have the nnnn ++ // field off by one byte ++ if ((mod_rm & 7) == 0x4) { ++ off++; ++ } ++ return off; ++} ++ ++void NativeMovRegMem::verify() {Unimplemented(); ++ // make sure code pattern is actually a mov [reg+offset], reg instruction ++ u_char test_byte = *(u_char*)instruction_address(); ++ switch (test_byte) { ++ case instruction_code_reg2memb: // 0x88 movb a, r ++ case instruction_code_reg2mem: // 0x89 movl a, r (can be movq in 64bit) ++ case instruction_code_mem2regb: // 0x8a movb r, a ++ case instruction_code_mem2reg: // 0x8b movl r, a (can be movq in 64bit) ++ break; ++ ++ case instruction_code_mem2reg_movslq: // 0x63 movsql r, a ++ case instruction_code_mem2reg_movzxb: // 0xb6 movzbl r, a (movzxb) ++ case instruction_code_mem2reg_movzxw: // 0xb7 movzwl r, a (movzxw) ++ case instruction_code_mem2reg_movsxb: // 0xbe movsbl r, a (movsxb) ++ case instruction_code_mem2reg_movsxw: // 0xbf movswl r, a (movsxw) ++ break; ++ ++ case instruction_code_float_s: // 0xd9 fld_s a ++ case instruction_code_float_d: // 0xdd fld_d a ++ case instruction_code_xmm_load: // 0x10 movsd xmm, a ++ case instruction_code_xmm_store: // 0x11 movsd a, xmm ++ case instruction_code_xmm_lpd: // 0x12 movlpd xmm, a ++ break; ++ ++ case instruction_code_lea: // 0x8d lea r, a ++ break; ++ ++ default: ++ fatal ("not a mov [reg+offs], reg instruction"); ++ } ++} ++ ++ ++void NativeMovRegMem::print() { ++ tty->print_cr(PTR_FORMAT ": mov reg, [reg + %x]", p2i(instruction_address()), offset()); ++} ++ ++//------------------------------------------------------------------- ++ ++void NativeLoadAddress::verify() { ++ // make sure code pattern is actually a mov [reg+offset], reg instruction ++ /*u_char test_byte = *(u_char*)instruction_address(); ++ ++ if ( (test_byte == instruction_prefix_wide || ++ test_byte == instruction_prefix_wide_extended) ) { ++ test_byte = *(u_char*)(instruction_address() + 1); ++ } ++ ++ if ( ! ((test_byte == lea_instruction_code) ++ LP64_ONLY(|| (test_byte == mov64_instruction_code) ))) { ++ fatal ("not a lea reg, [reg+offs] instruction"); ++ }*/ ++} ++ ++ ++void NativeLoadAddress::print() { ++ tty->print_cr(PTR_FORMAT ": lea [reg + %x], reg", p2i(instruction_address()), offset()); ++} ++ ++//-------------------------------------------------------------------------------- ++ ++void NativeJump::verify() { ++ NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++ // -4 because not include jmp instruction ++ NativeInstruction* jmp = nativeInstruction_at(addr_at(0) + NativeJump::instruction_size - 4); ++ ++ if (mov->is_mov_ptr() && jmp->is_jump_reg()) return; ++ ++ fatal("not a jump instruction"); ++} ++ ++bool NativeInstruction::is_sigill_zombie_not_entrant() { ++ return int_at(0) == NativeIllegalInstruction::instruction_code; ++} ++void NativeJump::insert(address code_pos, address entry) { ++ Unimplemented(); ++// intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4); ++// ++// guarantee(disp == (intptr_t)(int32_t)disp, "must be 32-bit offset"); ++// ++// *code_pos = instruction_code; ++// *((int32_t*)(code_pos + 1)) = (int32_t)disp; ++// ++// ICache::invalidate_range(code_pos, instruction_size); ++} ++ ++void NativeJump::check_verified_entry_alignment(address entry, address verified_entry) { ++ //Unimplemented(); ++ // Patching to not_entrant can happen while activations of the method are ++ // in use. The patching in that instance must happen only when certain ++ // alignment restrictions are true. These guarantees check those ++ // conditions. ++ ++ const int linesize = 64; ++ ++ // Must be wordSize aligned ++ guarantee(((uintptr_t) verified_entry & (wordSize -1)) == 0, ++ "illegal address for code patching 2"); ++ // First 5 bytes must be within the same cache line - 4827828 ++ guarantee((uintptr_t) verified_entry / linesize == ++ ((uintptr_t) verified_entry + 4) / linesize, ++ "illegal address for code patching 3"); ++} ++ ++// manual implementation of stl ++// ++// 00000001200009c0 : ++// 0: 10 01 11 42 addq a0,a1,a0 ++// 4: 00 00 50 ae stq a2,0(a0) ++// 8: 01 00 fa 0b ret zero,(ra),0x1 ++// c: 5f 07 ff 43 nop(excb) ++// ++typedef void (* atomic_store64_ptr)(long *addr, int offset, long data64); ++ ++static int *buf; ++static atomic_store64_ptr get_atomic_store64_func() { ++ static atomic_store64_ptr p = NULL; ++ if (p != NULL) ++ return p; ++ ++ buf = (int *)mmap(NULL, 64, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, ++ -1, 0); ++ buf[0] = 0x42110110; ++ buf[1] = 0xae500000; /* stq $a2, 0($a0) */ ++ buf[2] = 0x0bfa0001; ++ buf[3] = 0x43ff075f; /* nop */ ++ ++ p = (atomic_store64_ptr)buf; ++ return p; ++} ++ ++// MT safe inserting of a jump over an unknown instruction sequence (used by nmethod::makeZombie) ++// The problem: jmp is a 5-byte instruction. Atomical write can be only with 4 bytes. ++// First patches the first word atomically to be a jump to itself. ++// Then patches the last byte and then atomically patches the first word (4-bytes), ++// thus inserting the desired jump ++// This code is mt-safe with the following conditions: entry point is 4 byte aligned, ++// entry point is in same cache line as unverified entry point, and the instruction being ++// patched is >= 5 byte (size of patch). ++// ++// In C2 the 5+ byte sized instruction is enforced by code in MachPrologNode::emit. ++// In C1 the restriction is enforced by CodeEmitter::method_entry ++// In JVMCI, the restriction is enforced by HotSpotFrameContext.enter(...) ++// ++void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { ++ ++ // ensure 100% atomicity. ++ // The destination is fixed and can be cached in JavaThread. ++ ++ guarantee(dest == SharedRuntime::get_handle_wrong_method_stub(), "expected fixed destination of patch"); ++ NativeIllegalInstruction::insert(verified_entry); ++ ++// guarantee(!os::is_MP() || (((long)verified_entry % BytesPerWord) == 0), "destination must be aligned for SD"); ++// bool is_aligned = !os::is_MP() || (((long)verified_entry % BytesPerWord) == 0); ++// ++// if (is_aligned) { ++// int code_buffer[4]; ++// ++// CodeBuffer cb((address)code_buffer, instruction_size); ++// MacroAssembler masm(&cb); ++//#define __ masm. ++// __ ldl(T12, Address(rthread, in_bytes(JavaThread::handle_wrong_method_stub_offset()))); ++// __ jmp(T12); ++// __ nop(); ++// __ nop(); ++// ++// atomic_store64_ptr func = get_atomic_store64_func(); ++// (*func)((long *)verified_entry, 0, *(long *)&code_buffer[0]); ++// } else { ++//// if (Assembler::reachable_from_branch_at(verified_entry, dest)) { //for SW8A ++//// ptrdiff_t disp = dest - verified_entry - 4; ++//// guarantee(disp < 1 << 27 && disp > - (1 << 27), "branch overflow"); ++//// unsigned int insn = (0x1D << 26) | ((disp >> 2) & 0x3ffffff); ++////// *(unsigned int*)verified_entry = insn; ++//// } else { ++// // We use an illegal instruction for marking a method as ++// // not_entrant or zombie ++// NativeIllegalInstruction::insert(verified_entry); ++// } ++} ++ ++//address NativeFarJump::jump_destination() const { ++// NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++// return (address)mov->data(); ++//} ++// ++//void NativeFarJump::verify() { ++// if (is_far_jump()) { ++// NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++// NativeInstruction* jmp = nativeInstruction_at(mov->next_instruction_address()); ++// if (jmp->is_jump_reg()) return; ++// } ++// fatal("not a jump instruction"); ++//} ++ ++void NativePopReg::insert(address code_pos, Register reg) { ++ Unimplemented(); ++ assert(reg->encoding() < 8, "no space for REX"); ++ assert(NativePopReg::instruction_size == sizeof(char), "right address unit for update"); ++ *code_pos = (u_char)(instruction_code | reg->encoding()); ++ // ICache::invalidate_range(code_pos, instruction_size); ++} ++ ++ ++void NativeIllegalInstruction::insert(address code_pos) { ++ // Unimplemented(); ++ assert(NativeIllegalInstruction::instruction_size == sizeof(int), "right address unit for update"); ++ *(juint*)code_pos = instruction_code; ++// ICache::invalidate_range(code_pos, instruction_size); ++} ++ ++void NativeGeneralJump::verify() { ++ Unimplemented(); ++} ++ ++ ++void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { ++ Unimplemented(); ++ intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4); ++ ++ guarantee(disp == (intptr_t)(int32_t)disp, "must be 32-bit offset"); ++ ++ *code_pos = unconditional_long_jump; ++ *((int32_t *)(code_pos+1)) = (int32_t) disp; ++ //ICache::invalidate_range(code_pos, instruction_size); ++} ++ ++ ++// MT-safe patching of a long jump instruction. ++// First patches first word of instruction to two jmp's that jmps to them ++// selfs (spinlock). Then patches the last byte, and then atomicly replaces ++// the jmp's with the first 4 byte of the new instruction. ++void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { ++ Unimplemented(); ++} ++ ++void NativeGeneralJump::set_jump_destination(address dest) { ++ Unimplemented(); ++} ++ ++ ++address NativeGeneralJump::jump_destination() const { ++ Unimplemented(); ++ return NULL; ++} ++ ++intptr_t NativeMovConstReg::data() { ++ // wait_until_not_spinng(); ++ if (nativeInstruction_at(addr_at(0)) -> is_mov_ptr()) { ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl)) { ++ return (intptr_t) long_at(8); ++ } ++ if (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi)) { ++ return (intptr_t) long_at(4); ++ } ++ if (is_op(int_at(4), Assembler::op_slll_l)){ ++ /* li48 */ ++ int16_t msb_l = int_at(0)&0xffff; ++ int16_t lsb_h = int_at(8)&0xffff; ++ int16_t lsb_l = int_at(12)&0xffff; ++ ++ // -1 should be 0xffff ffff ffff ffff, so we can not use low 48 bits ++ return (((intptr_t) (msb_l) << 32) + ((intptr_t) (lsb_h) << 16) + (intptr_t) (lsb_l)); ++ } ++ else { ++ int16_t high = int_at(0)&0xffff; ++ int16_t low = int_at(4)&0xffff; ++ ++ // -1 should be 0xffff ffff ffff ffff, so we can not use low 48 bits ++ return ( ((intptr_t) (high) << 16) + (intptr_t) (low)); ++ } ++ } ++ ++ Unimplemented(); ++ return (intptr_t )NULL; ++} ++ ++void NativeMovConstReg::set_data(intptr_t x) { ++ if (is_mov_ptr()) { ++ OrderAccess::fence(); ++ //decide which type of data need be relocated li48 or 32 ++ if (is_op(int_at(4), Assembler::op_slll_l)) { ++ int16_t msb_l, lsb_h, lsb_l; ++ NativeInstruction::imm48_split((long)x, msb_l, lsb_h, lsb_l); ++ ++ int first_word = int_at(0); ++ set_int_at(0, 0x13FFFFFF); /* .1: br .1 */ ++ set_int_at(8, (int_at(8) & 0xffff0000) | (lsb_h & 0xffff)); ++ set_int_at(12, (int_at(12) & 0xffff0000) | (lsb_l & 0xffff)); ++ set_int_at(0, (first_word & 0xffff0000) | (msb_l & 0xffff)); ++ ++ // ICache::invalidate_range(addr_at(0), 16); ++ } ++ else if (is_op(int_at(8), Assembler::op_zapnot_l)) { ++ int16_t high = (x - (int16_t)(x))>>16; ++ int16_t low = (int16_t)(x); ++ int first_word = int_at(0); ++ set_int_at(0, 0x13FFFFFF); /* .1: br .1 */ ++ set_int_at(4, (int_at(4) & 0xffff0000) | (low & 0xffff)); ++ set_int_at(0, (first_word & 0xffff0000) | (high & 0xffff)); ++ ++ // ICache::invalidate_range(addr_at(0), 12); ++ } ++ } else { ++ fatal("not a call "); ++ } ++} ++ ++address NativeJump::jump_destination() { ++ NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++ address dest = (address) mov->data(); ++ // We use jump to self as the unresolved address which the inline ++ // cache code (and relocs) know about ++ ++ // return -1 if jump to self ++ dest = (dest == (address) this) ? (address) -1 : dest; ++ return dest; ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/nativeInst_sw64.hpp afu11u/src/hotspot/cpu/sw64/nativeInst_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/nativeInst_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/nativeInst_sw64.hpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,795 @@ ++/* ++ * 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. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_NATIVEINST_SW64_HPP ++#define CPU_SW64_VM_NATIVEINST_SW64_HPP ++ ++#include "asm/assembler.hpp" ++#include "runtime/icache.hpp" ++#include "runtime/os.hpp" ++#include "runtime/safepointMechanism.hpp" ++ ++// We have interfaces for the following instructions: ++// - NativeInstruction ++// - - NativeCall ++// - - NativeMovConstReg ++// - - NativeMovConstRegPatching ++// - - NativeMovRegMem ++// - - NativeMovRegMemPatching ++// - - NativeJump ++// - - NativeFarJump ++// - - NativeIllegalOpCode ++// - - NativeGeneralJump ++// - - NativeReturn ++// - - NativeReturnX (return with argument) ++// - - NativePushConst ++// - - NativeTstRegMem ++ ++// 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; ++ friend class MacroAssembler; ++ ++ public: ++ enum Sw64_specific_constants { ++ nop_instruction_code = 0, ++ nop_instruction_size = BytesPerInstWord ++ }; ++ ++ bool is_nop() { Unimplemented(); return ubyte_at(0) == nop_instruction_code; } ++ inline bool is_call(); ++ inline bool is_call_reg(); ++ inline bool is_illegal(); ++ inline bool is_return(); ++ inline bool is_jump(); ++ inline bool is_jump_reg(); ++ inline bool is_far_jump(); ++ inline bool is_cond_jump(); ++ inline bool is_safepoint_poll(); ++ inline bool is_mov_ptr(); ++ void wait_until_not_spinng() { ++ while (*((volatile int*)this) > 0);// wait until the first inst is not spin any more. spin is 13ffffff(>0), ldi and ldih is fxxxxxxx < 0 ++ } ++ ++ //We use an illegal instruction for marking a method as not_entrant or zombie. ++ bool is_sigill_zombie_not_entrant(); ++ ++protected: ++ address addr_at(int offset) const { return address(this) + offset; } ++ ++ s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); } ++ u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); } ++ ++ jint int_at(int offset) const { return *(jint*) addr_at(offset); } ++ ++ intptr_t ptr_at(int offset) const { return *(intptr_t*) addr_at(offset); } ++ ++ oop oop_at (int offset) const { return *(oop*) addr_at(offset); } ++ ++ void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; wrote(offset); } ++ void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; wrote(offset); } ++ void set_ptr_at (int offset, intptr_t ptr) { *(intptr_t*) addr_at(offset) = ptr; wrote(offset); } ++ void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; wrote(offset); } ++ ++ static void imm48_split(long imm48, int16_t &msb_l, int16_t &lsb_h, int16_t &lsb_l); ++ void set_address(address dest); ++ void set_long_at(int offset, long i); ++ jlong long_at(int offset) const { return *(jlong*)addr_at(offset); } ++ ++ static bool is_op (int insn, Assembler::ops_mem op) { return Assembler::sw2_op(insn) == (int)op; } ++ static bool is_op (int insn, Assembler::ops_opr op) { return Assembler::sw2_arith_op(insn) == (int)op; } ++ static bool is_op (int insn, Assembler::ops_oprl op) { return Assembler::sw2_arith_op(insn) == (int)op; } ++ static bool is_op (int insn, Assembler::ops_extra op) { return Assembler::sw2_mfc_op(insn) == (int)op; } ++ static bool is_op (int insn, Assembler::ops_bra op) { return Assembler::sw2_op(insn) == (int)op; } ++ static bool is_op (int insn, Assembler::ops_fp op) { return Assembler::sw2_op(insn) == (int)op; } ++ ++ // This doesn't really do anything on Intel, but it is the place where ++ // cache invalidation belongs, generically: ++ void wrote(int offset); ++ ++ public: ++ ++ // 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; ++} ++ ++class NativePltCall: public NativeInstruction { ++public: ++ enum Sw64_specific_constants { ++ instruction_code = 0xE8, ++ instruction_size = 5, ++ instruction_offset = 0, ++ displacement_offset = 1, ++ return_address_offset = 5 ++ }; ++ address instruction_address() const { return addr_at(instruction_offset); } ++ address next_instruction_address() const { return addr_at(return_address_offset); } ++ address displacement_address() const { return addr_at(displacement_offset); } ++ int displacement() const { Unimplemented(); return (jint) int_at(displacement_offset); } ++ address return_address() const { return addr_at(return_address_offset); } ++ address destination() const; ++ address plt_entry() const; ++ address plt_jump() const; ++ address plt_load_got() const; ++ address plt_resolve_call() const; ++ address plt_c2i_stub() const; ++ void set_stub_to_clean(); ++ ++ void reset_to_plt_resolve_call(); ++ void set_destination_mt_safe(address dest); ++ ++ void verify() const; ++}; ++ ++inline NativePltCall* nativePltCall_at(address address) { ++ NativePltCall* call = (NativePltCall*) address; ++#ifdef ASSERT ++ call->verify(); ++#endif ++ return call; ++} ++ ++inline NativePltCall* nativePltCall_before(address addr) { ++ address at = addr - NativePltCall::instruction_size; ++ return nativePltCall_at(at); ++} ++ ++// An interface for mov ptr to reg: ++// ldi ++// sll ++// ldih ++// ldi ++class NativeMovConstReg: public NativeInstruction { ++public: ++ enum Sw64_specific_constants { ++ instruction_size = 4 * BytesPerInstWord, ++ instruction_offset = 0, ++ next_instruction_offset = instruction_size, ++ }; ++ ++ address instruction_address() const { return addr_at(instruction_offset); } ++ address next_instruction_address() const { return addr_at(next_instruction_offset); } ++ intptr_t data(); ++ void set_data(intptr_t x); ++ ++ void verify(); ++ void print(); ++ ++ // unit test stuff ++ static void test() {} ++ ++ // Creation ++ inline friend NativeMovConstReg* nativeMovConstReg_at(address address); ++ inline friend NativeMovConstReg* nativeMovConstReg_before(address address); ++}; ++ ++inline NativeMovConstReg* nativeMovConstReg_at(address address) { ++ NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset); ++#ifdef ASSERT ++ test->verify(); ++#endif ++ return test; ++} ++ ++inline NativeMovConstReg* nativeMovConstReg_before(address address) { ++ NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset); ++#ifdef ASSERT ++ test->verify(); ++#endif ++ return test; ++} ++ ++inline NativeCall* nativeCall_at(address address); ++ ++class NativeCall: public NativeInstruction { ++ public: ++ enum Sw64_specific_constants { ++ // instruction_size = 5 * BytesPerInstWord, ++ instruction_offset = 0, ++ // return_address_offset = instruction_size ++ }; ++ static int instruction_size; //member variables can be reassigned in the templateTable_sw64.cpp_sw64.cpp when SafePatch is true. ++ static int return_address_offset; ++ ++ enum { cache_line_size = BytesPerWord }; // conservative estimate! ++ ++ address instruction_address() const { return addr_at(instruction_offset); } ++ address next_instruction_address() const { return addr_at(return_address_offset); } ++ address return_address() const { return addr_at(return_address_offset); } ++ address destination() const; ++ void set_destination(address dest) { ++ /*NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++ mov->set_data((intptr_t)dest);*/ ++ set_address(dest); ++ } ++ void set_destination_mt_safe(address dest); ++ ++ void verify_alignment() { } ++ void verify(); ++ void print(); ++ ++ // Creation ++ inline friend NativeCall* nativeCall_at(address address); ++ inline friend NativeCall* nativeCall_before(address return_address); ++ ++ static bool is_call_at(address instr) { ++ return nativeInstruction_at(instr)->is_call(); ++ } ++ ++ static bool is_call_before(address return_address) { ++ return is_call_at(return_address - NativeCall::return_address_offset); ++ } ++ ++// static bool is_call_to(address instr, address target) { ++// return nativeInstruction_at(instr)->is_call() && ++// nativeCall_at(instr)->destination() == target; ++// } ++ ++#if INCLUDE_AOT ++ static bool is_far_call(address instr, address target) { ++ intptr_t disp = target - (instr + sizeof(int32_t)); ++ return !Assembler::is_simm32(disp); ++ } ++#endif ++ ++ // MT-safe patching of a call instruction. ++ static void insert(address code_pos, address entry); ++ ++ static void replace_mt_safe(address instr_addr, address code_buffer); ++}; ++ ++inline NativeCall* nativeCall_at(address address) { ++ NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset); ++#ifdef ASSERT ++ call->verify(); ++#endif ++ return call; ++} ++ ++inline NativeCall* nativeCall_before(address return_address) { ++ NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset); ++#ifdef ASSERT ++ call->verify(); ++#endif ++ return call; ++} ++ ++//class NativeCallReg: public NativeInstruction { ++// public: ++// enum Sw64_specific_constants { ++// instruction_size = BytesPerInstWord ++// }; ++// ++// int next_instruction_offset() const { ++// return instruction_size; ++// } ++//}; ++ ++ ++class NativeMovConstRegPatching: public NativeMovConstReg { ++ private: ++ friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) { ++ Unimplemented(); ++ NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset); ++ #ifdef ASSERT ++ test->verify(); ++ #endif ++ return test; ++ } ++}; ++ ++// An interface for accessing/manipulating native moves of the form: ++// mov[b/w/l/q] [reg + offset], reg (instruction_code_reg2mem) ++// mov[b/w/l/q] reg, [reg+offset] (instruction_code_mem2reg ++// mov[s/z]x[w/b/q] [reg + offset], reg ++// fld_s [reg+offset] ++// fld_d [reg+offset] ++// fstp_s [reg + offset] ++// fstp_d [reg + offset] ++// mov_literal64 scratch, ; mov[b/w/l/q] 0(scratch),reg | mov[b/w/l/q] reg,0(scratch) ++// ++// Warning: These routines must be able to handle any instruction sequences ++// that are generated as a result of the load/store byte,word,long ++// macros. For example: The load_unsigned_byte instruction generates ++// an xor reg,reg inst prior to generating the movb instruction. This ++// class must skip the xor instruction. ++ ++class NativeMovRegMem: public NativeInstruction { ++ public: ++ enum Sw64_specific_constants { ++ //instruction_prefix_wide_lo = Assembler::REX, ++ //instruction_prefix_wide_hi = Assembler::REX_WRXB, ++ instruction_code_xor = 0x33, ++ instruction_extended_prefix = 0x0F, ++ instruction_code_mem2reg_movslq = 0x63, ++ instruction_code_mem2reg_movzxb = 0xB6, ++ instruction_code_mem2reg_movsxb = 0xBE, ++ instruction_code_mem2reg_movzxw = 0xB7, ++ instruction_code_mem2reg_movsxw = 0xBF, ++ instruction_operandsize_prefix = 0x66, ++ instruction_code_reg2mem = 0x89, ++ instruction_code_mem2reg = 0x8b, ++ instruction_code_reg2memb = 0x88, ++ instruction_code_mem2regb = 0x8a, ++ instruction_code_float_s = 0xd9, ++ instruction_code_float_d = 0xdd, ++ instruction_code_long_volatile = 0xdf, ++ instruction_code_xmm_ss_prefix = 0xf3, ++ instruction_code_xmm_sd_prefix = 0xf2, ++ instruction_code_xmm_code = 0x0f, ++ instruction_code_xmm_load = 0x10, ++ instruction_code_xmm_store = 0x11, ++ instruction_code_xmm_lpd = 0x12, ++ ++ instruction_code_lea = 0x8d, ++ ++ //instruction_VEX_prefix_2bytes = Assembler::VEX_2bytes, ++ //instruction_VEX_prefix_3bytes = Assembler::VEX_3bytes, ++ //instruction_EVEX_prefix_4bytes = Assembler::EVEX_4bytes, ++ ++ instruction_offset = 0, ++ data_offset = 2, ++ next_instruction_offset = 4 ++ }; ++ ++ // helper ++ int instruction_start() const; ++ ++ address instruction_address() const { ++ Unimplemented(); ++ return addr_at(instruction_start()); ++ } ++ ++ int num_bytes_to_end_of_patch() const { ++ Unimplemented(); ++ return patch_offset() + sizeof(jint); ++ } ++ ++ int offset() const { ++ Unimplemented(); ++ return int_at(patch_offset()); ++ } ++ ++ void set_offset(int x) { ++ Unimplemented(); ++ set_int_at(patch_offset(), x); ++ } ++ ++ void add_offset_in_bytes(int add_offset) { ++ Unimplemented(); ++ int patch_off = patch_offset(); ++ set_int_at(patch_off, int_at(patch_off) + add_offset); ++ } ++ ++ void verify(); ++ void print (); ++ ++ // unit test stuff ++ static void test() {} ++ ++ private: ++ int patch_offset() const; ++ inline friend NativeMovRegMem* nativeMovRegMem_at (address address); ++}; ++ ++inline NativeMovRegMem* nativeMovRegMem_at (address address) { ++ Unimplemented(); ++ NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset); ++#ifdef ASSERT ++ test->verify(); ++#endif ++ return test; ++} ++ ++ ++// An interface for accessing/manipulating native leal instruction of form: ++// leal reg, [reg + offset] ++ ++class NativeLoadAddress: public NativeMovRegMem { ++ public: ++ enum Sw64_specific_constants { ++ }; ++ ++ void verify(); ++ void print (); ++ ++ // unit test stuff ++ static void test() {} ++ ++ private: ++ friend NativeLoadAddress* nativeLoadAddress_at (address address) { ++ Unimplemented(); ++ NativeLoadAddress* test = (NativeLoadAddress*)(address - instruction_offset); ++ #ifdef ASSERT ++ test->verify(); ++ #endif ++ return test; ++ } ++}; ++ ++// destination is rbx or rax ++// mov rbx, [rip + offset] ++class NativeLoadGot: public NativeInstruction { ++ static const bool has_rex = true; ++ static const int rex_size = 1; ++public: ++ enum Sw64_specific_constants { ++ rex_prefix = 0x48, ++ instruction_code = 0x8b, ++ modrm_rbx_code = 0x1d, ++ modrm_rax_code = 0x05, ++ instruction_length = 6 + rex_size, ++ offset_offset = 2 + rex_size ++ }; ++ ++ address instruction_address() const { return addr_at(0); } ++ address rip_offset_address() const { return addr_at(offset_offset); } ++ int rip_offset() const { return int_at(offset_offset); } ++ address return_address() const { return addr_at(instruction_length); } ++ address got_address() const { return return_address() + rip_offset(); } ++ address next_instruction_address() const { return return_address(); } ++ intptr_t data() const; ++ void set_data(intptr_t data) { ++ Unimplemented(); ++ intptr_t *addr = (intptr_t *) got_address(); ++ *addr = data; ++ } ++ ++ void verify() const; ++private: ++ void report_and_fail() const; ++}; ++ ++inline NativeLoadGot* nativeLoadGot_at(address addr) { ++ Unimplemented(); ++ NativeLoadGot* load = (NativeLoadGot*) addr; ++#ifdef ASSERT ++ load->verify(); ++#endif ++ return load; ++} ++ ++class NativeJump: public NativeInstruction { ++ public: ++ enum Sw64_specific_constants { ++ // instruction_size = 5 * BytesPerInstWord, ++ instruction_offset = 0, ++ // next_instruction_offset = instruction_size ++ }; ++ static int instruction_size; //member variables can be reassigned in the templateTable_sw64.cpp when SafePatch is true. ++ static int next_instruction_offset; ++ address instruction_address() const { return addr_at(instruction_offset); } ++ address next_instruction_address() const { return addr_at(next_instruction_offset); } ++ address jump_destination(); ++ ++ void set_jump_destination(address dest) { ++ // NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0)); ++ // mov->set_data((intptr_t)dest); ++ set_address(dest); ++ } ++ ++ // Creation ++ inline friend NativeJump* nativeJump_at(address address); ++ ++ void verify(); ++ ++ // 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); ++ static void patch_verified_entry(address entry, address verified_entry, address dest); ++}; ++ ++inline NativeJump* nativeJump_at(address address) { ++ NativeJump* jump = (NativeJump*)(address - NativeJump::instruction_offset); ++#ifdef ASSERT ++ jump->verify(); ++#endif ++ return jump; ++} ++ ++//// far jump reg ++//class NativeFarJump: public NativeInstruction { ++// public: ++// address jump_destination() const; ++// ++// // Creation ++// inline friend NativeFarJump* nativeFarJump_at(address address); ++// ++// void verify(); ++// ++// // Unit testing stuff ++// static void test() {} ++// ++//}; ++ ++//inline NativeFarJump* nativeFarJump_at(address address) { ++// NativeFarJump* jump = (NativeFarJump*)(address); ++//#ifdef ASSERT ++// jump->verify(); ++//#endif ++// return jump; ++//} ++ ++// Handles all kinds of jump on Intel. Long/far, conditional/unconditional ++class NativeGeneralJump: public NativeInstruction { ++public: ++ enum Sw64_specific_constants { ++ instruction_offset = 0, ++ unconditional_long_jump = 0xe9, ++ unconditional_short_jump = 0xeb, ++ instruction_size = 5 ++ }; ++ ++ address instruction_address() const { Unimplemented(); return addr_at(0); } ++ address jump_destination() const; ++ ++ void set_jump_destination(address dest); ++ ++ // Creation ++ inline friend NativeGeneralJump* nativeGeneralJump_at(address address); ++ ++ // 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(); ++}; ++ ++inline NativeGeneralJump* nativeGeneralJump_at(address address) { ++ Unimplemented(); ++ NativeGeneralJump* jump = (NativeGeneralJump*)(address); ++ debug_only(jump->verify();) ++ return jump; ++} ++ ++class NativeGotJump: public NativeInstruction { ++public: ++ enum Sw64_specific_constants { ++ instruction_code = 0xff, ++ instruction_offset = 0, ++ instruction_size = 6, ++ rip_offset = 2 ++ }; ++ ++ void verify() const; ++ address instruction_address() const { Unimplemented(); return addr_at(instruction_offset); } ++ address destination() const; ++ address return_address() const { Unimplemented(); return addr_at(instruction_size); } ++ int got_offset() const { return (jint) int_at(rip_offset); } ++ address got_address() const { return return_address() + got_offset(); } ++ address next_instruction_address() const { return addr_at(instruction_size); } ++ bool is_GotJump() const { return ubyte_at(0) == instruction_code; } ++ ++ void set_jump_destination(address dest) { ++ Unimplemented(); ++ address *got_entry = (address *) got_address(); ++ *got_entry = dest; ++ } ++}; ++ ++inline NativeGotJump* nativeGotJump_at(address addr) { ++ Unimplemented(); ++ NativeGotJump* jump = (NativeGotJump*)(addr); ++ debug_only(jump->verify()); ++ return jump; ++} ++ ++class NativePopReg : public NativeInstruction { ++ public: ++ enum Sw64_specific_constants { ++ instruction_code = 0x58, ++ instruction_size = 1, ++ instruction_offset = 0, ++ data_offset = 1, ++ next_instruction_offset = 1 ++ }; ++ ++ // Insert a pop instruction ++ static void insert(address code_pos, Register reg); ++}; ++ ++ ++class NativeIllegalInstruction: public NativeInstruction { ++public: ++ enum Sw64_specific_constants { ++ instruction_code = 0x0000DEAD, // Special instruction ++ instruction_size = 4, //TODO:not check jzy ++ instruction_offset = 0, ++ next_instruction_offset = 4 //TODO:not check jzy ++ }; ++ ++ // Insert illegal opcode as specific address ++ static void insert(address code_pos); ++}; ++ ++// return instruction that does not pop values of the stack ++class NativeReturn: public NativeInstruction { ++ public: ++ enum Sw64_specific_constants { ++ instruction_size = BytesPerInstWord ++ }; ++}; ++ ++// Simple test vs memory ++class NativeTstRegMem: public NativeInstruction { ++ public: ++ enum Sw64_specific_constants { ++ }; ++}; ++ ++//class NativeCondJump; ++//inline NativeCondJump* nativeCondJump_at(address address); ++//class NativeCondJump: public NativeInstruction { ++// public: ++// enum Sw64_specific_constants { ++// instruction_size = 16, ++// instruction_offset = 12, ++// next_instruction_offset = 20 ++// }; ++// ++// ++// address instruction_address() const { Unimplemented(); return addr_at(0); } ++// address next_instruction_address() const { Unimplemented(); return addr_at(next_instruction_offset); } ++// ++// // Creation ++// inline friend NativeCondJump* nativeCondJump_at(address address); ++// ++// address jump_destination() const { ++// Unimplemented(); ++// return ::nativeCondJump_at(addr_at(12))->jump_destination(); ++// } ++// ++// void set_jump_destination(address dest) { ++// Unimplemented(); ++// ::nativeCondJump_at(addr_at(12))->set_jump_destination(dest); ++// } ++// ++//}; ++// ++//inline NativeCondJump* nativeCondJump_at(address address) { ++// Unimplemented(); ++// NativeCondJump* jump = (NativeCondJump*)(address); ++// return jump; ++//} ++ ++inline bool NativeInstruction::is_illegal() { Unimplemented(); return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; } ++ ++inline bool NativeInstruction::is_call() { ++ if (SafePatch) { ++ return is_op(int_at(20), Assembler::op_call) && ++ ((is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl)) || ++ (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi))); ++ } else { ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_slll_l) && ++ is_op(int_at(8), Assembler::op_ldih) && ++ is_op(int_at(12), Assembler::op_ldi) && ++ is_op(int_at(16), Assembler::op_call)) ++ return true; ++ } ++ ++ if (is_op(int_at(0), Assembler::op_ldih) && ++ is_op(int_at(4), Assembler::op_ldi) && ++ is_op(int_at(8), Assembler::op_slll_l) && ++ is_op(int_at(12), Assembler::op_ldih) && ++ is_op(int_at(16), Assembler::op_ldi) && ++ is_op(int_at(16), Assembler::op_call)) ++ return true; ++ ++ // Unimplemented(); ++ return false; ++} ++inline bool NativeInstruction::is_call_reg() { ++ return is_op(int_at(0), Assembler::op_call); ++} ++inline bool NativeInstruction::is_return() { ++ return is_op(int_at(NativeMovConstReg::instruction_size), Assembler::op_ret); ++} ++inline bool NativeInstruction::is_jump() { ++ if (SafePatch) { ++ return is_op(int_at(20), Assembler::op_jmp) && ++ ((is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl)) || ++ (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi))); ++ } else { ++ if (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_slll_l) && ++ is_op(int_at(8), Assembler::op_ldih) && ++ is_op(int_at(12), Assembler::op_ldi)) ++ return true; ++ } ++ ++ if (is_op(int_at(0), Assembler::op_ldih) && ++ is_op(int_at(4), Assembler::op_ldi) && ++ is_op(int_at(8), Assembler::op_slll_l) && ++ is_op(int_at(12), Assembler::op_ldih) && ++ is_op(int_at(16), Assembler::op_ldi)) ++ return true; ++ ++ // Unimplemented(); ++ return false; ++} ++inline bool NativeInstruction::is_jump_reg() { ++ return is_op(int_at(0), Assembler::op_jmp); ++} ++inline bool NativeInstruction::is_safepoint_poll() { ++ //Unimplemented(); ++ //refer to relocInfo::poll_return_type in sw64.ad ++ int x = int_at(0); ++ int op = Assembler::sw2_op(x); ++ if (op != Assembler::op_ldw) return false; ++ ++ Register ra = Assembler::sw2_ra(x); ++ if (ra != rscratch3) return false; //TODO:refactor jzy ++ ++ int mdisp = Assembler::sw2_mdisp(x); ++ if (mdisp != 0) return false; ++ ++ return true; ++} ++ ++inline bool NativeInstruction::is_mov_ptr() { ++ //wait_until_not_spinng(); ++ if ((is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_slll_l) && ++ is_op(int_at(8), Assembler::op_ldih) && ++ is_op(int_at(12), Assembler::op_ldi)) || ++ (is_op(int_at(0), Assembler::op_ldih) && ++ is_op(int_at(4), Assembler::op_ldi) && ++ is_op(int_at(8), Assembler::op_zapnot_l)) || ++ (is_op(int_at(0), Assembler::op_ldi) && ++ is_op(int_at(4), Assembler::op_br) && ++ is_op(int_at(16), Assembler::op_ldl))|| ++ (is_op(int_at(0), Assembler::op_br) && ++ is_op(int_at(12), Assembler::op_ldl) && ++ is_op(int_at(16), Assembler::op_ldi) )){ ++ return true; ++ } ++ return false; ++} ++ ++#endif // CPU_SW64_VM_NATIVEINST_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/register_definitions_sw64.cpp afu11u/src/hotspot/cpu/sw64/register_definitions_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/register_definitions_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/register_definitions_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,224 @@ ++/* ++ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/assembler.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "asm/register.hpp" ++#include "register_sw64.hpp" ++# include "interp_masm_sw64.hpp" ++ ++REGISTER_DEFINITION(Register, noreg); ++ ++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, i8); ++REGISTER_DEFINITION(Register, i9); ++REGISTER_DEFINITION(Register, i10); ++REGISTER_DEFINITION(Register, i11); ++REGISTER_DEFINITION(Register, i12); ++REGISTER_DEFINITION(Register, i13); ++REGISTER_DEFINITION(Register, i14); ++REGISTER_DEFINITION(Register, i15); ++REGISTER_DEFINITION(Register, i16); ++REGISTER_DEFINITION(Register, i17); ++REGISTER_DEFINITION(Register, i18); ++REGISTER_DEFINITION(Register, i19); ++REGISTER_DEFINITION(Register, i20); ++REGISTER_DEFINITION(Register, i21); ++REGISTER_DEFINITION(Register, i22); ++REGISTER_DEFINITION(Register, i23); ++REGISTER_DEFINITION(Register, i24); ++REGISTER_DEFINITION(Register, i25); ++REGISTER_DEFINITION(Register, i26); ++REGISTER_DEFINITION(Register, i27); ++REGISTER_DEFINITION(Register, i28); ++REGISTER_DEFINITION(Register, i29); ++REGISTER_DEFINITION(Register, i30); ++REGISTER_DEFINITION(Register, i31); ++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(Register, A0); ++REGISTER_DEFINITION(Register, A1); ++REGISTER_DEFINITION(Register, A2); ++REGISTER_DEFINITION(Register, A3); ++REGISTER_DEFINITION(Register, A4); ++REGISTER_DEFINITION(Register, A5); ++ ++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(Register, zr); ++REGISTER_DEFINITION(Register, c_rarg0); ++REGISTER_DEFINITION(Register, c_rarg1); ++REGISTER_DEFINITION(Register, c_rarg2); ++REGISTER_DEFINITION(Register, c_rarg3); ++REGISTER_DEFINITION(Register, c_rarg4); ++REGISTER_DEFINITION(Register, c_rarg5); ++ ++REGISTER_DEFINITION(FloatRegister, c_farg0); ++REGISTER_DEFINITION(FloatRegister, c_farg1); ++REGISTER_DEFINITION(FloatRegister, c_farg2); ++REGISTER_DEFINITION(FloatRegister, c_farg3); ++REGISTER_DEFINITION(FloatRegister, c_farg4); ++REGISTER_DEFINITION(FloatRegister, c_farg5); ++ ++REGISTER_DEFINITION(Register, j_rarg0);//A1 ++REGISTER_DEFINITION(Register, j_rarg1); ++REGISTER_DEFINITION(Register, j_rarg2); ++REGISTER_DEFINITION(Register, j_rarg3); ++REGISTER_DEFINITION(Register, j_rarg4);//A5 ++REGISTER_DEFINITION(Register, j_rarg5);//A0 ++ ++REGISTER_DEFINITION(FloatRegister, j_farg0);//F16 ++REGISTER_DEFINITION(FloatRegister, j_farg1); ++REGISTER_DEFINITION(FloatRegister, j_farg2); ++REGISTER_DEFINITION(FloatRegister, j_farg3); ++REGISTER_DEFINITION(FloatRegister, j_farg4); ++REGISTER_DEFINITION(FloatRegister, j_farg5);//F21 ++ ++REGISTER_DEFINITION(Register, rscratch1); //t5 ++REGISTER_DEFINITION(Register, rscratch2); //t6 ++ ++REGISTER_DEFINITION(Register, rscratch3); //t11 ++REGISTER_DEFINITION(Register, rscratch4); //at ++ ++REGISTER_DEFINITION(Register, rscratch1_GP); //GP ++REGISTER_DEFINITION(Register, rscratch2_AT); //AT ++REGISTER_DEFINITION(Register, rdispatch); //t8 ++REGISTER_DEFINITION(Register, rnext); //t10, jdk8 use s1 ++REGISTER_DEFINITION(Register, rmonitors); //t11 ++REGISTER_DEFINITION(Register, pv); //t12 ++//REGISTER_DEFINITION(Register, rcpool); //t12, ok?? ++ ++REGISTER_DEFINITION(Register, rbcp); //s0, consist with jdk8 ++REGISTER_DEFINITION(Register, rlocals); //s1, jdk8 use s5 ++REGISTER_DEFINITION(Register, rthread); //s2, consist with jdk8 ++REGISTER_DEFINITION(Register, rmethod); //s3, consist with jdk8 ++REGISTER_DEFINITION(Register, rsender); //s4, consist with jdk8 ++REGISTER_DEFINITION(Register, r12_heapbase); //s5, jdk8 use t5 ++REGISTER_DEFINITION(Register, rcc); //gp ++ ++REGISTER_DEFINITION(Register, RA); ++REGISTER_DEFINITION(Register, esp); ++REGISTER_DEFINITION(Register, lr); ++REGISTER_DEFINITION(Register, rfp); ++ ++REGISTER_DEFINITION(Register, FSR); //v0, First Stack Register ++REGISTER_DEFINITION(Register, SSR); //t4, Second Stack Register ++ ++REGISTER_DEFINITION(FloatRegister, FSF); //f0, First Stack Float ++REGISTER_DEFINITION(FloatRegister, SSF); //f1, Second Stack Float ++REGISTER_DEFINITION(FloatRegister, FTF); //f14, Float temp?? ++REGISTER_DEFINITION(FloatRegister, FcmpRES);//f29, TODO:need delete jzy ++REGISTER_DEFINITION(FloatRegister, fcc);//f29 ++REGISTER_DEFINITION(FloatRegister, fscratch1);//f28 ++REGISTER_DEFINITION(FloatRegister, fzero);//f31 ++ ++REGISTER_DEFINITION(Register, V0); ++REGISTER_DEFINITION(Register, T0); ++REGISTER_DEFINITION(Register, T1); ++REGISTER_DEFINITION(Register, T2); ++REGISTER_DEFINITION(Register, T3); ++REGISTER_DEFINITION(Register, T4); ++REGISTER_DEFINITION(Register, T5); ++REGISTER_DEFINITION(Register, T6); ++REGISTER_DEFINITION(Register, T7); ++REGISTER_DEFINITION(Register, S0); ++REGISTER_DEFINITION(Register, S1); ++REGISTER_DEFINITION(Register, S2); ++REGISTER_DEFINITION(Register, S3); ++REGISTER_DEFINITION(Register, S4); ++REGISTER_DEFINITION(Register, S5); ++REGISTER_DEFINITION(Register, T8); ++REGISTER_DEFINITION(Register, T9); ++REGISTER_DEFINITION(Register, T10); ++REGISTER_DEFINITION(Register, T11); ++REGISTER_DEFINITION(Register, T12); ++REGISTER_DEFINITION(Register, AT); ++REGISTER_DEFINITION(Register, GP); ++REGISTER_DEFINITION(Register, R0); ++ ++// x86 GPR simulation ++REGISTER_DEFINITION(Register, rax); ++REGISTER_DEFINITION(Register, rcx); ++REGISTER_DEFINITION(Register, rdx); ++REGISTER_DEFINITION(Register, rbx); ++REGISTER_DEFINITION(Register, rsi); ++REGISTER_DEFINITION(Register, rdi); ++REGISTER_DEFINITION(Register, rbp); ++REGISTER_DEFINITION(Register, rsp); ++REGISTER_DEFINITION(Register, r8); ++REGISTER_DEFINITION(Register, r9); ++REGISTER_DEFINITION(Register, r10); ++REGISTER_DEFINITION(Register, r11); ++REGISTER_DEFINITION(Register, r12); ++REGISTER_DEFINITION(Register, r13); ++REGISTER_DEFINITION(Register, r14); ++REGISTER_DEFINITION(Register, r15); +\ 文件尾没有换行符 +diff -uNr openjdk/src/hotspot/cpu/sw64/registerMap_sw64.hpp afu11u/src/hotspot/cpu/sw64/registerMap_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/registerMap_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/registerMap_sw64.hpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_REGISTERMAP_SW64_HPP ++#define CPU_SW64_VM_REGISTERMAP_SW64_HPP ++ ++// machine-dependent implemention for register maps ++ friend class frame; ++ ++ private: ++ // This is the hook for finding a register in an "well-known" location, ++ // such as a register block of a predetermined format. ++ // Since there is none, we just return NULL. ++ // See registerMap_sparc.hpp for an example of grabbing registers ++ // from register save areas of a standard layout. ++ address pd_location(VMReg reg) const {return NULL;} ++ ++ // no PD state to clear or copy: ++ void pd_clear() {} ++ void pd_initialize() {} ++ void pd_initialize_from(const RegisterMap* map) {} ++ ++#endif // CPU_SW64_VM_REGISTERMAP_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/register_sw64.cpp afu11u/src/hotspot/cpu/sw64/register_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/register_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/register_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "register_sw64.hpp" ++ ++const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers << 1; ++ ++const int ConcreteRegisterImpl::max_fpr ++ = ConcreteRegisterImpl::max_gpr + (FloatRegisterImpl::number_of_registers << 1); ++ ++const char* RegisterImpl::name() const { ++ const char* names[number_of_registers] = { ++ "V0", "T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7", ++ "S0", "S1", "S2", "S3", "S4", "S5", ++ "rfp", "A0", "A1", "A2", "A3", "A4", "A5", ++ "T8", "T9", "T10", "T11", ++ "RA", "T12", "AT", "GP", "esp", "Zero" ++ }; ++ 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" ++ }; ++ return is_valid() ? names[encoding()] : "noreg"; ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/register_sw64.hpp afu11u/src/hotspot/cpu/sw64/register_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/register_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/register_sw64.hpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,261 @@ ++/* ++ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_REGISTER_SW64_HPP ++#define CPU_SW64_VM_REGISTER_SW64_HPP ++ ++#include "asm/register.hpp" ++ ++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; ++} ++ ++class RegisterImpl: public AbstractRegisterImpl { ++ public: ++ enum { ++ number_of_registers = 32, ++ number_of_byte_registers = 32, ++ number_of_registers_for_jvmci = 34 // Including SP and ZR. ++ }; ++ ++ // derived registers, offsets, and addresses ++ Register successor() const { return as_Register(encoding() + 1); } ++ ++ // construction ++ inline friend Register as_Register(int encoding); ++ ++ VMReg as_VMReg(); ++ ++ // accessors ++ int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } ++ bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } ++ const char* name() const; ++ int encoding_nocheck() const { return (intptr_t)this; } ++ ++ // Return the bit which represents this register. This is intended ++ // to be ORed into a bitmask: for usage see class RegSet below. ++ unsigned long bit(bool should_set = true) const { return should_set ? 1 << encoding() : 0; } ++}; ++ ++// The integer registers of the sw64 architecture ++ ++CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); ++ ++ ++CONSTANT_REGISTER_DECLARATION(Register, i0, (0)); ++CONSTANT_REGISTER_DECLARATION(Register, i1, (1)); ++CONSTANT_REGISTER_DECLARATION(Register, i2, (2)); ++CONSTANT_REGISTER_DECLARATION(Register, i3, (3)); ++CONSTANT_REGISTER_DECLARATION(Register, i4, (4)); ++CONSTANT_REGISTER_DECLARATION(Register, i5, (5)); ++CONSTANT_REGISTER_DECLARATION(Register, i6, (6)); ++CONSTANT_REGISTER_DECLARATION(Register, i7, (7)); ++CONSTANT_REGISTER_DECLARATION(Register, i8, (8)); ++CONSTANT_REGISTER_DECLARATION(Register, i9, (9)); ++CONSTANT_REGISTER_DECLARATION(Register, i10, (10)); ++CONSTANT_REGISTER_DECLARATION(Register, i11, (11)); ++CONSTANT_REGISTER_DECLARATION(Register, i12, (12)); ++CONSTANT_REGISTER_DECLARATION(Register, i13, (13)); ++CONSTANT_REGISTER_DECLARATION(Register, i14, (14)); ++CONSTANT_REGISTER_DECLARATION(Register, i15, (15)); ++CONSTANT_REGISTER_DECLARATION(Register, i16, (16)); ++CONSTANT_REGISTER_DECLARATION(Register, i17, (17)); ++CONSTANT_REGISTER_DECLARATION(Register, i18, (18)); ++CONSTANT_REGISTER_DECLARATION(Register, i19, (19)); ++CONSTANT_REGISTER_DECLARATION(Register, i20, (20)); ++CONSTANT_REGISTER_DECLARATION(Register, i21, (21)); ++CONSTANT_REGISTER_DECLARATION(Register, i22, (22)); ++CONSTANT_REGISTER_DECLARATION(Register, i23, (23)); ++CONSTANT_REGISTER_DECLARATION(Register, i24, (24)); ++CONSTANT_REGISTER_DECLARATION(Register, i25, (25)); ++CONSTANT_REGISTER_DECLARATION(Register, i26, (26)); ++CONSTANT_REGISTER_DECLARATION(Register, i27, (27)); ++CONSTANT_REGISTER_DECLARATION(Register, i28, (28)); ++CONSTANT_REGISTER_DECLARATION(Register, i29, (29)); ++CONSTANT_REGISTER_DECLARATION(Register, i30, (30)); ++CONSTANT_REGISTER_DECLARATION(Register, i31, (31)); ++ ++ ++// r31 is not a general purpose register, but represents either the ++// stack pointer or the zero/discard register depending on the ++// instruction. ++//CONSTANT_REGISTER_DECLARATION(Register, r31_sp, (31)); ++CONSTANT_REGISTER_DECLARATION(Register, zr, (31)); ++CONSTANT_REGISTER_DECLARATION(Register, sp, (30)); ++ ++// Used as a filler in instructions where a register field is unused. ++const Register dummy_reg = zr; ++ ++// Use FloatRegister as shortcut ++class FloatRegisterImpl; ++typedef FloatRegisterImpl* FloatRegister; ++ ++inline FloatRegister as_FloatRegister(int encoding) { ++ return (FloatRegister)(intptr_t) encoding; ++} ++ ++// The implementation of floating point registers for the architecture ++class FloatRegisterImpl: public AbstractRegisterImpl { ++ public: ++ enum { ++ float_arg_base = 16, ++ number_of_registers = 32 ++ }; ++ ++ // construction ++ inline friend FloatRegister as_FloatRegister(int encoding); ++ ++ VMReg as_VMReg(); ++ ++ // derived registers, offsets, and addresses ++ FloatRegister successor() const { return as_FloatRegister(encoding() + 1); } ++ ++ // accessors ++ int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } ++ int encoding_nocheck() const { return (intptr_t)this; } ++ bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } ++ const char* name() const; ++ ++}; ++ ++// The float registers of the SW64 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)); ++ ++// Need to know the total number of registers of all sorts for SharedInfo. ++// Define a class that exports it. ++class ConcreteRegisterImpl : public AbstractRegisterImpl { ++ public: ++ enum { ++ // A big enough number for C2: all the registers plus flags ++ // 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 + ++ 4 * FloatRegisterImpl::number_of_registers + ++ 1) // flags ++ }; ++ ++ // added to make it compile ++ static const int max_gpr; ++ static const int max_fpr; ++}; ++ ++// A set of registers ++class RegSet { ++ uint32_t _bitset; ++ ++ RegSet(uint32_t bitset) : _bitset(bitset) { } ++ ++public: ++ ++ RegSet() : _bitset(0) { } ++ ++ RegSet(Register r1) : _bitset(r1->bit()) { } ++ ++ RegSet operator+(const RegSet aSet) const { ++ RegSet result(_bitset | aSet._bitset); ++ return result; ++ } ++ ++ RegSet operator-(const RegSet aSet) const { ++ RegSet result(_bitset & ~aSet._bitset); ++ return result; ++ } ++ ++ RegSet &operator+=(const RegSet aSet) { ++ *this = *this + aSet; ++ return *this; ++ } ++ ++ static RegSet of(Register r1) { ++ return RegSet(r1); ++ } ++ ++ static RegSet of(Register r1, Register r2) { ++ return of(r1) + r2; ++ } ++ ++ static RegSet of(Register r1, Register r2, Register r3) { ++ return of(r1, r2) + r3; ++ } ++ ++ static RegSet of(Register r1, Register r2, Register r3, Register r4) { ++ return of(r1, r2, r3) + r4; ++ } ++ ++ static RegSet range(Register start, Register end) { ++ uint32_t bits = ~0; ++ bits <<= start->encoding(); ++ bits <<= 31 - end->encoding(); ++ bits >>= 31 - end->encoding(); ++ ++ return RegSet(bits); ++ } ++ ++ uint32_t bits() const { return _bitset; } ++}; ++ ++#endif // CPU_SW64_VM_REGISTER_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/relocInfo_sw64.cpp afu11u/src/hotspot/cpu/sw64/relocInfo_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/relocInfo_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/relocInfo_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (c) 1998, 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.hpp" ++#include "code/relocInfo.hpp" ++#include "nativeInst_sw64.hpp" ++#include "oops/compressedOops.inline.hpp" ++#include "oops/klass.inline.hpp" ++#include "oops/oop.inline.hpp" ++#include "runtime/safepoint.hpp" ++#include "runtime/safepointMechanism.hpp" ++ ++ ++void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { ++ x += o; ++ typedef Assembler::WhichOperand WhichOperand; ++ WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm, call32, narrow oop ++ assert(which == Assembler::disp32_operand || ++ which == Assembler::narrow_oop_operand || ++ which == Assembler::imm_operand, "format unpacks ok"); ++ if (which == Assembler::imm_operand) { ++ if (verify_only) { ++ assert(nativeMovConstReg_at(addr())->data() == (long)x, "instructions must match"); ++ } else { ++ nativeMovConstReg_at(addr())->set_data((intptr_t)(x)); ++ } ++ } else if (which == Assembler::narrow_oop_operand) { ++ // Unimplemented(); ++ // both compressed oops and compressed classes look the same ++ if (Universe::heap()->is_in_reserved((oop)x)) { ++ if (verify_only) { ++ assert((int32_t)nativeMovConstReg_at(addr())->data() == (int32_t)CompressedOops::encode((oop)x), "instructions must match"); ++ } else { ++ nativeMovConstReg_at(addr())->set_data((intptr_t)(CompressedOops::encode((oop)x))); ++ } ++ } else { ++ if (verify_only) { ++ assert((int32_t)nativeMovConstReg_at(addr())->data() == (int32_t)Klass::encode_klass((Klass*)x), "instructions must match"); ++ } else { ++ nativeMovConstReg_at(addr())->set_data((intptr_t)(Klass::encode_klass((Klass*)x))); ++ } ++ } ++ } else { ++ // Note: Use runtime_call_type relocations for call32_operand. ++ Unimplemented(); ++ assert(0, "call32_operand not supported in SW64"); ++ } ++} ++ ++ ++//NOTICE HERE, this relocate is not need for SW64, since SW64 USE abosolutly target, ++//Maybe We should FORGET CALL RELOCATION ++address Relocation::pd_call_destination(address orig_addr) { ++ NativeInstruction* ni = nativeInstruction_at(addr()); ++ if (ni->is_call()) { ++ return nativeCall_at(addr())->destination(); ++ } else if (ni->is_jump()) { ++ return nativeJump_at(addr())->jump_destination(); ++ } else { ++ tty->print_cr("\nError!\ncall destination: 0x%lx", (long)addr()); ++ Disassembler::decode(addr() - 10 * 4, addr() + 10 * 4, tty); ++ Unimplemented(); ++ return NULL; ++ } ++} ++ ++ ++void Relocation::pd_set_call_destination(address x) { ++ NativeInstruction* ni = nativeInstruction_at(addr()); ++ if (ni->is_call()) { ++ nativeCall_at(addr())->set_destination(x); ++ } else if (ni->is_jump()) { ++ NativeJump* nj = nativeJump_at(addr()); ++ ++ // Unresolved jumps are recognized by a destination of -1 ++ // However 64bit can't actually produce such an address ++ // and encodes a jump to self but jump_destination will ++ // return a -1 as the signal. We must not relocate this ++ // jmp or the ic code will not see it as unresolved. ++ ++ if (nj->jump_destination() == (address) -1) { ++ x = addr(); // jump to self ++ } ++ nj->set_jump_destination(x); ++ } else { ++ ShouldNotReachHere(); ++ } ++} ++ ++ ++address* Relocation::pd_address_in_code() { ++ Unimplemented(); ++ return (address*)addr(); ++} ++ ++ ++address Relocation::pd_get_address_from_code() { ++ NativeMovConstReg* ni = nativeMovConstReg_at(addr()); ++ return (address)ni->data(); ++} ++ ++ ++ ++void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { ++} ++ ++void metadata_Relocation::pd_fix_value(address x) { ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/relocInfo_sw64.hpp afu11u/src/hotspot/cpu/sw64/relocInfo_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/relocInfo_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/relocInfo_sw64.hpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,45 @@ ++/* ++ * 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. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_RELOCINFO_SW64_HPP ++#define CPU_SW64_VM_RELOCINFO_SW64_HPP ++ ++ // machine-dependent parts of class relocInfo ++ private: ++ enum { ++ // Since SW64 instructions are whole words, ++ // the two low-order offset bits can always be discarded. ++ offset_unit = 4, ++ ++ // imm_oop_operand vs. narrow_oop_operand ++ format_width = 2 ++ }; ++ ++ public: ++ ++ // This platform has no oops in the code that are not also ++ // listed in the oop section. ++ static bool mustIterateImmediateOopsInCode() { return false; } ++ ++#endif // CPU_SW64_VM_RELOCINFO_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/runtime_sw64.cpp afu11u/src/hotspot/cpu/sw64/runtime_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/runtime_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/runtime_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,188 @@ ++/* ++ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#ifdef COMPILER2 ++#include "asm/macroAssembler.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "classfile/systemDictionary.hpp" ++#include "code/vmreg.hpp" ++#include "interpreter/interpreter.hpp" ++#include "opto/runtime.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "runtime/vframeArray.hpp" ++#include "utilities/globalDefinitions.hpp" ++#include "vmreg_sw64.inline.hpp" ++#endif ++ ++#define __ masm-> ++ ++//-------------- generate_exception_blob ----------- ++// creates _exception_blob. ++// The exception blob is jumped to 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 jump, and left with a jump. ++// ++// Arguments: ++// V0: exception oop ++// T4: exception pc ++// ++// Results: ++// A0: exception oop ++// A1: exception pc in caller or ??? ++// jumps to: exception handler of caller ++// ++// Note: the exception pc MUST be at a call (precise debug information) ++// ++// [stubGenerator_sw64.cpp] generate_forward_exception() ++// |- V0, T4 are created ++// |- T12 <= SharedRuntime::exception_handler_for_return_address ++// `- jr T12 ++// `- the caller's exception_handler ++// `- jr OptoRuntime::exception_blob ++// `- here ++// ++//void OptoRuntime::generate_exception_blob() { ++// // Capture info about frame layout ++// enum layout { ++// fp_off, ++// return_off, // slot for return address ++// framesize ++// }; ++// ++// // allocate space for the code ++// ResourceMark rm; ++// // setup code generation tools ++// CodeBuffer buffer("exception_blob", 5120, 5120); ++// MacroAssembler* masm = new MacroAssembler(&buffer); ++// ++// ++// address start = __ pc(); ++// ++// __ addiu(esp, -1 * framesize * wordSize, esp); // Prolog! ++// ++// // this frame will be treated as the original caller method. ++// // So, the return pc should be filled with the original exception pc. ++// // ref: X86's implementation ++// __ stl(T4, return_off *wordSize, esp); // return address ++// __ stl(rfp, fp_off *wordSize, esp); ++// ++// // Save callee saved registers. None for UseSSE=0, ++// // floats-only for UseSSE=1, and doubles for UseSSE=2. ++// ++// __ addiu(esp, fp_off * wordSize, rfp); ++// ++// // Store exception in Thread object. We cannot pass any arguments to the ++// // handle_exception call, since we do not want to make any assumption ++// // about the size of the frame where the exception happened in. ++// Register thread = rthread; ++// ++// __ std(V0, Address(thread, JavaThread::exception_oop_offset())); ++// __ std(T4, Address(thread, JavaThread::exception_pc_offset())); ++// ++// // This call does all the hard work. It checks if an exception handler ++// // exists in the method. ++// // If so, it returns the handler address. ++// // If not, it prepares for stack-unwinding, restoring the callee-save ++// // registers of the frame being removed. ++// //no matching function for call to 'MacroAssembler::set_last_Java_frame(RegisterImpl*&, RegisterImpl* const&, RegisterImpl* const&, address) ++//// __ set_last_Java_frame(thread, noreg, noreg, (address)NULL); ++// ++// __ mov(AT, -(StackAlignmentInBytes)); ++// __ andr(esp, esp, AT); // Fix stack alignment as required by ABI ++// ++//#ifdef ZHJ20180909 ++// __ relocate(relocInfo::internal_pc_type); ++// { ++// // patchable_set48 (4) + sd (1) + move (1) + patchable_call_setfpec1 ++// long save_pc = (long)__ pc() + 24 + NativeCall::return_address_offset; ++// __ patchable_set48(AT, save_pc); ++// } ++//#else ++// { ++// // addl (1) + sd (1) + move(1) + patchable_call_setfpec1 ++// intptr_t patch_off = 3 * BytesPerInstWord + NativeCall::return_address_offset; ++// __ br(AT, 0); ++// __ addl(AT, patch_off, AT); ++// } ++//#endif ++// __ stl(AT, in_bytes(JavaThread::last_Java_pc_offset()), thread); ++// ++// __ move(A0, thread); ++// __ patchable_call_setfpec1((address)OptoRuntime::handle_exception_C); ++// ++// // Set an oopmap for the call site ++// OopMapSet *oop_maps = new OopMapSet(); ++// OopMap* map = new OopMap( framesize, 0 ); ++// ++// oop_maps->add_gc_map( __ offset() - 4, map); ++// ++// __ reset_last_Java_frame(thread, true); ++// ++// // Pop self-frame. ++// __ leave(); // Epilog! ++// ++// // V0: exception handler ++// ++// // We have a handler in V0, (could be deopt blob) ++// __ move(T12, V0); ++// ++// // Get the exception ++// __ ld(A0, Address(thread, JavaThread::exception_oop_offset())); ++// // Get the exception pc in case we are deoptimized ++// __ ld(A1, Address(thread, JavaThread::exception_pc_offset())); ++//#ifdef ASSERT ++// __ std(R0, Address(thread, JavaThread::exception_handler_pc_offset())); ++// __ std(R0, Address(thread, JavaThread::exception_pc_offset())); ++//#endif ++// // Clear the exception oop so GC no longer processes it as a root. ++// __ std(R0, Address(thread, JavaThread::exception_oop_offset())); ++// ++// // Fix seg fault when running: ++// // Eclipse + Plugin + Debug As ++// // This is the only condition where C2 calls SharedRuntime::generate_deopt_blob() ++// // ++// __ move(V0, A0); ++// __ move(T4, A1); ++// ++// // V0: exception oop ++// // T12: exception handler ++// // A1: exception pc ++// __ jr(T12); ++// ++// // make sure all code is generated ++// masm->flush(); ++// ++// _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize); ++//} +diff -uNr openjdk/src/hotspot/cpu/sw64/sharedRuntime_sw64.cpp afu11u/src/hotspot/cpu/sw64/sharedRuntime_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/sharedRuntime_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/sharedRuntime_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,4578 @@ ++/* ++ * 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. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "code/debugInfoRec.hpp" ++#include "code/icBuffer.hpp" ++#include "code/nativeInst.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 "runtime/safepointMechanism.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/vframeArray.hpp" ++#include "runtime/vm_version.hpp" ++#include "utilities/align.hpp" ++#include "utilities/formatBuffer.hpp" ++#include "utilities/macros.hpp" ++#include "vmreg_sw64.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 ++#if INCLUDE_SHENANDOAHGC ++#include "gc/shenandoah/shenandoahBarrierSet.hpp" ++#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" ++#endif ++ ++#define __ masm-> ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; ++ ++class SimpleRuntimeFrame { ++ ++ public: ++ ++ // Most of the runtime stubs have this simple frame layout. ++ // This class exists to make the layout shared in one place. ++ // Offsets are for compiler stack slots, which are jints. ++ enum layout { ++ // The frame sender code expects that rbp will be in the "natural" place and ++ // will override any oopMap setting for it. We must therefore force the layout ++ // so that it agrees with the frame sender code. ++// rfp_off = frame::arg_reg_save_area_bytes/BytesPerInt,//not understand? jzy ++ rfp_off = 0, ++ rfp_off2, ++ return_off, return_off2, ++ framesize ++ }; ++}; ++ ++class RegisterSaver { ++public: ++ enum { FPU_regs_live = 32 }; ++ // Capture info about frame layout ++ enum layout { ++#define DEF_LAYOUT_OFFS(regname) regname ## _off, regname ## H_off, ++ DEF_LAYOUT_OFFS(for_16_bytes_aligned) ++ DEF_LAYOUT_OFFS(fpr0) ++ DEF_LAYOUT_OFFS(fpr1) ++ DEF_LAYOUT_OFFS(fpr2) ++ DEF_LAYOUT_OFFS(fpr3) ++ DEF_LAYOUT_OFFS(fpr4) ++ DEF_LAYOUT_OFFS(fpr5) ++ DEF_LAYOUT_OFFS(fpr6) ++ DEF_LAYOUT_OFFS(fpr7) ++ DEF_LAYOUT_OFFS(fpr8) ++ DEF_LAYOUT_OFFS(fpr9) ++ DEF_LAYOUT_OFFS(fpr10) ++ DEF_LAYOUT_OFFS(fpr11) ++ DEF_LAYOUT_OFFS(fpr12) ++ DEF_LAYOUT_OFFS(fpr13) ++ DEF_LAYOUT_OFFS(fpr14) ++ DEF_LAYOUT_OFFS(fpr15) ++ DEF_LAYOUT_OFFS(fpr16) ++ DEF_LAYOUT_OFFS(fpr17) ++ DEF_LAYOUT_OFFS(fpr18) ++ DEF_LAYOUT_OFFS(fpr19) ++ DEF_LAYOUT_OFFS(fpr20) ++ DEF_LAYOUT_OFFS(fpr21) ++ DEF_LAYOUT_OFFS(fpr22) ++ DEF_LAYOUT_OFFS(fpr23) ++ DEF_LAYOUT_OFFS(fpr24) ++ DEF_LAYOUT_OFFS(fpr25) ++ DEF_LAYOUT_OFFS(fpr26) ++ DEF_LAYOUT_OFFS(fpr27) ++ DEF_LAYOUT_OFFS(fpr28) ++ DEF_LAYOUT_OFFS(fpr29) ++ DEF_LAYOUT_OFFS(fpr30) ++ DEF_LAYOUT_OFFS(fpr31) ++ ++ DEF_LAYOUT_OFFS(v0) ++ DEF_LAYOUT_OFFS(t0) ++ DEF_LAYOUT_OFFS(t1) ++ DEF_LAYOUT_OFFS(t2) ++ DEF_LAYOUT_OFFS(t3) ++ DEF_LAYOUT_OFFS(t4) ++ DEF_LAYOUT_OFFS(t5) ++ DEF_LAYOUT_OFFS(t6) ++ DEF_LAYOUT_OFFS(t7) ++ DEF_LAYOUT_OFFS(s0) ++ DEF_LAYOUT_OFFS(s1) ++ DEF_LAYOUT_OFFS(s2) ++ DEF_LAYOUT_OFFS(s3) ++ DEF_LAYOUT_OFFS(s4) ++ DEF_LAYOUT_OFFS(s5) ++ // rfp move down ++ DEF_LAYOUT_OFFS(a0) ++ DEF_LAYOUT_OFFS(a1) ++ DEF_LAYOUT_OFFS(a2) ++ DEF_LAYOUT_OFFS(a3) ++ DEF_LAYOUT_OFFS(a4) ++ DEF_LAYOUT_OFFS(a5) ++ DEF_LAYOUT_OFFS(t8) ++ DEF_LAYOUT_OFFS(t9) ++ DEF_LAYOUT_OFFS(t10) ++ DEF_LAYOUT_OFFS(t11) ++ // RA move down ++ DEF_LAYOUT_OFFS(t12) ++ // no AT ++ DEF_LAYOUT_OFFS(gp) ++ // no esp ++ // no R0 ++ DEF_LAYOUT_OFFS(fp) ++ DEF_LAYOUT_OFFS(return) ++ reg_save_size ++ }; ++ ++ public: ++ static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors = false); ++ static void restore_live_registers(MacroAssembler* masm, bool restore_vectors = false); ++ ++ //static int raOffset(void) { return return_off / 2; } ++ //static int methodOffset(void) { return s3_off / 2; } ++ //static int v0Offset(void) { return v0_off / 2; } ++ ++ //static int fpResultOffset_todelete(void) { ShouldNotReachHere();return fpr0_off / 2; } ++ static int v0_offset_in_bytes(void) { return BytesPerInt * v0_off; } ++ static int a2_offset_in_bytes(void) { return a2_off / 2; } ++ static int rmethod_offset_in_bytes(void) { return BytesPerInt * s3_off; } ++ static int fsf_offset_in_bytes(void) { return BytesPerInt * fpr0_off; } ++ static int return_offset_in_bytes(void) { return BytesPerInt * return_off; } ++ // During deoptimization only the result registers need to be restored, ++ // all the other values have already been extracted. ++ static void restore_result_registers(MacroAssembler* masm); ++}; ++ ++//put here becauseof RegisterSaver's layout ++static void push_CPU_state(MacroAssembler* masm) { ++ __ subptr(esp, (RegisterSaver::reg_save_size-4) * jintSize, esp); ++ ++ __ fstd(f0, RegisterSaver::fpr0_off * jintSize, esp); __ fstd(f1, RegisterSaver::fpr1_off * jintSize, esp); ++ __ fstd(f2, RegisterSaver::fpr2_off * jintSize, esp); __ fstd(f3, RegisterSaver::fpr3_off * jintSize, esp); ++ __ fstd(f4, RegisterSaver::fpr4_off * jintSize, esp); __ fstd(f5, RegisterSaver::fpr5_off * jintSize, esp); ++ __ fstd(f6, RegisterSaver::fpr6_off * jintSize, esp); __ fstd(f7, RegisterSaver::fpr7_off * jintSize, esp); ++ __ fstd(f8, RegisterSaver::fpr8_off * jintSize, esp); __ fstd(f9, RegisterSaver::fpr9_off * jintSize, esp); ++ __ fstd(f10, RegisterSaver::fpr10_off * jintSize, esp); __ fstd(f11, RegisterSaver::fpr11_off * jintSize, esp); ++ __ fstd(f12, RegisterSaver::fpr12_off * jintSize, esp); __ fstd(f13, RegisterSaver::fpr13_off * jintSize, esp); ++ __ fstd(f14, RegisterSaver::fpr14_off * jintSize, esp); __ fstd(f15, RegisterSaver::fpr15_off * jintSize, esp); ++ __ fstd(f16, RegisterSaver::fpr16_off * jintSize, esp); __ fstd(f17, RegisterSaver::fpr17_off * jintSize, esp); ++ __ fstd(f18, RegisterSaver::fpr18_off * jintSize, esp); __ fstd(f19, RegisterSaver::fpr19_off * jintSize, esp); ++ __ fstd(f20, RegisterSaver::fpr20_off * jintSize, esp); __ fstd(f21, RegisterSaver::fpr21_off * jintSize, esp); ++ __ fstd(f22, RegisterSaver::fpr22_off * jintSize, esp); __ fstd(f23, RegisterSaver::fpr23_off * jintSize, esp); ++ __ fstd(f24, RegisterSaver::fpr24_off * jintSize, esp); __ fstd(f25, RegisterSaver::fpr25_off * jintSize, esp); ++ __ fstd(f26, RegisterSaver::fpr26_off * jintSize, esp); __ fstd(f27, RegisterSaver::fpr27_off * jintSize, esp); ++ __ fstd(f28, RegisterSaver::fpr28_off * jintSize, esp); __ fstd(f29, RegisterSaver::fpr29_off * jintSize, esp); ++ __ fstd(f30, RegisterSaver::fpr30_off * jintSize, esp); ++ ++ __ stl(V0, Address(esp, RegisterSaver::v0_off * jintSize)); ++ __ stl(i1, Address(esp, RegisterSaver::t0_off * jintSize)); ++ __ stl(i2, Address(esp, RegisterSaver::t1_off * jintSize)); ++ __ stl(i3, Address(esp, RegisterSaver::t2_off * jintSize)); ++ __ stl(i4, Address(esp, RegisterSaver::t3_off * jintSize)); ++ __ stl(i5, Address(esp, RegisterSaver::t4_off * jintSize)); ++ __ stl(i6, Address(esp, RegisterSaver::t5_off * jintSize)); ++ __ stl(i7, Address(esp, RegisterSaver::t6_off * jintSize)); ++ __ stl(i8, Address(esp, RegisterSaver::t7_off * jintSize)); ++ __ stl(i9, Address(esp, RegisterSaver::s0_off * jintSize)); ++ __ stl(i10, Address(esp, RegisterSaver::s1_off * jintSize)); ++ __ stl(i11, Address(esp, RegisterSaver::s2_off * jintSize)); ++ __ stl(i12, Address(esp, RegisterSaver::s3_off * jintSize)); ++ __ stl(i13, Address(esp, RegisterSaver::s4_off * jintSize)); ++ __ stl(i14, Address(esp, RegisterSaver::s5_off * jintSize)); ++ __ stl(i16, Address(esp, RegisterSaver::a0_off * jintSize)); ++ __ stl(i17, Address(esp, RegisterSaver::a1_off * jintSize)); ++ __ stl(i18, Address(esp, RegisterSaver::a2_off * jintSize)); ++ __ stl(i19, Address(esp, RegisterSaver::a3_off * jintSize)); ++ __ stl(i20, Address(esp, RegisterSaver::a4_off * jintSize)); ++ __ stl(i21, Address(esp, RegisterSaver::a5_off * jintSize)); ++ __ stl(i22, Address(esp, RegisterSaver::t8_off * jintSize)); ++ __ stl(i23, Address(esp, RegisterSaver::t9_off * jintSize)); ++ __ stl(i24, Address(esp, RegisterSaver::t10_off * jintSize)); ++ __ stl(i25, Address(esp, RegisterSaver::t11_off * jintSize)); ++ __ stl(i27, Address(esp, RegisterSaver::t12_off * jintSize)); ++ ++ __ stl(GP, Address(esp, RegisterSaver::gp_off * jintSize)); ++ //__ stl(rfp, Address(esp, RegisterSaver::fp_off * jintSize)); ++ //__ stl(RA, Address(esp, RegisterSaver::return_off * jintSize)); ++} ++ ++static void pop_CPU_state(MacroAssembler* masm) { ++ __ fldd(f0, RegisterSaver::fpr0_off * jintSize, esp); __ fldd(f1, RegisterSaver::fpr1_off * jintSize, esp); ++ __ fldd(f2, RegisterSaver::fpr2_off * jintSize, esp); __ fldd(f3, RegisterSaver::fpr3_off * jintSize, esp); ++ __ fldd(f4, RegisterSaver::fpr4_off * jintSize, esp); __ fldd(f5, RegisterSaver::fpr5_off * jintSize, esp); ++ __ fldd(f6, RegisterSaver::fpr6_off * jintSize, esp); __ fldd(f7, RegisterSaver::fpr7_off * jintSize, esp); ++ __ fldd(f8, RegisterSaver::fpr8_off * jintSize, esp); __ fldd(f9, RegisterSaver::fpr9_off * jintSize, esp); ++ __ fldd(f10, RegisterSaver::fpr10_off * jintSize, esp); __ fldd(f11, RegisterSaver::fpr11_off * jintSize, esp); ++ __ fldd(f12, RegisterSaver::fpr12_off * jintSize, esp); __ fldd(f13, RegisterSaver::fpr13_off * jintSize, esp); ++ __ fldd(f14, RegisterSaver::fpr14_off * jintSize, esp); __ fldd(f15, RegisterSaver::fpr15_off * jintSize, esp); ++ __ fldd(f16, RegisterSaver::fpr16_off * jintSize, esp); __ fldd(f17, RegisterSaver::fpr17_off * jintSize, esp); ++ __ fldd(f18, RegisterSaver::fpr18_off * jintSize, esp); __ fldd(f19, RegisterSaver::fpr19_off * jintSize, esp); ++ __ fldd(f20, RegisterSaver::fpr20_off * jintSize, esp); __ fldd(f21, RegisterSaver::fpr21_off * jintSize, esp); ++ __ fldd(f22, RegisterSaver::fpr22_off * jintSize, esp); __ fldd(f23, RegisterSaver::fpr23_off * jintSize, esp); ++ __ fldd(f24, RegisterSaver::fpr24_off * jintSize, esp); __ fldd(f25, RegisterSaver::fpr25_off * jintSize, esp); ++ __ fldd(f26, RegisterSaver::fpr26_off * jintSize, esp); __ fldd(f27, RegisterSaver::fpr27_off * jintSize, esp); ++ __ fldd(f28, RegisterSaver::fpr28_off * jintSize, esp); __ fldd(f29, RegisterSaver::fpr29_off * jintSize, esp); ++ __ fldd(f30, RegisterSaver::fpr30_off * jintSize, esp); ++ ++ __ ldl(V0, Address(esp, RegisterSaver::v0_off * jintSize)); ++ __ ldl(i1, Address(esp, RegisterSaver::t0_off * jintSize)); ++ __ ldl(i2, Address(esp, RegisterSaver::t1_off * jintSize)); ++ __ ldl(i3, Address(esp, RegisterSaver::t2_off * jintSize)); ++ __ ldl(i4, Address(esp, RegisterSaver::t3_off * jintSize)); ++ __ ldl(i5, Address(esp, RegisterSaver::t4_off * jintSize)); ++ __ ldl(i6, Address(esp, RegisterSaver::t5_off * jintSize)); ++ __ ldl(i7, Address(esp, RegisterSaver::t6_off * jintSize)); ++ __ ldl(i8, Address(esp, RegisterSaver::t7_off * jintSize)); ++ __ ldl(i9, Address(esp, RegisterSaver::s0_off * jintSize)); ++ __ ldl(i10, Address(esp, RegisterSaver::s1_off * jintSize)); ++ __ ldl(i11, Address(esp, RegisterSaver::s2_off * jintSize)); ++ __ ldl(i12, Address(esp, RegisterSaver::s3_off * jintSize)); ++ __ ldl(i13, Address(esp, RegisterSaver::s4_off * jintSize)); ++ __ ldl(i14, Address(esp, RegisterSaver::s5_off * jintSize)); ++ __ ldl(i16, Address(esp, RegisterSaver::a0_off * jintSize)); ++ __ ldl(i17, Address(esp, RegisterSaver::a1_off * jintSize)); ++ __ ldl(i18, Address(esp, RegisterSaver::a2_off * jintSize)); ++ __ ldl(i19, Address(esp, RegisterSaver::a3_off * jintSize)); ++ __ ldl(i20, Address(esp, RegisterSaver::a4_off * jintSize)); ++ __ ldl(i21, Address(esp, RegisterSaver::a5_off * jintSize)); ++ __ ldl(i22, Address(esp, RegisterSaver::t8_off * jintSize)); ++ __ ldl(i23, Address(esp, RegisterSaver::t9_off * jintSize)); ++ __ ldl(i24, Address(esp, RegisterSaver::t10_off * jintSize)); ++ __ ldl(i25, Address(esp, RegisterSaver::t11_off * jintSize)); ++ __ ldl(i27, Address(esp, RegisterSaver::t12_off * jintSize)); ++ ++ __ ldl(GP, Address(esp, RegisterSaver::gp_off * jintSize)); ++// __ ldl(rfp, Address(esp, RegisterSaver::fp_off * jintSize)); ++// __ ldl(RA, Address(esp, RegisterSaver::return_off * jintSize)); ++ ++ __ addptr(esp, (RegisterSaver::reg_save_size-4) * jintSize, esp); ++} ++ ++ ++OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) {SCOPEMARK_NAME(save_live_registers, masm);//__ stop("save_live_registers"); ++/*#if COMPILER2_OR_JVMCI ++ if (save_vectors) { ++ // Save upper half of vector registers ++ int vect_words = 32 * 8 / wordSize; ++ additional_frame_words += vect_words; ++ } ++#else ++ assert(!save_vectors, "vectors are generated only by C2 and JVMCI"); ++#endif ++*/ ++ int frame_size_in_bytes = align_up(additional_frame_words*wordSize + ++ reg_save_size*BytesPerInt, 16); ++ // OopMap frame size is in compiler stack slots (jint's) not bytes or words ++ int frame_size_in_slots = frame_size_in_bytes / BytesPerInt; ++ // The caller will allocate additional_frame_words ++ int additional_frame_slots = additional_frame_words*wordSize / BytesPerInt; ++ // CodeBlob frame size is in words. ++ int frame_size_in_words = frame_size_in_bytes / wordSize; ++ *total_frame_words = frame_size_in_words; ++ ++ // save registers ++ __ enter(); ++ push_CPU_state(masm); ++ /*__ subptr(esp, reg_save_size * jintSize, esp, rscratch1_GP); ++ ++ __ fstd(f0, fpr0_off * jintSize, esp); __ fstd(f1, fpr1_off * jintSize, esp); ++ __ fstd(f2, fpr2_off * jintSize, esp); __ fstd(f3, fpr3_off * jintSize, esp); ++ __ fstd(f4, fpr4_off * jintSize, esp); __ fstd(f5, fpr5_off * jintSize, esp); ++ __ fstd(f6, fpr6_off * jintSize, esp); __ fstd(f7, fpr7_off * jintSize, esp); ++ __ fstd(f8, fpr8_off * jintSize, esp); __ fstd(f9, fpr9_off * jintSize, esp); ++ __ fstd(f10, fpr10_off * jintSize, esp); __ fstd(f11, fpr11_off * jintSize, esp); ++ __ fstd(f12, fpr12_off * jintSize, esp); __ fstd(f13, fpr13_off * jintSize, esp); ++ __ fstd(f14, fpr14_off * jintSize, esp); __ fstd(f15, fpr15_off * jintSize, esp); ++ __ fstd(f16, fpr16_off * jintSize, esp); __ fstd(f17, fpr17_off * jintSize, esp); ++ __ fstd(f18, fpr18_off * jintSize, esp); __ fstd(f19, fpr19_off * jintSize, esp); ++ __ fstd(f20, fpr20_off * jintSize, esp); __ fstd(f21, fpr21_off * jintSize, esp); ++ __ fstd(f22, fpr22_off * jintSize, esp); __ fstd(f23, fpr23_off * jintSize, esp); ++ __ fstd(f24, fpr24_off * jintSize, esp); __ fstd(f25, fpr25_off * jintSize, esp); ++ __ fstd(f26, fpr26_off * jintSize, esp); __ fstd(f27, fpr27_off * jintSize, esp); ++ __ fstd(f28, fpr28_off * jintSize, esp); __ fstd(f29, fpr29_off * jintSize, esp); ++ __ fstd(f30, fpr30_off * jintSize, esp); ++ ++ __ stl(V0, Address(esp, v0_off * jintSize)); ++ __ stl(i1, Address(esp, t0_off * jintSize)); ++ __ stl(i2, Address(esp, t1_off * jintSize)); ++ __ stl(i3, Address(esp, t2_off * jintSize)); ++ __ stl(i4, Address(esp, t3_off * jintSize)); ++ __ stl(i5, Address(esp, t4_off * jintSize)); ++ __ stl(i6, Address(esp, t5_off * jintSize)); ++ __ stl(i7, Address(esp, t6_off * jintSize)); ++ __ stl(i8, Address(esp, t7_off * jintSize)); ++ __ stl(i9, Address(esp, s0_off * jintSize)); ++ __ stl(i10, Address(esp, s1_off * jintSize)); ++ __ stl(i11, Address(esp, s2_off * jintSize)); ++ __ stl(i12, Address(esp, s3_off * jintSize)); ++ __ stl(i13, Address(esp, s4_off * jintSize)); ++ __ stl(i14, Address(esp, s5_off * jintSize)); ++ __ stl(i16, Address(esp, a0_off * jintSize)); ++ __ stl(i17, Address(esp, a1_off * jintSize)); ++ __ stl(i18, Address(esp, a2_off * jintSize)); ++ __ stl(i19, Address(esp, a3_off * jintSize)); ++ __ stl(i20, Address(esp, a4_off * jintSize)); ++ __ stl(i21, Address(esp, a5_off * jintSize)); ++ __ stl(i22, Address(esp, t8_off * jintSize)); ++ __ stl(i23, Address(esp, t9_off * jintSize)); ++ __ stl(i24, Address(esp, t10_off * jintSize)); ++ __ stl(i25, Address(esp, t11_off * jintSize)); ++ __ stl(i27, Address(esp, t12_off * jintSize)); ++ ++ __ stl(GP, Address(esp, gp_off * jintSize)); ++ __ stl(rfp, Address(esp, fp_off * jintSize)); ++ __ stl(RA, Address(esp, return_off * jintSize));*/ ++ //__ addiu(SP, fp_off * jintSize, FP); //TODO:why add this in sw8? jzy ++ ++ OopMapSet *oop_maps = new OopMapSet(); ++ OopMap* map = new OopMap(frame_size_in_slots, 0); ++ ++#define STACK_OFFSET(x) VMRegImpl::stack2reg((x) + additional_frame_slots) ++ ++ map->set_callee_saved(STACK_OFFSET( v0_off), V0->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t0_off), i1->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t1_off), i2->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t2_off), i3->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t3_off), i4->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t4_off), i5->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t5_off), i6->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t6_off), i7->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t7_off), i8->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( s0_off), i9->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( s1_off), i10->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( s2_off), i11->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( s3_off), i12->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( s4_off), i13->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( s5_off), i14->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( a0_off), A0->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( a1_off), A1->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( a2_off), A2->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( a3_off), A3->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( a4_off), A4->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( a5_off), A5->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t8_off), i22->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t9_off), i23->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t10_off), i24->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t11_off), i25->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( t12_off), i27->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( gp_off), GP->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fp_off), rfp->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( return_off), RA->as_VMReg()); ++ ++ map->set_callee_saved(STACK_OFFSET( fpr0_off), f0->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr1_off), f1->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr2_off), f2->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr3_off), f3->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr4_off), f4->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr5_off), f5->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr6_off), f6->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr7_off), f7->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr8_off), f8->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr9_off), f9->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr10_off), f10->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr11_off), f11->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr12_off), f12->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr13_off), f13->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr14_off), f14->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr15_off), f15->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr16_off), f16->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr17_off), f17->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr18_off), f18->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr19_off), f19->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr20_off), f20->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr21_off), f21->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr22_off), f22->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr23_off), f23->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr24_off), f24->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr25_off), f25->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr26_off), f26->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr27_off), f27->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr28_off), f28->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr29_off), f29->as_VMReg()); ++ map->set_callee_saved(STACK_OFFSET( fpr30_off), f30->as_VMReg()); ++ ++#undef STACK_OFFSET ++ return map; ++} ++ ++void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_vectors) {SCOPEMARK_NAME(restore_live_registers, masm);//__ stop("restore_live_registers"); ++ /*__ fldd(f0, fpr0_off * jintSize, esp); __ fldd(f1, fpr1_off * jintSize, esp); ++ __ fldd(f2, fpr2_off * jintSize, esp); __ fldd(f3, fpr3_off * jintSize, esp); ++ __ fldd(f4, fpr4_off * jintSize, esp); __ fldd(f5, fpr5_off * jintSize, esp); ++ __ fldd(f6, fpr6_off * jintSize, esp); __ fldd(f7, fpr7_off * jintSize, esp); ++ __ fldd(f8, fpr8_off * jintSize, esp); __ fldd(f9, fpr9_off * jintSize, esp); ++ __ fldd(f10, fpr10_off * jintSize, esp); __ fldd(f11, fpr11_off * jintSize, esp); ++ __ fldd(f12, fpr12_off * jintSize, esp); __ fldd(f13, fpr13_off * jintSize, esp); ++ __ fldd(f14, fpr14_off * jintSize, esp); __ fldd(f15, fpr15_off * jintSize, esp); ++ __ fldd(f16, fpr16_off * jintSize, esp); __ fldd(f17, fpr17_off * jintSize, esp); ++ __ fldd(f18, fpr18_off * jintSize, esp); __ fldd(f19, fpr19_off * jintSize, esp); ++ __ fldd(f20, fpr20_off * jintSize, esp); __ fldd(f21, fpr21_off * jintSize, esp); ++ __ fldd(f22, fpr22_off * jintSize, esp); __ fldd(f23, fpr23_off * jintSize, esp); ++ __ fldd(f24, fpr24_off * jintSize, esp); __ fldd(f25, fpr25_off * jintSize, esp); ++ __ fldd(f26, fpr26_off * jintSize, esp); __ fldd(f27, fpr27_off * jintSize, esp); ++ __ fldd(f28, fpr28_off * jintSize, esp); __ fldd(f29, fpr29_off * jintSize, esp); ++ __ fldd(f30, fpr30_off * jintSize, esp); ++ ++ __ ldl(V0, Address(esp, v0_off * jintSize)); ++ __ ldl(i1, Address(esp, t0_off * jintSize)); ++ __ ldl(i2, Address(esp, t1_off * jintSize)); ++ __ ldl(i3, Address(esp, t2_off * jintSize)); ++ __ ldl(i4, Address(esp, t3_off * jintSize)); ++ __ ldl(i5, Address(esp, t4_off * jintSize)); ++ __ ldl(i6, Address(esp, t5_off * jintSize)); ++ __ ldl(i7, Address(esp, t6_off * jintSize)); ++ __ ldl(i8, Address(esp, t7_off * jintSize)); ++ __ ldl(i9, Address(esp, s0_off * jintSize)); ++ __ ldl(i10, Address(esp, s1_off * jintSize)); ++ __ ldl(i11, Address(esp, s2_off * jintSize)); ++ __ ldl(i12, Address(esp, s3_off * jintSize)); ++ __ ldl(i13, Address(esp, s4_off * jintSize)); ++ __ ldl(i14, Address(esp, s5_off * jintSize)); ++ __ ldl(i16, Address(esp, a0_off * jintSize)); ++ __ ldl(i17, Address(esp, a1_off * jintSize)); ++ __ ldl(i18, Address(esp, a2_off * jintSize)); ++ __ ldl(i19, Address(esp, a3_off * jintSize)); ++ __ ldl(i20, Address(esp, a4_off * jintSize)); ++ __ ldl(i21, Address(esp, a5_off * jintSize)); ++ __ ldl(i22, Address(esp, t8_off * jintSize)); ++ __ ldl(i23, Address(esp, t9_off * jintSize)); ++ __ ldl(i24, Address(esp, t10_off * jintSize)); ++ __ ldl(i25, Address(esp, t11_off * jintSize)); ++ __ ldl(i27, Address(esp, t12_off * jintSize)); ++ ++ __ ldl(GP, Address(esp, gp_off * jintSize)); ++ __ ldl(rfp, Address(esp, fp_off * jintSize)); ++ __ ldl(RA, Address(esp, return_off * jintSize)); ++ ++ __ addptr(esp, reg_save_size * jintSize, esp, rscratch1_GP);*/ ++ ++ // Recover CPU state ++ pop_CPU_state(masm); ++ // Get the rbp described implicitly by the calling convention (no oopMap) ++ __ leave(); ++} ++ ++void RegisterSaver::restore_result_registers(MacroAssembler* masm) {//__ stop("restore_result_registers"); ++ ++ // Just restore result register. Only used by deoptimization. By ++ // now any callee save register that needs to be restored to a c2 ++ // caller of the deoptee has been extracted into the vframeArray ++ // and will be stuffed into the c2i adapter we create for later ++ // restoration so only result registers need to be restored here. ++ ++ // Restore integer result register ++ __ ldl(V0, v0_offset_in_bytes(), esp); ++ // Restore fp result register ++ __ load_double(FSF, Address(esp, fsf_offset_in_bytes())); ++ ++ // Pop all of the register save are off the stack ++ __ addptr(esp, return_offset_in_bytes(), esp); ++} ++ ++// Is vector's size (in bytes) bigger than a size saved by default? ++// 16 bytes XMM registers are saved by default using fxsave/fxrstor instructions. ++bool SharedRuntime::is_wide_vector(int size) { ++ return size > 16; ++} ++ ++size_t SharedRuntime::trampoline_size() { ++ ShouldNotCallThis(); ++ return 16; ++} ++ ++void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {__ stop("generate_trampoline"); ++ __ jump(RuntimeAddress(destination));//TODO:which rscratch register in C2? ++} ++ ++// The java_calling_convention describes stack locations as ideal slots on ++// a frame with no abi restrictions. Si ++// nce we must observe abi restrictions ++// (like the placement of the register window) the slots must be biased by ++// the following value. ++static int reg2offset_in(VMReg r) { ++ // Account for saved rbp and return address ++ // This should really be in_preserve_stack_slots ++ return (r->reg2stack() + 4) * VMRegImpl::stack_slot_size; ++} ++ ++static int reg2offset_out(VMReg r) { ++ return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; ++} ++ ++// --------------------------------------------------------------------------- ++// 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 ++// quantities. Values less than VMRegImpl::stack0 are registers, those above ++// refer to 4-byte stack slots. All stack slots are based off of the stack pointer ++// as framesizes are fixed. ++// VMRegImpl::stack0 refers to the first slot 0(sp). ++// and VMRegImpl::stack0+1 refers to the memory word 4-byes higher. Register ++// up to RegisterImpl::number_of_registers) are the 64-bit ++// integer registers. ++ ++// 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. Of course for i486 there is no 64 bit build ++ ++// The Java calling convention is a "shifted" version of the C ABI. ++// By skipping the first C ABI register we can call non-static jni methods ++// with small numbers of arguments without having to shuffle the arguments ++// at all. Since we control the java ABI we ought to at least get some ++// advantage out of it. ++ ++int SharedRuntime::java_calling_convention(const BasicType *sig_bt, ++ VMRegPair *regs, ++ int total_args_passed, ++ int is_outgoing) { ++ ++ // Create the mapping between argument positions and ++ // registers. ++ static const Register INT_ArgReg[Argument::n_int_register_parameters_j] = { ++ j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5 ++ }; ++ static const FloatRegister FP_ArgReg[Argument::n_float_register_parameters_j] = { ++ j_farg0, j_farg1, j_farg2, j_farg3, ++ j_farg4, j_farg5, ++ }; ++ ++ ++ uint i_args = 0; ++ uint f_args = 0; ++ uint stk_args = 0; // inc by 2 each time ++ ++ for (int i = 0; i < total_args_passed; i++) { ++ switch (sig_bt[i]) { ++ case T_BOOLEAN: ++ case T_CHAR: ++ case T_BYTE: ++ case T_SHORT: ++ case T_INT: ++ if (i_args < Argument::n_int_register_parameters_j) { ++ regs[i].set1(INT_ArgReg[i_args++]->as_VMReg()); ++ } else { ++ regs[i].set1(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_VOID: ++ // halves of T_LONG or T_DOUBLE ++ assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half"); ++ regs[i].set_bad(); ++ break; ++ case T_LONG: ++ assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); ++ // fall through ++ case T_OBJECT: ++ case T_ARRAY: ++ case T_ADDRESS: ++ if (i_args < Argument::n_int_register_parameters_j) { ++ regs[i].set2(INT_ArgReg[i_args++]->as_VMReg()); ++ } else { ++ regs[i].set2(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_FLOAT: ++ if (f_args < Argument::n_float_register_parameters_j) { ++ regs[i].set1(FP_ArgReg[f_args++]->as_VMReg()); ++ } else { ++ regs[i].set1(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_DOUBLE: ++ assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); ++ if (f_args < Argument::n_float_register_parameters_j) { ++ regs[i].set2(FP_ArgReg[f_args++]->as_VMReg()); ++ } else { ++ regs[i].set2(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ } ++ ++ return align_up(stk_args, 2); ++} ++ ++// Patch the callers callsite with entry to compiled code if it exists. ++static void patch_callers_callsite(MacroAssembler *masm) { ++ Label L; ++ //__ stop("patch_callers_callsite"); ++ __ cmpptr(Address(rbx, in_bytes(Method::code_offset())), (int32_t)NULL_WORD, rscratch1_GP); ++ __ jcc(Assembler::equal, L, rscratch1_GP); ++ ++ __ enter(); ++ push_CPU_state(masm); ++ ++ // VM needs caller's callsite ++ // VM needs target method ++ // This needs to be a long call since we will relocate this adapter to ++ // the codeBuffer and it may not reach ++ ++#ifndef PRODUCT ++ assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); ++#endif ++ ++ __ movl(c_rarg0, rbx); ++ __ movl(c_rarg1, RA); ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite))); ++ ++ pop_CPU_state(masm); ++ __ leave(); ++ __ bind(L); ++} ++ ++ ++static void gen_c2i_adapter(MacroAssembler *masm, ++ int total_args_passed, ++ int comp_args_on_stack, ++ const BasicType *sig_bt, ++ const VMRegPair *regs, ++ Label& skip_fixup) {//__ stop("gen_c2i_adapter"); ++ // 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. ++ patch_callers_callsite(masm); ++ ++ __ bind(skip_fixup); ++ ++ // Since all args are passed on the stack, total_args_passed * ++ // Interpreter::stackElementSize is the space we need. ++ // Return address is in RA. ++ ++ int extraspace = (total_args_passed * Interpreter::stackElementSize); ++ ++ // stack is aligned, keep it that way ++ extraspace = align_up(extraspace, 2*wordSize); ++ ++ // set senderSP value ++ __ movl(rsender, esp); ++ ++ if (extraspace) ++ __ subptr(esp, extraspace, esp); ++ ++ // Now write the args into the outgoing interpreter space ++ for (int i = 0; i < total_args_passed; i++) { ++ if (sig_bt[i] == T_VOID) { ++ assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half"); ++ continue; ++ } ++ ++ // offset to start parameters ++ int st_off = (total_args_passed - i - 1) * Interpreter::stackElementSize; ++ int next_off = st_off - Interpreter::stackElementSize; ++ ++ // Say 4 args: ++ // i st_off ++ // 0 32 T_LONG ++ // 1 24 T_VOID ++ // 2 16 T_OBJECT ++ // 3 8 T_BOOL ++ // - 0 return address ++ // ++ // However to make thing extra confusing. Because we can fit a long/double in ++ // a single slot on a 64 bt vm and it would be silly to break them up, the interpreter ++ // leaves one slot empty and only stores to a single slot. In this case the ++ // slot that is occupied is the T_VOID slot. See I said it was confusing. ++ ++ 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()) { ++ // memory to memory use rax ++ int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace; ++ if (!r_2->is_valid()) { ++ // sign extend?? ++ __ ldws(rax, Address(esp, ld_off)); ++ __ stptr(rax, Address(esp, st_off)); ++ ++ } else { ++ ++ __ ldl(rax, Address(esp, ld_off)); ++ ++ // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG ++ // T_DOUBLE and T_LONG use two slots in the interpreter ++ if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { ++ // ld_off == LSW, ld_off+wordSize == MSW ++ // st_off == MSW, next_off == LSW ++ __ stl(rax, Address(esp, next_off)); ++#ifdef ASSERT ++ // Overwrite the unused slot with known junk ++ __ mov_immediate64(rax, CONST64(0xdeadffffdeadaaaa)); ++ __ stptr(rax, Address(esp, st_off)); ++#endif /* ASSERT */ ++ } else { ++ __ stl(rax, Address(esp, st_off)); ++ } ++ } ++ } else if (r_1->is_Register()) { ++ Register r = r_1->as_Register(); ++ if (!r_2->is_valid()) { ++ // must be only an int (or less ) so move only 32bits to slot ++ // why not sign extend?? ++ __ stw(r, Address(esp, st_off)); ++ } else { ++ // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG ++ // T_DOUBLE and T_LONG use two slots in the interpreter ++ if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { ++ // long/double in gpr ++#ifdef ASSERT ++ // Overwrite the unused slot with known junk ++ __ mov_immediate64(rax, CONST64(0xdeadffffdeadaaab)); ++ __ stptr(rax, Address(esp, st_off)); ++#endif /* ASSERT */ ++ __ stl(r, Address(esp, next_off)); ++ } else { ++ __ stl(r, Address(esp, st_off)); ++ } ++ } ++ } else { ++ assert(r_1->is_FloatRegister(), ""); ++ if (!r_2->is_valid()) { ++ // only a float use just part of the slot ++ __ store_float(r_1->as_FloatRegister(), Address(esp, st_off)); ++ } else { ++#ifdef ASSERT ++ // Overwrite the unused slot with known junk ++ __ mov_immediate64(rax, CONST64(0xdeadffffdeadaaac)); ++ __ stptr(rax, Address(esp, st_off)); ++#endif /* ASSERT */ ++ __ store_double(r_1->as_FloatRegister(), Address(esp, next_off)); ++ } ++ } ++ } ++ ++ // Schedule the branch target address early. ++ __ ldptr(rcx, Address(rbx, in_bytes(Method::interpreter_entry_offset()))); ++ __ jmp(rcx); ++} ++ ++static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg, ++ address code_start, address code_end, ++ Label& L_ok) {SCOPEMARK_NAME(range_check, masm); ++ Label L_fail; ++ __ lea(temp_reg, ExternalAddress(code_start)); ++ __ cmpptr(pc_reg, temp_reg, temp_reg); ++ __ jcc(Assembler::belowEqual, L_fail, temp_reg); ++ __ lea(temp_reg, ExternalAddress(code_end)); ++ __ cmpptr(pc_reg, temp_reg, temp_reg); ++ __ jcc(Assembler::below, L_ok, temp_reg); ++ __ bind(L_fail); ++} ++ ++void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, ++ int total_args_passed, ++ int comp_args_on_stack, ++ const BasicType *sig_bt, ++ const VMRegPair *regs) {__ block_comment("gen_i2c_adapter");//__ debug_stop("gen_i2c_adapter"); ++ ++ // Note: r13 contains the senderSP on entry. We must preserve it since ++ // we may do a i2c -> c2i transition if we lose a race where compiled ++ // code goes non-entrant while we get args ready. ++ // In addition we use r13 to locate all the interpreter args as ++ // we must align the stack to 16 bytes on an i2c entry else we ++ // lose alignment we expect in all compiled code and register ++ // save code can segv when fxsave instructions find improperly ++ // aligned stack pointer. ++ ++ // 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. ++ ++ // Pick up the return address ++ __ movl(rax, RA); ++ ++ 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, rax, r11, ++ Interpreter::code()->code_start(), Interpreter::code()->code_end(), ++ L_ok); ++ if (StubRoutines::code1() != NULL) ++ range_check(masm, rax, r11, ++ StubRoutines::code1()->code_begin(), StubRoutines::code1()->code_end(), ++ L_ok); ++ if (StubRoutines::code2() != NULL) ++ range_check(masm, rax, r11, ++ 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 "); ++ } ++ ++ // Must preserve original SP for loading incoming arguments because ++ // we need to align the outgoing SP for compiled code. ++ __ movl(r11, rsp); ++ ++ // Cut-out for having no stack args. Since up to 2 int/oop args are passed ++ // in registers, we will occasionally have no stack args. ++ int comp_words_on_stack = 0; ++ if (comp_args_on_stack) { ++ // Sig words on the stack are greater-than VMRegImpl::stack0. Those in ++ // registers are below. By subtracting stack0, we either get a negative ++ // number (all values in registers) or the maximum stack slot accessed. ++ ++ // Convert 4-byte c2 stack slots to words. ++ 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); ++ __ subptr(esp, comp_words_on_stack * wordSize, esp); ++ } ++ ++ // push the return address and misalign the stack that youngest frame always sees ++ // as far as the placement of the call instruction ++ //__ push(rax); //TODO:How to resolve this ? jzy ++ ++ // Put saved SP in another register ++ const Register saved_sp = rax; ++ __ movl(saved_sp, r11); ++ ++ // Will jump to the compiled code just as if compiled code was doing it. ++ // Pre-load the register-jump target early, to schedule it better. ++ __ ldptr(r11, Address(rmethod, in_bytes(Method::from_compiled_offset()))); //check jzy? ++ ++#if INCLUDE_JVMCI ++ if (EnableJVMCI || UseAOT) { ++ // check if this call should be routed towards a specific entry point ++ __ cmpptr(Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), R0); ++ Label no_alternative_target; ++ __ jcc(Assembler::equal, no_alternative_target); ++ __ ldptr(r11, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); ++ __ stptr(R0, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); ++ __ bind(no_alternative_target); ++ } ++#endif // INCLUDE_JVMCI ++ ++ // Now generate the shuffle code. Pick up all register args and move the ++ // rest through the floating point stack top. ++ 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 SP+offset. ++ ++ assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), ++ "scrambled load targets?"); ++ // Load in argument order going down. ++ int ld_off = (total_args_passed - 1 - i)*Interpreter::stackElementSize; ++ // Point to interpreter value (vs. tag) ++ int next_off = ld_off - Interpreter::stackElementSize; ++ // ++ // ++ // ++ 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()) { ++ // Convert stack slot to an SP offset ++ int st_off = regs[i].first()->reg2stack()*VMRegImpl::stack_slot_size ; ++ ++ // We can use r13 as a temp here because compiled code doesn't need r13 as an input ++ // and if we end up going thru a c2i because of a miss a reasonable value of r13 ++ // will be generated. ++ if (!r_2->is_valid()) { ++ // sign extend??? ++ __ ldws(r13, Address(saved_sp, ld_off)); ++ __ stptr(r13, Address(esp, st_off), rscratch2_AT); ++ } else { ++ // ++ // We are using two optoregs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE ++ // the interpreter allocates two slots but only uses one for thr T_LONG or T_DOUBLE case ++ // So we must adjust where to pick up the data to match the interpreter. ++ // ++ // Interpreter local[n] == MSW, local[n+1] == LSW however locals ++ // are accessed as negative so LSW is at LOW address ++ ++ // ld_off is MSW so get LSW ++ const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)? ++ next_off : ld_off; ++ __ ldl(r13, Address(saved_sp, offset)); ++ // st_off is LSW (i.e. reg.first()) ++ __ stl(r13, Address(esp, st_off)); ++ } ++ } else if (r_1->is_Register()) { // Register argument ++ Register r = r_1->as_Register(); ++ assert(r != rax, "must be different"); ++ if (r_2->is_valid()) { ++ // ++ // We are using two VMRegs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE ++ // the interpreter allocates two slots but only uses one for thr T_LONG or T_DOUBLE case ++ // So we must adjust where to pick up the data to match the interpreter. ++ ++ const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)? ++ next_off : ld_off; ++ ++ // this can be a misaligned move ++ __ ldl(r, Address(saved_sp, offset)); ++ } else { ++ // sign extend and use a full word? ++ __ ldws(r, Address(saved_sp, ld_off)); ++ } ++ } else { ++ if (!r_2->is_valid()) { ++ __ load_float(r_1->as_FloatRegister(), Address(saved_sp, ld_off)); ++ } else { ++ __ load_double(r_1->as_FloatRegister(), Address(saved_sp, next_off)); ++ } ++ } ++ } ++ ++ // 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. ++ ++ __ stptr(rbx, Address(rthread, JavaThread::callee_target_offset())); ++ ++ // put Method* where a c2i would expect should we end up there ++ // only needed becaus eof c2 resolve stubs return Method* as a result in ++ // rax ++ __ movl(rax, rbx); //TODO:why need this? jzy ++ __ jmp(r11); ++} ++ ++// --------------------------------------------------------------- ++AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, ++ int total_args_passed, ++ int comp_args_on_stack, ++ const BasicType *sig_bt, ++ const VMRegPair *regs, ++ AdapterFingerPrint* fingerprint) {__ block_comment("generate_i2c2i_adapters");//__ stop("generate_i2c2i_adapters"); ++ 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 rbx holds the Method* during calls ++ // to the interpreter. 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 RBP, get sick). ++ ++ address c2i_unverified_entry = __ pc(); ++ Label skip_fixup; ++ Label ok; ++ ++ Register holder = rax; ++ Register receiver = j_rarg0; ++ Register temp = rbx; ++ ++ { ++ __ load_klass(temp, receiver); ++ __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset()), rscratch1_GP); ++ __ ldptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset())); ++ __ jcc(Assembler::equal, ok, rscratch1_GP); ++ __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); ++ ++ __ bind(ok); ++ // Method might have been compiled since the call site was patched to ++ // interpreted if that is the case treat it as a miss so we can get ++ // the call site corrected. ++ __ cmpptr(Address(rbx, in_bytes(Method::code_offset())), R0, rscratch1_GP); ++ __ jcc(Assembler::equal, skip_fixup, rscratch1_GP); ++ __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()), rscratch1_GP); ++ } ++ ++ address c2i_entry = __ pc(); ++ ++ gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); ++ ++ __ flush(); ++ return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); ++} ++ ++int SharedRuntime::c_calling_convention(const BasicType *sig_bt, ++ VMRegPair *regs, ++ VMRegPair *regs2, ++ int total_args_passed) {//ShouldNotReachHere(); ++ assert(regs2 == NULL, "not needed on Sw64"); ++ ++ // We return the amount of VMRegImpl stack slots we need to reserve for all ++ // the arguments NOT counting out_preserve_stack_slots. ++ static const Register INT_ArgReg[Argument::n_register_parameters] = { ++ c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5 ++ }; ++ static const FloatRegister FP_ArgReg[Argument::n_float_register_parameters] = { ++ c_farg0, c_farg1, c_farg2, c_farg3, ++ c_farg4, c_farg5 ++ }; ++ ++ ++ uint args = 0; ++ uint stk_args = 0; // inc by 2 each time ++ ++ for (int i = 0; i < total_args_passed; i++) { ++ switch (sig_bt[i]) { ++ case T_BOOLEAN: ++ case T_CHAR: ++ case T_BYTE: ++ case T_SHORT: ++ case T_INT: ++ if (args < Argument::n_int_register_parameters_c) { ++ regs[i].set1(INT_ArgReg[args++]->as_VMReg()); ++ } else { ++ regs[i].set1(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_LONG: ++ assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); ++ // fall through ++ case T_OBJECT: ++ case T_ARRAY: ++ case T_ADDRESS: ++ case T_METADATA: ++ if (args < Argument::n_int_register_parameters_c) { ++ regs[i].set2(INT_ArgReg[args++]->as_VMReg()); ++ } else { ++ regs[i].set2(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_FLOAT: ++ if (args < Argument::n_float_register_parameters_c) { ++ regs[i].set1(FP_ArgReg[args++]->as_VMReg()); ++ ++ } else { ++ regs[i].set1(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_DOUBLE: ++ assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); ++ if (args < Argument::n_float_register_parameters_c) { ++ regs[i].set2(FP_ArgReg[args++]->as_VMReg()); ++ } else { ++ regs[i].set2(VMRegImpl::stack2reg(stk_args)); ++ stk_args += 2; ++ } ++ break; ++ case T_VOID: // Halves of longs and doubles ++ assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half"); ++ regs[i].set_bad(); ++ break; ++ default: ++ ShouldNotReachHere(); ++ break; ++ } ++ } ++ ++ return stk_args; ++} ++ ++// 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, Register tmp_reg = rax) { ++ if (src.first()->is_stack()) { ++ if (dst.first()->is_stack()) { ++ // stack to stack ++ __ ldws(tmp_reg, Address(rbp, reg2offset_in(src.first()))); ++ __ stl(tmp_reg, Address(rsp, reg2offset_out(dst.first()))); ++ } else { ++ // stack to reg ++ __ ldws(dst.first()->as_Register(), Address(rfp, reg2offset_in(src.first()))); ++ } ++ } else if (dst.first()->is_stack()) { ++ // reg to stack ++ // Do we really have to sign extend??? ++ // __ movslq(src.first()->as_Register(), src.first()->as_Register()); ++ __ stl(src.first()->as_Register(), Address(rsp, reg2offset_out(dst.first()))); ++ } else { ++ // Do we really have to sign extend??? ++ // __ movslq(dst.first()->as_Register(), src.first()->as_Register()); ++ if (dst.first() != src.first()) { ++ __ movl(dst.first()->as_Register(), src.first()->as_Register()); ++ } ++ } ++} ++ ++static void move_ptr(MacroAssembler* masm, VMRegPair src, VMRegPair dst, Register tmp_reg = rax) { ++ if (src.first()->is_stack()) { ++ if (dst.first()->is_stack()) { ++ // stack to stack ++ __ ldl(tmp_reg, Address(rbp, reg2offset_in(src.first()))); ++ __ stl(tmp_reg, Address(rsp, reg2offset_out(dst.first()))); ++ } else { ++ // stack to reg ++ __ ldl(dst.first()->as_Register(), Address(rbp, reg2offset_in(src.first()))); ++ } ++ } else if (dst.first()->is_stack()) { ++ // reg to stack ++ __ stl(src.first()->as_Register(), Address(rsp, reg2offset_out(dst.first()))); ++ } else { ++ if (dst.first() != src.first()) { ++ __ movl(dst.first()->as_Register(), src.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, Register tmp_reg = rax) { ++ ++ // must pass a handle. First figure out the location we use as a handle ++ ++ Register rHandle = dst.first()->is_stack() ? tmp_reg : dst.first()->as_Register(); ++ ++ // See if oop is NULL if it is we need no handle ++ ++ if (src.first()->is_stack()) { ++ ++ // Oop is already on the stack as an argument ++ int offset_in_older_frame = src.first()->reg2stack() + SharedRuntime::out_preserve_stack_slots(); ++ map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + framesize_in_slots)); ++ if (is_receiver) { ++ *receiver_offset = (offset_in_older_frame + framesize_in_slots) * VMRegImpl::stack_slot_size; ++ } ++ ++ __ cmpptr(Address(rbp, reg2offset_in(src.first())), R0); ++ __ lea(rHandle, Address(rbp, reg2offset_in(src.first()))); ++ // conditionally move a NULL ++ __ ldptr(rscratch3, Address(rbp, reg2offset_in(src.first()))); ++ __ cmove(Assembler::equal, rHandle, rscratch3, rHandle); ++ } else { ++ ++ // Oop is in an a register we must store it to the space we reserve ++ // on the stack for oop_handles and pass a handle if oop is non-NULL ++ ++ const Register rOop = src.first()->as_Register(); ++ int oop_slot; ++ if (rOop == j_rarg0) ++ oop_slot = 0; ++ else if (rOop == j_rarg1) ++ oop_slot = 1; ++ else if (rOop == j_rarg2) ++ oop_slot = 2; ++ else if (rOop == j_rarg3) ++ oop_slot = 3; ++ else if (rOop == j_rarg4) ++ oop_slot = 4; ++ else { ++ assert(rOop == j_rarg5, "wrong register"); ++ oop_slot = 5; ++ } ++ ++ oop_slot = oop_slot * VMRegImpl::slots_per_word + oop_handle_offset; ++ int offset = oop_slot*VMRegImpl::stack_slot_size; ++ ++ map->set_oop(VMRegImpl::stack2reg(oop_slot)); ++ // Store oop in handle area, may be NULL ++ __ stptr(rOop, Address(rsp, offset)); ++ if (is_receiver) { ++ *receiver_offset = offset; ++ } ++ ++ __ cmpptr(rOop, R0); ++ __ lea(rHandle, Address(rsp, offset)); ++ // conditionally move a NULL from the handle area where it was just stored ++ __ ldptr(rscratch3, Address(rsp, offset)); ++ __ cmove(Assembler::equal, rHandle, rscratch3, rHandle); ++ } ++ ++ // If arg is on the stack then place it otherwise it is already in correct reg. ++ if (dst.first()->is_stack()) { ++ __ stptr(rHandle, Address(rsp, reg2offset_out(dst.first()))); ++ } ++} ++ ++// A float arg may have to do float reg int reg conversion ++static void float_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst, Register tmp_reg = rax) { ++ assert(!src.second()->is_valid() && !dst.second()->is_valid(), "bad float_move"); ++ ++ // The calling conventions assures us that each VMregpair is either ++ // all really one physical register or adjacent stack slots. ++ // This greatly simplifies the cases here compared to sparc. ++ ++ if (src.first()->is_stack()) { ++ if (dst.first()->is_stack()) { ++ __ ldwu (tmp_reg, Address(rfp, reg2offset_in(src.first())));//TODO:check jzy ++ __ stptr(tmp_reg, Address(rsp, reg2offset_out(dst.first()))); ++ } else { ++ // stack to reg ++ assert(dst.first()->is_FloatRegister(), "only expect float registers as parameters"); ++ __ load_float(dst.first()->as_FloatRegister(), Address(rfp, reg2offset_in(src.first()))); ++ } ++ } else if (dst.first()->is_stack()) { ++ // reg to stack ++ assert(src.first()->is_FloatRegister(), "only expect xmm registers as parameters"); ++ __ store_float(src.first()->as_FloatRegister(), Address(esp, reg2offset_out(dst.first()))); ++ } else { ++ // reg to reg ++ // In theory these overlap but the ordering is such that this is likely a nop ++ if ( src.first() != dst.first()) { ++ __ fmovs(dst.first()->as_FloatRegister(), src.first()->as_FloatRegister()); ++ } ++ } ++} ++ ++// A long move ++static void long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst, Register tmp_reg = rax) { ++ ++ // The calling conventions assures us that each VMregpair is either ++ // all really one physical register or adjacent stack slots. ++ // This greatly simplifies the cases here compared to sparc. ++ ++ if (src.is_single_phys_reg() ) { ++ if (dst.is_single_phys_reg()) { ++ if (dst.first() != src.first()) { ++ __ movl(dst.first()->as_Register(), src.first()->as_Register()); ++ } ++ } else { ++ assert(dst.is_single_reg(), "not a stack pair"); ++ __ stl(src.first()->as_Register(), Address(rsp, reg2offset_out(dst.first()))); ++ } ++ } else if (dst.is_single_phys_reg()) { ++ assert(src.is_single_reg(), "not a stack pair"); ++ __ ldl(dst.first()->as_Register(), Address(rbp, reg2offset_out(src.first()))); ++ } else { ++ assert(src.is_single_reg() && dst.is_single_reg(), "not stack pairs"); ++ __ ldl(tmp_reg, Address(rbp, reg2offset_in(src.first()))); ++ __ stl(tmp_reg, Address(rsp, reg2offset_out(dst.first()))); ++ } ++} ++ ++// A double move ++static void double_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst, Register tmp_reg = rax) { ++ ++ // The calling conventions assures us that each VMregpair is either ++ // all really one physical register or adjacent stack slots. ++ // This greatly simplifies the cases here compared to sparc. ++ ++ if (src.is_single_phys_reg() ) { ++ if (dst.is_single_phys_reg()) { ++ // In theory these overlap but the ordering is such that this is likely a nop ++ if ( src.first() != dst.first()) { ++ __ fmovd(dst.first()->as_FloatRegister(), src.first()->as_FloatRegister()); ++ } ++ } else { ++ assert(dst.is_single_reg(), "not a stack pair"); ++ __ store_double(src.first()->as_FloatRegister(), Address(rsp, reg2offset_out(dst.first()))); ++ } ++ } else if (dst.is_single_phys_reg()) { ++ assert(src.is_single_reg(), "not a stack pair"); ++ __ load_double(dst.first()->as_FloatRegister(), Address(rbp, reg2offset_out(src.first()))); ++ } else { ++ assert(src.is_single_reg() && dst.is_single_reg(), "not stack pairs"); ++ __ ldl(tmp_reg, Address(rbp, reg2offset_in(src.first()))); ++ __ stl(tmp_reg, Address(rsp, reg2offset_out(dst.first()))); ++ } ++} ++ ++ ++void SharedRuntime::save_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) {//__ stop("save_native_result"); ++ // We always ignore the frame_slots arg and just use the space just below frame pointer ++ // which by this time is free to use ++ switch (ret_type) { ++ case T_FLOAT: ++ __ store_float(FSF, Address(rfp, -wordSize)); ++ break; ++ case T_DOUBLE: ++ __ store_double(FSF, Address(rfp, -wordSize)); ++ break; ++ case T_VOID: break; ++ default: { ++ __ stptr(V0, Address(rfp, -wordSize)); ++ } ++ } ++} ++ ++void SharedRuntime::restore_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) {//__ stop("restore_native_result"); ++ // We always ignore the frame_slots arg and just use the space just below frame pointer ++ // which by this time is free to use ++ switch (ret_type) { ++ case T_FLOAT: ++ __ load_float(FSF, Address(rfp, -wordSize)); ++ break; ++ case T_DOUBLE: ++ __ load_double(FSF, Address(rfp, -wordSize)); ++ break; ++ case T_VOID: break; ++ default: { ++ __ ldptr(V0, Address(rfp, -wordSize)); ++ } ++ } ++} ++ ++static void save_args(MacroAssembler *masm, int arg_count, int first_arg, VMRegPair *args) {//__ stop("save_args"); ++ for ( int i = first_arg ; i < arg_count ; i++ ) { ++ if (args[i].first()->is_Register()) { ++ __ push(args[i].first()->as_Register()); ++ } else if (args[i].first()->is_FloatRegister()) { ++ __ subptr(esp, 2*wordSize, esp); ++ __ store_double(args[i].first()->as_FloatRegister(), Address(esp, 0)); ++ } ++ } ++} ++ ++static void restore_args(MacroAssembler *masm, int arg_count, int first_arg, VMRegPair *args) {//__ stop("restore_args"); ++ for ( int i = arg_count - 1 ; i >= first_arg ; i-- ) { ++ if (args[i].first()->is_Register()) { ++ __ pop(args[i].first()->as_Register()); ++ } else if (args[i].first()->is_FloatRegister()) { ++ __ load_double(args[i].first()->as_FloatRegister(), Address(esp, 0)); ++ __ addptr(esp, 2*wordSize, esp); ++ } ++ } ++} ++ ++ ++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) {//__ stop("save_or_restore_arguments"); ++ // if map is non-NULL then the code should store the values, ++ // otherwise it should load them. ++ int slot = arg_save_area; ++ // Save down double word first ++ for ( int i = 0; i < total_in_args; i++) { ++ if (in_regs[i].first()->is_FloatRegister() && in_sig_bt[i] == T_DOUBLE) { ++ int offset = slot * VMRegImpl::stack_slot_size; ++ slot += VMRegImpl::slots_per_word; ++ assert(slot <= stack_slots, "overflow"); ++ if (map != NULL) { ++ __ store_double(in_regs[i].first()->as_FloatRegister(), Address(esp, offset)); ++ } else { ++ __ load_double(in_regs[i].first()->as_FloatRegister(), Address(esp, offset)); ++ } ++ } ++ if (in_regs[i].first()->is_Register() && ++ (in_sig_bt[i] == T_LONG || in_sig_bt[i] == T_ARRAY)) { ++ int offset = slot * VMRegImpl::stack_slot_size; ++ if (map != NULL) { ++ __ stl(in_regs[i].first()->as_Register(), Address(esp, offset)); ++ if (in_sig_bt[i] == T_ARRAY) { ++ map->set_oop(VMRegImpl::stack2reg(slot));; ++ } ++ } else { ++ __ ldl(in_regs[i].first()->as_Register(), Address(esp, offset)); ++ } ++ slot += VMRegImpl::slots_per_word; ++ } ++ } ++ // Save or restore single word registers ++ for ( int i = 0; i < total_in_args; i++) { ++ if (in_regs[i].first()->is_Register()) { ++ int offset = slot * VMRegImpl::stack_slot_size; ++ slot++; ++ assert(slot <= stack_slots, "overflow"); ++ ++ // Value is in an input register pass we must flush it to the stack ++ const Register reg = in_regs[i].first()->as_Register(); ++ switch (in_sig_bt[i]) { ++ case T_BOOLEAN: ++ case T_CHAR: ++ case T_BYTE: ++ case T_SHORT: ++ case T_INT: ++ if (map != NULL) { ++ __ stw(reg, Address(esp, offset)); ++ } else { ++ //__ stop("check @jzy 32-64bits"); ++ __ ldws(reg, Address(esp, offset)); ++ } ++ break; ++ case T_ARRAY: ++ case T_LONG: ++ // handled above ++ break; ++ case T_OBJECT: ++ default: ShouldNotReachHere(); ++ } ++ } else if (in_regs[i].first()->is_FloatRegister()) { ++ if (in_sig_bt[i] == T_FLOAT) { ++ int offset = slot * VMRegImpl::stack_slot_size; ++ slot++; ++ assert(slot <= stack_slots, "overflow"); ++ if (map != NULL) { ++ __ store_float(in_regs[i].first()->as_FloatRegister(), Address(esp, offset)); ++ } else { ++ __ load_float(in_regs[i].first()->as_FloatRegister(), Address(esp, offset)); ++ } ++ } ++ } else if (in_regs[i].first()->is_stack()) { ++ if (in_sig_bt[i] == T_ARRAY && map != NULL) { ++ 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)); ++ } ++ } ++ } ++} ++ ++ ++// 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, ++ int stack_slots, ++ int total_c_args, ++ int total_in_args, ++ int arg_save_area, ++ OopMapSet* oop_maps, ++ VMRegPair* in_regs, ++ BasicType* in_sig_bt) {//__ stop("check_needs_gc_for_critical_native"); ++ __ block_comment("check GCLocker::needs_gc"); ++ Label cont; ++ __ cmpb(ExternalAddress((address)GCLocker::needs_gc_address()), 0); //TODO:jzy? check ++ __ jcc(Assembler::equal, cont); ++ ++ // Save down any incoming oops 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); ++ ++ address the_pc = __ pc(); ++ oop_maps->add_gc_map( __ offset(), map); ++ __ set_last_Java_frame(esp, noreg, the_pc, rscratch3); ++ ++ __ block_comment("block_for_jni_critical"); ++ __ movl(c_rarg0, rthread); ++ __ movl(r12, esp); // remember sp ++ __ subptr(esp, frame::arg_reg_save_area_bytes, esp); // windows ++ __ andptr(esp, -16, esp); // align stack as required by ABI ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical))); ++ __ movl(esp, r12); // restore sp ++ __ reinit_heapbase(); ++ ++ __ reset_last_Java_frame(false); ++ ++ 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 - 1; i++) { ++ if (in_regs[i].first()->is_Register()) { ++ const Register reg = in_regs[i].first()->as_Register(); ++ __ xorptr(reg, reg, reg); ++ } else if (in_regs[i].first()->is_FloatRegister()) { ++ Unimplemented();//jzy ++ //__ xorp(in_regs[i].first()->is_FloatRegister(), in_regs[i].first()->is_FloatRegister()); ++ } else if (in_regs[i].first()->is_FloatRegister()) { ++ ShouldNotReachHere(); ++ } else if (in_regs[i].first()->is_stack()) { ++ // Nothing to do ++ } else { ++ ShouldNotReachHere(); ++ } ++ if (in_sig_bt[i] == T_LONG || in_sig_bt[i] == T_DOUBLE) { ++ i++; ++ } ++ } ++ ++ 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) { ++ Register tmp_reg = rax; ++ assert(!body_arg.first()->is_Register() || body_arg.first()->as_Register() != tmp_reg, ++ "possible collision"); ++ assert(!length_arg.first()->is_Register() || length_arg.first()->as_Register() != tmp_reg, ++ "possible collision"); ++ ++ __ block_comment("unpack_array_argument {"); ++ ++ // Pass the length, ptr pair ++ Label is_null, done; ++ VMRegPair tmp; ++ tmp.set_ptr(tmp_reg->as_VMReg()); ++ if (reg.first()->is_stack()) { ++ // Load the arg up from the stack ++ move_ptr(masm, reg, tmp); ++ reg = tmp; ++ } ++ __ testptr(reg.first()->as_Register(), reg.first()->as_Register()); ++ __ jcc(Assembler::equal, is_null); ++ __ lea(tmp_reg, Address(reg.first()->as_Register(), arrayOopDesc::base_offset_in_bytes(in_elem_type))); ++ move_ptr(masm, tmp, body_arg); ++ // load the length relative to the body. ++ __ ldws(tmp_reg, Address(tmp_reg, arrayOopDesc::length_offset_in_bytes() - ++ arrayOopDesc::base_offset_in_bytes(in_elem_type))); ++ move32_64(masm, tmp, length_arg); ++ __ jmp(done); ++ __ bind(is_null); ++ // Pass zeros ++ __ movl(tmp_reg, R0); ++ move_ptr(masm, tmp, body_arg); ++ move32_64(masm, tmp, length_arg); ++ __ bind(done); ++ ++ __ block_comment("} unpack_array_argument"); ++} ++ ++ ++// Different signatures may require very different orders for the move ++// to avoid clobbering other arguments. There's no simple way to ++// order them safely. Compute a safe order for issuing stores and ++// break any cycles in those stores. This code is fairly general but ++// it's not necessary on the other platforms so we keep it in the ++// platform dependent code instead of moving it into a shared file. ++// (See bugs 7013347 & 7145024.) ++// Note that this code is specific to LP64. ++class ComputeMoveOrder: public StackObj { ++ class MoveOperation: public ResourceObj { ++ friend class ComputeMoveOrder; ++ private: ++ VMRegPair _src; ++ VMRegPair _dst; ++ int _src_index; ++ int _dst_index; ++ bool _processed; ++ MoveOperation* _next; ++ MoveOperation* _prev; ++ ++ static int get_id(VMRegPair r) { ++ return r.first()->value(); ++ } ++ ++ public: ++ MoveOperation(int src_index, VMRegPair src, int dst_index, VMRegPair dst): ++ _src(src) ++ , _src_index(src_index) ++ , _dst(dst) ++ , _dst_index(dst_index) ++ , _next(NULL) ++ , _prev(NULL) ++ , _processed(false) { ++ } ++ ++ VMRegPair src() const { return _src; } ++ int src_id() const { return get_id(src()); } ++ int src_index() const { return _src_index; } ++ VMRegPair dst() const { return _dst; } ++ void set_dst(int i, VMRegPair dst) { _dst_index = i, _dst = dst; } ++ int dst_index() const { return _dst_index; } ++ int dst_id() const { return get_id(dst()); } ++ MoveOperation* next() const { return _next; } ++ MoveOperation* prev() const { return _prev; } ++ void set_processed() { _processed = true; } ++ bool is_processed() const { return _processed; } ++ ++ // insert ++ void break_cycle(VMRegPair temp_register) { ++ // create a new store following the last store ++ // to move from the temp_register to the original ++ MoveOperation* new_store = new MoveOperation(-1, temp_register, dst_index(), dst()); ++ ++ // break the cycle of links and insert new_store at the end ++ // break the reverse link. ++ MoveOperation* p = prev(); ++ assert(p->next() == this, "must be"); ++ _prev = NULL; ++ p->_next = new_store; ++ new_store->_prev = p; ++ ++ // change the original store to save it's value in the temp. ++ set_dst(-1, temp_register); ++ } ++ ++ void link(GrowableArray& killer) { ++ // link this store in front the store that it depends on ++ MoveOperation* n = killer.at_grow(src_id(), NULL); ++ if (n != NULL) { ++ assert(_next == NULL && n->_prev == NULL, "shouldn't have been set yet"); ++ _next = n; ++ n->_prev = this; ++ } ++ } ++ }; ++ ++ private: ++ GrowableArray edges; ++ ++ public: ++ ComputeMoveOrder(int total_in_args, VMRegPair* in_regs, int total_c_args, VMRegPair* out_regs, ++ BasicType* in_sig_bt, GrowableArray& arg_order, VMRegPair tmp_vmreg) { ++ // Move operations where the dest is the stack can all be ++ // scheduled first since they can't interfere with the other moves. ++ for (int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0; i--, c_arg--) { ++ if (in_sig_bt[i] == T_ARRAY) { ++ c_arg--; ++ if (out_regs[c_arg].first()->is_stack() && ++ out_regs[c_arg + 1].first()->is_stack()) { ++ arg_order.push(i); ++ arg_order.push(c_arg); ++ } else { ++ if (out_regs[c_arg].first()->is_stack() || ++ in_regs[i].first() == out_regs[c_arg].first()) { ++ add_edge(i, in_regs[i].first(), c_arg, out_regs[c_arg + 1]); ++ } else { ++ add_edge(i, in_regs[i].first(), c_arg, out_regs[c_arg]); ++ } ++ } ++ } else if (in_sig_bt[i] == T_VOID) { ++ arg_order.push(i); ++ arg_order.push(c_arg); ++ } else { ++ if (out_regs[c_arg].first()->is_stack() || ++ in_regs[i].first() == out_regs[c_arg].first()) { ++ arg_order.push(i); ++ arg_order.push(c_arg); ++ } else { ++ add_edge(i, in_regs[i].first(), c_arg, out_regs[c_arg]); ++ } ++ } ++ } ++ // Break any cycles in the register moves and emit the in the ++ // proper order. ++ GrowableArray* stores = get_store_order(tmp_vmreg); ++ for (int i = 0; i < stores->length(); i++) { ++ arg_order.push(stores->at(i)->src_index()); ++ arg_order.push(stores->at(i)->dst_index()); ++ } ++ } ++ ++ // Collected all the move operations ++ void add_edge(int src_index, VMRegPair src, int dst_index, VMRegPair dst) { ++ if (src.first() == dst.first()) return; ++ edges.append(new MoveOperation(src_index, src, dst_index, dst)); ++ } ++ ++ // Walk the edges breaking cycles between moves. The result list ++ // can be walked in order to produce the proper set of loads ++ GrowableArray* get_store_order(VMRegPair temp_register) { ++ // Record which moves kill which values ++ GrowableArray killer; ++ for (int i = 0; i < edges.length(); i++) { ++ MoveOperation* s = edges.at(i); ++ assert(killer.at_grow(s->dst_id(), NULL) == NULL, "only one killer"); ++ killer.at_put_grow(s->dst_id(), s, NULL); ++ } ++ assert(killer.at_grow(MoveOperation::get_id(temp_register), NULL) == NULL, ++ "make sure temp isn't in the registers that are killed"); ++ ++ // create links between loads and stores ++ for (int i = 0; i < edges.length(); i++) { ++ edges.at(i)->link(killer); ++ } ++ ++ // at this point, all the move operations are chained together ++ // in a doubly linked list. Processing it backwards finds ++ // the beginning of the chain, forwards finds the end. If there's ++ // a cycle it can be broken at any point, so pick an edge and walk ++ // backward until the list ends or we end where we started. ++ GrowableArray* stores = new GrowableArray(); ++ for (int e = 0; e < edges.length(); e++) { ++ MoveOperation* s = edges.at(e); ++ if (!s->is_processed()) { ++ MoveOperation* start = s; ++ // search for the beginning of the chain or cycle ++ while (start->prev() != NULL && start->prev() != s) { ++ start = start->prev(); ++ } ++ if (start->prev() == s) { ++ start->break_cycle(temp_register); ++ } ++ // walk the chain forward inserting to store list ++ while (start != NULL) { ++ stores->append(start); ++ start->set_processed(); ++ start = start->next(); ++ } ++ } ++ } ++ return stores; ++ } ++}; ++ ++static void verify_oop_args(MacroAssembler* masm, ++ const methodHandle& method, ++ const BasicType* sig_bt, ++ const VMRegPair* regs) {//__ stop("verify_oop_args"); ++ Register temp_reg = rmethod; // not part of any compiled calling seq ++ if (VerifyOops) { ++ for (int i = 0; i < method->size_of_parameters(); i++) { ++ if (sig_bt[i] == T_OBJECT || ++ sig_bt[i] == T_ARRAY) { ++ VMReg r = regs[i].first(); ++ assert(r->is_valid(), "bad oop arg"); ++ if (r->is_stack()) { ++ __ ldptr(temp_reg, Address(esp, r->reg2stack() * VMRegImpl::stack_slot_size)); ++ __ 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) {SCOPEMARK_NAME(gen_special_dispatch, masm); ++ verify_oop_args(masm, method, sig_bt, regs); ++ vmIntrinsics::ID iid = method->intrinsic_id(); ++ //__ stop("gen_special_dispatch"); ++ // 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 = rmethod; // 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()) { ++ __ ldptr(member_reg, Address(esp, r->reg2stack() * VMRegImpl::stack_slot_size)); ++ } 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 = j_rarg0; // known to be free at this point ++ __ ldptr(receiver_reg, Address(esp, r->reg2stack() * VMRegImpl::stack_slot_size)); ++ } 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) {//__ stop("generate_native_wrapper"); ++ 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"); ++ ++ // An OopMap for lock (and class if static) ++ OopMapSet *oop_maps = new OopMapSet(); ++ intptr_t start = (intptr_t)__ pc(); ++ ++ // 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; ++ 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) { ++ 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; ++ Symbol* atype = ss.as_symbol(CHECK_NULL); ++ const char* at = atype->as_C_string(); ++ if (strlen(at) == 2) { ++ assert(at[0] == '[', "must be"); ++ switch (at[1]) { ++ case 'B': in_elem_bt[i] = T_BYTE; break; ++ case 'C': in_elem_bt[i] = T_CHAR; break; ++ case 'D': in_elem_bt[i] = T_DOUBLE; break; ++ case 'F': in_elem_bt[i] = T_FLOAT; break; ++ case 'I': in_elem_bt[i] = T_INT; break; ++ case 'J': in_elem_bt[i] = T_LONG; break; ++ case 'S': in_elem_bt[i] = T_SHORT; break; ++ case 'Z': in_elem_bt[i] = T_BOOLEAN; break; ++ default: ShouldNotReachHere(); ++ } ++ } ++ } 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(), "must match"); ++ ss.next(); ++ } ++ } ++ } ++ ++ // Now figure out where the args must be stored and how much stack space ++ // they require. ++ int out_arg_slots; ++ out_arg_slots = c_calling_convention(out_sig_bt, out_regs, NULL, total_c_args); ++ ++ // Compute framesize for the wrapper. We need to handlize all oops in ++ // incoming registers ++ ++ // 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 total_save_slots = 6 * VMRegImpl::slots_per_word; // 6 arguments passed in registers ++ 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_BOOLEAN: ++ case T_BYTE: ++ case T_SHORT: ++ case T_CHAR: ++ case T_INT: single_slots++; break; ++ case T_ARRAY: // specific to LP64 (7145024) ++ case T_LONG: 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(); ++ } ++ } else if (in_regs[i].first()->is_FloatRegister()) { ++ ShouldNotReachHere(); ++ } ++ } ++ total_save_slots = double_slots * 2 + single_slots; ++ // align the save area ++ if (double_slots != 0) { ++ stack_slots = align_up(stack_slots, 2); ++ } ++ } ++ ++ int oop_handle_offset = stack_slots; ++ 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 (+2) to save return values or temp during shuffling ++ // + 4 for return address (which we own) and saved rbp ++ stack_slots += 6;// swjdk8 is 2+6, but i think 6 is enough ++ ++ // 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 (6 java arg registers) ++ // | outbound memory | ++ // | based arguments | ++ // | | ++ // |---------------------| ++ // | | ++ // 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, StackAlignmentInSlots); ++ ++ int stack_size = stack_slots * VMRegImpl::stack_slot_size; ++ ++ // First thing make an ic check to see if we should even be here ++ ++ // We are free to use all registers as temps without saving them and ++ // restoring them except rbp. rbp is the only callee save register ++ // as far as the interpreter and the compiler(s) are concerned. ++ ++ ++ const Register ic_reg = V0; ++ const Register receiver = j_rarg0; ++ ++ Label hit; ++ Label exception_pending; ++ //__ stop("generate_native_wrapper"); ++ assert_different_registers(ic_reg, receiver, rscratch3); ++ __ verify_oop(receiver); ++ __ load_klass(rscratch3, receiver); ++// __ cmpl(ic_reg, rscratch3); ++// __ jcc(Assembler::equal, hit); ++ __ beq_c(ic_reg, rscratch3, hit); ++ __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); ++ ++ // Verified entry point must be aligned ++ __ align(8); ++ ++ __ bind(hit); ++ ++ int vep_offset = ((intptr_t)__ pc()) - start; ++ ++#ifdef COMPILER1 ++ // For Object.hashCode, System.identityHashCode try to pull hashCode from object header if available. ++ if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) { ++ inline_check_hashcode_from_object_header(masm, method, j_rarg0 /*obj_reg*/, rax /*result*/); ++ } ++#endif // COMPILER1 ++ ++ // The instruction at the verified entry point must be 5 bytes or longer ++ // because it can be patched on the fly by make_non_entrant. The stack bang ++ // instruction fits that requirement. ++ ++ // Generate stack overflow check ++ ++ if (UseStackBanging) { ++ __ bang_stack_with_offset((int)JavaThread::stack_shadow_zone_size()); ++ } else { ++ // need a 5 byte instruction to allow MT safe patching to non-entrant ++ Unimplemented(); ++ } ++ ++ // Generate a new frame for the wrapper. ++ __ enter(); ++ // -2 because return address is already present and so is saved rbp ++ __ subptr(rsp, stack_size - 2*wordSize, rsp); ++ ++ // Frame is now completed as far as size and linkage. ++ int frame_complete = ((intptr_t)__ pc()) - start; ++ ++ //if (UseRTMLocking) { ++ // Abort RTM transaction before calling JNI ++ // because critical section will be large and will be ++ // aborted anyway. Also nmethod could be deoptimized. ++ //__ xabort(0); jzy? ++ //} ++//TODO:sw don't aligned? jzy ++/*#ifdef ASSERT ++ { ++ Label L; ++ __ movl(V0, esp); ++ __ andptr(V0, -16, V0); // must be 16 byte boundary (see amd64 ABI) ++ __ cmpptr(V0, esp); ++ __ jcc(Assembler::equal, L); ++ __ stop("improperly aligned stack"); ++ __ bind(L); ++ } ++#endif*/ /* ASSERT */ ++ ++ ++ // We use r14 as the oop handle for the receiver/klass ++ // It is callee save so it survives the call to native ++ ++ const Register oop_handle_reg = r14;//TODO:check jzy ++ ++ if (is_critical_native SHENANDOAHGC_ONLY(&& !UseShenandoahGC)) { ++ check_needs_gc_for_critical_native(masm, stack_slots, total_c_args, 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 ++ ++ // The Java calling convention is either equal (linux) or denser (win64) than the ++ // c calling convention. However the because of the jni_env argument the c calling ++ // convention always has at least one more (and two for static) arguments than Java. ++ // Therefore if we move the args from java -> c backwards then we will never have ++ // a register->register conflict and we don't have to build a dependency graph ++ // and figure out how to break any cycles. ++ // ++ ++ // Record esp-based slot for receiver on stack for non-static methods ++ int receiver_offset = -1; ++ ++ // 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*/); ++ ++ // Mark location of rbp (someday) ++ // map->set_callee_saved(VMRegImpl::stack2reg( stack_slots - 2), stack_slots * 2, 0, vmreg(rbp)); ++ ++ // Use eax, ebx as temporaries during any memory-memory moves we have to do ++ // All inbound args are referenced based on rbp and all outbound args via rsp. ++ ++ ++#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 */ ++ ++ // This may iterate in two different directions depending on the ++ // kind of native it is. The reason is that for regular JNI natives ++ // the incoming and outgoing registers are offset upwards and for ++ // critical natives they are offset down. ++ GrowableArray arg_order(2 * total_in_args); ++#if INCLUDE_SHENANDOAHGC ++ // Inbound arguments that need to be pinned for critical natives ++ GrowableArray pinned_args(total_in_args); ++ // Current stack slot for storing register based array argument ++ int pinned_slot = oop_handle_offset; ++#endif ++ VMRegPair tmp_vmreg; ++ tmp_vmreg.set2(rbx->as_VMReg()); ++ ++ if (!is_critical_native) { ++ for (int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0; i--, c_arg--) { ++ arg_order.push(i); ++ arg_order.push(c_arg); ++ } ++ } else { ++ // Compute a valid move order, using tmp_vmreg to break any cycles ++ ComputeMoveOrder cmo(total_in_args, in_regs, total_c_args, out_regs, in_sig_bt, arg_order, tmp_vmreg); ++ } ++ ++ int temploc = -1; ++ for (int ai = 0; ai < arg_order.length(); ai += 2) { ++ int i = arg_order.at(ai); ++ int c_arg = arg_order.at(ai + 1); ++ __ block_comment(err_msg("move %d -> %d", i, c_arg)); ++ if (c_arg == -1) { ++ assert(is_critical_native, "should only be required for critical natives"); ++ // This arg needs to be moved to a temporary ++ __ movl(tmp_vmreg.first()->as_Register(), in_regs[i].first()->as_Register()); ++ in_regs[i] = tmp_vmreg; ++ temploc = i; ++ continue; ++ } else if (i == -1) { ++ assert(is_critical_native, "should only be required for critical natives"); ++ // Read from the temporary location ++ assert(temploc != -1, "must be valid"); ++ i = temploc; ++ temploc = -1; ++ } ++#ifdef ASSERT ++ if (in_regs[i].first()->is_Register()) { ++ assert(!reg_destroyed[in_regs[i].first()->as_Register()->encoding()], "destroyed reg!"); ++ } else if (in_regs[i].first()->is_FloatRegister()) { ++ assert(!freg_destroyed[in_regs[i].first()->as_FloatRegister()->encoding()], "destroyed reg!"); ++ } ++ 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()] = true; ++ } ++#endif /* ASSERT */ ++ switch (in_sig_bt[i]) { ++ case T_ARRAY: ++ if (is_critical_native) { ++#if INCLUDE_SHENANDOAHGC ++ // pin before unpack ++ if (UseShenandoahGC) { ++ assert(pinned_slot <= stack_slots, "overflow"); ++ ShenandoahBarrierSet::assembler()->pin_critical_native_array(masm, in_regs[i], pinned_slot); ++ pinned_args.append(i); ++ } ++#endif ++ unpack_array_argument(masm, in_regs[i], in_elem_bt[i], out_regs[c_arg + 1], out_regs[c_arg]); ++ c_arg++; ++#ifdef ASSERT ++ 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()] = true; ++ } ++#endif ++ 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]); ++ } ++ } ++ ++ int c_arg; ++ ++ // Pre-load a static method's oop into r14. Used both by locking code and ++ // the normal JNI call code. ++ if (!is_critical_native) { ++ // point c_arg at the first arg that is already loaded in case we ++ // need to spill before we call out ++ c_arg = total_c_args - total_in_args; ++ ++ if (method->is_static()) { ++ ++ // load oop into a register ++ int oop_index = __ oop_recorder()->find_index(JNIHandles::make_local((method->method_holder())->java_mirror())); ++ RelocationHolder rspec = oop_Relocation::spec(oop_index); ++ __ relocate(rspec); ++ __ prepare_patch_li48(oop_handle_reg, (long)JNIHandles::make_local((method->method_holder())->java_mirror())); ++ ++ // Now handlize the static class mirror it's known not-null. ++ __ stptr(oop_handle_reg, Address(rsp, klass_offset)); ++ map->set_oop(VMRegImpl::stack2reg(klass_slot_offset)); ++ ++ // Now get the handle ++ __ lea(oop_handle_reg, Address(rsp, klass_offset)); ++ // store the klass handle as second argument ++ __ movl(c_rarg1, oop_handle_reg); ++ // and protect the arg if we must spill ++ c_arg--; ++ } ++ } else { ++ // For JNI critical methods we need to save all registers in save_args. ++ c_arg = 0; ++ } ++ ++ // Change state to native (we save the return address in the thread, since it might not ++ // be pushed on the stack when we do a a stack traversal). It is enough that the pc() ++ // points into the right code segment. It does not have to be the correct return pc. ++ // We use the same pc/oopMap repeatedly when we call out ++ ++ //intptr_t the_pc = (intptr_t) __ pc(); ++ //oop_maps->add_gc_map(the_pc - start, map); ++ Label native_return; ++ __ set_last_Java_frame(rsp, noreg, native_return, rscratch3); ++ //__ set_last_Java_frame(rsp, noreg, (address)the_pc, rscratch3); ++ // We have all of the arguments setup at this point. We must not touch any register ++ // argument registers at this point (what if we save/restore them there are no oop? ++ ++ { ++ SkipIfEqual skip(masm, &DTraceMethodProbes, false); ++ // protect the args we've loaded ++ save_args(masm, total_c_args, c_arg, out_regs); ++ __ mov_metadata(c_rarg1, method()); ++ __ call_VM_leaf( ++ CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), ++ rthread, c_rarg1); ++ restore_args(masm, total_c_args, c_arg, out_regs); ++ } ++ ++ // RedefineClasses() tracing support for obsolete method entry ++ if (log_is_enabled(Trace, redefine, class, obsolete)) { ++ // protect the args we've loaded ++ save_args(masm, total_c_args, c_arg, out_regs); ++ __ mov_metadata(c_rarg1, method()); ++ __ call_VM_leaf( ++ CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), ++ rthread, c_rarg1); ++ restore_args(masm, total_c_args, c_arg, out_regs); ++ } ++ ++ // Lock a synchronized method ++ ++ // Register definitions used by locking and unlocking ++ ++ const Register swap_reg = V0; // Must use rax for cmpxchg instruction ?jzy ++ const Register obj_reg = rmethod; // Will contain the oop ++ const Register lock_reg = rbcp; // Address of compiler lock object (BasicLock) ++ const Register old_hdr = rbcp; // value of old header at unlock time ++ ++ Label slow_path_lock; ++ Label lock_done; ++ ++ if (method->is_synchronized()) { ++ assert(!is_critical_native, "unhandled"); ++ ++ ++ const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); ++ ++ // Get the handle (the 2nd argument) ++ __ movl(oop_handle_reg, c_rarg1); ++ ++ // Get address of the box ++ ++ __ lea(lock_reg, Address(esp, lock_slot_offset * VMRegImpl::stack_slot_size)); ++ ++ // Load the oop from the handle ++ __ ldptr(obj_reg, Address(oop_handle_reg, 0)); ++ ++ if (UseBiasedLocking) { ++ __ biased_locking_enter(lock_reg, obj_reg, swap_reg, rscratch1, false, lock_done, &slow_path_lock); ++ } ++ ++ // Load immediate 1 into swap_reg %rax ++ __ movw(swap_reg, 1); ++ ++ // Load (object->mark() | 1) into swap_reg %rax ++ __ ldptr(rscratch3, Address(obj_reg, oopDesc::mark_offset_in_bytes())); ++ __ orptr(swap_reg, rscratch3, swap_reg); ++ ++ // Save (object->mark() | 1) into BasicLock's displaced header ++ __ stptr(swap_reg, Address(lock_reg, mark_word_offset)); ++ ++ if (os::is_MP()) { ++ __ lock(); ++ } ++ ++ // Address -> lock_reg if lock_reg == swap_reg else swap_reg = lock_reg ++ __ cmpxchg(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()), swap_reg); ++ __ jcc(Assembler::success, lock_done); ++ ++ // Hmm should this move to the slow path code area??? ++ ++ // Test if the oopMark is an obvious stack pointer, i.e., ++ // 1) (mark & 3) == 0, and ++ // 2) rsp <= mark < mark + os::pagesize() ++ // These 3 tests can be done by evaluating the following ++ // expression: ((mark - rsp) & (3 - os::vm_page_size())), ++ // assuming both stack pointer and pagesize have their ++ // least significant 2 bits clear. ++ // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg ++ //TODO:here is similar to interpreter ? jzy ++ __ subptr(swap_reg, esp, swap_reg); ++ __ andptr(swap_reg, 3 - os::vm_page_size(), swap_reg); ++ ++ // Save the test result, for recursive case, the result is zero ++ __ stptr(swap_reg, Address(lock_reg, mark_word_offset)); ++ __ jcc(Assembler::notEqual, slow_path_lock, swap_reg); ++ ++ // Slow path will re-enter here ++ ++ __ bind(lock_done); ++ } ++ ++ ++ // Finally just about ready to make the JNI call ++ ++ ++ // get JNIEnv* which is first argument to native ++ if (!is_critical_native) { ++ __ lea(c_rarg0, Address(rthread, in_bytes(JavaThread::jni_environment_offset()))); ++ } ++ ++ // Now set thread in native ++ __ stw(_thread_in_native, Address(rthread, JavaThread::thread_state_offset())); ++ ++ __ call(RuntimeAddress(native_func), &native_return); ++ // Verify or restore cpu control state after JNI call ++ //__ restore_cpu_control_state_after_jni(); //sw need this? jzy ++ ++ //intptr_t return_pc = (intptr_t) __ pc(); ++ oop_maps->add_gc_map( __ offset(native_return, (address)start), map); ++ ++ // Unpack native results. ++ switch (ret_type) { ++ case T_BOOLEAN: __ c2bool(V0); break; ++ case T_CHAR : __ zapnot(V0, 0x3, V0); break; ++ case T_BYTE : __ sign_extend_byte (V0); break; ++ case T_SHORT : __ sign_extend_short(V0); break; ++ case T_INT : /* nothing to do */ break; ++ case T_DOUBLE : ++ case T_FLOAT : ++ // Result is in xmm0 we'll save as needed ++ break; ++ case T_ARRAY: // Really a handle ++ case T_OBJECT: // Really a handle ++ break; // can't de-handlize until after safepoint check ++ case T_VOID: break; ++ case T_LONG: break; ++ default : ShouldNotReachHere(); ++ } ++ ++#if INCLUDE_SHENANDOAHGC ++ if (UseShenandoahGC) { ++ // unpin pinned arguments ++ pinned_slot = oop_handle_offset; ++ if (pinned_args.length() > 0) { ++ // save return value that may be overwritten otherwise. ++ save_native_result(masm, ret_type, stack_slots); ++ for (int index = 0; index < pinned_args.length(); index ++) { ++ int i = pinned_args.at(index); ++ assert(pinned_slot <= stack_slots, "overflow"); ++ ShenandoahBarrierSet::assembler()->unpin_critical_native_array(masm, in_regs[i], pinned_slot); ++ } ++ restore_native_result(masm, ret_type, stack_slots); ++ } ++ } ++#endif ++ // 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. ++ __ stw(_thread_in_native_trans, Address(rthread, JavaThread::thread_state_offset())); ++ ++ if(os::is_MP()) { ++ if (UseMembar) { ++ // Force this write out before the read below ++ __ memb(); ++ } else { ++ // Write serialization page so VM thread can do a pseudo remote membar. ++ // We use the current thread pointer to calculate a thread specific ++ // offset to write to within the page. This minimizes bus traffic ++ // due to cache line collision. ++ __ serialize_memory(rthread, rscratch3); ++ } ++ } ++ ++ Label after_transition; ++ ++ // check for safepoint operation in progress and/or pending suspend requests ++ { ++ Label Continue; ++ Label slow_path; ++ ++ __ safepoint_poll(slow_path, rthread, rscratch3); ++ ++ __ cmpw(Address(rthread, JavaThread::suspend_flags_offset()), R0); ++ __ jcc(Assembler::equal, Continue); ++ __ bind(slow_path); ++ ++ // Don't use call_VM as it will see a possible pending exception and forward it ++ // and never return here preventing us from clearing _last_native_pc down below. ++ // Also can't use call_VM_leaf either as it will check to see if rsi & rdi are ++ // preserved and correspond to the bcp/locals pointers. So we do a runtime call ++ // by hand. ++ // ++ //__ vzeroupper(); ++ Register r12 = r12_heapbase; ++ ++ save_native_result(masm, ret_type, stack_slots); ++ __ movl(c_rarg0, rthread); ++ __ movl(r12, esp); // remember sp ++ __ subptr(esp, frame::arg_reg_save_area_bytes, esp); // windows ++ __ andptr(esp, -16, esp); // align stack as required by ABI ++ if (!is_critical_native) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); ++ } else { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition))); ++ } ++ __ movl(esp, r12); // restore sp ++ __ reinit_heapbase(); ++ // 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. ++ __ jmp(after_transition); ++ } ++ ++ __ bind(Continue); ++ } ++ ++ // change thread state ++ __ stw(_thread_in_Java, Address(rthread, JavaThread::thread_state_offset())); ++ __ bind(after_transition); ++ ++ Label reguard; ++ Label reguard_done; ++ __ cmpw(Address(rthread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_reserved_disabled); ++ __ jcc(Assembler::equal, reguard); ++ __ bind(reguard_done); ++ ++ // native result if any is live ++ Register rax = V0; ++ Register rcx = rscratch3; ++ Register r12 = r12_heapbase; ++ ++ // Unlock ++ Label unlock_done; ++ Label slow_path_unlock; ++ if (method->is_synchronized()) { ++ ++ // Get locked oop from the handle we passed to jni ++ __ ldptr(obj_reg, Address(oop_handle_reg, 0)); ++ ++ Label done; ++ ++ if (UseBiasedLocking) { ++ __ biased_locking_exit(obj_reg, old_hdr, done); ++ } ++ ++ // Simple recursive lock? ++ ++ __ cmpptr(Address(esp, lock_slot_offset * VMRegImpl::stack_slot_size), R0); ++ __ jcc(Assembler::equal, done); ++ ++ // Must save rax if if it is live now because cmpxchg must use it ++ if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { ++ save_native_result(masm, ret_type, stack_slots); ++ } ++ ++ ++ // get address of the stack lock ++ __ lea(rax, Address(esp, lock_slot_offset * VMRegImpl::stack_slot_size)); ++ // get old displaced header ++ __ ldptr(old_hdr, Address(rax, 0)); ++ ++ // Atomic swap old header if oop still contains the stack lock ++ if (os::is_MP()) { ++ __ lock(); ++ } ++ ++ __ cmpxchg(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes()), rax); ++ __ jcc(Assembler::failed, slow_path_unlock); ++ ++ // slow path re-enters here ++ __ bind(unlock_done); ++ if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { ++ restore_native_result(masm, ret_type, stack_slots); ++ } ++ ++ __ bind(done); ++ ++ } ++ { ++ SkipIfEqual skip(masm, &DTraceMethodProbes, false); ++ save_native_result(masm, ret_type, stack_slots); ++ __ mov_metadata(c_rarg1, method()); ++ __ call_VM_leaf( ++ CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), ++ rthread, c_rarg1); ++ restore_native_result(masm, ret_type, stack_slots); ++ } ++ ++ __ reset_last_Java_frame(false); ++ ++ // Unbox oop result, e.g. JNIHandles::resolve value. ++ if (ret_type == T_OBJECT || ret_type == T_ARRAY) { ++ __ resolve_jobject(rax /* value */, ++ rthread /* thread */, ++ rcx /* tmp */); ++ } ++ ++ if (CheckJNICalls) { ++ // clear_pending_jni_exception_check ++ __ stptr(R0, Address(rthread, JavaThread::pending_jni_exception_check_fn_offset())); ++ } ++ ++ if (!is_critical_native) { ++ // reset handle block ++ __ ldptr(rcx, Address(rthread, JavaThread::active_handles_offset())); ++ __ stw(R0, Address(rcx, JNIHandleBlock::top_offset_in_bytes())); ++ } ++ ++ // pop our frame ++ ++ __ leave(); ++ ++ if (!is_critical_native) { ++ // Any exception pending? ++ __ cmpptr(Address(rthread, in_bytes(Thread::pending_exception_offset())), R0); ++ __ jcc(Assembler::notEqual, exception_pending); ++ } ++ ++ // Return ++ ++ __ ret(); ++ ++ // Unexpected paths are out of line and go here ++ ++ if (!is_critical_native) { ++ // forward the exception ++ __ bind(exception_pending); ++ ++ // and forward the exception ++ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); ++ } ++ ++ // Slow path locking & unlocking ++ if (method->is_synchronized()) { ++ ++ // BEGIN Slow path lock ++ __ bind(slow_path_lock); ++ ++ // has last_Java_frame setup. No exceptions so do vanilla call not call_VM ++ // args are (oop obj, BasicLock* lock, JavaThread* thread) ++ ++ // protect the args we've loaded ++ save_args(masm, total_c_args, c_arg, out_regs); ++ ++ __ movl(c_rarg0, obj_reg); ++ __ movl(c_rarg1, lock_reg); ++ __ movl(c_rarg2, rthread); ++ ++ // Not a leaf but we have last_Java_frame setup as we want ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C), 3); ++ restore_args(masm, total_c_args, c_arg, out_regs); ++ ++#ifdef ASSERT ++ { Label L; ++ __ cmpptr(Address(rthread, in_bytes(Thread::pending_exception_offset())), R0); ++ __ jcc(Assembler::equal, L); ++ __ stop("no pending exception allowed on exit from monitorenter"); ++ __ bind(L); ++ } ++#endif ++ __ jmp(lock_done); ++ ++ // END Slow path lock ++ ++ // BEGIN Slow path unlock ++ __ bind(slow_path_unlock); ++ ++ // If we haven't already saved the native result we must save it now as xmm registers ++ // are still exposed. ++ //__ vzeroupper(); ++ if (ret_type == T_FLOAT || ret_type == T_DOUBLE ) { ++ save_native_result(masm, ret_type, stack_slots); ++ } ++ ++ __ lea(c_rarg1, Address(esp, lock_slot_offset * VMRegImpl::stack_slot_size)); ++ Register r12 = r12_heapbase; ++ ++ __ movl(c_rarg0, obj_reg); ++ __ movl(c_rarg2, rthread); ++ __ movl(r12, esp); // remember sp ++ __ subptr(esp, frame::arg_reg_save_area_bytes, esp); // windows ++ __ andptr(esp, -16, esp); // align stack as required by ABI ++ ++ // Save pending exception around call to VM (which contains an EXCEPTION_MARK) ++ // NOTE that obj_reg == rbx currently ++ __ ldptr(rbx, Address(rthread, in_bytes(Thread::pending_exception_offset()))); ++ __ stptr(R0, Address(rthread, in_bytes(Thread::pending_exception_offset()))); ++ ++ // args are (oop obj, BasicLock* lock, JavaThread* thread) ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); ++ __ movl(esp, r12); // restore sp ++ __ reinit_heapbase(); ++#ifdef ASSERT ++ { ++ Label L; ++ __ cmpptr(Address(rthread, in_bytes(Thread::pending_exception_offset())), R0); ++ __ jcc(Assembler::equal, L); ++ __ stop("no pending exception allowed on exit complete_monitor_unlocking_C"); ++ __ bind(L); ++ } ++#endif /* ASSERT */ ++ ++ __ stptr(rbx, Address(rthread, in_bytes(Thread::pending_exception_offset()))); ++ ++ if (ret_type == T_FLOAT || ret_type == T_DOUBLE ) { ++ restore_native_result(masm, ret_type, stack_slots); ++ } ++ __ jmp(unlock_done); ++ ++ // END Slow path unlock ++ ++ } // synchronized ++ ++ // SLOW PATH Reguard the stack if needed ++ ++ __ bind(reguard); ++ //__ vzeroupper(); ++ save_native_result(masm, ret_type, stack_slots); ++ __ movl(r12, esp); // remember sp ++ __ subptr(esp, frame::arg_reg_save_area_bytes, esp); // windows ++ __ andptr(esp, -16, esp); // align stack as required by ABI ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages))); ++ __ movl(esp, r12); // restore sp ++ __ reinit_heapbase(); ++ restore_native_result(masm, ret_type, stack_slots); ++ // and continue ++ __ jmp(reguard_done); ++ ++ ++ ++ __ 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_slot_offset*VMRegImpl::stack_slot_size), ++ 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 ) { ++ return (callee_locals - callee_parameters) * Interpreter::stackElementWords; ++} ++ ++ ++uint SharedRuntime::out_preserve_stack_slots() { ++ return 0; ++} ++ ++//------------------------------generate_deopt_blob---------------------------- ++void SharedRuntime::generate_deopt_blob() { ++ // Allocate space for the code ++ ResourceMark rm; ++ // Setup code generation tools ++ int pad = 0; ++#if INCLUDE_JVMCI ++ if (EnableJVMCI || UseAOT) { ++ pad += 512; // Increase the buffer size when compiling for JVMCI ++ } ++#endif ++ CodeBuffer buffer("deopt_blob", 2560*2+pad, 1024); ++ MacroAssembler* masm = new MacroAssembler(&buffer); ++ int frame_size_in_words; ++ OopMap* map = NULL; ++ OopMapSet *oop_maps = new OopMapSet(); ++ ++ // ------------- ++ // This code enters when returning to a de-optimized nmethod. A return ++ // address has been pushed on the the stack, and return values are in ++ // registers. ++ // If we are doing a normal deopt then we were called from the patched ++ // nmethod from the point we returned to the nmethod. So the return ++ // address on the stack is wrong by NativeCall::instruction_size ++ // We will adjust the value so it looks like we have the original return ++ // address on the stack (like when we eagerly deoptimized). ++ // In the case of an exception pending when deoptimizing, we enter ++ // with a return address on the stack that points after the call we patched ++ // into the exception handler. We have the following register state from, ++ // e.g., the forward exception stub (see stubGenerator_x86_64.cpp). ++ // rax: exception oop ++ // rbx: exception handler ++ // rdx: throwing pc ++ // So in this case we simply jam rdx into the useless return address and ++ // the stack looks just like we want. ++ // ++ // At this point we need to de-opt. We save the argument return ++ // registers. We call the first C routine, fetch_unroll_info(). This ++ // routine captures the return values and returns a structure which ++ // describes the current frame size and the sizes of all replacement frames. ++ // The current frame is compiled code and may contain many inlined ++ // functions, each with their own JVM state. We pop the current frame, then ++ // push all the new frames. Then we call the C routine unpack_frames() to ++ // populate these frames. Finally unpack_frames() returns us the new target ++ // address. Notice that callee-save registers are BLOWN here; they have ++ // already been captured in the vframeArray at the time the return PC was ++ // patched. ++ address start = __ pc(); ++ Label cont; ++ //__ stop("check generate_deopt_blob @jzy"); ++ // Prolog for non exception case! ++ //__ subptr(RA, NativeCall::return_address_offset, RA); //TODO:need this? jzy ++ ++ // Save everything in sight. ++ map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); ++ Register r14 = rlocals; //should be callee saved jzy ++ //Register rax = V0; ++ //Register rdi = A0; ++ //Register rsi = A1; ++ //Register rdx = A2;//?is OK? jzy ++ //Register rcx = A3; ++ //Register rbx = rmethod; ++ //__ stop("generate_deopt_blob"); ++ // Normal deoptimization. Save exec mode for unpack_frames. ++ __ mov_immediate32(r14, Deoptimization::Unpack_deopt); // callee-saved why r14? jzy ++ __ jmp(cont); ++ ++ int reexecute_offset = __ pc() - start; ++#if INCLUDE_JVMCI && !defined(COMPILER1) ++ if (EnableJVMCI && UseJVMCICompiler) { ++ // JVMCI does not use this kind of deoptimization ++ __ should_not_reach_here(); ++ } ++#endif ++ ++ // Reexecute case ++ // return address is the pc describes what bci to do re-execute at ++ ++ // No need to update map as each call to save_live_registers will produce identical oopmap ++ (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); ++ ++ __ mov_immediate32(r14, Deoptimization::Unpack_reexecute); // callee-saved ++ __ jmp(cont); ++ ++#if INCLUDE_JVMCI ++ Label after_fetch_unroll_info_call; ++ int implicit_exception_uncommon_trap_offset = 0; ++ int uncommon_trap_offset = 0; ++ ++ if (EnableJVMCI || UseAOT) { ++ implicit_exception_uncommon_trap_offset = __ pc() - start; ++ ++ __ pushptr(Address(rthread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); ++ __ stptr(R0, Address(rthread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); ++ ++ uncommon_trap_offset = __ pc() - start; ++ ++ // Save everything in sight. ++ RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); ++ // fetch_unroll_info needs to call last_java_frame() ++ Label retaddr; ++ __ set_last_Java_frame(esp, noreg, retaddr, rscratch3, rscratch2_AT); ++ ++ __ ldws(c_rarg1, Address(rthread, in_bytes(JavaThread::pending_deoptimization_offset()))); ++ __ mov_immediate32(rscratch3, -1); ++ __ stw(rscratch3, Address(rthread, in_bytes(JavaThread::pending_deoptimization_offset()))); ++ ++ __ mov_immediate32(r14, (int32_t)Deoptimization::Unpack_reexecute); ++ __ movl(c_rarg0, rthread); ++ __ movl(c_rarg2, r14); // exec mode ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)), &retaddr); ++ oop_maps->add_gc_map( __ offset(retaddr, start), map->deep_copy()); ++ ++ __ reset_last_Java_frame(false); ++ ++ __ jmp(after_fetch_unroll_info_call); ++ } // EnableJVMCI ++#endif // INCLUDE_JVMCI ++ ++ int exception_offset = __ pc() - start; ++ ++ // Prolog for exception case ++ ++ // all registers are dead at this entry point, except for rax, and ++ // rdx which contain the exception oop and exception pc ++ // respectively. Set them in TLS and fall thru to the ++ // unpack_with_exception_in_tls entry point. ++ //__ stop("here should check:which is rax & rdx in sw?"); ++ __ stptr(rdx, Address(rthread, JavaThread::exception_pc_offset())); ++ __ stptr(rax, Address(rthread, JavaThread::exception_oop_offset())); ++ ++ int exception_in_tls_offset = __ pc() - start; ++ ++ // new implementation because exception oop is now passed in JavaThread ++ ++ // Prolog for exception case ++ // All registers must be preserved because they might be used by LinearScan ++ // Exceptiop oop and throwing PC are passed in JavaThread ++ // tos: stack at point of call to method that threw the exception (i.e. only ++ // args are on the stack, no return address) ++ ++ // make room on stack for the return address ++ // It will be patched later with the throwing pc. The correct value is not ++ // available now because loading it from memory would destroy registers. ++ //__ push(0); //TODO:check return address? jzy ++ //__ stop("generate_deopt_blob:exception here need check: jzy"); ++ // Save everything in sight. ++ map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); ++ ++ // Now it is safe to overwrite any register ++ ++ // Deopt during an exception. Save exec mode for unpack_frames. ++ __ mov_immediate32u(r14, Deoptimization::Unpack_exception); // callee-saved ++ ++ // load throwing pc from JavaThread and patch it as the return address ++ // of the current frame. Then clear the field in JavaThread ++ ++ __ ldptr(rdx, Address(rthread, JavaThread::exception_pc_offset())); ++ __ stptr(rdx, Address(rfp, wordSize)); ++ __ stptr(R0, Address(rthread, JavaThread::exception_pc_offset())); ++ ++#ifdef ASSERT ++ // verify that there is really an exception oop in JavaThread ++ __ ldptr(rax, Address(rthread, JavaThread::exception_oop_offset())); ++ __ verify_oop(rax); ++ ++ // verify that there is no pending exception ++ Label no_pending_exception; ++ __ ldptr(rax, Address(rthread, Thread::pending_exception_offset())); ++ __ jcc(Assembler::zero, no_pending_exception, rax); ++ __ stop("must not have pending exception here"); ++ __ bind(no_pending_exception); ++#endif ++ ++ __ bind(cont); ++ ++ // Call C code. Need thread and this frame, but NOT official VM entry ++ // crud. We cannot block on this call, no GC can happen. ++ // ++ // UnrollBlock* fetch_unroll_info(JavaThread* thread) ++ ++ // fetch_unroll_info needs to call last_java_frame(). ++ //__ stop("TODO:check how set pc? jzy"); ++ Label retaddr; ++ __ set_last_Java_frame(esp, noreg, retaddr, rscratch3, rscratch2_AT); ++#ifdef ASSERT ++ { Label L; ++ __ cmpptr(Address(rthread, ++ JavaThread::last_Java_fp_offset()), ++ R0); ++ __ jcc(Assembler::equal, L); ++ __ stop("SharedRuntime::generate_deopt_blob: last_Java_fp not cleared"); ++ __ bind(L); ++ } ++#endif // ASSERT ++ __ movl(c_rarg0, rthread); ++ __ movl(c_rarg1, r14); // exec_mode ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info)), &retaddr); ++ ++ // Need to have an oopmap that tells fetch_unroll_info where to ++ // find any register it might need. ++ oop_maps->add_gc_map(__ offset(retaddr, start), map); ++ ++ __ reset_last_Java_frame(false); ++ ++#if INCLUDE_JVMCI ++ if (EnableJVMCI || UseAOT) { ++ __ bind(after_fetch_unroll_info_call); ++ } ++#endif ++ ++ // Load UnrollBlock* into rdi ++ __ movl(rdi, rax); ++ ++ __ ldws(r14, Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); ++ Label noException; ++ __ cmpw(r14, Deoptimization::Unpack_exception); // Was exception pending? ++ __ jcc(Assembler::notEqual, noException); ++ __ ldptr(rax, Address(rthread, JavaThread::exception_oop_offset())); ++ // QQQ this is useless it was NULL above ++ __ ldptr(rdx, Address(rthread, JavaThread::exception_pc_offset())); ++ __ stptr(R0, Address(rthread, JavaThread::exception_oop_offset())); ++ __ stptr(R0, Address(rthread, JavaThread::exception_pc_offset())); ++ ++ __ verify_oop(rax); ++ ++ // Overwrite the result registers with the exception results. ++ __ stptr(rax, Address(esp, RegisterSaver::v0_offset_in_bytes())); ++ // I think this is useless ++ assert(rdx == A2, "rdx not a2 register"); ++ __ stptr(rdx, Address(esp, RegisterSaver::a2_offset_in_bytes())); ++ ++ __ bind(noException); ++ ++ // Only register save data is on the stack. ++ // Now restore the result registers. Everything else is either dead ++ // or captured in the vframeArray. ++ RegisterSaver::restore_result_registers(masm); ++ ++ // All of the register save area has been popped of the stack. Only the ++ // return address remains. ++ ++ // Pop all the frames we must move/replace. ++ // ++ // Frame picture (youngest to oldest) ++ // 1: self-frame (no frame link) ++ // 2: deopting frame (no frame link) ++ // 3: caller of deopting frame (could be compiled/interpreted). ++ // ++ // Note: by leaving the return address of self-frame on the stack ++ // and using the size of frame 2 to adjust the stack ++ // when we are done the return to frame 3 will still be on the stack. ++ ++ // Pop deoptimized frame ++ __ ldws(rcx, Address(rdi, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset_in_bytes())); ++ __ addptr(esp, rcx, esp); ++ //__ ldl(RA, - 1 * wordSize, esp); ++ //__ ldl(rfp, - 2 * wordSize, esp); ++ ++ // rsp should be pointing at the return address to the caller (3) ++ ++ // Pick up the initial fp we should save ++ // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved) ++ __ ldptr(rfp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset_in_bytes())); ++ ++/*#ifdef ASSERT ++ { ++ Label L; ++ __ movl(rscratch3, rfp); ++ __ ldptr(rfp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset_in_bytes())); ++ __ cmpl(rscratch3, rfp); ++ __ jcc(Assembler::zero, L); ++ __ stop("fp not equal @jzy"); ++ __ bind(L); ++ } ++#endif*/ ++ ++#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) { ++ __ ldws(rbx, Address(rdi, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes())); ++ __ bang_stack_size(rbx, rcx); ++ } ++#endif ++ ++ // Load address of array of frame pcs into rcx ++ __ ldptr(rcx, Address(rdi, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes())); ++ ++ // Trash the old pc ++ __ addptr(esp, wordSize, esp); ++ ++ // Load address of array of frame sizes into rsi ++ __ ldptr(rsi, Address(rdi, Deoptimization::UnrollBlock::frame_sizes_offset_in_bytes())); ++ ++ // Load counter into rdx ++ __ ldws(rdx, Address(rdi, Deoptimization::UnrollBlock::number_of_frames_offset_in_bytes())); ++ ++ // Now adjust the caller's stack to make up for the extra locals ++ // but record the original sp so that we can save it in the skeletal interpreter ++ // frame and the stack walking of interpreter_sender will get the unextended sp ++ // value and not the "real" sp value. ++ ++ const Register sender_sp = rscratch3;//? jzy ++ //__ stop("which register can we use?"); ++ __ movl(sender_sp, esp); ++ __ ldws(rbx, Address(rdi, ++ Deoptimization::UnrollBlock:: ++ caller_adjustment_offset_in_bytes())); ++ __ subptr(esp, rbx, esp); ++ ++ // Push interpreter frames in a loop ++ Label loop; ++ __ bind(loop); ++ __ ldptr(rbx, Address(rsi, 0)); // Load frame size ++ __ subptr(rbx, 2*wordSize, rbx); // We'll push pc and ebp by hand ++ __ ldptr(RA, Address(rcx, 0)); // Save return address ++ __ enter(); // Save old & set new ebp ++ __ subptr(esp, rbx, esp); // Prolog ++ // This value is corrected by layout_activation_impl ++ __ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ __ stptr(sender_sp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable ++ __ movl(sender_sp, esp); // Pass sender_sp to next frame ++ __ addptr(rsi, wordSize, rsi); // Bump array pointer (sizes) ++ __ addptr(rcx, wordSize, rcx); // Bump array pointer (pcs) ++ __ decrementl(rdx); // Decrement counter ++ __ jcc(Assembler::notZero, loop, rdx); ++ __ ldptr(RA, Address(rcx, 0)); // Save final return address ++ ++ // Re-push self-frame ++ __ enter(); // Save old & set new ebp ++ ++ // Allocate a full sized register save area. ++ // Return address and rbp are in place, so we allocate two less words. ++ __ subptr(esp, (frame_size_in_words - 2) * wordSize, esp); ++ ++ // Restore frame locals after moving the frame ++ __ store_double(FSF, Address(esp, RegisterSaver::fsf_offset_in_bytes())); ++ __ stptr(rax, Address(esp, RegisterSaver::v0_offset_in_bytes())); ++ ++ // Call C code. Need thread but NOT official VM entry ++ // crud. We cannot block on this call, no GC can happen. Call should ++ // restore return values to their stack-slots with the new SP. ++ // ++ // void Deoptimization::unpack_frames(JavaThread* thread, int exec_mode) ++ ++ // Use rbp because the frames look interpreted now ++ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. ++ // Don't need the precise return PC here, just precise enough to point into this code blob. ++ address the_pc = __ pc(); ++ __ set_last_Java_frame(esp, rfp, the_pc, rscratch3); ++ ++ //__ andptr(esp, -(StackAlignmentInBytes), esp); // Fix stack alignment as required by ABI ++ __ movl(c_rarg0, rthread); ++ __ movl(c_rarg1, r14); // second arg: exec_mode r14 should be callee saved in sw jzy ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); ++ // Revert SP alignment after call since we're going to do some SP relative addressing below ++ __ ldptr(esp, Address(rthread, JavaThread::last_Java_sp_offset())); ++ ++ // Set an oopmap for the call site ++ // Use the same PC we used for the last java frame TODO:need modify add_gc_map's offset? ++ oop_maps->add_gc_map(the_pc - start, ++ new OopMap( frame_size_in_words, 0 )); ++ ++ // Clear fp AND pc ++ __ reset_last_Java_frame(true); ++ ++ // Collect return values ++ __ load_double(FSF, Address(esp, RegisterSaver::fsf_offset_in_bytes())); ++ __ ldptr(rax, Address(esp, RegisterSaver::v0_offset_in_bytes())); ++ // I think this is useless (throwing pc?) ++ __ ldptr(rdx, Address(esp, RegisterSaver::a2_offset_in_bytes())); ++ ++ // Pop self-frame. ++ __ leave(); // Epilog ++ ++ // Jump to interpreter ++ __ ret(); ++ ++ // Make sure all code is generated ++ masm->flush(); ++ //__ stop("DeoptimizationBlob::create(unimplement): jzy"); ++ _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); ++ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); ++#if INCLUDE_JVMCI ++ if (EnableJVMCI || UseAOT) { ++ _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-------------------- ++void SharedRuntime::generate_uncommon_trap_blob() { ++ // Allocate space for the code ++ ResourceMark rm; ++ // Setup code generation tools ++ CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); ++ MacroAssembler* masm = new MacroAssembler(&buffer); ++ ++ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); ++ ++ address start = __ pc(); ++ //Register rax = V0; ++ //Register rbx = rmethod; ++ //Register rdi = c_rarg0; ++ //Register rsi = c_rarg1; ++ //Register rcx = c_rarg3; ++ //Register rdx = rscratch2_AT; ++ //Register rbp = rfp;//lsp?? ++ //__ stop("generate_uncommon_trap_blob"); ++ ++ // Push self-frame. We get here with a return address in RA ++ __ enter(); ++ // we don't expect an arg reg save area ++#ifndef PRODUCT ++ assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); ++#endif ++ ++ // compiler left unloaded_class_index in j_rarg0 move to where the ++ // runtime expects it. ++ __ movws(c_rarg1, j_rarg0); ++ ++ Label retaddr; ++ __ set_last_Java_frame(esp, noreg, retaddr, rscratch3); ++ ++ // Call C code. Need thread but NOT official VM entry ++ // crud. We cannot block on this call, no GC can happen. Call should ++ // capture callee-saved registers as well as return values. ++ // Thread is in rdi already. ++ // ++ // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); ++ ++ __ movl(c_rarg0, rthread); ++ __ mov_immediate32s(c_rarg2, Deoptimization::Unpack_uncommon_trap); ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)), &retaddr); ++ ++ // Set an oopmap for the call site ++ OopMapSet* oop_maps = new OopMapSet(); ++ OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); ++ ++ // location of rbp is known implicitly by the frame sender code ++ ++ oop_maps->add_gc_map(__ offset(retaddr, start), map);//TODO:check jzy ++ ++ __ reset_last_Java_frame(false); ++ ++ // Load UnrollBlock* into rdi ++ __ movl(rdi, rax); ++ ++#ifdef ASSERT ++ { Label L; ++ __ mov_immediate32(rscratch3, (int32_t)Deoptimization::Unpack_uncommon_trap); ++ __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()), rscratch3); ++ __ jcc(Assembler::equal, L); ++ __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); ++ __ bind(L); ++ } ++#endif ++ ++ // Pop all the frames we must move/replace. ++ // ++ // Frame picture (youngest to oldest) ++ // 1: self-frame (no frame link) ++ // 2: deopting frame (no frame link) ++ // 3: caller of deopting frame (could be compiled/interpreted). ++ ++ // Pop self-frame. We have no frame, and must rely only on rax and rsp. ++ __ addptr(esp, (SimpleRuntimeFrame::framesize - 2) << LogBytesPerInt, esp); // Epilog! ++ ++ // Pop deoptimized frame (int) ++ __ ldwu(rcx, Address(rdi, ++ Deoptimization::UnrollBlock:: ++ size_of_deoptimized_frame_offset_in_bytes())); ++ __ addptr(esp, rcx, esp); ++ ++ // rsp should be pointing at the return address to the caller (3) ++ ++ // Pick up the initial fp we should save ++ // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved) ++ __ ldptr(rfp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset_in_bytes())); ++ ++#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) { ++ __ ldws(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes())); ++ __ bang_stack_size(rbx, rcx); ++ } ++#endif ++ ++ // Load address of array of frame pcs into rcx (address*) ++ __ ldptr(rcx, Address(rdi, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes())); ++ ++ // Trash the return pc ++ __ addptr(esp, wordSize, esp); ++ ++ // Load address of array of frame sizes into rsi (intptr_t*) ++ __ ldptr(rsi, Address(rdi, Deoptimization::UnrollBlock:: frame_sizes_offset_in_bytes())); ++ ++ // Counter ++ __ ldws(rdx, Address(rdi, Deoptimization::UnrollBlock:: number_of_frames_offset_in_bytes())); // (int) ++ ++ // Now adjust the caller's stack to make up for the extra locals but ++ // record the original sp so that we can save it in the skeletal ++ // interpreter frame and the stack walking of interpreter_sender ++ // will get the unextended sp value and not the "real" sp value. ++ ++ const Register sender_sp = rsender; ++ __ movl(sender_sp, esp); ++ __ ldws(rbx, Address(rdi, Deoptimization::UnrollBlock:: caller_adjustment_offset_in_bytes())); // (int) ++ __ subptr(esp, rbx, esp); ++ ++ // Push interpreter frames in a loop ++ Label loop; ++ __ bind(loop); ++ __ ldptr(rbx, Address(rsi, 0)); // Load frame size ++ __ subptr(rbx, 2 * wordSize, rbx); // We'll push pc and rbp by hand ++ __ ldptr(RA, Address(rcx, 0)); // Save return address ++ __ enter(); // Save old & set new rbp ++ __ subptr(esp, rbx, esp); // Prolog ++ __ stptr(sender_sp, ++ Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable ++ // This value is corrected by layout_activation_impl ++ __ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ __ movl(sender_sp, esp); // Pass sender_sp to next frame ++ __ addptr(rsi, wordSize, rsi); // Bump array pointer (sizes) ++ __ addptr(rcx, wordSize, rcx); // Bump array pointer (pcs) ++ __ decrementl(rdx); // Decrement counter ++ __ jcc(Assembler::notZero, loop, rdx); ++ __ ldptr(RA, Address(rcx, 0)); // Save final return address ++ ++ // Re-push self-frame ++ __ enter(); // Save old & set new rbp ++ __ subptr(esp, (SimpleRuntimeFrame::framesize - 4) << LogBytesPerInt, esp, rscratch3); ++ // Prolog ++ ++ // Use rbp because the frames look interpreted now ++ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. ++ // Don't need the precise return PC here, just precise enough to point into this code blob. ++ address the_pc = __ pc(); ++ __ set_last_Java_frame(esp, rfp, the_pc, rscratch3); ++ ++ // Call C code. Need thread but NOT official VM entry ++ // crud. We cannot block on this call, no GC can happen. Call should ++ // restore return values to their stack-slots with the new SP. ++ // Thread is in rdi already. ++ // ++ // BasicType unpack_frames(JavaThread* thread, int exec_mode); ++ ++ //__ andptr(esp, -(StackAlignmentInBytes), esp); // Align SP as required by ABI ++ __ movl(c_rarg0, rthread); ++ __ mov_immediate64(c_rarg1, Deoptimization::Unpack_uncommon_trap); ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));//TODO:here need to modify offset? swjdk8 modifies this offset jzy ++ ++ // Set an oopmap for the call site ++ // Use the same PC we used for the last java frame ++ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); ++ ++ // Clear fp AND pc ++ __ reset_last_Java_frame(true); ++ ++ // Pop self-frame. ++ __ leave(); // Epilog ++ ++ // Jump to interpreter ++ __ ret(); ++ ++ // Make sure all code is generated ++ masm->flush(); ++ ++ _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, ++ SimpleRuntimeFrame::framesize >> 1); ++} ++#endif // COMPILER2 ++ ++ ++//------------------------------generate_handler_blob------ ++// ++// Generate a special Compile2Runtime blob that saves all registers, ++// and setup oopmap. ++// ++SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { ++ assert(StubRoutines::forward_exception_entry() != NULL, ++ "must be generated before"); ++ ++ ResourceMark rm; ++ OopMapSet *oop_maps = new OopMapSet(); ++ OopMap* map; ++ ++ // Allocate space for the code. Setup code generation tools. ++ CodeBuffer buffer("handler_blob", 2048, 1024); ++ MacroAssembler* masm = new MacroAssembler(&buffer); ++ ++ address start = __ pc(); ++ address call_pc = NULL; ++ int frame_size_in_words; ++ bool cause_return = (poll_type == POLL_AT_RETURN); ++ bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); ++ Register rbx = rmethod; ++ Register rax = V0; ++ ++// if (UseRTMLocking) { ++// // Abort RTM transaction before calling runtime ++// // because critical section will be large and will be ++// // aborted anyway. Also nmethod could be deoptimized. ++// __ xabort(0); ++// } ++//__ stop("generate_handler_blob"); ++ // Make room for return address (or push it again) ++ //if (!cause_return) { ++ //__ push(rbx); ++ //__ ldptr(RA, Address(rthread, JavaThread::saved_exception_pc_offset()));//TODO:need this? jzy ++ //} ++ ++ // Save registers, fpu state, and flags ++ map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words, save_vectors); ++ ++ // The following is basically a call_VM. However, we need the precise ++ // address of the call in order to generate an oopmap. Hence, we do all the ++ // work outselves. ++ Label retaddr; ++ __ set_last_Java_frame(esp, noreg, retaddr, rscratch3); ++ ++ // The return address must always be correct so that frame constructor never ++ // sees an invalid pc. ++ ++ if (!cause_return) { ++ // Get the return pc saved by the signal handler and stash it in its appropriate place on the stack. ++ // Additionally, rbx is a callee saved register and we can look at it later to determine ++ // if someone changed the return address for us! ++ __ ldptr(rbx, Address(rthread, JavaThread::saved_exception_pc_offset())); ++ __ stptr(rbx, Address(rfp, wordSize)); ++ } ++ ++ // Do the call ++ __ movl(c_rarg0, rthread); ++ __ call(RuntimeAddress(call_ptr), &retaddr); ++ ++ // Set an oopmap for the call site. This oopmap will map all ++ // oop-registers and debug-info registers as callee-saved. This ++ // will allow deoptimization at this safepoint to find all possible ++ // debug-info recordings, as well as let GC find all oops. ++ ++ oop_maps->add_gc_map( __ offset(retaddr, start), map); ++ ++ Label noException; ++ ++ __ reset_last_Java_frame(false); ++ ++ __ cmpptr(Address(rthread, Thread::pending_exception_offset()), R0); ++ __ jcc(Assembler::equal, noException); ++ ++ // Exception pending ++ ++ RegisterSaver::restore_live_registers(masm, save_vectors); ++ ++ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); ++ ++ // No exception case ++ __ bind(noException); ++ ++ Label no_adjust, bail, no_prefix, not_special; ++ if (SafepointMechanism::uses_thread_local_poll() && !cause_return) { ++ // If our stashed return pc was modified by the runtime we avoid touching it ++ __ cmpptr(rbx, Address(rfp, wordSize)); ++ __ jcc(Assembler::notEqual, no_adjust); ++ ++ // Skip over the poll instruction. ++ // See NativeInstruction::is_safepoint_poll() ++#ifdef ASSERT ++ // Verify the correct encoding of the poll we're about to skip. ++ __ ldwu(rscratch3, Address(rbx, 0)); ++ __ srll(rscratch3, 26, rscratch2_AT);//get op ++ __ cmpl(rscratch2_AT, Assembler::op_ldw); ++ __ jcc(Assembler::notEqual, bail); ++ ++ __ srll(rscratch3, 21, rscratch2_AT);//get ra ++ __ andw(rscratch2_AT, 0x1F, rscratch2_AT); ++ __ cmpl(rscratch2_AT, 25);//rscratch3 t11 ++ __ jcc(Assembler::notEqual, bail); ++ ++ __ andw(rscratch3, 0xFFFF, rscratch2_AT); ++// __ cmpl(rscratch2_AT, R0);//disp t11 ++// __ jcc(Assembler::notEqual, bail); ++ __ bne_l(rscratch2_AT, bail); ++ ++#endif ++ // Adjust return pc forward to step over the safepoint poll instruction ++ __ stop("TODO:need check jzy"); ++ __ addptr(rbx, 4, rbx); //TODO:refactor need const jzy ++ __ stptr(rbx, Address(rfp, wordSize)); ++ } ++ ++ __ bind(no_adjust); ++ // Normal exit, restore registers and exit. ++ RegisterSaver::restore_live_registers(masm, save_vectors); ++ __ ret(); ++ ++#ifdef ASSERT ++ __ bind(bail); ++ __ stop("Attempting to adjust pc to skip safepoint poll but the return point is not what we expected"); ++#endif ++ ++ // Make sure all code is generated ++ masm->flush(); ++ ++ // Fill-out other meta info ++ return SafepointBlob::create(&buffer, oop_maps, frame_size_in_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; ++ ++ CodeBuffer buffer(name, 2000, 512); ++ MacroAssembler* masm = new MacroAssembler(&buffer); ++ ++ int frame_size_in_words; ++ ++ OopMapSet *oop_maps = new OopMapSet(); ++ OopMap* map = NULL; ++ ++ //int start = __ offset(); ++ address start_pc = __ pc(); ++ Register rbx = rmethod; ++ Register rax = V0; ++ ++ map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); ++ ++ int frame_complete = __ offset(); ++ ++ Label retaddr; ++ //__ debug_stop("TODO:how set pc? jzy generate_resolve_blob"); ++ __ set_last_Java_frame(esp, noreg, retaddr, rscratch3, rscratch2_AT); ++ ++ __ movl(c_rarg0, rthread); ++ ++ __ call(RuntimeAddress(destination), &retaddr); ++ ++ // 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. ++ // sw need setfpec1, so we should -4. ++ oop_maps->add_gc_map( __ offset(retaddr, start_pc), map); ++ ++ // rax contains the address we are going to jump to assuming no exception got installed ++ ++ // clear last_Java_sp ++ __ reset_last_Java_frame(false); ++ // check for pending exceptions ++ Label pending; ++ __ cmpptr(Address(rthread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); ++ __ jcc(Assembler::notEqual, pending); ++ ++ // get the returned Method* ++ __ get_vm_result_2(rbx, rthread); ++ __ stptr(rbx, Address(esp, RegisterSaver::rmethod_offset_in_bytes())); ++ ++ __ stptr(rax, Address(esp, RegisterSaver::v0_offset_in_bytes())); ++ ++ RegisterSaver::restore_live_registers(masm); ++ ++ // We are back the the original state on entry and ready to go. ++ ++ __ jmp(rax); ++ ++ // Pending exception after the safepoint ++ ++ __ bind(pending); ++ ++ RegisterSaver::restore_live_registers(masm); ++ ++ // exception pending => remove activation and forward to exception handler ++ ++ __ stptr(R0, Address(rthread, JavaThread::vm_result_offset())); ++ ++ __ ldptr(rax, Address(rthread, Thread::pending_exception_offset())); ++ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); ++ ++ // ------------- ++ // 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_in_words, oop_maps, true); ++} ++ ++/* ================================= CRC32 ================================= */ ++/* ========================================================================= */ ++static const int crc_table[8][256] = ++ { ++ { ++ 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 ++ }, ++ { ++ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, ++ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, ++ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, ++ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, ++ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, ++ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, ++ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, ++ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, ++ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, ++ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, ++ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, ++ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, ++ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, ++ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, ++ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, ++ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, ++ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, ++ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, ++ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, ++ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, ++ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, ++ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, ++ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, ++ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, ++ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, ++ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, ++ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, ++ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, ++ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, ++ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, ++ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, ++ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, ++ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, ++ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, ++ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, ++ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, ++ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, ++ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, ++ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, ++ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, ++ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, ++ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, ++ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, ++ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, ++ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, ++ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, ++ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, ++ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, ++ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, ++ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, ++ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, ++ 0x9324fd72UL ++ }, ++ { ++ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, ++ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, ++ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, ++ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, ++ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, ++ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, ++ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, ++ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, ++ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, ++ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, ++ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, ++ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, ++ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, ++ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, ++ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, ++ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, ++ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, ++ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, ++ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, ++ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, ++ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, ++ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, ++ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, ++ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, ++ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, ++ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, ++ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, ++ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, ++ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, ++ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, ++ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, ++ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, ++ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, ++ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, ++ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, ++ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, ++ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, ++ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, ++ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, ++ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, ++ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, ++ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, ++ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, ++ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, ++ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, ++ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, ++ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, ++ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, ++ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, ++ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, ++ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, ++ 0xbe9834edUL ++ }, ++ { ++ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, ++ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, ++ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, ++ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, ++ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, ++ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, ++ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, ++ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, ++ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, ++ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, ++ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, ++ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, ++ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, ++ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, ++ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, ++ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, ++ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, ++ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, ++ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, ++ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, ++ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, ++ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, ++ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, ++ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, ++ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, ++ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, ++ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, ++ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, ++ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, ++ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, ++ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, ++ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, ++ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, ++ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, ++ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, ++ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, ++ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, ++ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, ++ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, ++ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, ++ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, ++ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, ++ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, ++ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, ++ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, ++ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, ++ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, ++ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, ++ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, ++ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, ++ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, ++ 0xde0506f1UL ++ }, ++ { ++ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, ++ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, ++ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, ++ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, ++ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, ++ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, ++ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, ++ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, ++ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, ++ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, ++ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, ++ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, ++ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, ++ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, ++ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, ++ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, ++ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, ++ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, ++ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, ++ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, ++ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, ++ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, ++ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, ++ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, ++ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, ++ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, ++ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, ++ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, ++ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, ++ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, ++ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, ++ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, ++ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, ++ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, ++ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, ++ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, ++ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, ++ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, ++ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, ++ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, ++ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, ++ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, ++ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, ++ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, ++ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, ++ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, ++ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, ++ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, ++ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, ++ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, ++ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, ++ 0x8def022dUL ++ }, ++ { ++ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, ++ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, ++ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, ++ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, ++ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, ++ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, ++ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, ++ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, ++ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, ++ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, ++ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, ++ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, ++ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, ++ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, ++ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, ++ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, ++ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, ++ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, ++ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, ++ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, ++ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, ++ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, ++ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, ++ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, ++ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, ++ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, ++ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, ++ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, ++ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, ++ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, ++ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, ++ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, ++ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, ++ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, ++ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, ++ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, ++ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, ++ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, ++ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, ++ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, ++ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, ++ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, ++ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, ++ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, ++ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, ++ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, ++ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, ++ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, ++ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, ++ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, ++ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, ++ 0x72fd2493UL ++ }, ++ { ++ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, ++ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, ++ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, ++ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, ++ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, ++ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, ++ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, ++ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, ++ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, ++ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, ++ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, ++ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, ++ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, ++ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, ++ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, ++ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, ++ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, ++ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, ++ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, ++ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, ++ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, ++ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, ++ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, ++ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, ++ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, ++ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, ++ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, ++ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, ++ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, ++ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, ++ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, ++ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, ++ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, ++ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, ++ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, ++ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, ++ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, ++ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, ++ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, ++ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, ++ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, ++ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, ++ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, ++ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, ++ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, ++ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, ++ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, ++ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, ++ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, ++ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, ++ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, ++ 0xed3498beUL ++ }, ++ { ++ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, ++ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, ++ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, ++ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, ++ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, ++ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, ++ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, ++ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, ++ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, ++ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, ++ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, ++ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, ++ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, ++ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, ++ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, ++ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, ++ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, ++ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, ++ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, ++ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, ++ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, ++ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, ++ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, ++ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, ++ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, ++ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, ++ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, ++ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, ++ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, ++ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, ++ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, ++ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, ++ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, ++ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, ++ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, ++ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, ++ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, ++ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, ++ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, ++ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, ++ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, ++ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, ++ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, ++ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, ++ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, ++ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, ++ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, ++ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, ++ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, ++ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, ++ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, ++ 0xf10605deUL ++ } ++ }; ++/* ========================================================================= */ ++#define DOLIT4 c ^= *buf4++; \ ++ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ ++ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] ++#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 ++ ++unsigned int SharedRuntime::updateBytesCRC32(unsigned long crc, const unsigned char *buf, unsigned int len) { ++ if (buf == 0) return 0UL; ++ ++ register unsigned int c; ++ register const unsigned int *buf4; ++ c = (unsigned int)crc; ++ c = ~c; ++ while (len && ((ptrdiff_t)buf & 3)) { ++ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); ++ len--; ++ } ++ ++ buf4 = (const unsigned int *) (const void *)buf; ++ while (len >= 32) { ++ DOLIT32; ++ len -= 32; ++ } ++ while (len >= 4) { ++ DOLIT4; ++ len -= 4; ++ } ++ buf = (const unsigned char *)buf4; ++ ++ if (len) do { ++ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); ++ } while (--len); ++ c = ~c; ++ return (unsigned long)c; ++} ++ ++//------------------------------Montgomery multiplication------------------------ ++// ++ ++#ifndef _WINDOWS ++ ++#define ASM_SUBTRACT ++#undef ASM_SUBTRACT //by jzy ++ ++#ifdef ASM_SUBTRACT ++// Subtract 0:b from carry:a. Return carry. ++static unsigned long ++sub(unsigned long a[], unsigned long b[], unsigned long carry, long len) { ++ long i = 0, cnt = len; ++ unsigned long tmp; ++ asm volatile("clc; " ++ "0: ; " ++ "mov (%[b], %[i], 8), %[tmp]; " ++ "sbb %[tmp], (%[a], %[i], 8); " ++ "inc %[i]; dec %[cnt]; " ++ "jne 0b; " ++ "mov %[carry], %[tmp]; sbb $0, %[tmp]; " ++ : [i]"+r"(i), [cnt]"+r"(cnt), [tmp]"=&r"(tmp) ++ : [a]"r"(a), [b]"r"(b), [carry]"r"(carry) ++ : "memory"); ++ return tmp; ++} ++#else // ASM_SUBTRACT ++typedef int __attribute__((mode(TI))) int128; ++ ++// Subtract 0:b from carry:a. Return carry. ++//static unsigned long ++//sub(unsigned long a[], unsigned long b[], unsigned long carry, int len) { ++// int128 tmp = 0; ++// int i; ++// for (i = 0; i < len; i++) { ++// tmp += a[i]; ++// tmp -= b[i]; ++// a[i] = tmp; ++// tmp >>= 64; ++// assert(-1 <= tmp && tmp <= 0, "invariant"); ++// } ++// return tmp + carry; ++//} ++static julong ++sub(julong a[], julong b[], julong carry, long len) { ++ long borrow = 0, t = 0; ++ julong tmp0, tmp1; ++ __asm__ __volatile__ ( ++ "0: \n" ++ "ldl %[tmp0], 0(%[a]) \n" ++ "ldl %[tmp1], 0(%[b]) \n" ++ "cmpult %[tmp0], %[borrow], %[t] \n" ++ "subl %[tmp0], %[borrow], %[tmp0] \n" ++ "cmpult %[tmp0], %[tmp1], %[borrow] \n" ++ "bis %[borrow], %[t], %[borrow] \n" ++ "subl %[tmp0], %[tmp1], %[tmp0] \n" ++ "stl %[tmp0], 0(%[a]) \n" ++ "addl %[a], 8, %[a] \n" ++ "addl %[b], 8, %[b] \n" ++ "subl %[len], 1, %[len] \n" ++ "bgt %[len], 0b \n" ++ "subl %[carry], %[borrow], %[tmp0] \n" ++ : [len]"+r"(len), [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [borrow]"+r"(borrow), [a]"+r"(a), [b]"+r"(b), [t]"+r"(t) ++ : [carry]"r"(carry) ++ : "memory" ++ ); ++ return tmp0; ++} ++#endif // ! ASM_SUBTRACT ++ ++// Multiply (unsigned) Long A by Long B, accumulating the double- ++// length result into the accumulator formed of T0, T1, and T2. ++//#define MACC(A, B, T0, T1, T2) \ ++//do { \ ++// ShouldNotReachHere(); \ ++//} while(0) ++inline void MACC(unsigned long A, unsigned long B, unsigned long &t0, unsigned long &t1, unsigned long &t2) { ++ unsigned long hi, lo, carry = 0, t = 0; ++ __asm__ __volatile__( ++ "mull %[A], %[B] , %[lo] \n" ++ "umulh %[A], %[B] , %[hi] \n" ++ "addl %[lo], %[t0], %[t0] \n" ++ "cmpult %[t0], %[lo], %[carry] \n" ++ "addl %[t1], %[carry], %[t1] \n" ++ "cmpult %[t1], %[carry], %[t] \n" ++ "addl %[t1], %[hi], %[t1] \n" ++ "cmpult %[t1], %[hi], %[carry] \n" ++ "bis %[carry], %[t] , %[carry] \n" ++ "addl %[t2], %[carry], %[t2] \n" ++ : [hi]"=&r"(hi), [lo]"=&r"(lo), [t0]"+r"(t0), [t1]"+r"(t1), [t2]"+r"(t2), [carry]"+r"(carry), [t]"+r"(t) ++ : [A]"r"(A), [B]"r"(B) ++ : ++ ); ++} ++ ++// As above, but add twice the double-length result into the ++// accumulator. ++//#define MACC2(A, B, T0, T1, T2) \ ++//do { \ ++//ShouldNotReachHere(); \ ++// } while(0) ++inline void MACC2(unsigned long A, unsigned long B, unsigned long &t0, unsigned long &t1, unsigned long &t2) { ++ unsigned long hi, lo, carry = 0, t = 0; ++ __asm__ __volatile__( ++ "mull %[A], %[B] , %[lo] \n" ++ "umulh %[A], %[B] , %[hi] \n" ++ "addl %[t0], %[lo], %[t0] \n" ++ "cmpult %[t0], %[lo], %[carry] \n" ++ "addl %[t1], %[carry], %[t1] \n" ++ "cmpult %[t1], %[carry], %[t] \n" ++ "addl %[t1], %[hi], %[t1] \n" ++ "cmpult %[t1], %[hi], %[carry] \n" ++ "bis %[carry], %[t], %[carry] \n" ++ "addl %[t2], %[carry], %[t2] \n" ++ "addl %[t0], %[lo], %[t0] \n" ++ "cmpult %[t0], %[lo], %[carry] \n" ++ "addl %[t1], %[carry], %[t1] \n" ++ "cmpult %[t1], %[carry], %[t] \n" ++ "addl %[t1], %[hi], %[t1] \n" ++ "cmpult %[t1], %[hi], %[carry] \n" ++ "bis %[carry], %[t], %[carry] \n" ++ "addl %[t2], %[carry], %[t2] \n" ++ : [hi]"=&r"(hi), [lo]"=&r"(lo), [t0]"+r"(t0), [t1]"+r"(t1), [t2]"+r"(t2), [carry]"+r"(carry), [t]"+r"(t) ++ : [A]"r"(A), [B]"r"(B) ++ : ++ ); ++} ++ ++// Fast Montgomery multiplication. The derivation of the algorithm is ++// in A Cryptographic Library for the Motorola DSP56000, ++// Dusse and Kaliski, Proc. EUROCRYPT 90, pp. 230-237. ++ ++static void NOINLINE ++montgomery_multiply(julong a[], julong b[], julong n[], ++ julong m[], julong inv, int len) { ++ julong t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator ++ int i; ++ ++ assert(inv * n[0] == ULLONG_MAX, "broken inverse in Montgomery multiply"); ++ //ShouldNotReachHere();//by jzy ++ for (i = 0; i < len; i++) { ++ int j; ++ for (j = 0; j < i; j++) { ++ MACC(a[j], b[i-j], t0, t1, t2); ++ MACC(m[j], n[i-j], t0, t1, t2); ++ } ++ MACC(a[i], b[0], t0, t1, t2); ++ m[i] = t0 * inv; ++ MACC(m[i], n[0], t0, t1, t2); ++ ++ assert(t0 == 0, "broken Montgomery multiply"); ++ ++ t0 = t1; t1 = t2; t2 = 0; ++ } ++ ++ for (i = len; i < 2*len; i++) { ++ int j; ++ for (j = i-len+1; j < len; j++) { ++ MACC(a[j], b[i-j], t0, t1, t2); ++ MACC(m[j], n[i-j], t0, t1, t2); ++ } ++ m[i-len] = t0; ++ t0 = t1; t1 = t2; t2 = 0; ++ } ++ ++ while (t0) ++ t0 = sub(m, n, t0, len); ++} ++ ++// Fast Montgomery squaring. This uses asymptotically 25% fewer ++// multiplies so it should be up to 25% faster than Montgomery ++// multiplication. However, its loop control is more complex and it ++// may actually run slower on some machines. ++ ++static void NOINLINE ++montgomery_square(julong a[], julong n[], ++ julong m[], julong inv, int len) { ++ julong t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator ++ int i; ++ ++ assert(inv * n[0] == ULLONG_MAX, "broken inverse in Montgomery square"); ++ //ShouldNotReachHere();//by jzy ++ for (i = 0; i < len; i++) { ++ int j; ++ int end = (i+1)/2; ++ for (j = 0; j < end; j++) { ++ MACC2(a[j], a[i-j], t0, t1, t2); ++ MACC(m[j], n[i-j], t0, t1, t2); ++ } ++ if ((i & 1) == 0) { ++ MACC(a[j], a[j], t0, t1, t2); ++ } ++ for (; j < i; j++) { ++ MACC(m[j], n[i-j], t0, t1, t2); ++ } ++ m[i] = t0 * inv; ++ MACC(m[i], n[0], t0, t1, t2); ++ ++ assert(t0 == 0, "broken Montgomery square"); ++ ++ t0 = t1; t1 = t2; t2 = 0; ++ } ++ ++ for (i = len; i < 2*len; i++) { ++ int start = i-len+1; ++ int end = start + (len - start)/2; ++ int j; ++ for (j = start; j < end; j++) { ++ MACC2(a[j], a[i-j], t0, t1, t2); ++ MACC(m[j], n[i-j], t0, t1, t2); ++ } ++ if ((i & 1) == 0) { ++ MACC(a[j], a[j], t0, t1, t2); ++ } ++ for (; j < len; j++) { ++ MACC(m[j], n[i-j], t0, t1, t2); ++ } ++ m[i-len] = t0; ++ t0 = t1; t1 = t2; t2 = 0; ++ } ++ ++ while (t0) ++ t0 = sub(m, n, t0, len); ++} ++ ++// Swap words in a longword. ++static julong swap(julong x) { ++ return (x << 32) | (x >> 32); ++} ++ ++// Copy len longwords from s to d, word-swapping as we go. The ++// destination array is reversed. ++static void reverse_words(julong *s, julong *d, int len) { ++ d += len; ++ while(len-- > 0) { ++ d--; ++ *d = swap(*s); ++ s++; ++ } ++} ++ ++// The threshold at which squaring is advantageous was determined ++// experimentally on an i7-3930K (Ivy Bridge) CPU @ 3.5GHz. ++#define MONTGOMERY_SQUARING_THRESHOLD 64 ++ ++void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints, ++ jint len, jlong inv, ++ jint *m_ints) { ++ assert(len % 2 == 0, "array length in montgomery_multiply must be even"); ++ int longwords = len/2; ++ ++ // Make very sure we don't use so much space that the stack might ++ // overflow. 512 jints corresponds to an 16384-bit integer and ++ // will use here a total of 8k bytes of stack space. ++ int total_allocation = longwords * sizeof (julong) * 4; ++ guarantee(total_allocation <= 8192, "must be"); ++ unsigned long *scratch = (julong *)alloca(total_allocation); ++ ++ // Local scratch arrays ++ julong ++ *a = scratch + 0 * longwords, ++ *b = scratch + 1 * longwords, ++ *n = scratch + 2 * longwords, ++ *m = scratch + 3 * longwords; ++ ++ reverse_words((julong *)a_ints, a, longwords); ++ reverse_words((julong *)b_ints, b, longwords); ++ reverse_words((julong *)n_ints, n, longwords); ++ ++ ::montgomery_multiply(a, b, n, m, (julong)inv, longwords); ++ ++ reverse_words(m, (julong *)m_ints, longwords); ++} ++ ++void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, ++ jint len, jlong inv, ++ jint *m_ints) { ++ assert(len % 2 == 0, "array length in montgomery_square must be even"); ++ int longwords = len/2; ++ ++ // Make very sure we don't use so much space that the stack might ++ // overflow. 512 jints corresponds to an 16384-bit integer and ++ // will use here a total of 6k bytes of stack space. ++ int total_allocation = longwords * sizeof (julong) * 3; ++ guarantee(total_allocation <= 8192, "must be"); ++ julong *scratch = (julong *)alloca(total_allocation); ++ ++ // Local scratch arrays ++ unsigned long ++ *a = scratch + 0 * longwords, ++ *n = scratch + 1 * longwords, ++ *m = scratch + 2 * longwords; ++ ++ reverse_words((julong *)a_ints, a, longwords); ++ reverse_words((julong *)n_ints, n, longwords); ++ ++ if (len >= MONTGOMERY_SQUARING_THRESHOLD) { ++ ::montgomery_square(a, n, m, (julong)inv, longwords); ++ } else { ++ ::montgomery_multiply(a, a, n, m, (julong)inv, longwords); ++ } ++ ++ reverse_words(m, (julong *)m_ints, longwords); ++} ++ ++#endif // WINDOWS ++ ++#ifdef COMPILER2 ++// This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame ++// ++//------------------------------generate_exception_blob--------------------------- ++// creates exception blob at the end ++// Using exception blob, this code is jumped from a compiled method. ++// (see emit_exception_handler in x86_64.ad file) ++// ++// Given an exception pc at a call we call into the runtime for the ++// handler in this method. This handler might merely restore state ++// (i.e. callee save registers) unwind the frame and jump to the ++// exception handler for the nmethod if there is no Java level handler ++// for the nmethod. ++// ++// This code is entered with a jmp. ++// ++// Arguments: ++// rax: exception oop ++// rdx: exception pc ++// ++// Results: ++// rax: exception oop ++// rdx: exception pc in caller or ??? ++// destination: exception handler of caller ++// ++// Note: the exception pc MUST be at a call (precise debug information) ++// Registers rax, rdx, rcx, rsi, rdi, r8-r11 are not callee saved. ++// ++ ++void OptoRuntime::generate_exception_blob() { ++ assert(!OptoRuntime::is_callee_saved_register(A2_num), ""); ++ assert(!OptoRuntime::is_callee_saved_register(A3_num), ""); ++ assert(!OptoRuntime::is_callee_saved_register(V0_num), ""); ++ ++ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); ++ ++ // Allocate space for the code ++ ResourceMark rm; ++ // Setup code generation tools ++ CodeBuffer buffer("exception_blob", 2048, 1024); ++ MacroAssembler* masm = new MacroAssembler(&buffer); ++ ++ ++ address start = __ pc(); ++ ++ //__ stop("generate_exception_blob"); ++ ++ // Exception pc is 'return address' for stack walker ++ __ push(rdx); ++ __ subptr(esp, SimpleRuntimeFrame::return_off << LogBytesPerInt, esp); // Prolog ++ ++ // Save callee-saved registers. See x86_64.ad. ++ ++ // rbp is an implicitly saved callee saved register (i.e., the calling ++ // convention will save/restore it in the prolog/epilog). Other than that ++ // there are no callee save registers now that adapter frames are gone. ++ ++ __ stptr(rfp, Address(esp, SimpleRuntimeFrame::rfp_off << LogBytesPerInt)); ++ ++ // Store exception in Thread object. We cannot pass any arguments to the ++ // handle_exception call, since we do not want to make any assumption ++ // about the size of the frame where the exception happened in. ++ // c_rarg0 is either rdi (Linux) or rcx (Windows). ++ __ stptr(rax, Address(rthread, JavaThread::exception_oop_offset())); ++ __ stptr(rdx, Address(rthread, JavaThread::exception_pc_offset())); ++ ++ // This call does all the hard work. It checks if an exception handler ++ // exists in the method. ++ // If so, it returns the handler address. ++ // If not, it prepares for stack-unwinding, restoring the callee-save ++ // registers of the frame being removed. ++ // ++ // address OptoRuntime::handle_exception_C(JavaThread* thread) ++ ++ // At a method handle call, the stack may not be properly aligned ++ // when returning with an exception. ++ address the_pc = __ pc(); ++ __ set_last_Java_frame(esp, noreg, the_pc, rscratch3); ++ __ movl(c_rarg0, rthread); ++ //__ andptr(esp, -(StackAlignmentInBytes), esp); // Align stack ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C))); ++ ++ // Set an oopmap for the call site. This oopmap will only be used if we ++ // are unwinding the stack. Hence, all locations will be dead. ++ // Callee-saved registers will be the same as the frame above (i.e., ++ // handle_exception_stub), since they were restored when we got the ++ // exception. ++ ++ OopMapSet* oop_maps = new OopMapSet(); ++ ++ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));//TODO:here need to modify offset? jzy ++ ++ __ reset_last_Java_frame(false); ++ ++ // Restore callee-saved registers ++ ++ // rbp is an implicitly saved callee-saved register (i.e., the calling ++ // convention will save restore it in prolog/epilog) Other than that ++ // there are no callee save registers now that adapter frames are gone. ++ ++ __ ldptr(rfp, Address(esp, SimpleRuntimeFrame::rfp_off << LogBytesPerInt)); ++ ++ __ addptr(esp, SimpleRuntimeFrame::return_off << LogBytesPerInt, esp); // Epilog ++ __ pop(rdx); // No need for exception pc anymore ++ ++ // rax: exception handler ++ ++ // We have a handler in rax (could be deopt blob). ++ __ movl(rscratch3, rax); ++ ++ // Get the exception oop ++ __ ldptr(rax, Address(rthread, JavaThread::exception_oop_offset())); ++ // Get the exception pc in case we are deoptimized ++ __ ldptr(rdx, Address(rthread, JavaThread::exception_pc_offset())); ++#ifdef ASSERT ++ __ stptr(R0, Address(rthread, JavaThread::exception_handler_pc_offset())); ++ __ stptr(R0, Address(rthread, JavaThread::exception_pc_offset())); ++#endif ++ // Clear the exception oop so GC no longer processes it as a root. ++ __ stptr(R0, Address(rthread, JavaThread::exception_oop_offset())); ++ ++ // rax: exception oop ++ // rscratch3: exception handler ++ // rdx: exception pc ++ // Jump to handler ++ ++ __ jmp(rscratch3); ++ ++ // Make sure all code is generated ++ masm->flush(); ++ ++ // Set exception blob ++ _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); ++} ++#endif // COMPILER2 +diff -uNr openjdk/src/hotspot/cpu/sw64/stubGenerator_sw64.cpp afu11u/src/hotspot/cpu/sw64/stubGenerator_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/stubGenerator_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/stubGenerator_sw64.cpp 2025-05-09 10:06:54.196292504 +0800 +@@ -0,0 +1,5922 @@ ++/* ++ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2019, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "gc/shared/barrierSet.hpp" ++#include "gc/shared/barrierSetAssembler.hpp" ++#include "interpreter/interpreter.hpp" ++#include "nativeInst_sw64.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" ++#include "utilities/align.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 ++ ++#undef __ ++#define __ _masm-> ++#define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8) ++//#define a__ ((Assembler*)_masm)-> ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024]; sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++const int MXCSR_MASK = 0xFFC0; // Mask out any pending exceptions ++ ++// Stub Code definitions ++ ++class StubGenerator: public StubCodeGenerator { ++ private: ++ ++#ifdef PRODUCT ++#define inc_counter_np(counter) ((void)0) ++#else ++ void inc_counter_np_(int& counter) { ++ // This can destroy rscratch1 if counter is far from the code cache ++ __ incrementw(ExternalAddress((address)&counter)); ++ } ++#define inc_counter_np(counter) \ ++ BLOCK_COMMENT("inc_counter " #counter); \ ++ inc_counter_np_(counter); ++#endif ++ ++ // Call stubs are used to call Java from C ++ // ++ // Linux Arguments: ++ // c_rarg0: call wrapper address address ++ // c_rarg1: result address ++ // c_rarg2: result type BasicType ++ // c_rarg3: method Method* ++ // c_rarg4: (interpreter) entry point address ++ // c_rarg5: parameters intptr_t* ++ // 16(rfp): parameter size (in words) int ++ // 24(rfp): thread Thread* ++ // ++ // [ return_from_Java ] <--- rsp ++ // [ argument word n ] ++ // ... ++ // -13 [ argument word 1 ] ++ // -12 [ saved S5 ] <--- rsp_after_call ++ // -11 [ saved S4 ] ++ // -10 [ saved S3 ] ++ // -9 [ saved S2 ] ++ // -8 [ saved S1 ] ++ // -7 [ saved S0 ] ++ // -6 [ call wrapper ] ++ // -5 [ result ] ++ // -4 [ result type ] ++ // -3 [ method ] ++ // -2 [ entry point ] ++ // -1 [ parameters ] ++ // 0 [ saved rfp ] <--- rfp ++ // 1 [ return address ] ++ // 2 [ parameter size ] ++ // 3 [ thread ] ++ // ++ ++// Call stub stack layout word offsets from rfp ++ enum call_stub_layout { ++ rsp_after_call_off = -20, ++ F9_off = rsp_after_call_off, ++ F8_off = -19, ++ F7_off = -18, ++ F6_off = -17, ++ F5_off = -16, ++ F4_off = -15, ++ F3_off = -14, ++ F2_off = -13, ++ S5_off = -12, ++ S4_off = -11, ++ S3_off = -10, ++ S2_off = -9, ++ S1_off = -8, ++ S0_off = -7, ++ call_wrapper_off = -6, ++ result_off = -5, ++ result_type_off = -4, ++ method_off = -3, ++ entry_point_off = -2, ++ parameters_off = -1, ++ rfp_off = 0, ++ retaddr_off = 1, ++ parameter_size_off = 2, ++ thread_off = 3 ++ }; ++ ++ address generate_call_stub(address& return_address) { ++ assert((int)frame::entry_frame_after_call_words == -(int)rsp_after_call_off + 1 && ++ (int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off, ++ "adjust this code"); ++ StubCodeMark mark(this, "StubRoutines", "call_stub"); ++ address start = __ pc(); ++ Register rax = V0; ++ ++ //set FPCR in kernel ++// if (SetFPCR) { ++// __ rfpcr(f28); ++// __ fimovd(f28, AT); ++// __ sbt(AT, 45, AT); ++// __ ifmovd(AT, f28); ++// __ wfpcr(f28); ++// } ++ ++ // same as in generate_catch_exception()! ++ const Address rsp_after_call(rfp, rsp_after_call_off * wordSize); ++ ++ const Address call_wrapper (rfp, call_wrapper_off * wordSize); ++ const Address result (rfp, result_off * wordSize); ++ const Address result_type (rfp, result_type_off * wordSize); ++ const Address method (rfp, method_off * wordSize); ++ const Address entry_point (rfp, entry_point_off * wordSize); ++ const Address parameters (rfp, parameters_off * wordSize); ++ const Address parameter_size(rfp, parameter_size_off * wordSize); ++ ++ // same as in generate_catch_exception()! ++ const Address thread (rfp, thread_off * wordSize); ++ ++ // call Java method from C function, by LIX20170503 ++ __ setfpec1(); ++ const Address S5_save(rfp, S5_off * wordSize); ++ const Address S4_save(rfp, S4_off * wordSize); ++ const Address S3_save(rfp, S3_off * wordSize); ++ const Address S2_save(rfp, S2_off * wordSize); ++ const Address S1_save(rfp, S1_off * wordSize); ++ const Address S0_save(rfp, S0_off * wordSize); ++ ++ // stub code ++ __ enter(); ++ __ subptr(esp, -rsp_after_call_off * wordSize, esp); ++ ++ __ stptr(c_rarg5, parameters); ++ __ stptr(c_rarg4, entry_point); ++ __ stptr(c_rarg3, method); ++ __ stptr(c_rarg2, result_type); ++ __ stptr(c_rarg1, result); ++ __ stptr(c_rarg0, call_wrapper); ++ ++ // save regs belonging to calling function ++ __ stptr(S5, S5_save); ++ __ stptr(S4, S4_save); ++ __ stptr(S3, S3_save); ++ __ stptr(S2, S2_save); ++ __ stptr(S1, S1_save); ++ __ stptr(S0, S0_save); ++ ++ __ fstd(f9, F9_off * wordSize, rfp); ++ __ fstd(f8, F8_off * wordSize, rfp); ++ __ fstd(f7, F7_off * wordSize, rfp); ++ __ fstd(f6, F6_off * wordSize, rfp); ++ __ fstd(f5, F5_off * wordSize, rfp); ++ __ fstd(f4, F4_off * wordSize, rfp); ++ __ fstd(f3, F3_off * wordSize, rfp); ++ __ fstd(f2, F2_off * wordSize, rfp); ++ __ ldptr(rthread, thread); ++ ++ __ reinit_heapbase(); ++ ++#ifdef ASSERT ++ // make sure we have no pending exceptions ++ { ++ Label L; ++ __ cmpptr(Address(rthread, Thread::pending_exception_offset()), R0); ++ __ jcc(Assembler::equal, L); ++ __ stop("StubRoutines::call_stub: entered with pending exception"); ++ __ bind(L); ++ } ++#endif ++ ++ // pass parameters if any ++ BLOCK_COMMENT("pass parameters if any"); ++ Label parameters_done; ++ __ ldws(c_rarg3, parameter_size); ++ __ testw(c_rarg3, c_rarg3); ++ __ jcc(Assembler::zero, parameters_done); ++ ++ Label loop; ++ __ ldptr(c_rarg2, parameters); // parameter pointer ++ __ movw(c_rarg1, c_rarg3); // parameter counter is in c_rarg1 ++ __ BIND(loop); ++ __ ldptr(rax, Address(c_rarg2, 0));// get parameter ++ __ addptr(c_rarg2, wordSize, c_rarg2); // advance to next parameter ++ __ decrementw(c_rarg1); // decrement counter ++ __ push(rax); // pass parameter ++ __ jcc(Assembler::notZero, loop, c_rarg1); ++ ++ // call Java function ++ __ BIND(parameters_done); ++ __ ldptr(rmethod, method); // get Method* ++ __ ldptr(c_rarg1, entry_point); // get entry_point ++ __ movl(rsender, esp); //set sender sp ++ BLOCK_COMMENT("call Java function"); ++ __ call(c_rarg1, return_address); //c_rarg4 is (interpreter) entry point ++ ++ // store result depending on type (everything that is not ++ // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) ++ __ ldptr(c_rarg0, result); ++ Label is_long, is_float, is_double, exit; ++ __ ldws(c_rarg1, result_type); ++ __ cmpw(c_rarg1, T_OBJECT); ++ __ jcc(Assembler::equal, is_long); ++ __ cmpw(c_rarg1, T_LONG); ++ __ jcc(Assembler::equal, is_long); ++ __ cmpw(c_rarg1, T_FLOAT); ++ __ jcc(Assembler::equal, is_float); ++ __ cmpw(c_rarg1, T_DOUBLE); ++ __ jcc(Assembler::equal, is_double); ++ ++ // handle T_INT case ++ __ stw(rax, Address(c_rarg0, 0)); ++ ++ __ BIND(exit); ++ ++ // pop parameters ++ __ lea(esp, rsp_after_call); ++ ++#ifdef ASSERT ++ // verify that threads correspond ++ { ++ Label L1, L2, L3; ++ Register rbx = c_rarg1; ++ __ cmpptr(rthread, thread); ++ __ jcc(Assembler::equal, L1); ++ __ stop("StubRoutines::call_stub: rthread is corrupted"); ++ __ bind(L1); ++ __ get_thread(rbx); ++ __ cmpptr(rthread, thread); ++ __ jcc(Assembler::equal, L2); ++ __ stop("StubRoutines::call_stub: rthread is modified by call"); ++ __ bind(L2); ++ __ cmpptr(rthread, rbx); ++ __ jcc(Assembler::equal, L3); ++ __ stop("StubRoutines::call_stub: threads must correspond"); ++ __ bind(L3); ++ } ++#endif ++ ++ // restore regs belonging to calling function ++ __ ldptr(S5, S5_save); ++ __ ldptr(S4, S4_save); ++ __ ldptr(S3, S3_save); ++ __ ldptr(S2, S2_save); ++ __ ldptr(S1, S1_save); ++ __ ldptr(S0, S0_save); ++ ++ __ fldd(f9, F9_off * wordSize, rfp); ++ __ fldd(f8, F8_off * wordSize, rfp); ++ __ fldd(f7, F7_off * wordSize, rfp); ++ __ fldd(f6, F6_off * wordSize, rfp); ++ __ fldd(f5, F5_off * wordSize, rfp); ++ __ fldd(f4, F4_off * wordSize, rfp); ++ __ fldd(f3, F3_off * wordSize, rfp); ++ __ fldd(f2, F2_off * wordSize, rfp); ++ ++ // restore rsp ++ __ addptr(esp, -rsp_after_call_off * wordSize, esp); ++ ++ __ leave(); ++ // return ++ __ ret(); ++ ++ // handle return types different from T_INT ++ __ BIND(is_long); ++ __ stl(rax, Address(c_rarg0, 0)); ++ __ jmp(exit); ++ ++ __ BIND(is_float); ++ __ fsts(f0, Address(c_rarg0, 0)); ++ __ jmp(exit); ++ ++ __ BIND(is_double); ++ __ fstd(f0, Address(c_rarg0, 0)); ++ __ jmp(exit); ++ ++ 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. ++ // ++ // Note: Usually the parameters are removed by the callee. In case ++ // of an exception crossing an activation frame boundary, that is ++ // not the case if the callee is compiled code => need to setup the ++ // rsp. ++ // ++ // rax: exception oop ++ ++ address generate_catch_exception() { ++ StubCodeMark mark(this, "StubRoutines", "catch_exception"); ++ address start = __ pc(); ++ //Register rbx = c_rarg2; ++ //Register rax = V0; ++ ++ // same as in generate_call_stub(): ++ const Address rsp_after_call(rfp, rsp_after_call_off * wordSize); ++ const Address thread (rfp, thread_off * wordSize); ++ ++#ifdef ASSERT ++ // verify that threads correspond ++ { ++ Label L1, L2, L3; ++ __ cmpptr(rthread, thread); ++ __ jcc(Assembler::equal, L1); ++ __ stop("StubRoutines::catch_exception: rthread is corrupted"); ++ __ bind(L1); ++ __ get_thread(rbx); ++ __ cmpptr(rthread, thread); ++ __ jcc(Assembler::equal, L2); ++ __ stop("StubRoutines::catch_exception: rthread is modified by call"); ++ __ bind(L2); ++ __ cmpptr(rthread, rbx); ++ __ jcc(Assembler::equal, L3); ++ __ stop("StubRoutines::catch_exception: threads must correspond"); ++ __ bind(L3); ++ } ++#endif ++ ++ // set pending exception ++ __ verify_oop(rax); ++ ++ __ stptr(rax, Address(rthread, Thread::pending_exception_offset())); ++ __ lea(rscratch3, ExternalAddress((address)__FILE__)); ++ __ stptr(rscratch3, Address(rthread, Thread::exception_file_offset())); ++ __ stw((int) __LINE__, Address(rthread, Thread::exception_line_offset())); ++ ++ // complete return to VM ++ assert(StubRoutines::_call_stub_return_address != NULL, ++ "_call_stub_return_address must have been generated before"); ++ __ jump(RuntimeAddress(StubRoutines::_call_stub_return_address)); ++ ++ 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 handlers: ++ // rax: exception ++ // rdx: throwing pc ++ // ++ // NOTE: At entry of this stub, exception-pc must be on stack !! ++ ++ address generate_forward_exception() { ++ StubCodeMark mark(this, "StubRoutines", "forward exception"); ++ address start = __ pc(); ++ //__ stop("not check:jzy"); ++ Register rax = V0; ++ Register rbx = rmethod; ++ Register rdx = c_rarg2; ++ // Upon entry, LR points to the return address returning into ++ // Java (interpreted or compiled) code; i.e., the return address ++ // becomes the throwing pc. ++ // ++ // Arguments pushed before the runtime call are still on the stack ++ // but the exception handler will reset the stack pointer -> ++ // ignore them. A potential result in registers can be ignored as ++ // well. ++ ++#ifdef ASSERT ++ // make sure this code is only executed if there is a pending exception ++ { ++ Label L; ++ __ cmpptr(Address(rthread, Thread::pending_exception_offset()), R0); ++ __ jcc(Assembler::notEqual, L); ++ __ stop("StubRoutines::forward exception: no pending exception (1)"); ++ __ bind(L); ++ } ++#endif ++ ++ // compute exception handler into rbx ++ ++ // call the VM to find the handler address associated with the ++ // caller address. pass thread in a0 and caller pc (ret address) ++ // in a1. n.b. the caller pc is in RA, unlike x86 where it is on ++ // the stack. ++ __ movl(r12_heapbase, RA); ++ __ movl(c_rarg1, RA); ++ __ block_comment("call exception_handler_for_return_address"); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ++ SharedRuntime::exception_handler_for_return_address), ++ rthread, c_rarg1); ++ // we should not really care that RA is no longer the callee ++ // address. we saved the value the handler needs in r12_heapbase so we can ++ // just copy it to rbx. however, the C2 handler will push its own ++ // frame and then calls into the VM and the VM code asserts that ++ // the PC for the frame above the handler belongs to a compiled ++ // Java method. So, we restore lr here to satisfy that assert. ++ __ movl(RA, r12_heapbase); ++ __ reinit_heapbase(); //reset r12_heapbase ++ ++ // setup rax & rdx, remove return address & clear pending exception ++ __ movl(rbx, rax); ++ __ movl(rdx, RA); ++ __ ldptr(rax, Address(rthread, Thread::pending_exception_offset())); ++ __ stptr(R0, Address(rthread, Thread::pending_exception_offset())); ++ ++#ifdef ASSERT ++ // make sure exception is set ++ { ++ Label L; ++ __ jcc(Assembler::notEqual, L, rax); ++ __ stop("StubRoutines::forward exception: no pending exception (2)"); ++ __ bind(L); ++ } ++#endif ++ ++ // continue at exception handler (return address removed) ++ // rax: exception ++ // rbx: exception handler ++ // rdx: throwing pc ++ __ verify_oop(rax); ++ __ jmp(rbx); ++ ++ return start; ++ } ++ ++ // Support for jint atomic::xchg(jint exchange_value, volatile jint* dest) ++ // ++ // Arguments : ++ // c_rarg0: exchange_value ++ // c_rarg0: dest ++ // ++ // Result: ++ // *dest <- ex, return (orig *dest) ++ address generate_atomic_xchg() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_xchg"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_xchg"); ++ __ movl(V0, c_rarg0); // Copy to eax we need a return value anyhow ++ __ xchgw(V0, Address(c_rarg1, 0)); // automatic LOCK ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for intptr_t atomic::xchg_long(jlong exchange_value, volatile jlong* dest) ++ // ++ // Arguments : ++ // c_rarg0: exchange_value ++ // c_rarg1: dest ++ // ++ // Result: ++ // *dest <- ex, return (orig *dest) ++ address generate_atomic_xchg_long() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_xchg_long"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_xchg_long"); ++ __ movl(V0, c_rarg0); // Copy to eax we need a return value anyhow ++ __ xchgptr(V0, Address(c_rarg1, 0)); // automatic LOCK ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for jint atomic::atomic_cmpxchg(jint exchange_value, volatile jint* dest, ++ // jint compare_value) ++ // ++ // Arguments : ++ // c_rarg0: exchange_value ++ // c_rarg1: dest ++ // c_rarg2: compare_value ++ // ++ // Result: ++ // if ( compare_value == *dest ) { ++ // *dest = exchange_value ++ // return compare_value; ++ // else ++ // return *dest; ++ address generate_atomic_cmpxchg() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_cmpxchg"); ++ __ movw(V0, c_rarg2); ++ //if ( os::is_MP() ) __ lock(); ++ __ cmpxchgw(c_rarg0, Address(c_rarg1, 0)); ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for int8_t atomic::atomic_cmpxchg(int8_t exchange_value, volatile int8_t* dest, ++ // int8_t compare_value) ++ // ++ // Arguments : ++ // c_rarg0: exchange_value ++ // c_rarg1: dest ++ // c_rarg2: compare_value ++ // ++ // Result: ++ // if ( compare_value == *dest ) { ++ // *dest = exchange_value ++ // return compare_value; ++ // else ++ // return *dest; ++ address generate_atomic_cmpxchg_byte() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg_byte"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_cmpxchg_byte"); ++ __ sextb(V0, c_rarg2); ++ //if ( os::is_MP() ) __ lock(); ++ __ cmpxchgb(c_rarg0, Address(c_rarg1, 0)); ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for int64_t atomic::atomic_cmpxchg(int64_t exchange_value, ++ // volatile int64_t* dest, ++ // int64_t compare_value) ++ // Arguments : ++ // c_rarg0: exchange_value ++ // c_rarg1: dest ++ // c_rarg2: compare_value ++ // ++ // Result: ++ // if ( compare_value == *dest ) { ++ // *dest = exchange_value ++ // return compare_value; ++ // else ++ // return *dest; ++ address generate_atomic_cmpxchg_long() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg_long"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_cmpxchg_long"); ++ __ movl(V0, c_rarg2); ++ //if ( os::is_MP() ) __ lock(); ++ __ cmpxchgq(c_rarg0, Address(c_rarg1, 0)); ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for jint atomic::add(jint add_value, volatile jint* dest) ++ // ++ // Arguments : ++ // c_rarg0: add_value ++ // c_rarg1: dest ++ // ++ // Result: ++ // *dest += add_value ++ // return *dest; ++ address generate_atomic_add() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_add"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_add"); ++// __ movw(V0, c_rarg0); ++// //if ( os::is_MP() ) __ lock(); ++// __ xaddw(Address(c_rarg1, 0), c_rarg0); ++// __ addw(V0, c_rarg0, V0); ++// __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for intptr_t atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) ++ // ++ // Arguments : ++ // c_rarg0: add_value ++ // c_rarg1: dest ++ // ++ // Result: ++ // *dest += add_value ++ // return *dest; ++ address generate_atomic_add_long() { ++ StubCodeMark mark(this, "StubRoutines", "atomic_add_long"); ++ address start = __ pc(); ++__ stop("unimplement generate_atomic_add_long"); ++// __ movl(V0, c_rarg0); // Copy to eax we need a return value anyhow ++// //if ( os::is_MP() ) __ lock(); ++// __ xaddptr(Address(c_rarg1, 0), c_rarg0); ++// __ addptr(V0, c_rarg0, V0); ++// __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for intptr_t OrderAccess::fence() ++ // ++ // Arguments : ++ // ++ // Result: ++ address generate_orderaccess_fence() { ++ StubCodeMark mark(this, "StubRoutines", "orderaccess_fence"); ++ address start = __ pc();__ stop("unimplement generate_orderaccess_fence"); ++ __ memb(); ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ // Support for intptr_t get_previous_fp() ++ // ++ // This routine is used to find the previous frame pointer for the ++ // caller (current_frame_guess). This is used as part of debugging ++ // ps() is seemingly lost trying to find frames. ++ // This code assumes that caller current_frame_guess) has a frame. ++ address generate_get_previous_fp() { ++ StubCodeMark mark(this, "StubRoutines", "get_previous_fp"); ++ const Address old_fp(rfp, 0); ++ const Address older_fp(V0, 0); ++ address start = __ pc();__ stop("unimplement generate_get_previous_fp"); ++ Register rax = V0; ++ ++ __ enter(); ++ __ ldptr(rax, old_fp); // callers fp ++ __ ldptr(rax, older_fp); // the frame for ps() ++ __ leave(); ++ __ ret_sw(); ++ return start; ++ } ++ ++ // Support for intptr_t get_previous_sp() ++ // ++ // This routine is used to find the previous stack pointer for the ++ // caller. ++ address generate_get_previous_sp() { ++ StubCodeMark mark(this, "StubRoutines", "get_previous_sp"); ++ address start = __ pc();__ stop("unimplement generate_get_previous_sp"); ++ ++ __ movl(V0, RA); ++ //__ addptr(V0, 8, V0); // return address is at the top of the stack. ++ __ ret_sw(); ++ ++ return start; ++ } ++ ++ address generate_f2i_fixup() { ++ StubCodeMark mark(this, "StubRoutines", "f2i_fixup"); ++ Address inout(esp, 5 * wordSize); // return address + 4 saves ++ ++ address start = __ pc(); ++ ++ Label L; ++ ShouldNotReachHere(); ++// __ push(rax); ++// __ push(c_rarg3); ++// __ push(c_rarg2); ++// __ push(c_rarg1); ++// ++// __ movl(rax, 0x7f800000); ++// __ xorl(c_rarg3, c_rarg3); ++// __ movl(c_rarg2, inout); ++// __ movl(c_rarg1, c_rarg2); ++// __ andl(c_rarg1, 0x7fffffff); ++// __ cmpl(rax, c_rarg1); // NaN? -> 0 ++// __ jcc(Assembler::negative, L); ++// __ testl(c_rarg2, c_rarg2); // signed ? min_jint : max_jint ++// __ movl(c_rarg3, 0x80000000); ++// __ movl(rax, 0x7fffffff); ++// __ cmovl(Assembler::positive, c_rarg3, rax); ++// ++// __ bind(L); ++// __ movptr(inout, c_rarg3); ++// ++// __ pop(c_rarg1); ++// __ pop(c_rarg2); ++// __ pop(c_rarg3); ++// __ pop(rax); ++// ++// __ ret(0); ++ ++ return start; ++ } ++ ++ address generate_f2l_fixup() { ++ StubCodeMark mark(this, "StubRoutines", "f2l_fixup"); ++ Address inout(esp, 5 * wordSize); // return address + 4 saves ++ address start = __ pc(); ++ ShouldNotReachHere(); ++ Label L; ++ ++// __ push(rax); ++// __ push(c_rarg3); ++// __ push(c_rarg2); ++// __ push(c_rarg1); ++// ++// __ movl(rax, 0x7f800000); ++// __ xorl(c_rarg3, c_rarg3); ++// __ movl(c_rarg2, inout); ++// __ movl(c_rarg1, c_rarg2); ++// __ andl(c_rarg1, 0x7fffffff); ++// __ cmpl(rax, c_rarg1); // NaN? -> 0 ++// __ jcc(Assembler::negative, L); ++// __ testl(c_rarg2, c_rarg2); // signed ? min_jlong : max_jlong ++// __ mov64(c_rarg3, 0x8000000000000000); ++// __ mov64(rax, 0x7fffffffffffffff); ++// __ cmov(Assembler::positive, c_rarg3, rax); ++// ++// __ bind(L); ++// __ movptr(inout, c_rarg3); ++// ++// __ pop(c_rarg1); ++// __ pop(c_rarg2); ++// __ pop(c_rarg3); ++// __ pop(rax); ++// ++// __ ret(0); ++ ++ return start; ++ } ++ ++ address generate_d2i_fixup() { ++ StubCodeMark mark(this, "StubRoutines", "d2i_fixup"); ++ Address inout(esp, 6 * wordSize); // return address + 5 saves ++ ++ address start = __ pc(); ++ ShouldNotReachHere(); ++// Label L; ++// ++// __ push(rax); ++// __ push(c_rarg3); ++// __ push(c_rarg2); ++// __ push(c_rarg1); ++// __ push(c_rarg0); ++// ++// __ movl(rax, 0x7ff00000); ++// __ movq(c_rarg2, inout); ++// __ movl(c_rarg3, c_rarg2); ++// __ mov(c_rarg1, c_rarg2); ++// __ mov(c_rarg0, c_rarg2); ++// __ negl(c_rarg3); ++// __ shrptr(c_rarg1, 0x20); ++// __ orl(c_rarg3, c_rarg2); ++// __ andl(c_rarg1, 0x7fffffff); ++// __ xorl(c_rarg2, c_rarg2); ++// __ shrl(c_rarg3, 0x1f); ++// __ orl(c_rarg1, c_rarg3); ++// __ cmpl(rax, c_rarg1); ++// __ jcc(Assembler::negative, L); // NaN -> 0 ++// __ testptr(c_rarg0, c_rarg0); // signed ? min_jint : max_jint ++// __ movl(c_rarg2, 0x80000000); ++// __ movl(rax, 0x7fffffff); ++// __ cmov(Assembler::positive, c_rarg2, rax); ++// ++// __ bind(L); ++// __ movptr(inout, c_rarg2); ++// ++// __ pop(c_rarg0); ++// __ pop(c_rarg1); ++// __ pop(c_rarg2); ++// __ pop(c_rarg3); ++// __ pop(rax); ++// ++// __ ret(0); ++ ++ return start; ++ } ++ ++ address generate_d2l_fixup() { ++ StubCodeMark mark(this, "StubRoutines", "d2l_fixup"); ++ Address inout(esp, 6 * wordSize); // return address + 5 saves ++ ++ address start = __ pc(); ++ ShouldNotReachHere(); ++ Label L; ++ ++// __ push(rax); ++// __ push(c_rarg3); ++// __ push(c_rarg2); ++// __ push(c_rarg1); ++// __ push(c_rarg0); ++// ++// __ movl(rax, 0x7ff00000); ++// __ movq(c_rarg2, inout); ++// __ movl(c_rarg3, c_rarg2); ++// __ mov(c_rarg1, c_rarg2); ++// __ mov(c_rarg0, c_rarg2); ++// __ negl(c_rarg3); ++// __ shrptr(c_rarg1, 0x20); ++// __ orl(c_rarg3, c_rarg2); ++// __ andl(c_rarg1, 0x7fffffff); ++// __ xorl(c_rarg2, c_rarg2); ++// __ shrl(c_rarg3, 0x1f); ++// __ orl(c_rarg1, c_rarg3); ++// __ cmpl(rax, c_rarg1); ++// __ jcc(Assembler::negative, L); // NaN -> 0 ++// __ testq(c_rarg0, c_rarg0); // signed ? min_jlong : max_jlong ++// __ mov64(c_rarg2, 0x8000000000000000); ++// __ mov64(rax, 0x7fffffffffffffff); ++// __ cmovq(Assembler::positive, c_rarg2, rax); ++// ++// __ bind(L); ++// __ movq(inout, c_rarg2); ++// ++// __ pop(c_rarg0); ++// __ pop(c_rarg1); ++// __ pop(c_rarg2); ++// __ pop(c_rarg3); ++// __ pop(rax); ++// ++// __ ret(0); ++ ++ return start; ++ } ++ ++ address generate_fp_mask(const char *stub_name, int64_t mask) { ++// __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", stub_name); ++ address start = __ pc(); ++ ShouldNotReachHere(); ++ ++// __ emit_data64( mask, relocInfo::none ); ++// __ emit_data64( mask, relocInfo::none ); ++ ++ return start; ++ } ++ ++ // Non-destructive plausibility checks for oops ++ // ++ // Arguments: ++ // all args on stack! ++ // ++ // Stack after saving c_rarg3: ++ // [tos + 0]: saved c_rarg3 ++ // [tos + 1]: saved c_rarg2 ++ // [tos + 2]: saved r12_heapbase (several TemplateTable methods use it) ++ // [tos + 3]: rscratch1 ++ // [tos + 4]: last RA ++ // * [tos + 5]: error message (char*) ++ // * [tos + 6]: object to verify (oop) ++ // * [tos + 7]: saved rax - saved by caller and bashed ++ // * = popped on exit ++ address generate_verify_oop() { ++ StubCodeMark mark(this, "StubRoutines", "verify_oop"); ++ address start = __ pc(); ++ Register rax = V0; ++ ++ Label exit, error; ++ __ push(rscratch1); ++ __ push(r12_heapbase); ++ ++ // save c_rarg2 and c_rarg3 ++ __ push(c_rarg2); ++ __ push(c_rarg3); ++ ++ __ incrementw(ExternalAddress((address) StubRoutines::verify_oop_count_addr()), 1, c_rarg2, c_rarg3); ++ ++ enum { ++ // After previous pushes. ++ oop_to_verify = 6 * wordSize, ++ saved_rax = 7 * wordSize, ++ ++ // Before the call to MacroAssembler::debug(), see below. ++ error_msg = 25 * wordSize ++ }; ++ ++ // get object ++ __ ldptr(rax, Address(esp, oop_to_verify)); ++ ++ // make sure object is 'reasonable' ++ __ jcc(Assembler::zero, exit, rax); // if obj is NULL it is OK ++ ++#if INCLUDE_ZGC ++ if (UseZGC) { ++ // Check if metadata bits indicate a bad oop ++ __ lea(rscratch3, Address(rthread, ZThreadLocalData::address_bad_mask_offset())); ++ __ testptr(rax, rscratch3); ++ __ jcc(Assembler::notZero, error); ++ } ++#endif ++ ++ // Check if the oop is in the right area of memory ++ __ movl(c_rarg2, rax); ++ __ mov_immediate64(c_rarg3, (intptr_t) Universe::verify_oop_mask()); ++ __ andptr(c_rarg2, c_rarg3, c_rarg2); ++ __ mov_immediate64(c_rarg3, (intptr_t) Universe::verify_oop_bits()); ++ __ cmpptr(c_rarg2, c_rarg3); ++ __ jcc(Assembler::notZero, error); ++ ++ // set rheapbaase to heapbase for load_klass() ++ __ reinit_heapbase(); ++ ++ // make sure klass is 'reasonable', which is not zero. ++ __ load_klass(rax, rax); // get klass ++ __ jcc(Assembler::zero, error, rax); // if klass is NULL it is broken ++ ++ // return if everything seems ok ++ __ bind(exit); ++ __ pop(c_rarg3); // restore c_rarg3 ++ __ pop(c_rarg2); // restore c_rarg2 ++ __ pop(r12_heapbase); // restore r12_heapbase ++ __ pop(rscratch1); // restore rscratch1 ++ ++ __ ret(); ++ ++ // handle errors ++ __ bind(error); ++ __ ldptr(rax, Address(esp, saved_rax)); // get saved rax back ++ __ pop(c_rarg3); // get saved c_rarg3 back ++ __ pop(c_rarg2); // get saved c_rarg2 back ++ __ pop(r12_heapbase); // get saved r12 back ++ __ pop(rscratch1); // restore rscratch1 ++ // will be ignored ++ __ push(RA); // sw need to save RA which need by ret after calling of debug64 ++ __ pushad(); // push registers ++ // (rip is already ++ // already pushed) ++ // debug(char* msg, int64_t pc, int64_t regs[]) ++ // We've popped the registers we'd saved (c_rarg3, c_rarg2 and flags), and ++ // pushed all the registers, so now the stack looks like: ++ // [tos + 0] 24 saved registers ++ // [tos + 24] current_RA ++ // [tos + 25] last RA ++ // * [tos + 26] error message (char*) ++ // * [tos + 27] object to verify (oop) ++ // * [tos + 28] saved rax - saved by caller and bashed ++ // * = popped on exit ++ ++ __ ldptr(c_rarg0, Address(esp, error_msg)); // pass address of error message ++ __ movl(c_rarg1, RA); // pass return address ++ __ movl(c_rarg2, esp); // pass address of regs on stack ++ __ movl(r12_heapbase, esp); // remember rsp ++ //__ subptr(esp, frame::arg_reg_save_area_bytes, esp); // windows ++ __ andptr(esp, -16, esp); // align stack as required by ABI ++ BLOCK_COMMENT("call MacroAssembler::debug"); ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); ++ __ movl(esp, r12_heapbase); // restore rsp ++ __ popad(); // pop registers (includes r12_heapbase) ++ __ pop(RA); ++ __ ret(); ++ ++ 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. ++ // ++ // Input: ++ // Rint - 32-bits value ++ // Rtmp - scratch ++ // ++ void assert_clean_int(Register Rint, Register Rtmp) { ++#ifdef ASSERT ++ Label L; ++ assert_different_registers(Rtmp, Rint); ++ __ movws(Rtmp, Rint); ++ __ cmpl_raw(Rtmp, Rint); ++ __ jcc(Assembler::equal, L); ++ __ stop("high 32-bits of int value are not 0"); ++ __ bind(L); ++#endif ++ } ++ ++ // Generate overlap test for array copy stubs ++ // ++ // Input: ++ // c_rarg0 - from ++ // c_rarg1 - to ++ // c_rarg2 - element count ++ // ++ // Output: ++ // rax - &from[element count - 1] ++ // ++ void array_overlap_test(address no_overlap_target, Address::ScaleFactor sf) {SCOPEMARK_NAME(array_overlap_test, _masm) ++ assert(no_overlap_target != NULL, "must be generated"); ++ array_overlap_test(no_overlap_target, NULL, sf); ++ } ++ void array_overlap_test(Label& L_no_overlap, Address::ScaleFactor sf) { ++ array_overlap_test(NULL, &L_no_overlap, sf); ++ } ++ void array_overlap_test(address no_overlap_target, Label* NOLp, Address::ScaleFactor sf) { ++ const Register from = c_rarg0; ++ const Register to = c_rarg1; ++ const Register count = c_rarg2; ++ const Register end_from = V0; ++ ++ __ cmpptr(to, from); ++ __ lea(end_from, Address(from, count, sf, 0)); ++ if (NOLp == NULL) { ++ ExternalAddress no_overlap(no_overlap_target); ++ __ jump_cc(Assembler::belowEqual, no_overlap); ++ __ cmpptr(to, end_from); ++ __ jump_cc(Assembler::aboveEqual, no_overlap); ++ } else { ++ __ jcc(Assembler::belowEqual, (*NOLp)); ++ __ cmpptr(to, end_from); ++ __ jcc(Assembler::aboveEqual, (*NOLp)); ++ } ++ } ++ ++ void array_overlap_test(address no_overlap_target, int log2_elem_size) {ShouldNotReachHere(); ++ int elem_size = 1 << log2_elem_size; ++ Address::ScaleFactor sf = Address::times_1; ++ ++ switch (log2_elem_size) { ++ case 0: sf = Address::times_1; break; ++ case 1: sf = Address::times_2; break; ++ case 2: sf = Address::times_4; break; ++ case 3: sf = Address::times_8; break; ++ } ++ ++ ExternalAddress no_overlap(no_overlap_target); ++ ++ __ slll(A2, sf, AT); ++ __ addl(AT, A0, AT); ++ __ addptr(AT, -elem_size, T12); ++ __ cmpl_raw(A1, A0); ++ __ jump_cc(Assembler::lessEqual, no_overlap); ++ __ cmpl_raw(A1, T12); ++ __ jump_cc(Assembler::greater, no_overlap); ++ ++ // If A0 = 0xf... and A1 = 0x0..., than goto no_overlap_target ++ Label L; ++ __ jcc(Assembler::greaterEqual, L, A0); ++ __ jump_cc(Assembler::greater, no_overlap, A1); ++ __ bind(L); ++ ++ } ++ ++ // Shuffle first three arg regs on Windows into Linux/Solaris locations. ++ // ++ // Outputs: ++ // rdi - rcx ++ // rsi - rdx ++ // rdx - r8 ++ // rcx - r9 ++ // ++ // Registers r9 and r10 are used to save rdi and rsi on Windows, which latter ++ // are non-volatile. r9 and r10 should not be used by the caller. ++ // ++ void setup_arg_regs(int nargs = 3) { ++ assert(nargs == 3 || nargs == 4, "else fix"); ++ assert(c_rarg0 == A0 && c_rarg1 == A1 && c_rarg2 == A2 && c_rarg3 == A3, ++ "unexpected argument registers"); ++ } ++ ++ void restore_arg_regs() { ++ } ++ ++ ++ // Copy big chunks forward ++ // ++ // Inputs: ++ // end_from - source arrays end address ++ // end_to - destination array end address ++ // qword_count - 64-bits element count, negative ++ // to - scratch ++ // L_copy_bytes - entry label ++ // L_copy_8_bytes - exit label ++ // ++ void copy_bytes_forward(Register end_from, Register end_to, ++ Register qword_count, Register to, ++ Label& L_copy_bytes, Label& L_copy_8_bytes) { ++ ShouldNotReachHere(); ++// DEBUG_ONLY(__ stop("enter at entry label, not here")); ++// Label L_loop; ++// __ align(OptoLoopAlignment); ++// if (UseUnalignedLoadStores) { ++// Label L_end; ++// // Copy 64-bytes per iteration ++// if (UseAVX > 2) { ++// Label L_loop_avx512, L_loop_avx2, L_32_byte_head, L_above_threshold, L_below_threshold; ++// ++// __ BIND(L_copy_bytes); ++// __ cmpptr(qword_count, (-1 * AVX3Threshold / 8)); ++// __ jccb(Assembler::less, L_above_threshold); ++// __ jmpb(L_below_threshold); ++// ++// __ bind(L_loop_avx512); ++// __ evmovdqul(xmm0, Address(end_from, qword_count, Address::times_8, -56), Assembler::AVX_512bit); ++// __ evmovdqul(Address(end_to, qword_count, Address::times_8, -56), xmm0, Assembler::AVX_512bit); ++// __ bind(L_above_threshold); ++// __ addptr(qword_count, 8); ++// __ jcc(Assembler::lessEqual, L_loop_avx512); ++// __ jmpb(L_32_byte_head); ++// ++// __ bind(L_loop_avx2); ++// __ vmovdqu(xmm0, Address(end_from, qword_count, Address::times_8, -56)); ++// __ vmovdqu(Address(end_to, qword_count, Address::times_8, -56), xmm0); ++// __ vmovdqu(xmm1, Address(end_from, qword_count, Address::times_8, -24)); ++// __ vmovdqu(Address(end_to, qword_count, Address::times_8, -24), xmm1); ++// __ bind(L_below_threshold); ++// __ addptr(qword_count, 8); ++// __ jcc(Assembler::lessEqual, L_loop_avx2); ++// ++// __ bind(L_32_byte_head); ++// __ subptr(qword_count, 4); // sub(8) and add(4) ++// __ jccb(Assembler::greater, L_end); ++// } else { ++// __ BIND(L_loop); ++// if (UseAVX == 2) { ++// __ vmovdqu(xmm0, Address(end_from, qword_count, Address::times_8, -56)); ++// __ vmovdqu(Address(end_to, qword_count, Address::times_8, -56), xmm0); ++// __ vmovdqu(xmm1, Address(end_from, qword_count, Address::times_8, -24)); ++// __ vmovdqu(Address(end_to, qword_count, Address::times_8, -24), xmm1); ++// } else { ++// __ movdqu(xmm0, Address(end_from, qword_count, Address::times_8, -56)); ++// __ movdqu(Address(end_to, qword_count, Address::times_8, -56), xmm0); ++// __ movdqu(xmm1, Address(end_from, qword_count, Address::times_8, -40)); ++// __ movdqu(Address(end_to, qword_count, Address::times_8, -40), xmm1); ++// __ movdqu(xmm2, Address(end_from, qword_count, Address::times_8, -24)); ++// __ movdqu(Address(end_to, qword_count, Address::times_8, -24), xmm2); ++// __ movdqu(xmm3, Address(end_from, qword_count, Address::times_8, - 8)); ++// __ movdqu(Address(end_to, qword_count, Address::times_8, - 8), xmm3); ++// } ++// ++// __ BIND(L_copy_bytes); ++// __ addptr(qword_count, 8); ++// __ jcc(Assembler::lessEqual, L_loop); ++// __ subptr(qword_count, 4); // sub(8) and add(4) ++// __ jccb(Assembler::greater, L_end); ++// } ++// // Copy trailing 32 bytes ++// if (UseAVX >= 2) { ++// __ vmovdqu(xmm0, Address(end_from, qword_count, Address::times_8, -24)); ++// __ vmovdqu(Address(end_to, qword_count, Address::times_8, -24), xmm0); ++// } else { ++// __ movdqu(xmm0, Address(end_from, qword_count, Address::times_8, -24)); ++// __ movdqu(Address(end_to, qword_count, Address::times_8, -24), xmm0); ++// __ movdqu(xmm1, Address(end_from, qword_count, Address::times_8, - 8)); ++// __ movdqu(Address(end_to, qword_count, Address::times_8, - 8), xmm1); ++// } ++// __ addptr(qword_count, 4); ++// __ BIND(L_end); ++// if (UseAVX >= 2) { ++// // clean upper bits of YMM registers ++// __ vpxor(xmm0, xmm0); ++// __ vpxor(xmm1, xmm1); ++// } ++// } else { ++// // Copy 32-bytes per iteration ++// __ BIND(L_loop); ++// __ movq(to, Address(end_from, qword_count, Address::times_8, -24)); ++// __ movq(Address(end_to, qword_count, Address::times_8, -24), to); ++// __ movq(to, Address(end_from, qword_count, Address::times_8, -16)); ++// __ movq(Address(end_to, qword_count, Address::times_8, -16), to); ++// __ movq(to, Address(end_from, qword_count, Address::times_8, - 8)); ++// __ movq(Address(end_to, qword_count, Address::times_8, - 8), to); ++// __ movq(to, Address(end_from, qword_count, Address::times_8, - 0)); ++// __ movq(Address(end_to, qword_count, Address::times_8, - 0), to); ++// ++// __ BIND(L_copy_bytes); ++// __ addptr(qword_count, 4); ++// __ jcc(Assembler::lessEqual, L_loop); ++// } ++// __ subptr(qword_count, 4); ++// __ jcc(Assembler::less, L_copy_8_bytes); // Copy trailing qwords ++ } ++ ++ // Copy big chunks backward ++ // ++ // Inputs: ++ // from - source arrays address ++ // dest - destination array address ++ // qword_count - 64-bits element count ++ // to - scratch ++ // L_copy_bytes - entry label ++ // L_copy_8_bytes - exit label ++ // ++ void copy_bytes_backward(Register from, Register dest, ++ Register qword_count, Register to, ++ Label& L_copy_bytes, Label& L_copy_8_bytes) { ++ ShouldNotReachHere(); ++ /*DEBUG_ONLY(__ stop("enter at entry label, not here")); ++ Label L_loop; ++ __ align(OptoLoopAlignment); ++ if (UseUnalignedLoadStores) { ++ Label L_end; ++ // Copy 64-bytes per iteration ++ if (UseAVX > 2) { ++ Label L_loop_avx512, L_loop_avx2, L_32_byte_head, L_above_threshold, L_below_threshold; ++ ++ __ BIND(L_copy_bytes); ++ __ cmpptr(qword_count, (AVX3Threshold / 8)); ++ __ jccb(Assembler::greater, L_above_threshold); ++ __ jmpb(L_below_threshold); ++ ++ __ BIND(L_loop_avx512); ++ __ evmovdqul(xmm0, Address(from, qword_count, Address::times_8, 0), Assembler::AVX_512bit); ++ __ evmovdqul(Address(dest, qword_count, Address::times_8, 0), xmm0, Assembler::AVX_512bit); ++ __ bind(L_above_threshold); ++ __ subptr(qword_count, 8); ++ __ jcc(Assembler::greaterEqual, L_loop_avx512); ++ __ jmpb(L_32_byte_head); ++ ++ __ bind(L_loop_avx2); ++ __ vmovdqu(xmm0, Address(from, qword_count, Address::times_8, 32)); ++ __ vmovdqu(Address(dest, qword_count, Address::times_8, 32), xmm0); ++ __ vmovdqu(xmm1, Address(from, qword_count, Address::times_8, 0)); ++ __ vmovdqu(Address(dest, qword_count, Address::times_8, 0), xmm1); ++ __ bind(L_below_threshold); ++ __ subptr(qword_count, 8); ++ __ jcc(Assembler::greaterEqual, L_loop_avx2); ++ ++ __ bind(L_32_byte_head); ++ __ addptr(qword_count, 4); // add(8) and sub(4) ++ __ jccb(Assembler::less, L_end); ++ } else { ++ __ BIND(L_loop); ++ if (UseAVX == 2) { ++ __ vmovdqu(xmm0, Address(from, qword_count, Address::times_8, 32)); ++ __ vmovdqu(Address(dest, qword_count, Address::times_8, 32), xmm0); ++ __ vmovdqu(xmm1, Address(from, qword_count, Address::times_8, 0)); ++ __ vmovdqu(Address(dest, qword_count, Address::times_8, 0), xmm1); ++ } else { ++ __ movdqu(xmm0, Address(from, qword_count, Address::times_8, 48)); ++ __ movdqu(Address(dest, qword_count, Address::times_8, 48), xmm0); ++ __ movdqu(xmm1, Address(from, qword_count, Address::times_8, 32)); ++ __ movdqu(Address(dest, qword_count, Address::times_8, 32), xmm1); ++ __ movdqu(xmm2, Address(from, qword_count, Address::times_8, 16)); ++ __ movdqu(Address(dest, qword_count, Address::times_8, 16), xmm2); ++ __ movdqu(xmm3, Address(from, qword_count, Address::times_8, 0)); ++ __ movdqu(Address(dest, qword_count, Address::times_8, 0), xmm3); ++ } ++ ++ __ BIND(L_copy_bytes); ++ __ subptr(qword_count, 8); ++ __ jcc(Assembler::greaterEqual, L_loop); ++ ++ __ addptr(qword_count, 4); // add(8) and sub(4) ++ __ jccb(Assembler::less, L_end); ++ } ++ // Copy trailing 32 bytes ++ if (UseAVX >= 2) { ++ __ vmovdqu(xmm0, Address(from, qword_count, Address::times_8, 0)); ++ __ vmovdqu(Address(dest, qword_count, Address::times_8, 0), xmm0); ++ } else { ++ __ movdqu(xmm0, Address(from, qword_count, Address::times_8, 16)); ++ __ movdqu(Address(dest, qword_count, Address::times_8, 16), xmm0); ++ __ movdqu(xmm1, Address(from, qword_count, Address::times_8, 0)); ++ __ movdqu(Address(dest, qword_count, Address::times_8, 0), xmm1); ++ } ++ __ subptr(qword_count, 4); ++ __ BIND(L_end); ++ if (UseAVX >= 2) { ++ // clean upper bits of YMM registers ++ __ vpxor(xmm0, xmm0); ++ __ vpxor(xmm1, xmm1); ++ } ++ } else { ++ // Copy 32-bytes per iteration ++ __ BIND(L_loop); ++ __ movq(to, Address(from, qword_count, Address::times_8, 24)); ++ __ movq(Address(dest, qword_count, Address::times_8, 24), to); ++ __ movq(to, Address(from, qword_count, Address::times_8, 16)); ++ __ movq(Address(dest, qword_count, Address::times_8, 16), to); ++ __ movq(to, Address(from, qword_count, Address::times_8, 8)); ++ __ movq(Address(dest, qword_count, Address::times_8, 8), to); ++ __ movq(to, Address(from, qword_count, Address::times_8, 0)); ++ __ movq(Address(dest, qword_count, Address::times_8, 0), to); ++ ++ __ BIND(L_copy_bytes); ++ __ subptr(qword_count, 4); ++ __ jcc(Assembler::greaterEqual, L_loop); ++ } ++ __ addptr(qword_count, 4); ++ __ jcc(Assembler::greater, L_copy_8_bytes); // Copy trailing qwords ++ * */ ++ } ++ ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries, ++ // we let the hardware handle it. The one to eight bytes within words, ++ // dwords or qwords that span cache line boundaries will still be loaded ++ // and stored atomically. ++ // ++ // Side Effects: ++ // disjoint_byte_copy_entry is set to the no-overlap entry point ++ // used by generate_conjoint_byte_copy(). ++ // ++ address generate_disjoint_byte_copy(bool aligned, address* entry, const char * name) {SCOPEMARK_NAME(generate_disjoint_byte_copy, _masm) ++ StubCodeMark mark(this, "StubRoutines", name); ++ __ align(CodeEntryAlignment); ++ ++ Register src = c_rarg0; ++ Register dst = c_rarg1; ++ Register count = c_rarg2; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ ++ address start = __ pc(); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ assert_clean_int(c_rarg2, rscratch3); // 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:"); ++ } ++ ++ //__ movl(src, A0); ++ //__ movl(dst, A1); ++ //__ movl(count, A2); ++ ++ Label l_align_dst, l_align_src, l_tail_bytes, l_end, l_tail; ++ ++ if(UseSimdForward){ ++ __ beq_l(count, l_end); ++ ++ __ cmple(count, 63, tmp1); ++ __ bne_l(tmp1, l_tail_bytes); //when count <= 63, don't use simd ++ ++ __ BIND(l_align_dst); ++ __ and_ins(dst, 31, tmp1); //is dst 0mod32? ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldbu(src, 0, tmp1); //grab 1 byte at a time, until dst is 0mod32 ++ __ stb(tmp1, 0, dst); ++ __ subl(count, 1, count); ++ __ addl(dst, 1, dst); ++ __ addl(src, 1, src); ++ __ beq_l(R0, l_align_dst); ++ ++ __ BIND(l_align_src); ++ copy_core_forward(32, src, dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ //copy tail bytes. ++ __ BIND(l_tail_bytes); ++ __ ldbu(src, 0, tmp1); ++ __ stb(tmp1, 0, dst); ++ __ addl(src, 1, src); ++ __ addl(dst, 1, dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_bytes); ++ ++ __ BIND(l_end); ++ ++ }else{ ++ generate_disjoint_copy(0, src, dst, count); ++ } ++ ++ inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter ++ __ movl(V0, R0); // return 0 ++ __ leave(); ++ __ ret(); ++ ++ return start; ++ } ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries, ++ // we let the hardware handle it. The one to eight bytes within words, ++ // dwords or qwords that span cache line boundaries will still be loaded ++ // and stored atomically. ++ // ++ address generate_conjoint_byte_copy(bool aligned, address nooverlap_target, ++ address* entry, const char *name) {SCOPEMARK_NAME(generate_conjoint_byte_copy, _masm); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name); ++ address start = __ pc(); ++//__ stop("generate_conjoint_byte_copy"); ++ Label l_exit; ++ Label l_copy_byte; ++ Label l_align_dst, l_align_src, l_tail_bytes, l_end, l_tail; ++ ++ /*address nooverlap_target = aligned ? ++ StubRoutines::arrayof_jbyte_disjoint_arraycopy() : ++ StubRoutines::jbyte_disjoint_arraycopy();*/ ++ ++ Register src = c_rarg0; // source array address ++ Register dst = c_rarg1; // destination array address ++ Register count = c_rarg2; // elements count ++ Register end_src = src; // source array end address ++ Register end_dst = dst; // destination array end address ++ Register end_count = count; // destination array end address ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ assert_clean_int(c_rarg2, rscratch3); // 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, Address::times_1); ++ // copy from high to low ++ //__ movl(end_count, count); ++ __ addl(src, end_count, end_src); ++ __ addl(dst, end_count, end_dst); ++ ++ if (UseSimdBackward) { ++ ++ __ beq_l(count, l_end); ++ ++ __ cmple(count, 63, tmp1); ++ __ bne_l(tmp1, l_tail_bytes); //when count <= 63, don't use simd ++ ++ __ BIND(l_align_dst); ++ __ and_ins(end_dst, 31, tmp1); //is dst 0mod32? ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldbu(end_src, -1, tmp2); //grab 1 bytes at a time, until dst is 0mod32 ++ __ stb(tmp2, -1, end_dst); ++ __ subl(count, 1, count); ++ __ subl(end_dst, 1, end_dst); ++ __ subl(end_src, 1, end_src); ++ __ beq_l(R0, l_align_dst); ++ ++ __ BIND(l_align_src); ++ copy_core_backward(32, end_src, end_dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_bytes); ++ __ ldbu(end_src, -1, tmp1); ++ __ stb(tmp1, -1, end_dst); ++ __ subl(end_src, 1, end_src); ++ __ subl(end_dst, 1, end_dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_bytes); ++ ++ __ BIND(l_end); ++ ++ } else { ++ generate_conjoint_copy(0, end_src, end_dst, end_count); ++ } ++ ++ inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter ++ __ movl(V0, R0); // return 0 ++ __ leave(); ++ __ ret(); ++ return start; ++ } ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we ++ // let the hardware handle it. The two or four words within dwords ++ // or qwords that span cache line boundaries will still be loaded ++ // and stored atomically. ++ // ++ // Side Effects: ++ // disjoint_short_copy_entry is set to the no-overlap entry point ++ // used by generate_conjoint_short_copy(). ++ // ++ address generate_disjoint_short_copy(bool aligned, address *entry, const char * name) {SCOPEMARK_NAME(generate_disjoint_short_copy, _masm) ++ StubCodeMark mark(this, "StubRoutines", name); ++ __ align(CodeEntryAlignment); ++ ++ Register src = T0; ++ Register dst = T1; ++ Register count = T3; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ ++ Register tmp4 = T11; ++ Register tmp5 = T12; ++ Register tmp6 = T2; ++ ++ address start = __ pc(); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ assert_clean_int(c_rarg2, V0); // 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:"); ++ } ++ ++ __ movl(src, A0); ++ __ movl(dst, A1); ++ __ movl(count, A2); ++ ++ Label l_1, l_2, l_3, l_4, l_5, l_6, l_7, l_8, l_9, l_10, l_11, l_12, l_13, l_14; ++ Label l_debug; ++ Label l_align_dst, l_align_src, l_tail_2_bytes, l_end, l_tail; ++ // don't try anything fancy if arrays don't have many elements ++ ++ if(UseSimdForward){ ++ __ cmple(count, 31, tmp1); //if count < 32(bytes < 64), then copy 2 bytes at a time ++ __ bne_l(tmp1, l_tail); ++ ++ __ BIND(l_align_dst); ++ __ and_ins(dst, 31, tmp1); ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldhu(src, 0, tmp2); ++ __ subl(count, 1, count); ++ __ sth(tmp2, 0, dst); ++ __ addl(src, 2, src); ++ __ addl(dst, 2, dst); ++ __ beq_l(R0, l_align_dst); ++ ++ __ BIND(l_align_src); ++ copy_core_forward(16, src, dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_2_bytes); ++ __ ldhu(src, 0, tmp1); ++ __ sth(tmp1, 0, dst); ++ __ addl(src, 2, src); ++ __ addl(dst, 2, dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_2_bytes); ++ ++ ++ __ BIND(l_end); ++ ++ } else { ++ __ slll(count, 1, count); ++ generate_disjoint_copy(1, src, dst, count); ++ } ++ ++ inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter ++ __ movl(V0, R0); // return 0 ++ __ leave(); ++ __ ret(); ++ ++ __ bind(l_debug); ++ __ stop("generate_disjoint_short_copy should not reach here"); ++ return start; ++ } ++ ++ ++ address generate_fill(BasicType t, bool aligned, const char *name) {SCOPEMARK_NAME(generate_fill, _masm) ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name); ++ address start = __ pc(); ++ ++ __ block_comment("Entry:"); ++ ++ const Register to = c_rarg0; // source array address ++ const Register value = c_rarg1; // value ++ const Register count = c_rarg2; // elements count ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ __ generate_fill(t, aligned, to, value, count, FSR); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(); ++ return start; ++ } ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we ++ // let the hardware handle it. The two or four words within dwords ++ // or qwords that span cache line boundaries will still be loaded ++ // and stored atomically. ++ // ++ address generate_conjoint_short_copy(bool aligned, address nooverlap_target, ++ address* entry, const char *name) {SCOPEMARK_NAME(generate_conjoint_short_copy, _masm) ++ Label l_tail_2_bytes, l_align_dst, l_align_src, l_tail, l_end, l_exit, l_copy_2_bytes; ++ StubCodeMark mark(this, "StubRoutines", name); ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++ ++ Register end_src = T3; ++ Register end_dst = T0; ++ Register count = T1; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ assert_clean_int(c_rarg2, V0); // 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, Address::times_2); ++ __ movl(end_src, A0); ++ __ movl(end_dst, A1); ++ __ movl(count, A2); ++ ++ if(UseSimdBackward){ ++ __ beq_l(count, l_end); ++ ++ __ sll(T1, Address::times_2, tmp1); ++ __ addl(T3, tmp1, end_src); ++ __ addl(T0, tmp1, end_dst); ++ ++ __ cmple(count, 31, tmp1); ++ __ bne_l(tmp1, l_tail_2_bytes); //when count <= 31, don't use simd ++ ++ __ BIND(l_align_dst); ++ __ and_ins(end_dst, 31, tmp1); //is dst 0mod32? ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldhu(end_src, -2, tmp2); //grab 2 bytes at a time, until dst is 0mod32 ++ __ sth(tmp2, -2, end_dst); ++ __ subl(count, 1, count); ++ __ subl(end_dst, 2, end_dst); ++ __ subl(end_src, 2, end_src); ++ __ beq_l(R0, l_align_dst); ++ ++ __ BIND(l_align_src); ++ copy_core_backward(16, end_src, end_dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_2_bytes); ++ __ ldhu(end_src, -2, tmp1); ++ __ sth(tmp1, -2, end_dst); ++ __ subl(end_src, 2, end_src); ++ __ subl(end_dst, 2, end_dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_2_bytes); ++ ++ __ BIND(l_end); ++ ++ }else{ ++ __ slll(count, 1, count); ++ __ addl(T3, count, end_src); ++ __ addl(T0, count, end_dst); ++ generate_conjoint_copy(1, end_src, end_dst, count); ++ } ++ ++ inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter ++ __ movl(V0, R0); // return 0 ++ __ leave(); ++ __ ret(); ++ return start; ++ } ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // is_oop - true => oop array, so generate store check code ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let ++ // the hardware handle it. The two dwords within qwords that span ++ // cache line boundaries will still be loaded and stored atomicly. ++ // ++ // Side Effects: ++ // disjoint_int_copy_entry is set to the no-overlap entry point ++ // used by generate_conjoint_int_oop_copy(). ++ // ++ address generate_disjoint_int_oop_copy(bool aligned, bool is_oop, address* entry, const char *name, bool dest_uninitialized = false) {SCOPEMARK_NAME(generate_disjoint_int_oop_copy, _masm) ++ Label l_tail_4_bytes, l_align_dst, l_align_src, l_align_simd, l_misalign, l_misalign_simd, l_tail, l_before_tail, l_end; ++ StubCodeMark mark(this, "StubRoutines", name); ++ ++ Register src = T3; ++ Register dst = T0; ++ Register count = T1; ++ Register dword_count = T4; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ assert_clean_int(c_rarg2, V0); // 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:"); ++ } ++ ++ __ movl(src, A0); ++ __ movl(dst, A1); ++ __ movl(count, A2); ++ ++ DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; ++ if (dest_uninitialized) { ++ decorators |= IS_DEST_UNINITIALIZED; ++ } ++ if (aligned) { ++ decorators |= ARRAYCOPY_ALIGNED; ++ } ++ ++ BasicType type = is_oop ? T_OBJECT : T_INT; ++ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->arraycopy_prologue(_masm, decorators, type, src, dst, count); ++ ++ __ movl(dword_count, count); ++ ++ if(UseSimdForward){ ++ __ cmple(count, 15, tmp1); ++ __ bne_l(tmp1, l_tail); ++ ++ __ BIND(l_align_dst); ++ __ and_ins(dst, 31, tmp1); ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldw(src, 0, tmp1); ++ __ subl(count, 1, count); ++ __ stw(tmp1, 0, dst); ++ __ addl(src, 4, src); ++ __ addl(dst, 4, dst); ++ __ beq_l(R0, l_align_dst); ++ ++ __ BIND(l_align_src); ++ copy_core_forward(8, src, dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_4_bytes); ++ __ ldw(src, 0, tmp2); ++ __ stw(tmp2, 0, dst); ++ __ addl(src, 4, src); ++ __ addl(dst, 4, dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_4_bytes); ++ ++ ++ __ BIND(l_end); ++ ++ } else { ++ __ slll(count, 2, count); ++ generate_disjoint_copy(2, src, dst, count); ++ } ++ ++ bs->arraycopy_epilogue(_masm, decorators, type, src, dst, dword_count); ++ inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter ++ __ movl(V0, R0); ++ __ leave(); ++ __ ret(); ++ return start; ++ } ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // is_oop - true => oop array, so generate store check code ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let ++ // the hardware handle it. The two dwords within qwords that span ++ // cache line boundaries will still be loaded and stored atomicly. ++ // ++ address generate_conjoint_int_oop_copy(bool aligned, bool is_oop, address nooverlap_target, ++ address* entry, const char *name, bool dest_uninitialized = false) { ++ Label l_2, l_4; ++ Label l_tail_4_bytes, l_align_dst, l_align_src, l_tail, l_end; ++ StubCodeMark mark(this, "StubRoutines", name); ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++ Register from = c_rarg0; ++ Register to = c_rarg1; ++ Register end_src = T3; ++ Register end_dst = T0; ++ Register count = T1; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ Register dword_count = T4; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ 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, Address::times_4); ++ ++ __ movl(count, A2); ++ __ movl(end_src, A0); ++ __ movl(end_dst, A1); ++ ++ DecoratorSet decorators = IN_HEAP | IS_ARRAY; ++ if (dest_uninitialized) { ++ decorators |= IS_DEST_UNINITIALIZED; ++ } ++ if (aligned) { ++ decorators |= ARRAYCOPY_ALIGNED; ++ } ++ ++ BasicType type = is_oop ? T_OBJECT : T_INT; ++ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ // no registers are destroyed by this call ++ bs->arraycopy_prologue(_masm, decorators, type, from, to, count); ++ ++ assert_clean_int(count, V0); // Make sure 'count' is clean int. ++ __ movl(dword_count, count); ++ ++ // T3: source array address ++ // T0: destination array address ++ // T1: element count ++ ++ if(UseSimdBackward){ ++ __ beq_l(count, l_end); ++ ++ __ sll(T1, Address::times_4, tmp1); ++ __ addl(T3, tmp1, end_src); ++ __ addl(T0, tmp1, end_dst); ++ ++ __ cmple(count, 15, tmp1); ++ __ bne_l(tmp1, l_tail_4_bytes); //when count <= 15, don't use simd ++ ++ __ BIND(l_align_dst); ++ __ and_ins(end_dst, 31, tmp1); //is dst 0mod32? ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldw(end_src, -4, tmp1); //grab 4 bytes at a time, until dst is 0mod32 ++ __ stw(tmp1, -4, end_dst); ++ __ subl(count, 1, count); ++ __ subl(end_dst, 4, end_dst); ++ __ subl(end_src, 4, end_src); ++ __ beq_l(R0, l_align_dst); // todo zl check? ++ ++ __ BIND(l_align_src); ++ copy_core_backward(8, end_src, end_dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_4_bytes); ++ __ ldw(end_src, -4, tmp1); ++ __ stw(tmp1, -4, end_dst); ++ __ subl(end_src, 4, end_src); ++ __ subl(end_dst, 4, end_dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_4_bytes); ++ ++ __ BIND(l_end); ++ ++ }else{ ++ __ slll(count, 2, count); ++ __ addl(end_src, count, end_src); ++ __ addl(end_dst, count, end_dst); ++ generate_conjoint_copy(2, end_src, end_dst, count); ++ } ++ ++ bs->arraycopy_epilogue(_masm, decorators, type, from, to, dword_count); ++ inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free ++ __ movl(V0, R0); // return 0 ++ ++ __ leave(); ++ __ ret(); ++ return start; ++ } ++ ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord boundary == 8 bytes ++ // ignored ++ // is_oop - true => oop array, so generate store check code ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // Side Effects: ++ // disjoint_oop_copy_entry or disjoint_long_copy_entry is set to the ++ // no-overlap entry point used by generate_conjoint_long_oop_copy(). ++ // ++ address generate_disjoint_long_oop_copy(bool aligned, bool is_oop, address* entry, const char *name, bool dest_uninitialized = false) {SCOPEMARK_NAME(generate_disjoint_long_oop_copy, _masm) ++ Label l_3, l_4; ++ Label l_tail_8_bytes, l_align_dst, l_align_src, l_tail, l_end; ++ ++ Register src = c_rarg0; ++ Register dst = c_rarg1; ++ Register count = c_rarg2; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ //Register saved_count = T11;//special, relate to arraycopy_prologue TODO:refactor, maybe put saved_count as parameter? jzy ++ ++ StubCodeMark mark(this, "StubRoutines", name); ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++//__ stop("generate_disjoint_long_oop_copy"); ++ //__ movl(src, A0); ++ //__ movl(dst, A1); ++ //__ movl(count, A2); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ // Save no-overlap entry point for generate_conjoint_long_oop_copy() ++ assert_clean_int(c_rarg2, rscratch3); // 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:"); ++ } ++ ++ DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; ++ if (dest_uninitialized) { ++ decorators |= IS_DEST_UNINITIALIZED; ++ } ++ if (aligned) { ++ decorators |= ARRAYCOPY_ALIGNED; ++ } ++ ++ BasicType type = is_oop ? T_OBJECT : T_LONG; ++ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->arraycopy_prologue(_masm, decorators, type, src, dst, count); ++ ++ // T3: source array address ++ // T0: destination array address ++ // T1: element count ++ //TODO:refact jzy saved_count(T11) should not changed before arraycopy_epilogue, because count is saved in arraycopy_prologue ++ if(UseSimdForward){ ++ __ align(16); ++ __ beq_l(count, l_end); ++ ++ __ cmple(count, 7, tmp1); ++ __ bne_l(tmp1, l_tail_8_bytes); //when count <= 7, don't use simd ++ ++ __ BIND(l_align_dst); ++ __ and_ins(dst, 31, tmp1); //is dst 0mod32? ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldl(src, 0, tmp1); //grab 8 bytes at a time, until dst is 0mod32 ++ __ stl(tmp1, 0, dst); ++ __ subl(count, 1, count); ++ __ addl(dst, 8, dst); ++ __ addl(src, 8, src); ++ __ beq_l(R0, l_align_dst); //todo zl check? ++ ++ __ BIND(l_align_src); ++ copy_core_forward(4, src, dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_8_bytes); ++ __ ldl(src, 0, tmp1); ++ __ stl(tmp1, 0, dst); ++ __ addl(src, 8, src); ++ __ addl(dst, 8, dst); ++ __ subl(count, 1, count); ++ __ bne_l(count, l_tail_8_bytes); ++ ++ __ BIND(l_end); ++ ++ }else{ ++ __ slll(count, 3, count); ++ generate_disjoint_copy(3, src, dst, count); ++ } ++ ++ bs->arraycopy_epilogue(_masm, decorators, type, src, dst, count); ++ if (is_oop) { ++ inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free ++ } else { ++ inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free ++ } ++ ++ __ movl(V0, R0); //return 0 ++ __ leave(); ++ __ ret(); ++ ++ return start; ++ } ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord boundary == 8 bytes ++ // ignored ++ // is_oop - true => oop array, so generate store check code ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let ++ // the hardware handle it. The two dwords within qwords that span ++ // cache line boundaries will still be loaded and stored atomicly. ++ // ++ address generate_conjoint_long_oop_copy(bool aligned, bool is_oop, ++ address nooverlap_target, address *entry, ++ const char *name, bool dest_uninitialized = false) {SCOPEMARK_NAME(generate_conjoint_long_oop_copy, _masm) ++ ++ Label l_1, l_2; ++ Label l_tail_8_bytes, l_align_dst, l_align_src, l_tail, l_end; ++ ++ StubCodeMark mark(this, "StubRoutines", name); ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++ Register end_src = c_rarg0; ++ Register end_dst = c_rarg1; ++ Register count = c_rarg2; ++ Register tmp1 = rscratch1; ++ Register tmp2 = rscratch2; ++ ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ assert_clean_int(c_rarg2, rscratch3); // 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, Address::times_8); ++ //__ movl(end_src, A0); ++ //__ movl(end_dst, A1); ++ //__ movl(count, A2); ++ ++ DecoratorSet decorators = IN_HEAP | IS_ARRAY; ++ if (dest_uninitialized) { ++ decorators |= IS_DEST_UNINITIALIZED; ++ } ++ if (aligned) { ++ decorators |= ARRAYCOPY_ALIGNED; ++ } ++ ++ BasicType type = is_oop ? T_OBJECT : T_LONG; ++ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->arraycopy_prologue(_masm, decorators, type, end_src, end_dst, count); ++ ++ if(UseSimdBackward){ ++ __ align(16); ++ __ beq_l(count, l_end); ++ ++ __ sll(T1, Address::times_8, tmp1); ++ __ addl(T3, tmp1, end_src); ++ __ addl(T0, tmp1, end_dst); ++ ++ __ cmple(count, 7, tmp1); ++ __ bne_l(tmp1, l_tail_8_bytes); //when count <= 7, don't use simd ++ ++ __ BIND(l_align_dst); ++ __ and_ins(end_dst, 31, tmp1); //is dst 0mod32? ++ __ beq_l(tmp1, l_align_src); ++ ++ __ ldl(end_src, -8, tmp1); //grab 8 bytes at a time, until dst is 0mod32 ++ __ stl(tmp1, -8, end_dst); ++ __ subl(count, 1, count); ++ __ subl(end_dst, 8, end_dst); ++ __ subl(end_src, 8, end_src); ++ __ ble_l(count, l_end); ++ __ beq_l(R0, l_align_dst); ++ ++ __ BIND(l_align_src); ++ copy_core_backward(4, end_src, end_dst, count, tmp1, tmp2); ++ ++ __ BIND(l_tail); ++ __ ble_l(count, l_end); ++ ++ __ BIND(l_tail_8_bytes); ++ __ ldl(end_src, -8, tmp1); ++ __ stl(tmp1, -8, end_dst); ++ __ subl(end_src, 8, end_src); ++ __ subl(end_dst, 8, end_dst); ++ __ subl(count, 1, count); ++ __ bne_l(count,l_tail_8_bytes); ++ ++ __ BIND(l_end); ++ ++ }else{ ++ __ slll(count, Address::times_8, count); ++ __ addl(end_src, count, end_src); ++ __ addl(end_dst, count, end_dst); ++ generate_conjoint_copy(3, end_src, end_dst, count); ++ } ++ ++ bs->arraycopy_epilogue(_masm, decorators, type, end_src, end_dst, count); ++ if (is_oop) { ++ inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free ++ } else { ++ inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free ++ } ++ ++ __ movl(V0, R0); //return 0 ++ __ leave(); ++ __ ret(); ++ return start; ++ } ++ ++ ++ // Helper for generating a dynamic type check. ++ // Smashes no registers. ++ void generate_type_check(Register sub_klass, ++ Register super_check_offset, ++ Register super_klass, ++ Label& L_success, Register temp_reg = noreg, Register temp2_reg = noreg) { ++ assert_different_registers(sub_klass, super_check_offset, super_klass); ++ ++ __ block_comment("type_check:"); ++ Label L_miss; ++ ++ __ check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_miss, NULL, ++ super_check_offset); ++ __ check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, temp2_reg, &L_success, NULL); ++ ++ // Fall through on failure! ++ __ bind(L_miss); ++ } ++ ++ // ++ // Generate checkcasting array copy stub ++ // ++ // Input: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // c_rarg3 - size_t ckoff (super_check_offset) ++ // not Win64 ++ // c_rarg4 - oop ckval (super_klass) ++ // Win64 ++ // rsp+40 - oop ckval (super_klass) ++ // ++ // Output: ++ // rax == 0 - success ++ // rax == -1^K - failure, where K is partial transfer count ++ // ++ address generate_checkcast_copy(const char *name, address *entry, ++ bool dest_uninitialized = false) {SCOPEMARK_NAME(generate_checkcast_copy, _masm) ++ ++ Label L_load_element, L_store_element, L_do_card_marks, L_done; ++ ++ // Input registers (after setup_arg_regs) ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register length = c_rarg2; // elements count ++ const Register ckoff = c_rarg3; // super_check_offset ++ const Register ckval = c_rarg4; // super_klass ++ ++ // Registers used as temps (r13, r14 are save-on-entry) ++ const Register end_from = from; // source array end address ++ const Register end_to = r13; // destination array end address ++ const Register count = c_rarg2; // -(count_remaining) ++ const Register r14_length = r14; // saved copy of length ++ // End pointers are inclusive, and if length is not zero they point ++ // to the last unit copied: end_to[0] := end_from[0] ++ ++// const Register rax = V0; ++// const Register r13 = end_to; ++// const Register r14 = r14_length; ++ //const Register rcx = ckoff; ++ const Register rax_oop = V0; // actual oop copied ++ const Register r11_klass = T4; // oop._klass ++ ++ //--------------------------------------------------------------- ++ // Assembler stub will be used for this call to arraycopy ++ // if the two arrays are subtypes of Object[] but the ++ // destination array type is not equal to or a supertype ++ // of the source type. Each element must be separately ++ // checked. ++ ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name); ++ address start = __ pc(); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef ASSERT ++ // caller guarantees that the arrays really are different ++ // otherwise, we would have to make conjoint checks ++ { Label L; ++ array_overlap_test(L, TIMES_OOP); ++ __ stop("checkcast_copy within a single array"); ++ __ bind(L); ++ } ++#endif //ASSERT ++ ++ setup_arg_regs(4); // from => rdi, to => rsi, length => rdx ++ // ckoff => rcx, ckval => r8 ++ // r9 and r10 may be used to save non-volatile registers ++ ++ // Caller of this entry point must set up the argument registers. ++ if (entry != NULL) { ++ *entry = __ pc(); ++ __ block_comment("Entry:"); ++ } ++ ++ // allocate spill slots for r13, r14 ++ enum { ++ saved_r13_offset, ++ saved_r14_offset, ++ saved_rbp_offset ++ }; ++ __ subptr(rsp, saved_rbp_offset * wordSize,rsp); ++ __ stl(r13, Address(rsp, saved_r13_offset * wordSize)); ++ __ stl(r14, Address(rsp, saved_r14_offset * wordSize)); ++ ++ // check that int operands are properly extended to size_t ++ assert_clean_int(length, rax); ++ assert_clean_int(ckoff, rax); ++ ++#ifdef ASSERT ++ __ block_comment("assert consistent ckoff/ckval"); ++ // The ckoff and ckval must be mutually consistent, ++ // even though caller generates both. ++ { Label L; ++ int sco_offset = in_bytes(Klass::super_check_offset_offset()); ++ __ cmpw(ckoff, Address(ckval, sco_offset)); ++ __ jcc(Assembler::equal, L); ++ __ stop("super_check_offset inconsistent"); ++ __ bind(L); ++ } ++#endif //ASSERT ++ ++ // Loop-invariant addresses. They are exclusive end pointers. ++ Address end_from_addr(from, length, TIMES_OOP, 0); ++ Address end_to_addr(to, length, TIMES_OOP, 0); ++ // Loop-variant addresses. They assume post-incremented count < 0. ++ Address from_element_addr(end_from, count, TIMES_OOP, 0); ++ Address to_element_addr(end_to, count, TIMES_OOP, 0); ++ ++ DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT; ++ if (dest_uninitialized) { ++ decorators |= IS_DEST_UNINITIALIZED; ++ } ++ ++ BasicType type = T_OBJECT; ++ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); ++ bs->arraycopy_prologue(_masm, decorators, type, from, to, count); ++ ++ // Copy from low to high addresses, indexed from the end of each array. ++ __ lea(end_from, end_from_addr); ++ __ lea(end_to, end_to_addr); ++ __ movl(r14_length, length); // save a copy of the length ++ assert(length == count, ""); // else fix next line: ++ __ subptr(R0, count, count); // negate and test the length ++ __ jcc(Assembler::notZero, L_load_element, count); ++ ++ // Empty array: Nothing to do. ++ __ movl(rax, R0); // return 0 on (trivial) success ++ __ jmp(L_done); ++ ++ // ======== begin loop ======== ++ // (Loop is rotated; its entry is L_load_element.) ++ // Loop control: ++ // for (count = -count; count != 0; count++) ++ // Base pointers src, dst are biased by 8*(count-1),to last element. ++ __ align(OptoLoopAlignment); ++ ++ __ BIND(L_store_element); ++ __ store_heap_oop(to_element_addr, rax_oop, noreg, noreg, AS_RAW); // store the oop ++ __ increment(count); // increment the count toward zero ++ __ jcc(Assembler::zero, L_do_card_marks, count); ++ ++ // ======== loop entry is here ======== ++ __ BIND(L_load_element); ++ __ load_heap_oop(rax_oop, from_element_addr, noreg, noreg, AS_RAW); // load the oop ++ __ testptr(rax_oop, rax_oop); ++ __ jcc(Assembler::zero, L_store_element); ++ ++ __ load_klass(r11_klass, rax_oop);// query the object klass ++ //will kill rscratch1 rscratch2 ++ generate_type_check(r11_klass, ckoff, ckval, L_store_element, rscratch1, rscratch2); ++ // ======== end loop ======== ++ ++ // It was a real error; we must depend on the caller to finish the job. ++ // Register rdx = -1 * number of *remaining* oops, r14 = *total* oops. ++ // Emit GC store barriers for the oops we have copied (r14 + rdx), ++ // and report their number to the caller. ++ assert_different_registers(rax, r14_length, count, to, end_to, rscratch1); ++ Label L_post_barrier; ++ __ addptr(r14_length, count, r14_length); // K = (original - remaining) oops ++ __ movl(rax, r14_length); // save the value ++ __ notptr(rax); // report (-1^K) to caller (does not affect flags) ++ __ jcc(Assembler::notZero, L_post_barrier); ++ __ jmp(L_done); // K == 0, nothing was copied, skip post barrier ++ ++ // Come here on success only. ++ __ BIND(L_do_card_marks); ++ __ movl(rax, R0); // return 0 on success ++ ++ __ BIND(L_post_barrier); ++ bs->arraycopy_epilogue(_masm, decorators, type, from, to, r14_length); ++ ++ // Common exit point (success or failure). ++ __ BIND(L_done); ++ __ ldptr(r13, Address(rsp, saved_r13_offset * wordSize)); ++ __ ldptr(r14, Address(rsp, saved_r14_offset * wordSize)); ++ restore_arg_regs(); ++ inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); // Update counter after rscratch1 is free ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret_sw(); ++ ++ 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. ++ // ++ // Input: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - 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) { ++ SCOPEMARK_NAME(generate_unsafe_copy, _masm) ++ ++ Label L_long_aligned, L_int_aligned, L_short_aligned; ++ ++ // Input registers (before setup_arg_regs) ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register size = c_rarg2; // byte count (size_t) ++ ++ // Register used as a temp ++ const Register bits = V0; // test copy of low bits ++ ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name); ++ address start = __ pc(); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ // bump this on entry, not on exit: ++ inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr); ++ ++ __ movl(bits, from); ++// __ xorptr(bits, to, bits); ++// __ xorptr(bits, size, bits); ++ __ orptr(bits, to, bits); ++ __ orptr(bits, size, bits); ++ ++ __ testb(bits, BytesPerLong-1); ++ __ jcc(Assembler::zero, L_long_aligned); ++ ++ __ testb(bits, BytesPerInt-1); ++ __ jcc(Assembler::zero, L_int_aligned); ++ ++ __ testb(bits, BytesPerShort-1); ++ __ jump_cc(Assembler::notZero, RuntimeAddress(byte_copy_entry)); ++ ++ __ BIND(L_short_aligned); ++ __ srll(size, LogBytesPerShort, size); // size => short_count ++ __ jump(RuntimeAddress(short_copy_entry)); ++ ++ __ BIND(L_int_aligned); ++ __ srll(size, LogBytesPerInt, size); // size => int_count ++ __ jump(RuntimeAddress(int_copy_entry)); ++ ++ __ BIND(L_long_aligned); ++ __ srll(size, LogBytesPerLong, size); // size => qword_count ++ __ jump(RuntimeAddress(long_copy_entry)); ++ ++ return start; ++ } ++ ++ // Perform range checks on the proposed arraycopy. ++ // Kills temp, but nothing else. ++ // Also, clean the sign bits of src_pos and dst_pos. ++ void arraycopy_range_checks(Register src, // source array oop (c_rarg0) ++ Register src_pos, // source position (c_rarg1) ++ Register dst, // destination array oo (c_rarg2) ++ Register dst_pos, // destination position (c_rarg3) ++ Register length, ++ Register temp, ++ Label& L_failed) { ++ __ block_comment("arraycopy_range_checks:"); ++ ++ // if (src_pos + length > arrayOop(src)->length()) FAIL; ++ __ movw(temp, length); ++ __ addw(temp, src_pos, temp); // src_pos + length ++ __ cmpw(temp, Address(src, arrayOopDesc::length_offset_in_bytes())); ++ __ jcc(Assembler::above, L_failed); ++ ++ // if (dst_pos + length > arrayOop(dst)->length()) FAIL; ++ __ movw(temp, length); ++ __ addw(temp, dst_pos, temp); // dst_pos + length ++ __ cmpw(temp, Address(dst, arrayOopDesc::length_offset_in_bytes())); ++ __ jcc(Assembler::above, 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. ++ __ movws(src_pos, src_pos); ++ __ movws(dst_pos, dst_pos); ++ ++ __ block_comment("arraycopy_range_checks done"); ++ } ++ ++ // ++ // Generate generic array copy stubs ++ // ++ // Input: ++ // c_rarg0 - src oop ++ // c_rarg1 - src_pos (32-bits) ++ // c_rarg2 - dst oop ++ // c_rarg3 - dst_pos (32-bits) ++ // not Win64 ++ // c_rarg4 - element count (32-bits) ++ // Win64 ++ // rsp+40 - element count (32-bits) ++ // ++ // Output: ++ // rax == 0 - success ++ // rax == -1^K - failure, where K is partial transfer count ++ // ++ address generate_generic_copy(const char *name, ++ address byte_copy_entry, address short_copy_entry, ++ address int_copy_entry, address oop_copy_entry, ++ address long_copy_entry, address checkcast_copy_entry) { ++ SCOPEMARK_NAME(generate_generic_copy, _masm) ++ ++ Label L_failed, L_failed_0, L_objArray; ++ Label L_copy_bytes, L_copy_shorts, L_copy_ints, L_copy_longs; ++ ++ // Input registers ++ const Register src = c_rarg0; // source array oop ++ const Register src_pos = c_rarg1; // source position ++ const Register dst = c_rarg2; // destination array oop ++ const Register dst_pos = c_rarg3; // destination position ++ const Register length = c_rarg4; ++ ++ StubCodeMark mark(this, "StubRoutines", name); ++ ++ // Short-hop target to L_failed. Makes for denser prologue code. ++ __ BIND(L_failed_0); ++ __ jmp(L_failed); ++ ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ // bump this on entry, not on exit: ++ inc_counter_np(SharedRuntime::_generic_array_copy_ctr); ++ ++ //----------------------------------------------------------------------- ++ // Assembler stub 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. ++ // ++ ++ // if (src == NULL) return -1; ++ __ testptr(src, src); // src oop ++ size_t j1off = __ offset(); ++ __ jcc(Assembler::zero, L_failed_0, src); ++ ++ // if (src_pos < 0) return -1; ++ __ addw(src_pos, R0, rcc); // src_pos (32-bits) ++ __ jcc(Assembler::negative, L_failed_0, rcc); ++ ++ // if (dst == NULL) return -1; ++ __ testptr(dst, dst); // dst oop ++ __ jcc(Assembler::zero, L_failed_0); ++ ++ // if (dst_pos < 0) return -1; ++ __ addw(dst_pos, R0, rcc); // dst_pos (32-bits) ++ size_t j4off = __ offset(); ++ __ jcc(Assembler::negative, L_failed_0, rcc); ++ ++ // The first four tests are very dense code, ++ // but not quite dense enough to put four ++ // jumps in a 16-byte instruction fetch buffer. ++ // That's good, because some branch predicters ++ // do not like jumps so close together. ++ // Make sure of this. ++ guarantee(((j1off ^ j4off) & ~15) != 0, "I$ line of 1st & 4th jumps"); //should sw need this? jzy ++ ++ // registers used as temp ++ const Register r11_length = T0; // elements count to copy ++ const Register r10_src_klass = T1; // array klass ++ const Register r10 = r10_src_klass; ++ const Register r11 = r11_length; ++ const Register rscratch = rscratch1; ++ ++ // if (length < 0) return -1; ++ __ movl(r11_length, length); // length (elements count, 32-bits value) ++ __ jcc(Assembler::negative, L_failed_0, r11_length); ++ ++ __ load_klass(r10_src_klass, src); ++#ifdef ASSERT ++ // assert(src->klass() != NULL); ++ { ++ BLOCK_COMMENT("assert klasses not null {"); ++ Label L1, L2; ++ __ testptr(r10_src_klass, r10_src_klass); ++ __ jcc(Assembler::notZero, L2); // it is broken if klass is NULL ++ __ bind(L1); ++ __ stop("broken null klass"); ++ __ bind(L2); ++ __ load_klass(rax, dst); ++ __ cmpl(rax, 0); ++ __ jcc(Assembler::equal, L1); // this would be broken also ++ BLOCK_COMMENT("} assert klasses not null done"); ++ } ++#endif ++ ++ // Load layout helper (32-bits) ++ // ++ // |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 ++ // ++ ++ const int lh_offset = in_bytes(Klass::layout_helper_offset()); ++ ++ // Handle objArrays completely differently... ++ const jint objArray_lh = Klass::array_layout_helper(T_OBJECT); ++// __ mov_immediate32(rscratch, objArray_lh); ++ __ cmpw(Address(r10_src_klass, lh_offset), objArray_lh); ++ __ jcc(Assembler::equal, L_objArray); ++ ++ // if (src->klass() != dst->klass()) return -1; ++ __ load_klass(rax, dst); ++// __ cmpl(r10_src_klass, rax); ++// __ jcc(Assembler::notEqual, L_failed); ++ __ cmpq(rax, r10_src_klass); ++ __ jcc(Assembler::notEqual, L_failed); ++// __ bne_c(rax, r10_src_klass, L_failed); //todo zl check? ++ const Register rax_lh = rax; // layout helper ++ __ ldws(rax_lh, Address(r10_src_klass, lh_offset)); ++ ++ // if (!src->is_Array()) return -1; ++ __ cmpw(rax_lh, Klass::_lh_neutral_value); ++ __ jcc(Assembler::greaterEqual, L_failed); ++ ++ // At this point, it is known to be a typeArray (array_tag 0x3). ++#ifdef ASSERT ++ { ++ BLOCK_COMMENT("assert primitive array {"); ++ Label L; ++// __ mov_immediate32(rscratch ,(Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift)); ++ __ cmpw(rax_lh, (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift)); ++ __ jcc(Assembler::greaterEqual, L); ++ __ stop("must be a primitive array"); ++ __ bind(L); ++ BLOCK_COMMENT("} assert primitive array done"); ++ } ++#endif ++ ++ arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, ++ r10, 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 r10_offset = r10; // array offset ++ const Register rax_elsize = rax_lh; // element size ++ ++ __ movw(r10_offset, rax_lh); ++ __ srll(r10_offset, Klass::_lh_header_size_shift, r10_offset); ++ __ andptr(r10_offset, Klass::_lh_header_size_mask, r10_offset); // array_offset ++ __ addptr(src, r10_offset, src); // src array offset ++ __ addptr(dst, r10_offset, dst); // dst array offset ++ BLOCK_COMMENT("choose copy loop based on element size"); ++ __ andw(rax_lh, Klass::_lh_log2_element_size_mask, rax_lh); // rax_lh -> rax_elsize ++ ++ // next registers should be set before the jump to corresponding stub ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register count = c_rarg2; // elements count ++ ++ // 'from', 'to', 'count' registers should be set in such order ++ // since they are the same as 'src', 'src_pos', 'dst'. ++ ++ __ BIND(L_copy_bytes); ++ __ cmpw(rax_elsize, 0); ++ __ jcc(Assembler::notEqual, L_copy_shorts); ++ __ lea(from, Address(src, src_pos, Address::times_1, 0));// src_addr ++ __ lea(to, Address(dst, dst_pos, Address::times_1, 0));// dst_addr ++ __ movws(count, r11_length); // length ++ __ jump(RuntimeAddress(byte_copy_entry)); ++ ++ __ BIND(L_copy_shorts); ++ __ cmpw(rax_elsize, LogBytesPerShort); ++ __ jcc(Assembler::notEqual, L_copy_ints); ++ __ lea(from, Address(src, src_pos, Address::times_2, 0));// src_addr ++ __ lea(to, Address(dst, dst_pos, Address::times_2, 0));// dst_addr ++ __ movws(count, r11_length); // length ++ __ jump(RuntimeAddress(short_copy_entry)); ++ ++ __ BIND(L_copy_ints); ++ __ cmpw(rax_elsize, LogBytesPerInt); ++ __ jcc(Assembler::notEqual, L_copy_longs); ++ __ lea(from, Address(src, src_pos, Address::times_4, 0));// src_addr ++ __ lea(to, Address(dst, dst_pos, Address::times_4, 0));// dst_addr ++ __ movws(count, r11_length); // length ++ __ jump(RuntimeAddress(int_copy_entry)); ++ ++ __ BIND(L_copy_longs); ++#ifdef ASSERT ++ { ++ BLOCK_COMMENT("assert long copy {"); ++ Label L; ++ __ cmpw(rax_elsize, LogBytesPerLong); ++ __ jcc(Assembler::equal, L); ++ __ stop("must be long copy, but elsize is wrong"); ++ __ bind(L); ++ BLOCK_COMMENT("} assert long copy done"); ++ } ++#endif ++ __ lea(from, Address(src, src_pos, Address::times_8, 0));// src_addr ++ __ lea(to, Address(dst, dst_pos, Address::times_8, 0));// dst_addr ++ __ movws(count, r11_length); // length ++ __ jump(RuntimeAddress(long_copy_entry)); ++ ++ // ObjArrayKlass ++ __ BIND(L_objArray); ++ // live at this point: r10_src_klass, r11_length, src[_pos], dst[_pos] ++ ++ Label L_plain_copy, L_checkcast_copy; ++ // test array classes for subtyping ++ __ load_klass(rax, dst); ++// __ cmpl(r10_src_klass, rax); // usual case is exact equality ++// __ jcc(Assembler::notEqual, L_checkcast_copy); ++// __ bne_c(r10_src_klass, rax, L_checkcast_copy); ++ __ cmpq(rax, r10_src_klass); ++ __ jcc(Assembler::notEqual, L_checkcast_copy); ++ ++ // Identically typed arrays can be copied without element-wise checks. ++ arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, ++ r10, L_failed); ++ ++ __ lea(from, Address(src, src_pos, TIMES_OOP, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT))); // src_addr ++ __ lea(to, Address(dst, dst_pos, TIMES_OOP, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT))); // dst_addr ++ __ movws(count, r11_length); // length ++ __ BIND(L_plain_copy); ++ __ jump(RuntimeAddress(oop_copy_entry)); ++ ++ __ BIND(L_checkcast_copy); ++ // live at this point: r10_src_klass, r11_length, rax (dst_klass) ++ { ++ // Before looking at dst.length, make sure dst is also an objArray. ++ __ mov_immediate32(rscratch, objArray_lh); ++ __ cmpw(Address(rax, lh_offset), rscratch); ++ __ jcc(Assembler::notEqual, L_failed); ++ ++ // It is safe to examine both src.length and dst.length. ++ arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, ++ rax, L_failed); ++ ++ const Register r11_dst_klass = r11; ++ __ load_klass(r11_dst_klass, dst); // reload ++ ++ // Marshal the base address arguments now, freeing registers. ++ __ lea(from, Address(src, src_pos, TIMES_OOP, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT))); ++ __ lea(to, Address(dst, dst_pos, TIMES_OOP, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT))); ++ __ movw(count, length); // length (reloaded) ++ Register sco_temp = c_rarg3; // this register is free now ++ assert_different_registers(from, to, count, sco_temp, ++ r11_dst_klass, r10_src_klass); ++ assert_clean_int(count, sco_temp); ++ ++ // Generate the type check. ++ const int sco_offset = in_bytes(Klass::super_check_offset_offset()); ++ __ ldws(sco_temp, Address(r11_dst_klass, sco_offset)); ++ assert_clean_int(sco_temp, rax); ++ //will kill rscratch1 rscratch2 ++ generate_type_check(r10_src_klass, sco_temp, r11_dst_klass, L_plain_copy, rscratch1, rscratch2); ++ ++ // Fetch destination element klass from the ObjArrayKlass header. ++ int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); ++ __ ldptr(r11_dst_klass, Address(r11_dst_klass, ek_offset)); ++ __ ldws( sco_temp, Address(r11_dst_klass, sco_offset)); ++ assert_clean_int(sco_temp, rax); ++ ++ // the checkcast_copy loop needs two extra arguments: ++ assert(c_rarg3 == sco_temp, "#3 already in place"); ++ // Set up arguments for checkcast_copy_entry. ++ setup_arg_regs(4); ++ __ movl(c_rarg4, r11_dst_klass); // dst.klass.element_klass, r8 is c_rarg4 on Linux/Solaris ++ __ jump(RuntimeAddress(checkcast_copy_entry)); ++ } ++ ++ __ BIND(L_failed); ++ __ ldi(rax, -1, R0);// return -1 ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret_sw(); ++ ++ 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; ++//TODO:jzy fast path to arraycopy ++ 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::_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::_jint_disjoint_arraycopy = generate_disjoint_int_oop_copy(false, false, &entry, ++ "jint_disjoint_arraycopy"); ++ StubRoutines::_jint_arraycopy = generate_conjoint_int_oop_copy(false, false, entry, ++ &entry_jint_arraycopy, "jint_arraycopy"); ++ ++ StubRoutines::_jlong_disjoint_arraycopy = generate_disjoint_long_oop_copy(false, false, &entry, ++ "jlong_disjoint_arraycopy"); ++ StubRoutines::_jlong_arraycopy = generate_conjoint_long_oop_copy(false, false, entry, ++ &entry_jlong_arraycopy, "jlong_arraycopy"); ++ ++ ++ if (UseCompressedOops) { ++ StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_int_oop_copy(false, true, &entry, ++ "oop_disjoint_arraycopy"); ++ StubRoutines::_oop_arraycopy = generate_conjoint_int_oop_copy(false, true, entry, ++ &entry_oop_arraycopy, "oop_arraycopy"); ++ StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_int_oop_copy(false, true, &entry, ++ "oop_disjoint_arraycopy_uninit", ++ /*dest_uninitialized*/true); ++ StubRoutines::_oop_arraycopy_uninit = generate_conjoint_int_oop_copy(false, true, entry, ++ NULL, "oop_arraycopy_uninit", ++ /*dest_uninitialized*/true); ++ } else { ++ StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_long_oop_copy(false, true, &entry, ++ "oop_disjoint_arraycopy"); ++ StubRoutines::_oop_arraycopy = generate_conjoint_long_oop_copy(false, true, entry, ++ &entry_oop_arraycopy, "oop_arraycopy"); ++ StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_long_oop_copy(false, true, &entry, ++ "oop_disjoint_arraycopy_uninit", ++ /*dest_uninitialized*/true); ++ StubRoutines::_oop_arraycopy_uninit = generate_conjoint_long_oop_copy(false, true, entry, ++ NULL, "oop_arraycopy_uninit", ++ /*dest_uninitialized*/true); ++ } ++ //TODO:jzy fast path to checkcast ++ 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); ++ //TODO:fast path jzy ++ 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"); ++ ++ // We don't generate specialized code for HeapWord-aligned source ++ // arrays, so just use the code we've already generated ++ StubRoutines::_arrayof_jbyte_disjoint_arraycopy = StubRoutines::_jbyte_disjoint_arraycopy; ++ StubRoutines::_arrayof_jbyte_arraycopy = StubRoutines::_jbyte_arraycopy; ++ ++ StubRoutines::_arrayof_jshort_disjoint_arraycopy = StubRoutines::_jshort_disjoint_arraycopy; ++ StubRoutines::_arrayof_jshort_arraycopy = StubRoutines::_jshort_arraycopy; ++ ++ StubRoutines::_arrayof_jint_disjoint_arraycopy = StubRoutines::_jint_disjoint_arraycopy; ++ StubRoutines::_arrayof_jint_arraycopy = StubRoutines::_jint_arraycopy; ++ ++ StubRoutines::_arrayof_jlong_disjoint_arraycopy = StubRoutines::_jlong_disjoint_arraycopy; ++ StubRoutines::_arrayof_jlong_arraycopy = StubRoutines::_jlong_arraycopy; ++ ++ StubRoutines::_arrayof_oop_disjoint_arraycopy = StubRoutines::_oop_disjoint_arraycopy; ++ StubRoutines::_arrayof_oop_arraycopy = StubRoutines::_oop_arraycopy; ++ ++ StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = StubRoutines::_oop_disjoint_arraycopy_uninit; ++ StubRoutines::_arrayof_oop_arraycopy_uninit = StubRoutines::_oop_arraycopy_uninit; ++ } ++ ++ // AES intrinsic stubs ++ enum {AESBlockSize = 16}; ++ ++ address generate_key_shuffle_mask() { ++ __ align(16); ++ StubCodeMark mark(this, "StubRoutines", "key_shuffle_mask"); ++ address start = __ pc();ShouldNotReachHere(); ++// __ emit_data64( 0x0405060700010203, relocInfo::none ); ++// __ emit_data64( 0x0c0d0e0f08090a0b, relocInfo::none ); ++ return start; ++ } ++ ++ address generate_counter_shuffle_mask() { ++ __ align(16); ++ StubCodeMark mark(this, "StubRoutines", "counter_shuffle_mask"); ++ address start = __ pc();ShouldNotReachHere(); ++// __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); ++// __ emit_data64(0x0001020304050607, relocInfo::none); ++ return start; ++ } ++ ++ // Utility routine for loading a 128-bit key word in little endian format ++ // can optionally specify that the shuffle mask is already in an xmmregister ++ /*void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) { ++ __ movdqu(xmmdst, Address(key, offset)); ++ if (xmm_shuf_mask != NULL) { ++ __ pshufb(xmmdst, xmm_shuf_mask); ++ } else { ++ __ pshufb(xmmdst, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ } ++ }*/ ++ ++ // Utility routine for increase 128bit counter (iv in CTR mode) ++ /*void inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block) { ++ __ pextrq(reg, xmmdst, 0x0); ++ __ addq(reg, inc_delta); ++ __ pinsrq(xmmdst, reg, 0x0); ++ __ jcc(Assembler::carryClear, next_block); // jump if no carry ++ __ pextrq(reg, xmmdst, 0x01); // Carry ++ __ addq(reg, 0x01); ++ __ pinsrq(xmmdst, reg, 0x01); //Carry end ++ __ BIND(next_block); // next instruction ++ }*/ ++ ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // ++ address generate_aescrypt_encryptBlock() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock"); ++ Label L_doLast; ++ address start = __ pc();ShouldNotReachHere(); ++/* ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register keylen = rax; ++ ++ const XMMRegister xmm_result = xmm0; ++ const XMMRegister xmm_key_shuf_mask = xmm1; ++ // On win64 xmm6-xmm15 must be preserved so don't use them. ++ const XMMRegister xmm_temp1 = xmm2; ++ const XMMRegister xmm_temp2 = xmm3; ++ const XMMRegister xmm_temp3 = xmm4; ++ const XMMRegister xmm_temp4 = xmm5; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ // keylen could be only {11, 13, 15} * 4 = {44, 52, 60} ++ __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ __ movdqu(xmm_result, Address(from, 0)); // get 16 bytes of input ++ ++ // For encryption, the java expanded key ordering is just what we need ++ // we don't know if the key is aligned, hence not using load-execute form ++ ++ load_key(xmm_temp1, key, 0x00, xmm_key_shuf_mask); ++ __ pxor(xmm_result, xmm_temp1); ++ ++ load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask); ++ load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask); ++ load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask); ++ ++ __ aesenc(xmm_result, xmm_temp1); ++ __ aesenc(xmm_result, xmm_temp2); ++ __ aesenc(xmm_result, xmm_temp3); ++ __ aesenc(xmm_result, xmm_temp4); ++ ++ load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask); ++ load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask); ++ load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask); ++ ++ __ aesenc(xmm_result, xmm_temp1); ++ __ aesenc(xmm_result, xmm_temp2); ++ __ aesenc(xmm_result, xmm_temp3); ++ __ aesenc(xmm_result, xmm_temp4); ++ ++ load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask); ++ ++ __ cmpl(keylen, 44); ++ __ jccb(Assembler::equal, L_doLast); ++ ++ __ aesenc(xmm_result, xmm_temp1); ++ __ aesenc(xmm_result, xmm_temp2); ++ ++ load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask); ++ ++ __ cmpl(keylen, 52); ++ __ jccb(Assembler::equal, L_doLast); ++ ++ __ aesenc(xmm_result, xmm_temp1); ++ __ aesenc(xmm_result, xmm_temp2); ++ ++ load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask); ++ ++ __ BIND(L_doLast); ++ __ aesenc(xmm_result, xmm_temp1); ++ __ aesenclast(xmm_result, xmm_temp2); ++ __ movdqu(Address(to, 0), xmm_result); // store the result ++ __ xorptr(rax, rax); // return 0 ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++ ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // ++ address generate_aescrypt_decryptBlock() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock"); ++ Label L_doLast; ++ address start = __ pc();ShouldNotReachHere(); ++/* ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register keylen = rax; ++ ++ const XMMRegister xmm_result = xmm0; ++ const XMMRegister xmm_key_shuf_mask = xmm1; ++ // On win64 xmm6-xmm15 must be preserved so don't use them. ++ const XMMRegister xmm_temp1 = xmm2; ++ const XMMRegister xmm_temp2 = xmm3; ++ const XMMRegister xmm_temp3 = xmm4; ++ const XMMRegister xmm_temp4 = xmm5; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ // keylen could be only {11, 13, 15} * 4 = {44, 52, 60} ++ __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ __ movdqu(xmm_result, Address(from, 0)); ++ ++ // for decryption java expanded key ordering is rotated one position from what we want ++ // so we start from 0x10 here and hit 0x00 last ++ // we don't know if the key is aligned, hence not using load-execute form ++ load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask); ++ load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask); ++ load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask); ++ ++ __ pxor (xmm_result, xmm_temp1); ++ __ aesdec(xmm_result, xmm_temp2); ++ __ aesdec(xmm_result, xmm_temp3); ++ __ aesdec(xmm_result, xmm_temp4); ++ ++ load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask); ++ load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask); ++ load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask); ++ ++ __ aesdec(xmm_result, xmm_temp1); ++ __ aesdec(xmm_result, xmm_temp2); ++ __ aesdec(xmm_result, xmm_temp3); ++ __ aesdec(xmm_result, xmm_temp4); ++ ++ load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask); ++ load_key(xmm_temp3, key, 0x00, xmm_key_shuf_mask); ++ ++ __ cmpl(keylen, 44); ++ __ jccb(Assembler::equal, L_doLast); ++ ++ __ aesdec(xmm_result, xmm_temp1); ++ __ aesdec(xmm_result, xmm_temp2); ++ ++ load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask); ++ ++ __ cmpl(keylen, 52); ++ __ jccb(Assembler::equal, L_doLast); ++ ++ __ aesdec(xmm_result, xmm_temp1); ++ __ aesdec(xmm_result, xmm_temp2); ++ ++ load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask); ++ load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask); ++ ++ __ BIND(L_doLast); ++ __ aesdec(xmm_result, xmm_temp1); ++ __ aesdec(xmm_result, xmm_temp2); ++ ++ // for decryption the aesdeclast operation is always on key+0x00 ++ __ aesdeclast(xmm_result, xmm_temp3); ++ __ movdqu(Address(to, 0), xmm_result); // store the result ++ __ xorptr(rax, rax); // return 0 ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++ ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // c_rarg3 - r vector byte array address ++ // c_rarg4 - input length ++ // ++ // Output: ++ // rax - input length ++ // ++ address generate_cipherBlockChaining_encryptAESCrypt() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt"); ++ address start = __ pc();ShouldNotReachHere(); ++/* ++ Label L_exit, L_key_192_256, L_key_256, L_loopTop_128, L_loopTop_192, L_loopTop_256; ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register rvec = c_rarg3; // r byte array initialized from initvector array address ++ // and left with the results of the last encryption block ++#ifndef _WIN64 ++ const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) ++#else ++ const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 ++ const Register len_reg = r11; // pick the volatile windows register ++#endif ++ const Register pos = rax; ++ ++ // xmm register assignments for the loops below ++ const XMMRegister xmm_result = xmm0; ++ const XMMRegister xmm_temp = xmm1; ++ // keys 0-10 preloaded into xmm2-xmm12 ++ const int XMM_REG_NUM_KEY_FIRST = 2; ++ const int XMM_REG_NUM_KEY_LAST = 15; ++ const XMMRegister xmm_key0 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST); ++ const XMMRegister xmm_key10 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+10); ++ const XMMRegister xmm_key11 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+11); ++ const XMMRegister xmm_key12 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+12); ++ const XMMRegister xmm_key13 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+13); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ // on win64, fill len_reg from stack position ++ __ movl(len_reg, len_mem); ++#else ++ __ push(len_reg); // Save ++#endif ++ ++ const XMMRegister xmm_key_shuf_mask = xmm_temp; // used temporarily to swap key bytes up front ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ // load up xmm regs xmm2 thru xmm12 with key 0x00 - 0xa0 ++ for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x00; rnum <= XMM_REG_NUM_KEY_FIRST+10; rnum++) { ++ load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask); ++ offset += 0x10; ++ } ++ __ movdqu(xmm_result, Address(rvec, 0x00)); // initialize xmm_result with r vec ++ ++ // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256)) ++ __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ __ cmpl(rax, 44); ++ __ jcc(Assembler::notEqual, L_key_192_256); ++ ++ // 128 bit code follows here ++ __ movptr(pos, 0); ++ __ align(OptoLoopAlignment); ++ ++ __ BIND(L_loopTop_128); ++ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input ++ __ pxor (xmm_result, xmm_temp); // xor with the current r vector ++ __ pxor (xmm_result, xmm_key0); // do the aes rounds ++ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 9; rnum++) { ++ __ aesenc(xmm_result, as_XMMRegister(rnum)); ++ } ++ __ aesenclast(xmm_result, xmm_key10); ++ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output ++ // no need to store r to memory until we exit ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::notEqual, L_loopTop_128); ++ ++ __ BIND(L_exit); ++ __ movdqu(Address(rvec, 0), xmm_result); // final value of r stored in rvec of CipherBlockChaining object ++ ++#ifdef _WIN64 ++ __ movl(rax, len_mem); ++#else ++ __ pop(rax); // return length ++#endif ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++ ++ __ BIND(L_key_192_256); ++ // here rax = len in ints of AESCrypt.KLE array (52=192, or 60=256) ++ load_key(xmm_key11, key, 0xb0, xmm_key_shuf_mask); ++ load_key(xmm_key12, key, 0xc0, xmm_key_shuf_mask); ++ __ cmpl(rax, 52); ++ __ jcc(Assembler::notEqual, L_key_256); ++ ++ // 192-bit code follows here (could be changed to use more xmm registers) ++ __ movptr(pos, 0); ++ __ align(OptoLoopAlignment); ++ ++ __ BIND(L_loopTop_192); ++ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input ++ __ pxor (xmm_result, xmm_temp); // xor with the current r vector ++ __ pxor (xmm_result, xmm_key0); // do the aes rounds ++ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 11; rnum++) { ++ __ aesenc(xmm_result, as_XMMRegister(rnum)); ++ } ++ __ aesenclast(xmm_result, xmm_key12); ++ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output ++ // no need to store r to memory until we exit ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::notEqual, L_loopTop_192); ++ __ jmp(L_exit); ++ ++ __ BIND(L_key_256); ++ // 256-bit code follows here (could be changed to use more xmm registers) ++ load_key(xmm_key13, key, 0xd0, xmm_key_shuf_mask); ++ __ movptr(pos, 0); ++ __ align(OptoLoopAlignment); ++ ++ __ BIND(L_loopTop_256); ++ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input ++ __ pxor (xmm_result, xmm_temp); // xor with the current r vector ++ __ pxor (xmm_result, xmm_key0); // do the aes rounds ++ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 13; rnum++) { ++ __ aesenc(xmm_result, as_XMMRegister(rnum)); ++ } ++ load_key(xmm_temp, key, 0xe0); ++ __ aesenclast(xmm_result, xmm_temp); ++ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output ++ // no need to store r to memory until we exit ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::notEqual, L_loopTop_256); ++ __ jmp(L_exit); ++*/ ++ 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: ++ // c_rarg0 = adr ++ // c_rarg1 = errValue ++ // ++ // result: ++ // PPC_RET = *adr or errValue ++ ++ StubCodeMark mark(this, "StubRoutines", name); ++ ++ // Entry point, pc or function descriptor. ++ *entry = __ pc(); ++ ++ // Load *adr into c_rarg1, may fault. ++ *fault_pc = __ pc(); ++ switch (size) { ++ case 4: ++ // int32_t ++ __ ldws(c_rarg1, Address(c_rarg0, 0)); //__ stop("here should extend? jzy");//here should extend? jzy ++ break; ++ case 8: ++ // int64_t ++ __ ldl(c_rarg1, Address(c_rarg0, 0)); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ // return errValue or *adr ++ *continuation_pc = __ pc(); ++ __ movl(V0, c_rarg1); ++ __ ret_sw(); ++ } ++ ++ // This is a version of CBC/AES Decrypt which does 4 blocks in a loop at a time ++ // to hide instruction latency ++ // ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // c_rarg3 - r vector byte array address ++ // c_rarg4 - input length ++ // ++ // Output: ++ // rax - input length ++ // ++ address generate_cipherBlockChaining_decryptAESCrypt_Parallel() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt"); ++ address start = __ pc();ShouldNotReachHere(); ++/* ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register rvec = c_rarg3; // r byte array initialized from initvector array address ++ // and left with the results of the last encryption block ++#ifndef _WIN64 ++ const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) ++#else ++ const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 ++ const Register len_reg = r11; // pick the volatile windows register ++#endif ++ const Register pos = rax; ++ ++ const int PARALLEL_FACTOR = 4; ++ const int ROUNDS[3] = { 10, 12, 14 }; // aes rounds for key128, key192, key256 ++ ++ Label L_exit; ++ Label L_singleBlock_loopTopHead[3]; // 128, 192, 256 ++ Label L_singleBlock_loopTopHead2[3]; // 128, 192, 256 ++ Label L_singleBlock_loopTop[3]; // 128, 192, 256 ++ Label L_multiBlock_loopTopHead[3]; // 128, 192, 256 ++ Label L_multiBlock_loopTop[3]; // 128, 192, 256 ++ ++ // keys 0-10 preloaded into xmm5-xmm15 ++ const int XMM_REG_NUM_KEY_FIRST = 5; ++ const int XMM_REG_NUM_KEY_LAST = 15; ++ const XMMRegister xmm_key_first = as_XMMRegister(XMM_REG_NUM_KEY_FIRST); ++ const XMMRegister xmm_key_last = as_XMMRegister(XMM_REG_NUM_KEY_LAST); ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ // on win64, fill len_reg from stack position ++ __ movl(len_reg, len_mem); ++#else ++ __ push(len_reg); // Save ++#endif ++ __ push(rbx); ++ // the java expanded key ordering is rotated one position from what we want ++ // so we start from 0x10 here and hit 0x00 last ++ const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ // load up xmm regs 5 thru 15 with key 0x10 - 0xa0 - 0x00 ++ for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x10; rnum < XMM_REG_NUM_KEY_LAST; rnum++) { ++ load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask); ++ offset += 0x10; ++ } ++ load_key(xmm_key_last, key, 0x00, xmm_key_shuf_mask); ++ ++ const XMMRegister xmm_prev_block_cipher = xmm1; // holds cipher of previous block ++ ++ // registers holding the four results in the parallelized loop ++ const XMMRegister xmm_result0 = xmm0; ++ const XMMRegister xmm_result1 = xmm2; ++ const XMMRegister xmm_result2 = xmm3; ++ const XMMRegister xmm_result3 = xmm4; ++ ++ __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // initialize with initial rvec ++ ++ __ xorptr(pos, pos); ++ ++ // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256)) ++ __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ __ cmpl(rbx, 52); ++ __ jcc(Assembler::equal, L_multiBlock_loopTopHead[1]); ++ __ cmpl(rbx, 60); ++ __ jcc(Assembler::equal, L_multiBlock_loopTopHead[2]); ++ ++#define DoFour(opc, src_reg) \ ++ __ opc(xmm_result0, src_reg); \ ++ __ opc(xmm_result1, src_reg); \ ++ __ opc(xmm_result2, src_reg); \ ++ __ opc(xmm_result3, src_reg); \ ++ ++ for (int k = 0; k < 3; ++k) { ++ __ BIND(L_multiBlock_loopTopHead[k]); ++ if (k != 0) { ++ __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least 4 blocks left ++ __ jcc(Assembler::less, L_singleBlock_loopTopHead2[k]); ++ } ++ if (k == 1) { ++ __ subptr(rsp, 6 * wordSize); ++ __ movdqu(Address(rsp, 0), xmm15); //save last_key from xmm15 ++ load_key(xmm15, key, 0xb0); // 0xb0; 192-bit key goes up to 0xc0 ++ __ movdqu(Address(rsp, 2 * wordSize), xmm15); ++ load_key(xmm1, key, 0xc0); // 0xc0; ++ __ movdqu(Address(rsp, 4 * wordSize), xmm1); ++ } else if (k == 2) { ++ __ subptr(rsp, 10 * wordSize); ++ __ movdqu(Address(rsp, 0), xmm15); //save last_key from xmm15 ++ load_key(xmm15, key, 0xd0); // 0xd0; 256-bit key goes upto 0xe0 ++ __ movdqu(Address(rsp, 6 * wordSize), xmm15); ++ load_key(xmm1, key, 0xe0); // 0xe0; ++ __ movdqu(Address(rsp, 8 * wordSize), xmm1); ++ load_key(xmm15, key, 0xb0); // 0xb0; ++ __ movdqu(Address(rsp, 2 * wordSize), xmm15); ++ load_key(xmm1, key, 0xc0); // 0xc0; ++ __ movdqu(Address(rsp, 4 * wordSize), xmm1); ++ } ++ __ align(OptoLoopAlignment); ++ __ BIND(L_multiBlock_loopTop[k]); ++ __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least 4 blocks left ++ __ jcc(Assembler::less, L_singleBlock_loopTopHead[k]); ++ ++ if (k != 0) { ++ __ movdqu(xmm15, Address(rsp, 2 * wordSize)); ++ __ movdqu(xmm1, Address(rsp, 4 * wordSize)); ++ } ++ ++ __ movdqu(xmm_result0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); // get next 4 blocks into xmmresult registers ++ __ movdqu(xmm_result1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); ++ __ movdqu(xmm_result2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); ++ __ movdqu(xmm_result3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); ++ ++ DoFour(pxor, xmm_key_first); ++ if (k == 0) { ++ for (int rnum = 1; rnum < ROUNDS[k]; rnum++) { ++ DoFour(aesdec, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); ++ } ++ DoFour(aesdeclast, xmm_key_last); ++ } else if (k == 1) { ++ for (int rnum = 1; rnum <= ROUNDS[k]-2; rnum++) { ++ DoFour(aesdec, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); ++ } ++ __ movdqu(xmm_key_last, Address(rsp, 0)); // xmm15 needs to be loaded again. ++ DoFour(aesdec, xmm1); // key : 0xc0 ++ __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // xmm1 needs to be loaded again ++ DoFour(aesdeclast, xmm_key_last); ++ } else if (k == 2) { ++ for (int rnum = 1; rnum <= ROUNDS[k] - 4; rnum++) { ++ DoFour(aesdec, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); ++ } ++ DoFour(aesdec, xmm1); // key : 0xc0 ++ __ movdqu(xmm15, Address(rsp, 6 * wordSize)); ++ __ movdqu(xmm1, Address(rsp, 8 * wordSize)); ++ DoFour(aesdec, xmm15); // key : 0xd0 ++ __ movdqu(xmm_key_last, Address(rsp, 0)); // xmm15 needs to be loaded again. ++ DoFour(aesdec, xmm1); // key : 0xe0 ++ __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // xmm1 needs to be loaded again ++ DoFour(aesdeclast, xmm_key_last); ++ } ++ ++ // for each result, xor with the r vector of previous cipher block ++ __ pxor(xmm_result0, xmm_prev_block_cipher); ++ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ pxor(xmm_result1, xmm_prev_block_cipher); ++ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 1 * AESBlockSize)); ++ __ pxor(xmm_result2, xmm_prev_block_cipher); ++ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 2 * AESBlockSize)); ++ __ pxor(xmm_result3, xmm_prev_block_cipher); ++ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 3 * AESBlockSize)); // this will carry over to next set of blocks ++ if (k != 0) { ++ __ movdqu(Address(rvec, 0x00), xmm_prev_block_cipher); ++ } ++ ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); // store 4 results into the next 64 bytes of output ++ __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); ++ __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); ++ __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); ++ ++ __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); ++ __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); ++ __ jmp(L_multiBlock_loopTop[k]); ++ ++ // registers used in the non-parallelized loops ++ // xmm register assignments for the loops below ++ const XMMRegister xmm_result = xmm0; ++ const XMMRegister xmm_prev_block_cipher_save = xmm2; ++ const XMMRegister xmm_key11 = xmm3; ++ const XMMRegister xmm_key12 = xmm4; ++ const XMMRegister key_tmp = xmm4; ++ ++ __ BIND(L_singleBlock_loopTopHead[k]); ++ if (k == 1) { ++ __ addptr(rsp, 6 * wordSize); ++ } else if (k == 2) { ++ __ addptr(rsp, 10 * wordSize); ++ } ++ __ cmpptr(len_reg, 0); // any blocks left?? ++ __ jcc(Assembler::equal, L_exit); ++ __ BIND(L_singleBlock_loopTopHead2[k]); ++ if (k == 1) { ++ load_key(xmm_key11, key, 0xb0); // 0xb0; 192-bit key goes upto 0xc0 ++ load_key(xmm_key12, key, 0xc0); // 0xc0; 192-bit key goes upto 0xc0 ++ } ++ if (k == 2) { ++ load_key(xmm_key11, key, 0xb0); // 0xb0; 256-bit key goes upto 0xe0 ++ } ++ __ align(OptoLoopAlignment); ++ __ BIND(L_singleBlock_loopTop[k]); ++ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input ++ __ movdqa(xmm_prev_block_cipher_save, xmm_result); // save for next r vector ++ __ pxor(xmm_result, xmm_key_first); // do the aes dec rounds ++ for (int rnum = 1; rnum <= 9 ; rnum++) { ++ __ aesdec(xmm_result, as_XMMRegister(rnum + XMM_REG_NUM_KEY_FIRST)); ++ } ++ if (k == 1) { ++ __ aesdec(xmm_result, xmm_key11); ++ __ aesdec(xmm_result, xmm_key12); ++ } ++ if (k == 2) { ++ __ aesdec(xmm_result, xmm_key11); ++ load_key(key_tmp, key, 0xc0); ++ __ aesdec(xmm_result, key_tmp); ++ load_key(key_tmp, key, 0xd0); ++ __ aesdec(xmm_result, key_tmp); ++ load_key(key_tmp, key, 0xe0); ++ __ aesdec(xmm_result, key_tmp); ++ } ++ ++ __ aesdeclast(xmm_result, xmm_key_last); // xmm15 always came from key+0 ++ __ pxor(xmm_result, xmm_prev_block_cipher); // xor with the current r vector ++ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output ++ // no need to store r to memory until we exit ++ __ movdqa(xmm_prev_block_cipher, xmm_prev_block_cipher_save); // set up next r vector with cipher input from this block ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::notEqual, L_singleBlock_loopTop[k]); ++ if (k != 2) { ++ __ jmp(L_exit); ++ } ++ } //for 128/192/256 ++ ++ __ BIND(L_exit); ++ __ movdqu(Address(rvec, 0), xmm_prev_block_cipher); // final value of r stored in rvec of CipherBlockChaining object ++ __ pop(rbx); ++#ifdef _WIN64 ++ __ movl(rax, len_mem); ++#else ++ __ pop(rax); // return length ++#endif ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++ return start; ++} ++ ++ address generate_upper_word_mask() { ++ __ align(64); ++ StubCodeMark mark(this, "StubRoutines", "upper_word_mask"); ++ address start = __ pc(); ++ __ emit_data64(0x0000000000000000, relocInfo::none); ++ __ emit_data64(0xFFFFFFFF00000000, relocInfo::none); ++ return start; ++ } ++ ++ address generate_shuffle_byte_flip_mask() { ++ __ align(64); ++ StubCodeMark mark(this, "StubRoutines", "shuffle_byte_flip_mask"); ++ address start = __ pc(); ++ __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); ++ __ emit_data64(0x0001020304050607, relocInfo::none); ++ return start; ++ } ++ ++ // ofs and limit are use for multi-block byte array. ++ // int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit) ++ address generate_sha1_implCompress(bool multi_block, const char *name) { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name); ++ address start = __ pc(); ++ ++ Register buf = c_rarg0; ++ Register state = c_rarg1; ++ Register ofs = c_rarg2; ++ Register limit = c_rarg3; ++ ++ const XMMRegister abcd = xmm0; ++ const XMMRegister e0 = xmm1; ++ const XMMRegister e1 = xmm2; ++ const XMMRegister msg0 = xmm3; ++ ++ const XMMRegister msg1 = xmm4; ++ const XMMRegister msg2 = xmm5; ++ const XMMRegister msg3 = xmm6; ++ const XMMRegister shuf_mask = xmm7; ++ ++ __ enter(); ++ ++ __ subptr(rsp, 4 * wordSize); ++ ++ __ fast_sha1(abcd, e0, e1, msg0, msg1, msg2, msg3, shuf_mask, ++ buf, state, ofs, limit, rsp, multi_block); ++ ++ __ addptr(rsp, 4 * wordSize); ++ ++ __ leave(); ++ __ ret(0);*/ ++ return start; ++ } ++ ++ address generate_pshuffle_byte_flip_mask() { ++ __ align(64); ++ StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x0405060700010203, relocInfo::none); ++ __ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none); ++ ++ if (VM_Version::supports_avx2()) { ++ __ emit_data64(0x0405060700010203, relocInfo::none); // second copy ++ __ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none); ++ // _SHUF_00BA ++ __ emit_data64(0x0b0a090803020100, relocInfo::none); ++ __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); ++ __ emit_data64(0x0b0a090803020100, relocInfo::none); ++ __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); ++ // _SHUF_DC00 ++ __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); ++ __ emit_data64(0x0b0a090803020100, relocInfo::none); ++ __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); ++ __ emit_data64(0x0b0a090803020100, relocInfo::none); ++ } ++*/ ++ return start; ++ } ++ ++ //Mask for byte-swapping a couple of qwords in an XMM register using (v)pshufb. ++ address generate_pshuffle_byte_flip_mask_sha512() { ++ __ align(32); ++ StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask_sha512");ShouldNotReachHere(); ++ address start = __ pc();/* ++ if (VM_Version::supports_avx2()) { ++ __ emit_data64(0x0001020304050607, relocInfo::none); // PSHUFFLE_BYTE_FLIP_MASK ++ __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); ++ __ emit_data64(0x1011121314151617, relocInfo::none); ++ __ emit_data64(0x18191a1b1c1d1e1f, relocInfo::none); ++ __ emit_data64(0x0000000000000000, relocInfo::none); //MASK_YMM_LO ++ __ emit_data64(0x0000000000000000, relocInfo::none); ++ __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); ++ __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); ++ } ++*/ ++ return start; ++ } ++ ++// ofs and limit are use for multi-block byte array. ++// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit) ++ address generate_sha256_implCompress(bool multi_block, const char *name) { ++ //assert(VM_Version::supports_sha() || VM_Version::supports_avx2(), ""); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name);ShouldNotReachHere(); ++ address start = __ pc();/* ++ ++ Register buf = c_rarg0; ++ Register state = c_rarg1; ++ Register ofs = c_rarg2; ++ Register limit = c_rarg3; ++ ++ const XMMRegister msg = xmm0; ++ const XMMRegister state0 = xmm1; ++ const XMMRegister state1 = xmm2; ++ const XMMRegister msgtmp0 = xmm3; ++ ++ const XMMRegister msgtmp1 = xmm4; ++ const XMMRegister msgtmp2 = xmm5; ++ const XMMRegister msgtmp3 = xmm6; ++ const XMMRegister msgtmp4 = xmm7; ++ ++ const XMMRegister shuf_mask = xmm8; ++ ++ __ enter(); ++ ++ __ subptr(rsp, 4 * wordSize); ++ ++ if (VM_Version::supports_sha()) { ++ __ fast_sha256(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4, ++ buf, state, ofs, limit, rsp, multi_block, shuf_mask); ++ } else if (VM_Version::supports_avx2()) { ++ __ sha256_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4, ++ buf, state, ofs, limit, rsp, multi_block, shuf_mask); ++ } ++ __ addptr(rsp, 4 * wordSize); ++ __ vzeroupper(); ++ __ leave(); ++ __ ret(0);*/ ++ return start; ++ } ++ ++ address generate_sha512_implCompress(bool multi_block, const char *name) { ++ //assert(VM_Version::supports_avx2(), ""); ++ //assert(VM_Version::supports_bmi2(), ""); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", name);ShouldNotReachHere(); ++ address start = __ pc();/* ++ ++ Register buf = c_rarg0; ++ Register state = c_rarg1; ++ Register ofs = c_rarg2; ++ Register limit = c_rarg3; ++ ++ const XMMRegister msg = xmm0; ++ const XMMRegister state0 = xmm1; ++ const XMMRegister state1 = xmm2; ++ const XMMRegister msgtmp0 = xmm3; ++ const XMMRegister msgtmp1 = xmm4; ++ const XMMRegister msgtmp2 = xmm5; ++ const XMMRegister msgtmp3 = xmm6; ++ const XMMRegister msgtmp4 = xmm7; ++ ++ const XMMRegister shuf_mask = xmm8; ++ ++ __ enter(); ++ ++ __ sha512_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4, ++ buf, state, ofs, limit, rsp, multi_block, shuf_mask); ++ ++ __ vzeroupper(); ++ __ leave(); ++ __ ret(0);*/ ++ return start; ++ } ++ ++ // This is a version of CTR/AES crypt which does 6 blocks in a loop at a time ++ // to hide instruction latency ++ // ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // c_rarg3 - counter vector byte array address ++ // Linux ++ // c_rarg4 - input length ++ // c_rarg5 - saved encryptedCounter start ++ // rbp + 6 * wordSize - saved used length ++ // Windows ++ // rbp + 6 * wordSize - input length ++ // rbp + 7 * wordSize - saved encryptedCounter start ++ // rbp + 8 * wordSize - saved used length ++ // ++ // Output: ++ // rax - input length ++ // ++ address generate_counterMode_AESCrypt_Parallel() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "counterMode_AESCrypt");ShouldNotReachHere(); ++ address start = __ pc();/* ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register counter = c_rarg3; // counter byte array initialized from counter array address ++ // and updated with the incremented counter in the end ++#ifndef _WIN64 ++ const Register len_reg = c_rarg4; ++ const Register saved_encCounter_start = c_rarg5; ++ const Register used_addr = r10; ++ const Address used_mem(rbp, 2 * wordSize); ++ const Register used = r11; ++#else ++ const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 ++ const Address saved_encCounter_mem(rbp, 7 * wordSize); // length is on stack on Win64 ++ const Address used_mem(rbp, 8 * wordSize); // length is on stack on Win64 ++ const Register len_reg = r10; // pick the first volatile windows register ++ const Register saved_encCounter_start = r11; ++ const Register used_addr = r13; ++ const Register used = r14; ++#endif ++ const Register pos = rax; ++ ++ const int PARALLEL_FACTOR = 6; ++ const XMMRegister xmm_counter_shuf_mask = xmm0; ++ const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front ++ const XMMRegister xmm_curr_counter = xmm2; ++ ++ const XMMRegister xmm_key_tmp0 = xmm3; ++ const XMMRegister xmm_key_tmp1 = xmm4; ++ ++ // registers holding the four results in the parallelized loop ++ const XMMRegister xmm_result0 = xmm5; ++ const XMMRegister xmm_result1 = xmm6; ++ const XMMRegister xmm_result2 = xmm7; ++ const XMMRegister xmm_result3 = xmm8; ++ const XMMRegister xmm_result4 = xmm9; ++ const XMMRegister xmm_result5 = xmm10; ++ ++ const XMMRegister xmm_from0 = xmm11; ++ const XMMRegister xmm_from1 = xmm12; ++ const XMMRegister xmm_from2 = xmm13; ++ const XMMRegister xmm_from3 = xmm14; //the last one is xmm14. we have to preserve it on WIN64. ++ const XMMRegister xmm_from4 = xmm3; //reuse xmm3~4. Because xmm_key_tmp0~1 are useless when loading input text ++ const XMMRegister xmm_from5 = xmm4; ++ ++ //for key_128, key_192, key_256 ++ const int rounds[3] = {10, 12, 14}; ++ Label L_exit_preLoop, L_preLoop_start; ++ Label L_multiBlock_loopTop[3]; ++ Label L_singleBlockLoopTop[3]; ++ Label L__incCounter[3][6]; //for 6 blocks ++ Label L__incCounter_single[3]; //for single block, key128, key192, key256 ++ Label L_processTail_insr[3], L_processTail_4_insr[3], L_processTail_2_insr[3], L_processTail_1_insr[3], L_processTail_exit_insr[3]; ++ Label L_processTail_extr[3], L_processTail_4_extr[3], L_processTail_2_extr[3], L_processTail_1_extr[3], L_processTail_exit_extr[3]; ++ ++ Label L_exit; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ // allocate spill slots for r13, r14 ++ enum { ++ saved_r13_offset, ++ saved_r14_offset ++ }; ++ __ subptr(rsp, 2 * wordSize); ++ __ movptr(Address(rsp, saved_r13_offset * wordSize), r13); ++ __ movptr(Address(rsp, saved_r14_offset * wordSize), r14); ++ ++ // on win64, fill len_reg from stack position ++ __ movl(len_reg, len_mem); ++ __ movptr(saved_encCounter_start, saved_encCounter_mem); ++ __ movptr(used_addr, used_mem); ++ __ movl(used, Address(used_addr, 0)); ++#else ++ __ push(len_reg); // Save ++ __ movptr(used_addr, used_mem); ++ __ movl(used, Address(used_addr, 0)); ++#endif ++ ++ __ push(rbx); // Save RBX ++ __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter ++ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch ++ __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled ++ __ movptr(pos, 0); ++ ++ // Use the partially used encrpyted counter from last invocation ++ __ BIND(L_preLoop_start); ++ __ cmpptr(used, 16); ++ __ jcc(Assembler::aboveEqual, L_exit_preLoop); ++ __ cmpptr(len_reg, 0); ++ __ jcc(Assembler::lessEqual, L_exit_preLoop); ++ __ movb(rbx, Address(saved_encCounter_start, used)); ++ __ xorb(rbx, Address(from, pos)); ++ __ movb(Address(to, pos), rbx); ++ __ addptr(pos, 1); ++ __ addptr(used, 1); ++ __ subptr(len_reg, 1); ++ ++ __ jmp(L_preLoop_start); ++ ++ __ BIND(L_exit_preLoop); ++ __ movl(Address(used_addr, 0), used); ++ ++ // key length could be only {11, 13, 15} * 4 = {44, 52, 60} ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch ++ __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ __ cmpl(rbx, 52); ++ __ jcc(Assembler::equal, L_multiBlock_loopTop[1]); ++ __ cmpl(rbx, 60); ++ __ jcc(Assembler::equal, L_multiBlock_loopTop[2]); ++ ++#define CTR_DoSix(opc, src_reg) \ ++ __ opc(xmm_result0, src_reg); \ ++ __ opc(xmm_result1, src_reg); \ ++ __ opc(xmm_result2, src_reg); \ ++ __ opc(xmm_result3, src_reg); \ ++ __ opc(xmm_result4, src_reg); \ ++ __ opc(xmm_result5, src_reg); ++ ++ // k == 0 : generate code for key_128 ++ // k == 1 : generate code for key_192 ++ // k == 2 : generate code for key_256 ++ for (int k = 0; k < 3; ++k) { ++ //multi blocks starts here ++ __ align(OptoLoopAlignment); ++ __ BIND(L_multiBlock_loopTop[k]); ++ __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least PARALLEL_FACTOR blocks left ++ __ jcc(Assembler::less, L_singleBlockLoopTop[k]); ++ load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); ++ ++ //load, then increase counters ++ CTR_DoSix(movdqa, xmm_curr_counter); ++ inc_counter(rbx, xmm_result1, 0x01, L__incCounter[k][0]); ++ inc_counter(rbx, xmm_result2, 0x02, L__incCounter[k][1]); ++ inc_counter(rbx, xmm_result3, 0x03, L__incCounter[k][2]); ++ inc_counter(rbx, xmm_result4, 0x04, L__incCounter[k][3]); ++ inc_counter(rbx, xmm_result5, 0x05, L__incCounter[k][4]); ++ inc_counter(rbx, xmm_curr_counter, 0x06, L__incCounter[k][5]); ++ CTR_DoSix(pshufb, xmm_counter_shuf_mask); // after increased, shuffled counters back for PXOR ++ CTR_DoSix(pxor, xmm_key_tmp0); //PXOR with Round 0 key ++ ++ //load two ROUND_KEYs at a time ++ for (int i = 1; i < rounds[k]; ) { ++ load_key(xmm_key_tmp1, key, (0x10 * i), xmm_key_shuf_mask); ++ load_key(xmm_key_tmp0, key, (0x10 * (i+1)), xmm_key_shuf_mask); ++ CTR_DoSix(aesenc, xmm_key_tmp1); ++ i++; ++ if (i != rounds[k]) { ++ CTR_DoSix(aesenc, xmm_key_tmp0); ++ } else { ++ CTR_DoSix(aesenclast, xmm_key_tmp0); ++ } ++ i++; ++ } ++ ++ // get next PARALLEL_FACTOR blocks into xmm_result registers ++ __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ movdqu(xmm_from1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); ++ __ movdqu(xmm_from2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); ++ __ movdqu(xmm_from3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); ++ __ movdqu(xmm_from4, Address(from, pos, Address::times_1, 4 * AESBlockSize)); ++ __ movdqu(xmm_from5, Address(from, pos, Address::times_1, 5 * AESBlockSize)); ++ ++ __ pxor(xmm_result0, xmm_from0); ++ __ pxor(xmm_result1, xmm_from1); ++ __ pxor(xmm_result2, xmm_from2); ++ __ pxor(xmm_result3, xmm_from3); ++ __ pxor(xmm_result4, xmm_from4); ++ __ pxor(xmm_result5, xmm_from5); ++ ++ // store 6 results into the next 64 bytes of output ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); ++ __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); ++ __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); ++ __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); ++ __ movdqu(Address(to, pos, Address::times_1, 4 * AESBlockSize), xmm_result4); ++ __ movdqu(Address(to, pos, Address::times_1, 5 * AESBlockSize), xmm_result5); ++ ++ __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); // increase the length of crypt text ++ __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // decrease the remaining length ++ __ jmp(L_multiBlock_loopTop[k]); ++ ++ // singleBlock starts here ++ __ align(OptoLoopAlignment); ++ __ BIND(L_singleBlockLoopTop[k]); ++ __ cmpptr(len_reg, 0); ++ __ jcc(Assembler::lessEqual, L_exit); ++ load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); ++ __ movdqa(xmm_result0, xmm_curr_counter); ++ inc_counter(rbx, xmm_curr_counter, 0x01, L__incCounter_single[k]); ++ __ pshufb(xmm_result0, xmm_counter_shuf_mask); ++ __ pxor(xmm_result0, xmm_key_tmp0); ++ for (int i = 1; i < rounds[k]; i++) { ++ load_key(xmm_key_tmp0, key, (0x10 * i), xmm_key_shuf_mask); ++ __ aesenc(xmm_result0, xmm_key_tmp0); ++ } ++ load_key(xmm_key_tmp0, key, (rounds[k] * 0x10), xmm_key_shuf_mask); ++ __ aesenclast(xmm_result0, xmm_key_tmp0); ++ __ cmpptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::less, L_processTail_insr[k]); ++ __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ pxor(xmm_result0, xmm_from0); ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jmp(L_singleBlockLoopTop[k]); ++ __ BIND(L_processTail_insr[k]); // Process the tail part of the input array ++ __ addptr(pos, len_reg); // 1. Insert bytes from src array into xmm_from0 register ++ __ testptr(len_reg, 8); ++ __ jcc(Assembler::zero, L_processTail_4_insr[k]); ++ __ subptr(pos,8); ++ __ pinsrq(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_4_insr[k]); ++ __ testptr(len_reg, 4); ++ __ jcc(Assembler::zero, L_processTail_2_insr[k]); ++ __ subptr(pos,4); ++ __ pslldq(xmm_from0, 4); ++ __ pinsrd(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_2_insr[k]); ++ __ testptr(len_reg, 2); ++ __ jcc(Assembler::zero, L_processTail_1_insr[k]); ++ __ subptr(pos, 2); ++ __ pslldq(xmm_from0, 2); ++ __ pinsrw(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_1_insr[k]); ++ __ testptr(len_reg, 1); ++ __ jcc(Assembler::zero, L_processTail_exit_insr[k]); ++ __ subptr(pos, 1); ++ __ pslldq(xmm_from0, 1); ++ __ pinsrb(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_exit_insr[k]); ++ ++ __ movdqu(Address(saved_encCounter_start, 0), xmm_result0); // 2. Perform pxor of the encrypted counter and plaintext Bytes. ++ __ pxor(xmm_result0, xmm_from0); // Also the encrypted counter is saved for next invocation. ++ ++ __ testptr(len_reg, 8); ++ __ jcc(Assembler::zero, L_processTail_4_extr[k]); // 3. Extract bytes from xmm_result0 into the dest. array ++ __ pextrq(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 8); ++ __ addptr(pos, 8); ++ __ BIND(L_processTail_4_extr[k]); ++ __ testptr(len_reg, 4); ++ __ jcc(Assembler::zero, L_processTail_2_extr[k]); ++ __ pextrd(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 4); ++ __ addptr(pos, 4); ++ __ BIND(L_processTail_2_extr[k]); ++ __ testptr(len_reg, 2); ++ __ jcc(Assembler::zero, L_processTail_1_extr[k]); ++ __ pextrw(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 2); ++ __ addptr(pos, 2); ++ __ BIND(L_processTail_1_extr[k]); ++ __ testptr(len_reg, 1); ++ __ jcc(Assembler::zero, L_processTail_exit_extr[k]); ++ __ pextrb(Address(to, pos), xmm_result0, 0); ++ ++ __ BIND(L_processTail_exit_extr[k]); ++ __ movl(Address(used_addr, 0), len_reg); ++ __ jmp(L_exit); ++ ++ } ++ ++ __ BIND(L_exit); ++ __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back. ++ __ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back ++ __ pop(rbx); // pop the saved RBX. ++#ifdef _WIN64 ++ __ movl(rax, len_mem); ++ __ movptr(r13, Address(rsp, saved_r13_offset * wordSize)); ++ __ movptr(r14, Address(rsp, saved_r14_offset * wordSize)); ++ __ addptr(rsp, 2 * wordSize); ++#else ++ __ pop(rax); // return 'len' ++#endif ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0);*/ ++ return start; ++ } ++ ++/*void roundDec(XMMRegister xmm_reg) { ++ __ vaesdec(xmm1, xmm1, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm2, xmm2, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm3, xmm3, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm4, xmm4, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm5, xmm5, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm6, xmm6, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm7, xmm7, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdec(xmm8, xmm8, xmm_reg, Assembler::AVX_512bit); ++}*/ ++ ++/*void roundDeclast(XMMRegister xmm_reg) { ++ __ vaesdeclast(xmm1, xmm1, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm2, xmm2, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm3, xmm3, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm4, xmm4, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm5, xmm5, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm6, xmm6, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm7, xmm7, xmm_reg, Assembler::AVX_512bit); ++ __ vaesdeclast(xmm8, xmm8, xmm_reg, Assembler::AVX_512bit); ++}*/ ++ ++/*void ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask = NULL) { ++ __ movdqu(xmmdst, Address(key, offset)); ++ if (xmm_shuf_mask != NULL) { ++ __ pshufb(xmmdst, xmm_shuf_mask); ++ } else { ++ __ pshufb(xmmdst, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ } ++ __ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit); ++ ++ }*/ ++ ++address generate_cipherBlockChaining_decryptVectorAESCrypt() { ++ //assert(VM_Version::supports_vaes(), "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");ShouldNotReachHere(); ++ address start = __ pc();/* ++ ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register rvec = c_rarg3; // r byte array initialized from initvector array address ++ // and left with the results of the last encryption block ++#ifndef _WIN64 ++ const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) ++#else ++ const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 ++ const Register len_reg = r11; // pick the volatile windows register ++#endif ++ ++ Label Loop, Loop1, L_128, L_256, L_192, KEY_192, KEY_256, Loop2, Lcbc_dec_rem_loop, ++ Lcbc_dec_rem_last, Lcbc_dec_ret, Lcbc_dec_rem, Lcbc_exit; ++ ++ __ enter(); ++ ++#ifdef _WIN64 ++ // on win64, fill len_reg from stack position ++ __ movl(len_reg, len_mem); ++#else ++ __ push(len_reg); // Save ++#endif ++ __ push(rbx); ++ __ vzeroupper(); ++ ++ // Temporary variable declaration for swapping key bytes ++ const XMMRegister xmm_key_shuf_mask = xmm1; ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ ++ // Calculate number of rounds from key size: 44 for 10-rounds, 52 for 12-rounds, 60 for 14-rounds ++ const Register rounds = rbx; ++ __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ ++ const XMMRegister IV = xmm0; ++ // Load IV and broadcast value to 512-bits ++ __ evbroadcasti64x2(IV, Address(rvec, 0), Assembler::AVX_512bit); ++ ++ // Temporary variables for storing round keys ++ const XMMRegister RK0 = xmm30; ++ const XMMRegister RK1 = xmm9; ++ const XMMRegister RK2 = xmm18; ++ const XMMRegister RK3 = xmm19; ++ const XMMRegister RK4 = xmm20; ++ const XMMRegister RK5 = xmm21; ++ const XMMRegister RK6 = xmm22; ++ const XMMRegister RK7 = xmm23; ++ const XMMRegister RK8 = xmm24; ++ const XMMRegister RK9 = xmm25; ++ const XMMRegister RK10 = xmm26; ++ ++ // Load and shuffle key ++ // the java expanded key ordering is rotated one position from what we want ++ // so we start from 1*16 here and hit 0*16 last ++ ev_load_key(RK1, key, 1 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK2, key, 2 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK3, key, 3 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK4, key, 4 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK5, key, 5 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK6, key, 6 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK7, key, 7 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK8, key, 8 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK9, key, 9 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK10, key, 10 * 16, xmm_key_shuf_mask); ++ ev_load_key(RK0, key, 0*16, xmm_key_shuf_mask); ++ ++ // Variables for storing source cipher text ++ const XMMRegister S0 = xmm10; ++ const XMMRegister S1 = xmm11; ++ const XMMRegister S2 = xmm12; ++ const XMMRegister S3 = xmm13; ++ const XMMRegister S4 = xmm14; ++ const XMMRegister S5 = xmm15; ++ const XMMRegister S6 = xmm16; ++ const XMMRegister S7 = xmm17; ++ ++ // Variables for storing decrypted text ++ const XMMRegister B0 = xmm1; ++ const XMMRegister B1 = xmm2; ++ const XMMRegister B2 = xmm3; ++ const XMMRegister B3 = xmm4; ++ const XMMRegister B4 = xmm5; ++ const XMMRegister B5 = xmm6; ++ const XMMRegister B6 = xmm7; ++ const XMMRegister B7 = xmm8; ++ ++ __ cmpl(rounds, 44); ++ __ jcc(Assembler::greater, KEY_192); ++ __ jmp(Loop); ++ ++ __ BIND(KEY_192); ++ const XMMRegister RK11 = xmm27; ++ const XMMRegister RK12 = xmm28; ++ ev_load_key(RK11, key, 11*16, xmm_key_shuf_mask); ++ ev_load_key(RK12, key, 12*16, xmm_key_shuf_mask); ++ ++ __ cmpl(rounds, 52); ++ __ jcc(Assembler::greater, KEY_256); ++ __ jmp(Loop); ++ ++ __ BIND(KEY_256); ++ const XMMRegister RK13 = xmm29; ++ const XMMRegister RK14 = xmm31; ++ ev_load_key(RK13, key, 13*16, xmm_key_shuf_mask); ++ ev_load_key(RK14, key, 14*16, xmm_key_shuf_mask); ++ ++ __ BIND(Loop); ++ __ cmpl(len_reg, 512); ++ __ jcc(Assembler::below, Lcbc_dec_rem); ++ __ BIND(Loop1); ++ __ subl(len_reg, 512); ++ __ evmovdquq(S0, Address(from, 0 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S1, Address(from, 1 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S2, Address(from, 2 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S3, Address(from, 3 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S4, Address(from, 4 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S5, Address(from, 5 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S6, Address(from, 6 * 64), Assembler::AVX_512bit); ++ __ evmovdquq(S7, Address(from, 7 * 64), Assembler::AVX_512bit); ++ __ leaq(from, Address(from, 8 * 64)); ++ ++ __ evpxorq(B0, S0, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B1, S1, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B2, S2, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B3, S3, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B4, S4, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B5, S5, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B6, S6, RK1, Assembler::AVX_512bit); ++ __ evpxorq(B7, S7, RK1, Assembler::AVX_512bit); ++ ++ __ evalignq(IV, S0, IV, 0x06); ++ __ evalignq(S0, S1, S0, 0x06); ++ __ evalignq(S1, S2, S1, 0x06); ++ __ evalignq(S2, S3, S2, 0x06); ++ __ evalignq(S3, S4, S3, 0x06); ++ __ evalignq(S4, S5, S4, 0x06); ++ __ evalignq(S5, S6, S5, 0x06); ++ __ evalignq(S6, S7, S6, 0x06); ++ ++ roundDec(RK2); ++ roundDec(RK3); ++ roundDec(RK4); ++ roundDec(RK5); ++ roundDec(RK6); ++ roundDec(RK7); ++ roundDec(RK8); ++ roundDec(RK9); ++ roundDec(RK10); ++ ++ __ cmpl(rounds, 44); ++ __ jcc(Assembler::belowEqual, L_128); ++ roundDec(RK11); ++ roundDec(RK12); ++ ++ __ cmpl(rounds, 52); ++ __ jcc(Assembler::belowEqual, L_192); ++ roundDec(RK13); ++ roundDec(RK14); ++ ++ __ BIND(L_256); ++ roundDeclast(RK0); ++ __ jmp(Loop2); ++ ++ __ BIND(L_128); ++ roundDeclast(RK0); ++ __ jmp(Loop2); ++ ++ __ BIND(L_192); ++ roundDeclast(RK0); ++ ++ __ BIND(Loop2); ++ __ evpxorq(B0, B0, IV, Assembler::AVX_512bit); ++ __ evpxorq(B1, B1, S0, Assembler::AVX_512bit); ++ __ evpxorq(B2, B2, S1, Assembler::AVX_512bit); ++ __ evpxorq(B3, B3, S2, Assembler::AVX_512bit); ++ __ evpxorq(B4, B4, S3, Assembler::AVX_512bit); ++ __ evpxorq(B5, B5, S4, Assembler::AVX_512bit); ++ __ evpxorq(B6, B6, S5, Assembler::AVX_512bit); ++ __ evpxorq(B7, B7, S6, Assembler::AVX_512bit); ++ __ evmovdquq(IV, S7, Assembler::AVX_512bit); ++ ++ __ evmovdquq(Address(to, 0 * 64), B0, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 1 * 64), B1, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 2 * 64), B2, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 3 * 64), B3, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 4 * 64), B4, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 5 * 64), B5, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 6 * 64), B6, Assembler::AVX_512bit); ++ __ evmovdquq(Address(to, 7 * 64), B7, Assembler::AVX_512bit); ++ __ leaq(to, Address(to, 8 * 64)); ++ __ jmp(Loop); ++ ++ __ BIND(Lcbc_dec_rem); ++ __ evshufi64x2(IV, IV, IV, 0x03, Assembler::AVX_512bit); ++ ++ __ BIND(Lcbc_dec_rem_loop); ++ __ subl(len_reg, 16); ++ __ jcc(Assembler::carrySet, Lcbc_dec_ret); ++ ++ __ movdqu(S0, Address(from, 0)); ++ __ evpxorq(B0, S0, RK1, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK2, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK3, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK4, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK5, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK6, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK7, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK8, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK9, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK10, Assembler::AVX_512bit); ++ __ cmpl(rounds, 44); ++ __ jcc(Assembler::belowEqual, Lcbc_dec_rem_last); ++ ++ __ vaesdec(B0, B0, RK11, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK12, Assembler::AVX_512bit); ++ __ cmpl(rounds, 52); ++ __ jcc(Assembler::belowEqual, Lcbc_dec_rem_last); ++ ++ __ vaesdec(B0, B0, RK13, Assembler::AVX_512bit); ++ __ vaesdec(B0, B0, RK14, Assembler::AVX_512bit); ++ ++ __ BIND(Lcbc_dec_rem_last); ++ __ vaesdeclast(B0, B0, RK0, Assembler::AVX_512bit); ++ ++ __ evpxorq(B0, B0, IV, Assembler::AVX_512bit); ++ __ evmovdquq(IV, S0, Assembler::AVX_512bit); ++ __ movdqu(Address(to, 0), B0); ++ __ leaq(from, Address(from, 16)); ++ __ leaq(to, Address(to, 16)); ++ __ jmp(Lcbc_dec_rem_loop); ++ ++ __ BIND(Lcbc_dec_ret); ++ __ movdqu(Address(rvec, 0), IV); ++ ++ // Zero out the round keys ++ __ evpxorq(RK0, RK0, RK0, Assembler::AVX_512bit); ++ __ evpxorq(RK1, RK1, RK1, Assembler::AVX_512bit); ++ __ evpxorq(RK2, RK2, RK2, Assembler::AVX_512bit); ++ __ evpxorq(RK3, RK3, RK3, Assembler::AVX_512bit); ++ __ evpxorq(RK4, RK4, RK4, Assembler::AVX_512bit); ++ __ evpxorq(RK5, RK5, RK5, Assembler::AVX_512bit); ++ __ evpxorq(RK6, RK6, RK6, Assembler::AVX_512bit); ++ __ evpxorq(RK7, RK7, RK7, Assembler::AVX_512bit); ++ __ evpxorq(RK8, RK8, RK8, Assembler::AVX_512bit); ++ __ evpxorq(RK9, RK9, RK9, Assembler::AVX_512bit); ++ __ evpxorq(RK10, RK10, RK10, Assembler::AVX_512bit); ++ __ cmpl(rounds, 44); ++ __ jcc(Assembler::belowEqual, Lcbc_exit); ++ __ evpxorq(RK11, RK11, RK11, Assembler::AVX_512bit); ++ __ evpxorq(RK12, RK12, RK12, Assembler::AVX_512bit); ++ __ cmpl(rounds, 52); ++ __ jcc(Assembler::belowEqual, Lcbc_exit); ++ __ evpxorq(RK13, RK13, RK13, Assembler::AVX_512bit); ++ __ evpxorq(RK14, RK14, RK14, Assembler::AVX_512bit); ++ ++ __ BIND(Lcbc_exit); ++ __ pop(rbx); ++#ifdef _WIN64 ++ __ movl(rax, len_mem); ++#else ++ __ pop(rax); // return length ++#endif ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0);*/ ++ return start; ++} ++ ++ // byte swap x86 long ++ address generate_ghash_long_swap_mask() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "ghash_long_swap_mask"); ++ address start = __ pc();ShouldNotReachHere(); ++// __ emit_data64(0x0f0e0d0c0b0a0908, relocInfo::none ); ++// __ emit_data64(0x0706050403020100, relocInfo::none ); ++ return start; ++ } ++ ++ // byte swap x86 byte array ++ address generate_ghash_byte_swap_mask() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "ghash_byte_swap_mask"); ++ address start = __ pc();ShouldNotReachHere(); ++// __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none ); ++// __ emit_data64(0x0001020304050607, relocInfo::none ); ++ return start; ++ } ++ ++ /* Single and multi-block ghash operations */ ++ address generate_ghash_processBlocks() { ++ __ align(CodeEntryAlignment); ++ Label L_ghash_loop, L_exit; ++ StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks");ShouldNotReachHere(); ++ address start = __ pc();/* ++ ++ const Register state = c_rarg0; ++ const Register subkeyH = c_rarg1; ++ const Register data = c_rarg2; ++ const Register blocks = c_rarg3; ++ ++ const XMMRegister xmm_temp0 = xmm0; ++ const XMMRegister xmm_temp1 = xmm1; ++ const XMMRegister xmm_temp2 = xmm2; ++ const XMMRegister xmm_temp3 = xmm3; ++ const XMMRegister xmm_temp4 = xmm4; ++ const XMMRegister xmm_temp5 = xmm5; ++ const XMMRegister xmm_temp6 = xmm6; ++ const XMMRegister xmm_temp7 = xmm7; ++ const XMMRegister xmm_temp8 = xmm8; ++ const XMMRegister xmm_temp9 = xmm9; ++ const XMMRegister xmm_temp10 = xmm10; ++ ++ __ enter(); ++ ++ __ movdqu(xmm_temp10, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); ++ ++ __ movdqu(xmm_temp0, Address(state, 0)); ++ __ pshufb(xmm_temp0, xmm_temp10); ++ ++ ++ __ BIND(L_ghash_loop); ++ __ movdqu(xmm_temp2, Address(data, 0)); ++ __ pshufb(xmm_temp2, ExternalAddress(StubRoutines::x86::ghash_byte_swap_mask_addr())); ++ ++ __ movdqu(xmm_temp1, Address(subkeyH, 0)); ++ __ pshufb(xmm_temp1, xmm_temp10); ++ ++ __ pxor(xmm_temp0, xmm_temp2); ++ ++ // ++ // Multiply with the hash key ++ // ++ __ movdqu(xmm_temp3, xmm_temp0); ++ __ pclmulqdq(xmm_temp3, xmm_temp1, 0); // xmm3 holds a0*b0 ++ __ movdqu(xmm_temp4, xmm_temp0); ++ __ pclmulqdq(xmm_temp4, xmm_temp1, 16); // xmm4 holds a0*b1 ++ ++ __ movdqu(xmm_temp5, xmm_temp0); ++ __ pclmulqdq(xmm_temp5, xmm_temp1, 1); // xmm5 holds a1*b0 ++ __ movdqu(xmm_temp6, xmm_temp0); ++ __ pclmulqdq(xmm_temp6, xmm_temp1, 17); // xmm6 holds a1*b1 ++ ++ __ pxor(xmm_temp4, xmm_temp5); // xmm4 holds a0*b1 + a1*b0 ++ ++ __ movdqu(xmm_temp5, xmm_temp4); // move the contents of xmm4 to xmm5 ++ __ psrldq(xmm_temp4, 8); // shift by xmm4 64 bits to the right ++ __ pslldq(xmm_temp5, 8); // shift by xmm5 64 bits to the left ++ __ pxor(xmm_temp3, xmm_temp5); ++ __ pxor(xmm_temp6, xmm_temp4); // Register pair holds the result ++ // of the carry-less multiplication of ++ // xmm0 by xmm1. ++ ++ // We shift the result of the multiplication by one bit position ++ // to the left to cope for the fact that the bits are reversed. ++ __ movdqu(xmm_temp7, xmm_temp3); ++ __ movdqu(xmm_temp8, xmm_temp6); ++ __ pslld(xmm_temp3, 1); ++ __ pslld(xmm_temp6, 1); ++ __ psrld(xmm_temp7, 31); ++ __ psrld(xmm_temp8, 31); ++ __ movdqu(xmm_temp9, xmm_temp7); ++ __ pslldq(xmm_temp8, 4); ++ __ pslldq(xmm_temp7, 4); ++ __ psrldq(xmm_temp9, 12); ++ __ por(xmm_temp3, xmm_temp7); ++ __ por(xmm_temp6, xmm_temp8); ++ __ por(xmm_temp6, xmm_temp9); ++ ++ // ++ // First phase of the reduction ++ // ++ // Move xmm3 into xmm7, xmm8, xmm9 in order to perform the shifts ++ // independently. ++ __ movdqu(xmm_temp7, xmm_temp3); ++ __ movdqu(xmm_temp8, xmm_temp3); ++ __ movdqu(xmm_temp9, xmm_temp3); ++ __ pslld(xmm_temp7, 31); // packed right shift shifting << 31 ++ __ pslld(xmm_temp8, 30); // packed right shift shifting << 30 ++ __ pslld(xmm_temp9, 25); // packed right shift shifting << 25 ++ __ pxor(xmm_temp7, xmm_temp8); // xor the shifted versions ++ __ pxor(xmm_temp7, xmm_temp9); ++ __ movdqu(xmm_temp8, xmm_temp7); ++ __ pslldq(xmm_temp7, 12); ++ __ psrldq(xmm_temp8, 4); ++ __ pxor(xmm_temp3, xmm_temp7); // first phase of the reduction complete ++ ++ // ++ // Second phase of the reduction ++ // ++ // Make 3 copies of xmm3 in xmm2, xmm4, xmm5 for doing these ++ // shift operations. ++ __ movdqu(xmm_temp2, xmm_temp3); ++ __ movdqu(xmm_temp4, xmm_temp3); ++ __ movdqu(xmm_temp5, xmm_temp3); ++ __ psrld(xmm_temp2, 1); // packed left shifting >> 1 ++ __ psrld(xmm_temp4, 2); // packed left shifting >> 2 ++ __ psrld(xmm_temp5, 7); // packed left shifting >> 7 ++ __ pxor(xmm_temp2, xmm_temp4); // xor the shifted versions ++ __ pxor(xmm_temp2, xmm_temp5); ++ __ pxor(xmm_temp2, xmm_temp8); ++ __ pxor(xmm_temp3, xmm_temp2); ++ __ pxor(xmm_temp6, xmm_temp3); // the result is in xmm6 ++ ++ __ decrement(blocks); ++ __ jcc(Assembler::zero, L_exit); ++ __ movdqu(xmm_temp0, xmm_temp6); ++ __ addptr(data, 16); ++ __ jmp(L_ghash_loop); ++ ++ __ BIND(L_exit); ++ __ pshufb(xmm_temp6, xmm_temp10); // Byte swap 16-byte result ++ __ movdqu(Address(state, 0), xmm_temp6); // store the result ++ __ leave(); ++ __ ret(0);*/ ++ return start; ++ } ++ ++ //base64 character set ++ address base64_charset_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "base64_charset");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x0000004200000041, relocInfo::none); ++ __ emit_data64(0x0000004400000043, relocInfo::none); ++ __ emit_data64(0x0000004600000045, relocInfo::none); ++ __ emit_data64(0x0000004800000047, relocInfo::none); ++ __ emit_data64(0x0000004a00000049, relocInfo::none); ++ __ emit_data64(0x0000004c0000004b, relocInfo::none); ++ __ emit_data64(0x0000004e0000004d, relocInfo::none); ++ __ emit_data64(0x000000500000004f, relocInfo::none); ++ __ emit_data64(0x0000005200000051, relocInfo::none); ++ __ emit_data64(0x0000005400000053, relocInfo::none); ++ __ emit_data64(0x0000005600000055, relocInfo::none); ++ __ emit_data64(0x0000005800000057, relocInfo::none); ++ __ emit_data64(0x0000005a00000059, relocInfo::none); ++ __ emit_data64(0x0000006200000061, relocInfo::none); ++ __ emit_data64(0x0000006400000063, relocInfo::none); ++ __ emit_data64(0x0000006600000065, relocInfo::none); ++ __ emit_data64(0x0000006800000067, relocInfo::none); ++ __ emit_data64(0x0000006a00000069, relocInfo::none); ++ __ emit_data64(0x0000006c0000006b, relocInfo::none); ++ __ emit_data64(0x0000006e0000006d, relocInfo::none); ++ __ emit_data64(0x000000700000006f, relocInfo::none); ++ __ emit_data64(0x0000007200000071, relocInfo::none); ++ __ emit_data64(0x0000007400000073, relocInfo::none); ++ __ emit_data64(0x0000007600000075, relocInfo::none); ++ __ emit_data64(0x0000007800000077, relocInfo::none); ++ __ emit_data64(0x0000007a00000079, relocInfo::none); ++ __ emit_data64(0x0000003100000030, relocInfo::none); ++ __ emit_data64(0x0000003300000032, relocInfo::none); ++ __ emit_data64(0x0000003500000034, relocInfo::none); ++ __ emit_data64(0x0000003700000036, relocInfo::none); ++ __ emit_data64(0x0000003900000038, relocInfo::none); ++ __ emit_data64(0x0000002f0000002b, relocInfo::none);*/ ++ return start; ++ } ++ ++ //base64 url character set ++ address base64url_charset_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "base64url_charset");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x0000004200000041, relocInfo::none); ++ __ emit_data64(0x0000004400000043, relocInfo::none); ++ __ emit_data64(0x0000004600000045, relocInfo::none); ++ __ emit_data64(0x0000004800000047, relocInfo::none); ++ __ emit_data64(0x0000004a00000049, relocInfo::none); ++ __ emit_data64(0x0000004c0000004b, relocInfo::none); ++ __ emit_data64(0x0000004e0000004d, relocInfo::none); ++ __ emit_data64(0x000000500000004f, relocInfo::none); ++ __ emit_data64(0x0000005200000051, relocInfo::none); ++ __ emit_data64(0x0000005400000053, relocInfo::none); ++ __ emit_data64(0x0000005600000055, relocInfo::none); ++ __ emit_data64(0x0000005800000057, relocInfo::none); ++ __ emit_data64(0x0000005a00000059, relocInfo::none); ++ __ emit_data64(0x0000006200000061, relocInfo::none); ++ __ emit_data64(0x0000006400000063, relocInfo::none); ++ __ emit_data64(0x0000006600000065, relocInfo::none); ++ __ emit_data64(0x0000006800000067, relocInfo::none); ++ __ emit_data64(0x0000006a00000069, relocInfo::none); ++ __ emit_data64(0x0000006c0000006b, relocInfo::none); ++ __ emit_data64(0x0000006e0000006d, relocInfo::none); ++ __ emit_data64(0x000000700000006f, relocInfo::none); ++ __ emit_data64(0x0000007200000071, relocInfo::none); ++ __ emit_data64(0x0000007400000073, relocInfo::none); ++ __ emit_data64(0x0000007600000075, relocInfo::none); ++ __ emit_data64(0x0000007800000077, relocInfo::none); ++ __ emit_data64(0x0000007a00000079, relocInfo::none); ++ __ emit_data64(0x0000003100000030, relocInfo::none); ++ __ emit_data64(0x0000003300000032, relocInfo::none); ++ __ emit_data64(0x0000003500000034, relocInfo::none); ++ __ emit_data64(0x0000003700000036, relocInfo::none); ++ __ emit_data64(0x0000003900000038, relocInfo::none); ++ __ emit_data64(0x0000005f0000002d, relocInfo::none); ++*/ ++ return start; ++ } ++ ++ address base64_bswap_mask_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "bswap_mask_base64");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x0504038002010080, relocInfo::none); ++ __ emit_data64(0x0b0a098008070680, relocInfo::none); ++ __ emit_data64(0x0908078006050480, relocInfo::none); ++ __ emit_data64(0x0f0e0d800c0b0a80, relocInfo::none); ++ __ emit_data64(0x0605048003020180, relocInfo::none); ++ __ emit_data64(0x0c0b0a8009080780, relocInfo::none); ++ __ emit_data64(0x0504038002010080, relocInfo::none); ++ __ emit_data64(0x0b0a098008070680, relocInfo::none); ++*/ ++ return start; ++ } ++ ++ address base64_right_shift_mask_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "right_shift_mask");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++ __ emit_data64(0x0006000400020000, relocInfo::none); ++*/ ++ return start; ++ } ++ ++ address base64_left_shift_mask_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "left_shift_mask");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++ __ emit_data64(0x0000000200040000, relocInfo::none); ++*/ ++ return start; ++ } ++ ++ address base64_and_mask_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "and_mask");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none); ++ __ emit_data64(0x3f003f003f000000, relocInfo::none);*/ ++ return start; ++ } ++ ++ address base64_gather_mask_addr() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "gather_mask");ShouldNotReachHere(); ++ address start = __ pc(); ++// __ emit_data64(0xffffffffffffffff, relocInfo::none); ++ return start; ++ } ++ ++// Code for generating Base64 encoding. ++// Intrinsic function prototype in Base64.java: ++// private void encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL) { ++ address generate_base64_encodeBlock() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "implEncode");ShouldNotReachHere(); ++ address start = __ pc();/* ++ __ enter(); ++ ++ // Save callee-saved registers before using them ++ __ push(r12); ++ __ push(r13); ++ __ push(r14); ++ __ push(r15); ++ ++ // arguments ++ const Register source = c_rarg0; // Source Array ++ const Register start_offset = c_rarg1; // start offset ++ const Register end_offset = c_rarg2; // end offset ++ const Register dest = c_rarg3; // destination array ++ ++#ifndef _WIN64 ++ const Register dp = c_rarg4; // Position for writing to dest array ++ const Register isURL = c_rarg5;// Base64 or URL character set ++#else ++ const Address dp_mem(rbp, 6 * wordSize); // length is on stack on Win64 ++ const Address isURL_mem(rbp, 7 * wordSize); ++ const Register isURL = r10; // pick the volatile windows register ++ const Register dp = r12; ++ __ movl(dp, dp_mem); ++ __ movl(isURL, isURL_mem); ++#endif ++ ++ const Register length = r14; ++ Label L_process80, L_process32, L_process3, L_exit, L_processdata; ++ ++ // calculate length from offsets ++ __ movl(length, end_offset); ++ __ subl(length, start_offset); ++ __ cmpl(length, 0); ++ __ jcc(Assembler::lessEqual, L_exit); ++ ++ __ lea(r11, ExternalAddress(StubRoutines::x86::base64_charset_addr())); ++ // check if base64 charset(isURL=0) or base64 url charset(isURL=1) needs to be loaded ++ __ cmpl(isURL, 0); ++ __ jcc(Assembler::equal, L_processdata); ++ __ lea(r11, ExternalAddress(StubRoutines::x86::base64url_charset_addr())); ++ ++ // load masks required for encoding data ++ __ BIND(L_processdata); ++ __ movdqu(xmm16, ExternalAddress(StubRoutines::x86::base64_gather_mask_addr())); ++ // Set 64 bits of K register. ++ __ evpcmpeqb(k3, xmm16, xmm16, Assembler::AVX_512bit); ++ __ evmovdquq(xmm12, ExternalAddress(StubRoutines::x86::base64_bswap_mask_addr()), Assembler::AVX_256bit, r13); ++ __ evmovdquq(xmm13, ExternalAddress(StubRoutines::x86::base64_right_shift_mask_addr()), Assembler::AVX_512bit, r13); ++ __ evmovdquq(xmm14, ExternalAddress(StubRoutines::x86::base64_left_shift_mask_addr()), Assembler::AVX_512bit, r13); ++ __ evmovdquq(xmm15, ExternalAddress(StubRoutines::x86::base64_and_mask_addr()), Assembler::AVX_512bit, r13); ++ ++ // Vector Base64 implementation, producing 96 bytes of encoded data ++ __ BIND(L_process80); ++ __ cmpl(length, 80); ++ __ jcc(Assembler::below, L_process32); ++ __ evmovdquq(xmm0, Address(source, start_offset, Address::times_1, 0), Assembler::AVX_256bit); ++ __ evmovdquq(xmm1, Address(source, start_offset, Address::times_1, 24), Assembler::AVX_256bit); ++ __ evmovdquq(xmm2, Address(source, start_offset, Address::times_1, 48), Assembler::AVX_256bit); ++ ++ //permute the input data in such a manner that we have continuity of the source ++ __ vpermq(xmm3, xmm0, 148, Assembler::AVX_256bit); ++ __ vpermq(xmm4, xmm1, 148, Assembler::AVX_256bit); ++ __ vpermq(xmm5, xmm2, 148, Assembler::AVX_256bit); ++ ++ //shuffle input and group 3 bytes of data and to it add 0 as the 4th byte. ++ //we can deal with 12 bytes at a time in a 128 bit register ++ __ vpshufb(xmm3, xmm3, xmm12, Assembler::AVX_256bit); ++ __ vpshufb(xmm4, xmm4, xmm12, Assembler::AVX_256bit); ++ __ vpshufb(xmm5, xmm5, xmm12, Assembler::AVX_256bit); ++ ++ //convert byte to word. Each 128 bit register will have 6 bytes for processing ++ __ vpmovzxbw(xmm3, xmm3, Assembler::AVX_512bit); ++ __ vpmovzxbw(xmm4, xmm4, Assembler::AVX_512bit); ++ __ vpmovzxbw(xmm5, xmm5, Assembler::AVX_512bit); ++ ++ // Extract bits in the following pattern 6, 4+2, 2+4, 6 to convert 3, 8 bit numbers to 4, 6 bit numbers ++ __ evpsrlvw(xmm0, xmm3, xmm13, Assembler::AVX_512bit); ++ __ evpsrlvw(xmm1, xmm4, xmm13, Assembler::AVX_512bit); ++ __ evpsrlvw(xmm2, xmm5, xmm13, Assembler::AVX_512bit); ++ ++ __ evpsllvw(xmm3, xmm3, xmm14, Assembler::AVX_512bit); ++ __ evpsllvw(xmm4, xmm4, xmm14, Assembler::AVX_512bit); ++ __ evpsllvw(xmm5, xmm5, xmm14, Assembler::AVX_512bit); ++ ++ __ vpsrlq(xmm0, xmm0, 8, Assembler::AVX_512bit); ++ __ vpsrlq(xmm1, xmm1, 8, Assembler::AVX_512bit); ++ __ vpsrlq(xmm2, xmm2, 8, Assembler::AVX_512bit); ++ ++ __ vpsllq(xmm3, xmm3, 8, Assembler::AVX_512bit); ++ __ vpsllq(xmm4, xmm4, 8, Assembler::AVX_512bit); ++ __ vpsllq(xmm5, xmm5, 8, Assembler::AVX_512bit); ++ ++ __ vpandq(xmm3, xmm3, xmm15, Assembler::AVX_512bit); ++ __ vpandq(xmm4, xmm4, xmm15, Assembler::AVX_512bit); ++ __ vpandq(xmm5, xmm5, xmm15, Assembler::AVX_512bit); ++ ++ // Get the final 4*6 bits base64 encoding ++ __ vporq(xmm3, xmm3, xmm0, Assembler::AVX_512bit); ++ __ vporq(xmm4, xmm4, xmm1, Assembler::AVX_512bit); ++ __ vporq(xmm5, xmm5, xmm2, Assembler::AVX_512bit); ++ ++ // Shift ++ __ vpsrlq(xmm3, xmm3, 8, Assembler::AVX_512bit); ++ __ vpsrlq(xmm4, xmm4, 8, Assembler::AVX_512bit); ++ __ vpsrlq(xmm5, xmm5, 8, Assembler::AVX_512bit); ++ ++ // look up 6 bits in the base64 character set to fetch the encoding ++ // we are converting word to dword as gather instructions need dword indices for looking up encoding ++ __ vextracti64x4(xmm6, xmm3, 0); ++ __ vpmovzxwd(xmm0, xmm6, Assembler::AVX_512bit); ++ __ vextracti64x4(xmm6, xmm3, 1); ++ __ vpmovzxwd(xmm1, xmm6, Assembler::AVX_512bit); ++ ++ __ vextracti64x4(xmm6, xmm4, 0); ++ __ vpmovzxwd(xmm2, xmm6, Assembler::AVX_512bit); ++ __ vextracti64x4(xmm6, xmm4, 1); ++ __ vpmovzxwd(xmm3, xmm6, Assembler::AVX_512bit); ++ ++ __ vextracti64x4(xmm4, xmm5, 0); ++ __ vpmovzxwd(xmm6, xmm4, Assembler::AVX_512bit); ++ ++ __ vextracti64x4(xmm4, xmm5, 1); ++ __ vpmovzxwd(xmm7, xmm4, Assembler::AVX_512bit); ++ ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm4, k2, Address(r11, xmm0, Address::times_4, 0), Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm5, k2, Address(r11, xmm1, Address::times_4, 0), Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm8, k2, Address(r11, xmm2, Address::times_4, 0), Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm9, k2, Address(r11, xmm3, Address::times_4, 0), Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm10, k2, Address(r11, xmm6, Address::times_4, 0), Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm11, k2, Address(r11, xmm7, Address::times_4, 0), Assembler::AVX_512bit); ++ ++ //Down convert dword to byte. Final output is 16*6 = 96 bytes long ++ __ evpmovdb(Address(dest, dp, Address::times_1, 0), xmm4, Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 16), xmm5, Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 32), xmm8, Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 48), xmm9, Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 64), xmm10, Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 80), xmm11, Assembler::AVX_512bit); ++ ++ __ addq(dest, 96); ++ __ addq(source, 72); ++ __ subq(length, 72); ++ __ jmp(L_process80); ++ ++ // Vector Base64 implementation generating 32 bytes of encoded data ++ __ BIND(L_process32); ++ __ cmpl(length, 32); ++ __ jcc(Assembler::below, L_process3); ++ __ evmovdquq(xmm0, Address(source, start_offset), Assembler::AVX_256bit); ++ __ vpermq(xmm0, xmm0, 148, Assembler::AVX_256bit); ++ __ vpshufb(xmm6, xmm0, xmm12, Assembler::AVX_256bit); ++ __ vpmovzxbw(xmm6, xmm6, Assembler::AVX_512bit); ++ __ evpsrlvw(xmm2, xmm6, xmm13, Assembler::AVX_512bit); ++ __ evpsllvw(xmm3, xmm6, xmm14, Assembler::AVX_512bit); ++ ++ __ vpsrlq(xmm2, xmm2, 8, Assembler::AVX_512bit); ++ __ vpsllq(xmm3, xmm3, 8, Assembler::AVX_512bit); ++ __ vpandq(xmm3, xmm3, xmm15, Assembler::AVX_512bit); ++ __ vporq(xmm1, xmm2, xmm3, Assembler::AVX_512bit); ++ __ vpsrlq(xmm1, xmm1, 8, Assembler::AVX_512bit); ++ __ vextracti64x4(xmm9, xmm1, 0); ++ __ vpmovzxwd(xmm6, xmm9, Assembler::AVX_512bit); ++ __ vextracti64x4(xmm9, xmm1, 1); ++ __ vpmovzxwd(xmm5, xmm9, Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm8, k2, Address(r11, xmm6, Address::times_4, 0), Assembler::AVX_512bit); ++ __ kmovql(k2, k3); ++ __ evpgatherdd(xmm10, k2, Address(r11, xmm5, Address::times_4, 0), Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 0), xmm8, Assembler::AVX_512bit); ++ __ evpmovdb(Address(dest, dp, Address::times_1, 16), xmm10, Assembler::AVX_512bit); ++ __ subq(length, 24); ++ __ addq(dest, 32); ++ __ addq(source, 24); ++ __ jmp(L_process32); ++*/ ++ // Scalar data processing takes 3 bytes at a time and produces 4 bytes of encoded data ++ /* This code corresponds to the scalar version of the following snippet in Base64.java ++ ** int bits = (src[sp0++] & 0xff) << 16 |(src[sp0++] & 0xff) << 8 |(src[sp0++] & 0xff); ++ ** dst[dp0++] = (byte)base64[(bits >> > 18) & 0x3f]; ++ ** dst[dp0++] = (byte)base64[(bits >> > 12) & 0x3f]; ++ ** dst[dp0++] = (byte)base64[(bits >> > 6) & 0x3f]; ++ ** dst[dp0++] = (byte)base64[bits & 0x3f];*//* ++ __ BIND(L_process3); ++ __ cmpl(length, 3); ++ __ jcc(Assembler::below, L_exit); ++ // Read 1 byte at a time ++ __ movzbl(rax, Address(source, start_offset)); ++ __ shll(rax, 0x10); ++ __ movl(r15, rax); ++ __ movzbl(rax, Address(source, start_offset, Address::times_1, 1)); ++ __ shll(rax, 0x8); ++ __ movzwl(rax, rax); ++ __ orl(r15, rax); ++ __ movzbl(rax, Address(source, start_offset, Address::times_1, 2)); ++ __ orl(rax, r15); ++ // Save 3 bytes read in r15 ++ __ movl(r15, rax); ++ __ shrl(rax, 0x12); ++ __ andl(rax, 0x3f); ++ // rax contains the index, r11 contains base64 lookup table ++ __ movb(rax, Address(r11, rax, Address::times_4)); ++ // Write the encoded byte to destination ++ __ movb(Address(dest, dp, Address::times_1, 0), rax); ++ __ movl(rax, r15); ++ __ shrl(rax, 0xc); ++ __ andl(rax, 0x3f); ++ __ movb(rax, Address(r11, rax, Address::times_4)); ++ __ movb(Address(dest, dp, Address::times_1, 1), rax); ++ __ movl(rax, r15); ++ __ shrl(rax, 0x6); ++ __ andl(rax, 0x3f); ++ __ movb(rax, Address(r11, rax, Address::times_4)); ++ __ movb(Address(dest, dp, Address::times_1, 2), rax); ++ __ movl(rax, r15); ++ __ andl(rax, 0x3f); ++ __ movb(rax, Address(r11, rax, Address::times_4)); ++ __ movb(Address(dest, dp, Address::times_1, 3), rax); ++ __ subl(length, 3); ++ __ addq(dest, 4); ++ __ addq(source, 3); ++ __ jmp(L_process3); ++ __ BIND(L_exit); ++ __ pop(r15); ++ __ pop(r14); ++ __ pop(r13); ++ __ pop(r12); ++ __ leave(); ++ __ ret(0);*/ ++ return start; ++ } ++ ++ /** ++ * Arguments: ++ * ++ * Inputs: ++ * c_rarg0 - int crc ++ * c_rarg1 - byte* buf ++ * c_rarg2 - int length ++ * ++ * Ouput: ++ * rax - int crc result ++ */ ++ address generate_updateBytesCRC32() { ++ assert(UseCRC32Intrinsics, "need AVX and CLMUL instructions"); ++ ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32");ShouldNotReachHere(); ++ ++ address start = __ pc(); ++ __ stop("generate_updateBytesCRC32"); ++ /* ++ // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) ++ // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) ++ // rscratch1: r10 ++ const Register crc = c_rarg0; // crc ++ const Register buf = c_rarg1; // source java byte array address ++ const Register len = c_rarg2; // length ++ const Register table = c_rarg3; // crc_table address (reuse register) ++ const Register tmp = r11; ++ assert_different_registers(crc, buf, len, table, tmp, rax); ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ __ kernel_crc32(crc, buf, len, table, tmp); ++ ++ __ movl(rax, crc); ++ __ vzeroupper(); ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++ /** ++ * Arguments: ++ * ++ * Inputs: ++ * c_rarg0 - int crc ++ * c_rarg1 - byte* buf ++ * c_rarg2 - long length ++ * c_rarg3 - table_start - optional (present only when doing a library_call, ++ * not used by x86 algorithm) ++ * ++ * Ouput: ++ * rax - int crc result ++ */ ++ address generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { ++ assert(UseCRC32CIntrinsics, "need SSE4_2"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C");ShouldNotReachHere(); ++ address start = __ pc(); ++ __ stop("generate_updateBytesCRC32C"); ++ /* ++ //reg.arg int#0 int#1 int#2 int#3 int#4 int#5 float regs ++ //Windows RCX RDX R8 R9 none none XMM0..XMM3 ++ //Lin / Sol RDI RSI RDX RCX R8 R9 XMM0..XMM7 ++ const Register crc = c_rarg0; // crc ++ const Register buf = c_rarg1; // source java byte array address ++ const Register len = c_rarg2; // length ++ const Register a = rax; ++ const Register j = r9; ++ const Register k = r10; ++ const Register l = r11; ++#ifdef _WIN64 ++ const Register y = rdi; ++ const Register z = rsi; ++#else ++ const Register y = rcx; ++ const Register z = r8; ++#endif ++ assert_different_registers(crc, buf, len, a, j, k, l, y, z); ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++#ifdef _WIN64 ++ __ push(y); ++ __ push(z); ++#endif ++ __ crc32c_ipl_alg2_alt2(crc, buf, len, ++ a, j, k, ++ l, y, z, ++ c_farg0, c_farg1, c_farg2, ++ is_pclmulqdq_supported); ++ __ movl(rax, crc); ++#ifdef _WIN64 ++ __ pop(z); ++ __ pop(y); ++#endif ++ __ vzeroupper(); ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++ /** ++ * Arguments: ++ * ++ * Input: ++ * c_rarg0 - x address ++ * c_rarg1 - x length ++ * c_rarg2 - y address ++ * c_rarg3 - y length ++ * not Win64 ++ * c_rarg4 - z address ++ * c_rarg5 - z length ++ * Win64 ++ * rsp+40 - z address ++ * rsp+48 - z length ++ */ ++ address generate_multiplyToLen() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "multiplyToLen");ShouldNotReachHere(); ++ ++ address start = __ pc(); ++ __ stop("generate_multiplyToLen"); ++ /* ++ // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) ++ // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) ++ const Register x = rdi; ++ const Register xlen = rax; ++ const Register y = rsi; ++ const Register ylen = rcx; ++ const Register z = r8; ++ const Register zlen = r11; ++ ++ // Next registers will be saved on stack in multiply_to_len(). ++ const Register tmp1 = r12; ++ const Register tmp2 = r13; ++ const Register tmp3 = r14; ++ const Register tmp4 = r15; ++ const Register tmp5 = rbx; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifndef _WIN64 ++ __ movptr(zlen, r9); // Save r9 in r11 - zlen ++#endif ++ setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx ++ // ylen => rcx, z => r8, zlen => r11 ++ // r9 and r10 may be used to save non-volatile registers ++#ifdef _WIN64 ++ // last 2 arguments (#4, #5) are on stack on Win64 ++ __ movptr(z, Address(rsp, 6 * wordSize)); ++ __ movptr(zlen, Address(rsp, 7 * wordSize)); ++#endif ++ ++ __ movptr(xlen, rsi); ++ __ movptr(y, rdx); ++ __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5); ++ ++ restore_arg_regs(); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++ /** ++ * Arguments: ++ * ++ * Input: ++ * c_rarg0 - obja address ++ * c_rarg1 - objb address ++ * c_rarg3 - length length ++ * c_rarg4 - scale log2_array_indxscale ++ * ++ * Output: ++ * rax - int >= mismatched index, < 0 bitwise complement of tail ++ */ ++ address generate_vectorizedMismatch() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "vectorizedMismatch");ShouldNotReachHere(); ++ address start = __ pc();/* ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); ++ ++#ifdef _WIN64 // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) ++ const Register scale = c_rarg0; //rcx, will exchange with r9 ++ const Register objb = c_rarg1; //rdx ++ const Register length = c_rarg2; //r8 ++ const Register obja = c_rarg3; //r9 ++ __ xchgq(obja, scale); //now obja and scale contains the correct contents ++ ++ const Register tmp1 = r10; ++ const Register tmp2 = r11; ++#endif ++#ifndef _WIN64 // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) ++ const Register obja = c_rarg0; //U:rdi ++ const Register objb = c_rarg1; //U:rsi ++ const Register length = c_rarg2; //U:rdx ++ const Register scale = c_rarg3; //U:rcx ++ const Register tmp1 = r8; ++ const Register tmp2 = r9; ++#endif ++ const Register result = rax; //return value ++ const XMMRegister vec0 = xmm0; ++ const XMMRegister vec1 = xmm1; ++ const XMMRegister vec2 = xmm2; ++ ++ __ vectorized_mismatch(obja, objb, length, scale, result, tmp1, tmp2, vec0, vec1, vec2); ++ ++ __ vzeroupper(); ++ __ leave(); ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++/** ++ * Arguments: ++ * ++ // Input: ++ // c_rarg0 - x address ++ // c_rarg1 - x length ++ // c_rarg2 - z address ++ // c_rarg3 - z lenth ++ * ++ */ ++ address generate_squareToLen() { ++ ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "squareToLen");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) ++ // Unix: rdi, rsi, rdx, rcx (c_rarg0, c_rarg1, ...) ++ const Register x = rdi; ++ const Register len = rsi; ++ const Register z = r8; ++ const Register zlen = rcx; ++ ++ const Register tmp1 = r12; ++ const Register tmp2 = r13; ++ const Register tmp3 = r14; ++ const Register tmp4 = r15; ++ const Register tmp5 = rbx; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ setup_arg_regs(4); // x => rdi, len => rsi, z => rdx ++ // zlen => rcx ++ // r9 and r10 may be used to save non-volatile registers ++ __ movptr(r8, rdx); ++ __ square_to_len(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax); ++ ++ restore_arg_regs(); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ } ++ ++ /** ++ * Arguments: ++ * ++ * Input: ++ * c_rarg0 - out address ++ * c_rarg1 - in address ++ * c_rarg2 - offset ++ * c_rarg3 - len ++ * not Win64 ++ * c_rarg4 - k ++ * Win64 ++ * rsp+40 - k ++ */ ++ address generate_mulAdd() { ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "mulAdd");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) ++ // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) ++ const Register out = rdi; ++ const Register in = rsi; ++ const Register offset = r11; ++ const Register len = rcx; ++ const Register k = r8; ++ ++ // Next registers will be saved on stack in mul_add(). ++ const Register tmp1 = r12; ++ const Register tmp2 = r13; ++ const Register tmp3 = r14; ++ const Register tmp4 = r15; ++ const Register tmp5 = rbx; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ setup_arg_regs(4); // out => rdi, in => rsi, offset => rdx ++ // len => rcx, k => r8 ++ // r9 and r10 may be used to save non-volatile registers ++#ifdef _WIN64 ++ // last argument is on stack on Win64 ++ __ movl(k, Address(rsp, 6 * wordSize)); ++#endif ++ __ movptr(r11, rdx); // move offset in rdx to offset(r11) ++ __ mul_add(out, in, offset, len, k, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax); ++ ++ restore_arg_regs(); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++ ++ return start; ++ } ++ ++ address generate_libmExp() { ++ StubCodeMark mark(this, "StubRoutines", "libmExp"); ++ ++ address start = __ pc(); ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp = r11; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ __ fast_exp(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ address generate_libmLog() { ++ StubCodeMark mark(this, "StubRoutines", "libmLog");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp1 = r11; ++ const Register tmp2 = r8; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ __ fast_log(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp1, tmp2); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ address generate_libmLog10() { ++ StubCodeMark mark(this, "StubRoutines", "libmLog10");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp = r11; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ __ fast_log10(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ address generate_libmPow() { ++ StubCodeMark mark(this, "StubRoutines", "libmPow");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp1 = r8; ++ const Register tmp2 = r9; ++ const Register tmp3 = r10; ++ const Register tmp4 = r11; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++ __ fast_pow(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp1, tmp2, tmp3, tmp4); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ address generate_libmSin() { ++ StubCodeMark mark(this, "StubRoutines", "libmSin");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp1 = r8; ++ const Register tmp2 = r9; ++ const Register tmp3 = r10; ++ const Register tmp4 = r11; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ __ push(rsi); ++ __ push(rdi); ++#endif ++ __ fast_sin(x0, x1, x2, x3, x4, x5, x6, x7, rax, rbx, rcx, rdx, tmp1, tmp2, tmp3, tmp4); ++ ++#ifdef _WIN64 ++ __ pop(rdi); ++ __ pop(rsi); ++#endif ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ address generate_libmCos() { ++ StubCodeMark mark(this, "StubRoutines", "libmCos");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp1 = r8; ++ const Register tmp2 = r9; ++ const Register tmp3 = r10; ++ const Register tmp4 = r11; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ __ push(rsi); ++ __ push(rdi); ++#endif ++ __ fast_cos(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp1, tmp2, tmp3, tmp4); ++ ++#ifdef _WIN64 ++ __ pop(rdi); ++ __ pop(rsi); ++#endif ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ address generate_libmTan() { ++ StubCodeMark mark(this, "StubRoutines", "libmTan");ShouldNotReachHere(); ++ ++ address start = __ pc();/* ++ ++ const XMMRegister x0 = xmm0; ++ const XMMRegister x1 = xmm1; ++ const XMMRegister x2 = xmm2; ++ const XMMRegister x3 = xmm3; ++ ++ const XMMRegister x4 = xmm4; ++ const XMMRegister x5 = xmm5; ++ const XMMRegister x6 = xmm6; ++ const XMMRegister x7 = xmm7; ++ ++ const Register tmp1 = r8; ++ const Register tmp2 = r9; ++ const Register tmp3 = r10; ++ const Register tmp4 = r11; ++ ++ BLOCK_COMMENT("Entry:"); ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ __ push(rsi); ++ __ push(rdi); ++#endif ++ __ fast_tan(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp1, tmp2, tmp3, tmp4); ++ ++#ifdef _WIN64 ++ __ pop(rdi); ++ __ pop(rsi); ++#endif ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++*/ ++ return start; ++ ++ } ++ ++ ++ ++ void copy_core_forward(int limit, Register src, Register dst, Register count, Register tmp1, Register tmp2){ ++ Label l_misalign, l_misalign_simd, l_align_simd, l_before_tail, l_exit; ++ ++ __ and_ins(src, 31, tmp1); ++ __ beq_l(tmp1, l_align_simd); ++ ++ __ BIND(l_misalign); ++ __ and_ins(src, 31, tmp1); //from low-5-bit = src mod 32 ++ __ slll(tmp1, 3, tmp1); ++ __ ifmovs(tmp1, f15); ++ __ ldi(tmp2, 256, R0); ++ __ subl(tmp2, tmp1, tmp1); ++ __ ifmovs(tmp1, F17); ++ __ andnot(src, 31, tmp1); ++ __ vldd(f10, 0, tmp1); //load 32 bytes from src ++ ++ __ BIND(l_misalign_simd); ++ __ srlow(f10, f15, f12);//get high feild bytes of 32 bytes ++ __ vldd(f10, 32, tmp1); //load next 32 bytes from src+32 ++ __ sllow(f10, F17, f13);//get low field bytes of 32 bytes ++ __ vlog(0xfc, f12, f13, f31, f12); //merge f12, f13, into f12 ++ __ vstd(f12, 0, dst); ++ ++ __ addl(tmp1, 32, tmp1); ++ __ addl(dst, 32, dst); ++ __ subl(count, limit, count); ++ ++ __ cmple(count, limit-1, tmp2); //At least one more trip? ++ __ beq_l(tmp2, l_misalign_simd); ++ __ beq_l(R0, l_before_tail); ++ ++ __ BIND(l_align_simd); ++ __ vldd(f10, 0, src); ++ __ vstd(f10, 0, dst); ++ __ subl(count, limit, count); ++ __ addl(src, 32, src); ++ __ addl(dst, 32, dst); ++ __ cmple(count, limit-1, tmp1); //while count >=32, do simd ++ __ beq_l(tmp1, l_align_simd); ++ __ beq_l(R0, l_exit); ++ ++ __ BIND(l_before_tail); ++ __ and_ins(src, 31, src); ++ __ addl(tmp1, src, src); ++ ++ __ BIND(l_exit); ++ } ++ ++ void copy_core_backward(int limit, Register end_src, Register end_dst, Register count, Register tmp1, Register tmp2){ ++ Label l_misalign, l_misalign_simd, l_align_simd, l_before_tail, l_exit; ++ ++ __ and_ins(end_src, 31, tmp1); ++ __ beq_l(tmp1, l_align_simd); ++ ++ __ BIND(l_misalign); ++ __ and_ins(end_src, 31, tmp1); //from low-5-bit = src mod 32 ++ __ slll(tmp1, 3, tmp1); ++ __ ifmovs(tmp1, f15); ++ __ ldi(tmp2, 256, R0); ++ __ subl(tmp2, tmp1, tmp1); ++ __ ifmovs(tmp1, F17); ++ __ andnot(end_src, 31, tmp1); ++ __ vldd(f10, 0, tmp1); //load 32 bytes from src ++ ++ __ BIND(l_misalign_simd); ++ __ sllow(f10, F17, f13);//get low field bytes of 32 bytes ++ __ vldd(f10, -32, tmp1); //load next 32 bytes from src+32 ++ __ srlow(f10, f15, f12);//get high feild bytes of 32 bytes ++ __ vlog(0xfc, f12, f13, f31, f12); //merge f12, f13, into f12 ++ __ vstd(f12, -32, end_dst); ++ ++ __ subl(tmp1, 32, tmp1); ++ __ subl(end_dst, 32, end_dst); ++ __ subl(count, limit, count); ++ ++ __ cmple(count, limit-1, tmp2); //At least one more trip? ++ __ beq_l(tmp2, l_misalign_simd); ++ __ beq_l(R0, l_before_tail); ++ ++ __ BIND(l_align_simd); ++ __ vldd(f10, -32, end_src); ++ __ vstd(f10, -32, end_dst); ++ __ subl(count, limit, count); ++ __ subl(end_src, 32, end_src); ++ __ subl(end_dst, 32, end_dst); ++ __ cmple(count, limit-1, tmp1); //while count >=32, do simd ++ __ beq_l(tmp1, l_align_simd); ++ __ beq_l(R0, l_exit); ++ ++ __ BIND(l_before_tail); ++ __ and_ins(end_src, 31, end_src); ++ __ addl(tmp1, end_src, end_src); ++ ++ __ BIND(l_exit); ++ } ++ ++ // Continuation point for throwing of implicit exceptions that are ++ // not handled in the current activation. Fabricates an exception ++ // oop and initiates normal exception dispatching in this ++ // frame. Since we need to preserve callee-saved values (currently ++ // only for C2, but done for C1 as well) we need a callee-saved oop ++ // map and therefore have to make these stubs into RuntimeStubs ++ // rather than BufferBlobs. If the compiler needs all registers to ++ // be preserved between the fault point and the exception handler ++ // then it must assume responsibility for that in ++ // AbstractCompiler::continuation_for_implicit_null_exception or ++ // continuation_for_implicit_division_by_zero_exception. All other ++ // implicit exceptions (e.g., NullPointerException or ++ // AbstractMethodError on entry) are either at call sites or ++ // otherwise assume that stack unwinding will be initiated, so ++ // caller saved registers were assumed volatile in the compiler. ++ ++ ++ // Arguments: ++ // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary ++ // ignored ++ // name - stub name string ++ // ++ // Inputs: ++ // c_rarg0 - source array address ++ // c_rarg1 - destination array address ++ // c_rarg2 - element count, treated as ssize_t, can be zero ++ // ++ // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries, ++ // we let the hardware handle it. The one to eight bytes within words, ++ // dwords or qwords that span cache line boundaries will still be loaded ++ // and stored atomically. ++ // ++ // Side Effects: ++ // disjoint_byte_copy_entry is set to the no-overlap entry point ++ // used by generate_conjoint_byte_copy(). ++ // ++ void generate_disjoint_copy(int widthInByte, Register src, Register dst, Register count) { ++ // Label lblMissAlignInByte, lblMissAlignInShort, lblMissAlignInWord, lblMissAlignInLong; ++ Label lblMissAlign[4]; ++ // Label lblSkipByte, lblSkipInShort, lblSkipInWord, lblSkipInLong; ++ Label lblSkip[4]; ++ // Label lblCopyByte, lblCopyShort, lblCopyWord, lblCopyLong; ++ Label lblCopy[4]; ++ char buf[50]; ++ if (widthInByte == 0) {__ subl(count, 9, AT); __ ble_l(AT, lblMissAlign[1]);} ++ if (widthInByte == 1) {__ subl(count, 9, AT); __ ble_l(AT, lblMissAlign[2]);} ++ ++ for (int i = widthInByte; i < 3; i++) { ++ __ xorptr(src, dst, AT); ++ __ andptr(AT, 1 << i, AT); // if the backward ith bit of src and and dst is the same ++ __ jcc(Assembler::notEqual, lblMissAlign[i+1], AT); // if arrays don't have the same alignment, ... ++ ++ __ andptr(src, 1 << i, AT); ++ __ jcc(Assembler::equal, lblSkip[i], AT); // have same alignment but extra byte/short/int ++ ++ __ load(i, AT, 0, src); ++ __ store(i, AT, 0, dst); ++ __ addl(src, 1 << i, src); ++ __ addl(dst, 1 << i, dst); ++ __ subl(count, 1 << i, count); ++ ++ __ bind(lblSkip[i]); ++ sprintf(buf, "lblSkip[%d]", i); ++ __ block_comment(buf); ++ } ++ ++ for (int i = 3; i >= widthInByte; i--) { // FasterArrayCopy ++ if (i == widthInByte) { ++ __ jcc(Assembler::equal, lblMissAlign[i], count); ++ } else { ++ __ cmplt(count, 1 << i, AT); ++ __ jcc(Assembler::notEqual, lblMissAlign[i], AT); ++ } ++ __ bind(lblCopy[i]); ++ sprintf(buf, "lblCopy[%d]", i); ++ __ block_comment(buf); ++ ++ __ load(i, AT, 0, src); ++ __ store(i, AT, 0, dst); ++ __ addl(src, 1 << i, src); ++ __ addl(dst, 1 << i, dst); ++ __ subl(count, 1 << i, count); ++ if(i == widthInByte){ ++ __ jcc(Assembler::notEqual, lblCopy[i], count); ++ }else{ ++ __ subl(count, 1 << i, AT); ++ __ jcc(Assembler::greaterEqual, lblCopy[i], AT); ++ } ++ __ bind(lblMissAlign[i]); ++ sprintf(buf, "lblMissAlign[%d]", i); ++ __ block_comment(buf); ++ } ++ } ++ ++ void generate_conjoint_copy(int widthInByte,Register src, Register dst, Register count) {SCOPEMARK_NAME(generate_conjoint_copy, _masm) ++ // Label lblMissAlignInByte, lblMissAlignInShort, lblMissAlignInWord, lblMissAlignInLong; ++ Label lblMissAlign[4]; ++ // Label lblSkipByte, lblSkipInShort, lblSkipInWord, lblSkipInLong; ++ Label lblSkip[4]; ++ // Label lblCopyByte, lblCopyShort, lblCopyWord, lblCopyLong; ++ Label lblCopy[4]; ++ char buf[50]; ++ ++ assert_different_registers(src, dst, AT); ++ //__ stop("TODO:generate_conjoint_copy jzy"); ++ if (widthInByte == 0) {__ subl(count, 9, AT); __ ble_l(AT, lblMissAlign[1]);} ++ if (widthInByte == 1) {__ subl(count, 9, AT); __ ble_l(AT, lblMissAlign[2]);} ++ ++ ++ for (int i = widthInByte; i < 3; i++) { ++ __ xorptr(src, dst, AT); ++ __ andptr(AT, 1 << i, AT); // if the backward ith bit of src and and dst is the same ++ __ jcc(Assembler::notEqual, lblMissAlign[i+1], AT); // if arrays don't have the same alignment, ... ++ ++ __ andptr(src, 1 << i, AT); ++ __ jcc(Assembler::equal, lblSkip[i], AT); // have same alignment but extra byte/short/int ++ ++ __ subl(src, 1 << i, src); ++ __ subl(dst, 1 << i, dst); ++ __ load(i, AT, 0, src); //TODO:refactor? jzy ++ __ store(i, AT, 0, dst);//TODO:refactor? jzy ++ __ subl(count, 1 << i, count); ++ ++ __ bind(lblSkip[i]); ++ sprintf(buf, "lblSkip[%d]", i); ++ __ block_comment(buf); ++ } ++ ++ for (int i = 3; i >= widthInByte; i--) { // FasterArrayCopy ++ if(i == widthInByte){ ++ __ jcc(Assembler::equal, lblMissAlign[i], count); ++ }else{ ++ __ cmpl(count, 1 << i); ++ __ jcc(Assembler::less, lblMissAlign[i]); ++ } ++ ++ __ bind(lblCopy[i]); ++ sprintf(buf, "lblCopy[%d]", i); ++ __ block_comment(buf); ++ ++ __ subl(src, 1 << i, src); ++ __ subl(dst, 1 << i, dst); ++ __ load(i, AT, 0, src); ++ __ store(i, AT, 0, dst); ++ __ subl(count, 1 << i, count); ++ if (i == widthInByte) { ++ __ jcc(Assembler::notEqual, lblCopy[i], count); ++ } else { ++ __ cmpl(count, 1 << i); ++ __ jcc(Assembler::greaterEqual, lblCopy[i]); ++ } ++ __ bind(lblMissAlign[i]); ++ sprintf(buf, "lblMissAlign[%d]", i); ++ __ block_comment(buf); ++ } ++ } ++ ++#undef __ ++#define __ masm-> ++ ++ address generate_throw_exception(const char* name, ++ address runtime_entry, ++ Register arg1 = noreg, ++ Register arg2 = noreg) { ++ // Information about frame layout at time of blocking runtime call. ++ // Note that we only have to preserve callee-saved registers since ++ // the compilers are responsible for supplying a continuation point ++ // if they expect all registers to be preserved. ++ // n.b. sw64 asserts that frame::arg_reg_save_area_bytes == 0 ++ enum layout { ++ rfp_off = frame::arg_reg_save_area_bytes/BytesPerInt, ++ rfp_off2, ++ return_off, ++ return_off2, ++ framesize // inclusive of return address ++ }; ++ ++ int insts_size = 2048; ++ int locs_size = 32; ++ ++ CodeBuffer code(name, insts_size, locs_size); ++ OopMapSet* oop_maps = new OopMapSet(); ++ MacroAssembler* masm = new MacroAssembler(&code); ++ ++ address start = __ pc(); ++ ++ // This is an inlined and slightly modified version of call_VM ++ // which has the ability to fetch the return PC out of ++ // thread-local storage and also sets up last_Java_sp slightly ++ // differently than the real call_VM ++ Register java_thread = rthread; ++ ++ //Label frame_return; ++ //__ stop("no check:jzy"); ++ __ enter(); // Save FP and LR before call ++ ++ __ mov_immediate64(rscratch3, (framesize-4) << LogBytesPerWord); ++ __ subptr(esp, rscratch3, esp); // prolog ++ ++ int frame_complete = __ pc() - start; ++ ++ // Set up last_Java_sp and last_Java_fp ++ address the_pc = __ pc(); ++ __ set_last_Java_frame(esp, rfp, the_pc, rscratch3); ++ ++ // Call runtime ++ if (arg1 != noreg) { ++ assert(arg2 != c_rarg1, "clobbered"); ++ __ movl(c_rarg1, arg1); ++ } ++ if (arg2 != noreg) { ++ __ movl(c_rarg2, arg2); ++ } ++ __ movl(c_rarg0, rthread); ++ ++ // Call runtime ++ __ call(RuntimeAddress(runtime_entry)); ++ ++ // Generate oop map ++ OopMap* map = new OopMap(framesize, 0); ++ oop_maps->add_gc_map(the_pc - start, map); ++ ++ __ reset_last_Java_frame(true); ++ ++ // discard arguments ++ __ leave(); ++ // check for pending exceptions ++#ifdef ASSERT ++ Label L; ++ __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), ++ (int32_t) NULL_WORD); ++ __ jcc(Assembler::notEqual, L); ++ __ should_not_reach_here("Thread::pending_exception_offset"); ++ __ bind(L); ++#endif //ASSERT ++// __ push(RA); ++ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); ++ ++ ++ // codeBlob framesize is in words (not VMRegImpl::slot_size) ++ RuntimeStub* stub = ++ RuntimeStub::new_runtime_stub(name, ++ &code, ++ frame_complete, ++ (framesize >> (LogBytesPerWord - LogBytesPerInt)), ++ oop_maps, false); ++ return stub->entry_point(); ++ } ++ ++ // Initialization ++ void generate_initial() { ++ if (SafePatch) { ++ NativeCall::instruction_size = 6 * BytesPerInstWord; ++ NativeCall::return_address_offset = 6 * BytesPerInstWord; ++ NativeJump::instruction_size = 6 * BytesPerInstWord; ++ NativeJump::instruction_size = 6 * BytesPerInstWord; ++// NativeMovConstReg::instruction_size = 5 * BytesPerInstWord; ++// NativeMovConstReg::next_instruction_offset = 5 * BytesPerInstWord; ++ } ++ // Generate initial 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); ++ ++ // is referenced by megamorphic call ++ StubRoutines::_catch_exception_entry = generate_catch_exception(); ++ ++ // atomic calls ++ StubRoutines::_atomic_xchg_entry = generate_atomic_xchg(); ++ StubRoutines::_atomic_xchg_long_entry = generate_atomic_xchg_long(); ++ StubRoutines::_atomic_cmpxchg_entry = generate_atomic_cmpxchg(); ++ StubRoutines::_atomic_cmpxchg_byte_entry = generate_atomic_cmpxchg_byte(); ++ StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long(); ++ StubRoutines::_atomic_add_entry = generate_atomic_add(); ++ StubRoutines::_atomic_add_long_entry = generate_atomic_add_long(); ++ StubRoutines::_fence_entry = generate_orderaccess_fence(); ++ ++//// StubRoutines::_handler_for_unsafe_access_entry = generate_handler_for_unsafe_access(); ++ ++ StubRoutines::_throw_StackOverflowError_entry = ++ generate_throw_exception("StackOverflowError throw_exception", ++ CAST_FROM_FN_PTR(address, ++ SharedRuntime:: ++ throw_StackOverflowError)); ++ // platform dependent ++ StubRoutines::sw64::_get_previous_fp_entry = generate_get_previous_fp(); ++ StubRoutines::sw64::_get_previous_sp_entry = generate_get_previous_sp(); ++ if (UseCRC32Intrinsics) { ++ // set table address before stub generation which use it ++ StubRoutines::_crc_table_adr = (address)StubRoutines::sw64::_crc_table; ++ //ShouldNotReachHere(); ++ StubRoutines::_updateBytesCRC32 = CAST_FROM_FN_PTR(address, SharedRuntime::updateBytesCRC32); ++ } ++ } ++ ++ void generate_all() { ++ // Generates all stubs and initializes the entry points ++ ++ // These entry points require SharedInfo::stack0 to be set up in ++ // non-core builds and need to be relocatable, so they each ++ // fabricate a RuntimeStub internally. ++ StubRoutines::_throw_AbstractMethodError_entry = ++ generate_throw_exception("AbstractMethodError throw_exception", ++ CAST_FROM_FN_PTR(address, ++ SharedRuntime:: ++ throw_AbstractMethodError)); ++ ++ StubRoutines::_throw_IncompatibleClassChangeError_entry = ++ generate_throw_exception("IncompatibleClassChangeError throw_exception", ++ CAST_FROM_FN_PTR(address, ++ SharedRuntime:: ++ throw_IncompatibleClassChangeError)); ++ ++ StubRoutines::_throw_NullPointerException_at_call_entry = ++ generate_throw_exception("NullPointerException at call throw_exception", ++ CAST_FROM_FN_PTR(address, ++ SharedRuntime:: ++ throw_NullPointerException_at_call)); ++ ++ // entry points that are platform specific ++ ++ // support for verify_oop (must happen after universe_init) ++ StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); ++ // arraycopy stubs used by compilers ++ generate_arraycopy_stubs(); ++ ++ // 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); ++#ifdef COMPILER2 ++ //TODO:jzy ++ if (UseMontgomeryMultiplyIntrinsic) { ++ StubRoutines::_montgomeryMultiply ++ = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_multiply); ++ } ++ if (UseMontgomerySquareIntrinsic) { ++ StubRoutines::_montgomerySquare ++ = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square); ++ } ++#endif ++ ++ } ++ ++ public: ++ StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { ++ if (all) { ++ generate_all(); ++ } else { ++ generate_initial(); ++ } ++ } ++}; // end class declaration ++ ++void StubGenerator_generate(CodeBuffer* code, bool all) { ++ StubGenerator g(code, all); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/stubRoutines_sw64.cpp afu11u/src/hotspot/cpu/sw64/stubRoutines_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/stubRoutines_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/stubRoutines_sw64.cpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,95 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "runtime/deoptimization.hpp" ++#include "runtime/frame.inline.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "runtime/thread.inline.hpp" ++#include "utilities/globalDefinitions.hpp" ++ ++// Implementation of the platform-specific part of StubRoutines - for ++// a description of how to extend it, see the stubRoutines.hpp file. ++ ++//find the last fp value ++address StubRoutines::sw64::_get_previous_fp_entry = NULL; ++address StubRoutines::sw64::_get_previous_sp_entry = NULL; ++address StubRoutines::sw64::_call_stub_compiled_return = NULL; ++ ++juint StubRoutines::sw64::_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 ++}; +diff -uNr openjdk/src/hotspot/cpu/sw64/stubRoutines_sw64.hpp afu11u/src/hotspot/cpu/sw64/stubRoutines_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/stubRoutines_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/stubRoutines_sw64.hpp 2025-05-09 10:05:55.884290534 +0800 +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_STUBROUTINES_SW64_HPP ++#define CPU_SW64_VM_STUBROUTINES_SW64_HPP ++ ++// This file holds the platform specific parts of the StubRoutines ++// definition. See stubRoutines.hpp for a description on how to ++// extend it. ++ ++static bool returns_to_call_stub(address return_pc) { ++ return return_pc == _call_stub_return_address || return_pc == sw64::get_call_stub_compiled_return(); ++} ++ ++enum platform_dependent_constants { ++ code_size1 = 20000 LP64_ONLY(+12000), // simply increase if too small (assembler will crash if too small) ++ code_size2 = 42000 LP64_ONLY(+12000) // simply increase if too small (assembler will crash if too small) ++}; ++ ++class sw64 { ++ friend class StubGenerator; ++ friend class VMStructs; ++ private: ++ // If we call compiled code directly from the call stub we will ++ // need to adjust the return back to the call stub to a specialized ++ // piece of code that can handle compiled results and cleaning the fpu ++ // stack. The variable holds that location. ++ static address _call_stub_compiled_return; ++ static address _get_previous_fp_entry; ++ static address _get_previous_sp_entry; ++ static address _verify_mxcsr_entry; ++ // shuffle mask for fixing up 128-bit words consisting of big-endian 32-bit integers ++ static address _key_shuffle_mask_addr; ++ // masks and table for CRC32 ++ static uint64_t _crc_by128_masks[]; ++ static juint _crc_table[]; ++public: ++ // Call back points for traps in compiled code ++ static address get_previous_fp_entry() { return _get_previous_fp_entry; } ++ static address get_previous_sp_entry() { return _get_previous_sp_entry; } ++ static address get_call_stub_compiled_return() { return _call_stub_compiled_return; } ++ static void set_call_stub_compiled_return(address ret) { _call_stub_compiled_return = ret; } ++ ++}; ++ ++#endif // CPU_SW64_VM_STUBROUTINES_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/sw64.ad afu11u/src/hotspot/cpu/sw64/sw64.ad +--- openjdk/src/hotspot/cpu/sw64/sw64.ad 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/sw64.ad 2025-05-09 10:06:54.196292504 +0800 +@@ -0,0 +1,16196 @@ ++// ++// Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. ++// Copyright (c) 2014, 2019, Red Hat, Inc. All rights reserved. ++// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++// ++// This code is free software; you can redistribute it and/or modify it ++// under the terms of the GNU General Public License version 2 only, as ++// published by the Free Software Foundation. ++// ++// This code is distributed in the hope that it will be useful, but WITHOUT ++// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++// version 2 for more details (a copy is included in the LICENSE file that ++// accompanied this code). ++// ++// You should have received a copy of the GNU General Public License version ++// 2 along with this work; if not, write to the Free Software Foundation, ++// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++// ++// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++// or visit www.oracle.com if you need additional information or have any ++// questions. ++// ++// ++ ++// Sw64 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. ++ ++// format: ++// reg_def name (call convention, c-call convention, ideal type, encoding); ++// call convention : ++// NS = No-Save ++// SOC = Save-On-Call ++// SOE = Save-On-Entry ++// AS = Always-Save ++// ideal type : ++// see opto/opcodes.hpp for more info ++// reg_class name (reg, ...); ++// alloc_class name (reg, ...); ++ ++register %{ ++// We must define the 64 bit int registers in two 32 bit halves, the ++// real lower register and a virtual upper half register. upper halves ++// are used by the register allocator but are not actually supplied as ++// operands to memory ops. ++// ++// follow the C1 compiler in making registers ++// ++// r0-r7,r10-r26 volatile (caller save) ++// r27-r32 system (no save, no allocate) ++// r8-r9 invisible to the allocator (so we can use them as scratch regs) ++// ++// as regards Java usage. we don't use any callee save registers ++// because this makes it difficult to de-optimise a frame (see comment ++// in x86 implementation of Deoptimization::unwind_callee_save_values) ++// ++ ++// General Registers ++// Integer Registers ++reg_def V0 (SOC, SOC, Op_RegI, 0, i0->as_VMReg()); ++reg_def V0_H (SOC, SOC, Op_RegI, 0, i0->as_VMReg()->next()); ++ ++reg_def T0 (SOC, SOC, Op_RegI, 1, i1->as_VMReg()); ++reg_def T0_H (SOC, SOC, Op_RegI, 1, i1->as_VMReg()->next()); ++reg_def T1 (SOC, SOC, Op_RegI, 2, i2->as_VMReg()); ++reg_def T1_H (SOC, SOC, Op_RegI, 2, i2->as_VMReg()->next()); ++reg_def T2 (SOC, SOC, Op_RegI, 3, i3->as_VMReg()); ++reg_def T2_H (SOC, SOC, Op_RegI, 3, i3->as_VMReg()->next()); ++reg_def T3 (SOC, SOC, Op_RegI, 4, i4->as_VMReg()); ++reg_def T3_H (SOC, SOC, Op_RegI, 4, i4->as_VMReg()->next()); ++reg_def T4 (SOC, SOC, Op_RegI, 5, i5->as_VMReg()); ++reg_def T4_H (SOC, SOC, Op_RegI, 5, i5->as_VMReg()->next()); ++reg_def T5 (SOC, SOC, Op_RegI, 6, i6->as_VMReg()); ++reg_def T5_H (SOC, SOC, Op_RegI, 6, i6->as_VMReg()->next()); ++reg_def T6 (SOC, SOC, Op_RegI, 7, i7->as_VMReg()); ++reg_def T6_H (SOC, SOC, Op_RegI, 7, i7->as_VMReg()->next()); ++reg_def T7 (SOC, SOC, Op_RegI, 8, i8->as_VMReg()); ++reg_def T7_H (SOC, SOC, Op_RegI, 8, i8->as_VMReg()->next()); ++ ++reg_def S0 (SOC, SOE, Op_RegI, 9, i9->as_VMReg()); ++reg_def S0_H (SOC, SOE, Op_RegI, 9, i9->as_VMReg()->next()); ++reg_def S1 (SOC, SOE, Op_RegI, 10, i10->as_VMReg()); ++reg_def S1_H (SOC, SOE, Op_RegI, 10, i10->as_VMReg()->next()); ++reg_def S2 (SOC, SOE, Op_RegI, 11, i11->as_VMReg()); ++reg_def S2_H (SOC, SOE, Op_RegI, 11, i11->as_VMReg()->next()); ++reg_def S3 (SOC, SOE, Op_RegI, 12, i12->as_VMReg()); ++reg_def S3_H (SOC, SOE, Op_RegI, 12, i12->as_VMReg()->next()); ++reg_def S4 (SOC, SOE, Op_RegI, 13, i13->as_VMReg()); ++reg_def S4_H (SOC, SOE, Op_RegI, 13, i13->as_VMReg()->next()); ++reg_def S5 (SOC, SOE, Op_RegI, 14, i14->as_VMReg()); ++reg_def S5_H (SOC, SOE, Op_RegI, 14, i14->as_VMReg()->next()); ++reg_def FP ( NS, SOE, Op_RegI, 15, i15->as_VMReg()); ++reg_def FP_H ( NS, SOE, Op_RegI, 15, i15->as_VMReg()->next()); ++ ++reg_def A0 (SOC, SOC, Op_RegI, 16, i16->as_VMReg()); ++reg_def A0_H (SOC, SOC, Op_RegI, 16, i16->as_VMReg()->next()); ++reg_def A1 (SOC, SOC, Op_RegI, 17, i17->as_VMReg()); ++reg_def A1_H (SOC, SOC, Op_RegI, 17, i17->as_VMReg()->next()); ++reg_def A2 (SOC, SOC, Op_RegI, 18, i18->as_VMReg()); ++reg_def A2_H (SOC, SOC, Op_RegI, 18, i18->as_VMReg()->next()); ++reg_def A3 (SOC, SOC, Op_RegI, 19, i19->as_VMReg()); ++reg_def A3_H (SOC, SOC, Op_RegI, 19, i19->as_VMReg()->next()); ++reg_def A4 (SOC, SOC, Op_RegI, 20, i20->as_VMReg()); ++reg_def A4_H (SOC, SOC, Op_RegI, 20, i20->as_VMReg()->next()); ++reg_def A5 (SOC, SOC, Op_RegI, 21, i21->as_VMReg()); ++reg_def A5_H (SOC, SOC, Op_RegI, 21, i21->as_VMReg()->next()); ++ ++reg_def T8 (SOC, SOC, Op_RegI, 22, i22->as_VMReg()); ++reg_def T8_H (SOC, SOC, Op_RegI, 22, i22->as_VMReg()->next()); ++reg_def T9 (SOC, SOC, Op_RegI, 23, i23->as_VMReg()); ++reg_def T9_H (SOC, SOC, Op_RegI, 23, i23->as_VMReg()->next()); ++reg_def T10 (SOC, SOC, Op_RegI, 24, i24->as_VMReg()); ++reg_def T10_H (SOC, SOC, Op_RegI, 24, i24->as_VMReg()->next()); ++reg_def T11 (SOC, SOC, Op_RegI, 25, i25->as_VMReg()); ++reg_def T11_H (SOC, SOC, Op_RegI, 25, i25->as_VMReg()->next()); ++reg_def RA ( NS, NS, Op_RegI, 26, i26->as_VMReg()); ++reg_def RA_H ( NS, NS, Op_RegI, 26, i26->as_VMReg()->next()); ++reg_def T12 (SOC, SOC, Op_RegI, 27, i27->as_VMReg()); ++reg_def T12_H (SOC, SOC, Op_RegI, 27, i27->as_VMReg()->next()); ++reg_def AT ( NS, NS, Op_RegI, 28, i28->as_VMReg()); ++reg_def AT_H ( NS, NS, Op_RegI, 28, i28->as_VMReg()->next()); ++reg_def GP ( NS, NS, Op_RegI, 29, i29->as_VMReg()); ++reg_def GP_H ( NS, NS, Op_RegI, 29, i29->as_VMReg()->next()); ++reg_def SP ( NS, NS, Op_RegI, 30, i30->as_VMReg()); ++reg_def SP_H ( NS, NS, Op_RegI, 30, i30->as_VMReg()->next()); ++reg_def R0 ( NS, NS, Op_RegI, 31, VMRegImpl::Bad()); ++ ++// Floating registers. ++reg_def F0 ( SOC, SOC, Op_RegF, 0, f0->as_VMReg()); ++reg_def F0_H ( SOC, SOC, Op_RegF, 0, f0->as_VMReg()->next()); ++reg_def F1 ( SOC, SOC, Op_RegF, 1, f1->as_VMReg()); ++reg_def F1_H ( SOC, SOC, Op_RegF, 1, f1->as_VMReg()->next()); ++reg_def F2 ( SOC, SOC, Op_RegF, 2, f2->as_VMReg()); ++reg_def F2_H ( SOC, SOC, Op_RegF, 2, f2->as_VMReg()->next()); ++reg_def F3 ( SOC, SOC, Op_RegF, 3, f3->as_VMReg()); ++reg_def F3_H ( SOC, SOC, Op_RegF, 3, f3->as_VMReg()->next()); ++reg_def F4 ( SOC, SOC, Op_RegF, 4, f4->as_VMReg()); ++reg_def F4_H ( SOC, SOC, Op_RegF, 4, f4->as_VMReg()->next()); ++reg_def F5 ( SOC, SOC, Op_RegF, 5, f5->as_VMReg()); ++reg_def F5_H ( SOC, SOC, Op_RegF, 5, f5->as_VMReg()->next()); ++reg_def F6 ( SOC, SOC, Op_RegF, 6, f6->as_VMReg()); ++reg_def F6_H ( SOC, SOC, Op_RegF, 6, f6->as_VMReg()->next()); ++reg_def F7 ( SOC, SOC, Op_RegF, 7, f7->as_VMReg()); ++reg_def F7_H ( SOC, SOC, Op_RegF, 7, f7->as_VMReg()->next()); ++reg_def F8 ( SOC, SOC, Op_RegF, 8, f8->as_VMReg()); ++reg_def F8_H ( SOC, SOC, Op_RegF, 8, f8->as_VMReg()->next()); ++reg_def F9 ( SOC, SOC, Op_RegF, 9, f9->as_VMReg()); ++reg_def F9_H ( SOC, SOC, Op_RegF, 9, f9->as_VMReg()->next()); ++reg_def F10 ( SOC, SOC, Op_RegF, 10, f10->as_VMReg()); ++reg_def F10_H ( SOC, SOC, Op_RegF, 10, f10->as_VMReg()->next()); ++reg_def F11 ( SOC, SOC, Op_RegF, 11, f11->as_VMReg()); ++reg_def F11_H ( SOC, SOC, Op_RegF, 11, f11->as_VMReg()->next()); ++reg_def F12 ( SOC, SOC, Op_RegF, 12, f12->as_VMReg()); ++reg_def F12_H ( SOC, SOC, Op_RegF, 12, f12->as_VMReg()->next()); ++reg_def F13 ( SOC, SOC, Op_RegF, 13, f13->as_VMReg()); ++reg_def F13_H ( SOC, SOC, Op_RegF, 13, f13->as_VMReg()->next()); ++reg_def F14 ( SOC, SOC, Op_RegF, 14, f14->as_VMReg()); ++reg_def F14_H ( SOC, SOC, Op_RegF, 14, f14->as_VMReg()->next()); ++reg_def F15 ( SOC, SOC, Op_RegF, 15, f15->as_VMReg()); ++reg_def F15_H ( SOC, SOC, Op_RegF, 15, f15->as_VMReg()->next()); ++reg_def F16 ( SOC, SOC, Op_RegF, 16, f16->as_VMReg()); ++reg_def F16_H ( SOC, SOC, Op_RegF, 16, f16->as_VMReg()->next()); ++reg_def F17 ( SOC, SOC, Op_RegF, 17, f17->as_VMReg()); ++reg_def F17_H ( SOC, SOC, Op_RegF, 17, f17->as_VMReg()->next()); ++reg_def F18 ( SOC, SOC, Op_RegF, 18, f18->as_VMReg()); ++reg_def F18_H ( SOC, SOC, Op_RegF, 18, f18->as_VMReg()->next()); ++reg_def F19 ( SOC, SOC, Op_RegF, 19, f19->as_VMReg()); ++reg_def F19_H ( SOC, SOC, Op_RegF, 19, f19->as_VMReg()->next()); ++reg_def F20 ( SOC, SOC, Op_RegF, 20, f20->as_VMReg()); ++reg_def F20_H ( SOC, SOC, Op_RegF, 20, f20->as_VMReg()->next()); ++reg_def F21 ( SOC, SOC, Op_RegF, 21, f21->as_VMReg()); ++reg_def F21_H ( SOC, SOC, Op_RegF, 21, f21->as_VMReg()->next()); ++reg_def F22 ( SOC, SOC, Op_RegF, 22, f22->as_VMReg()); ++reg_def F22_H ( SOC, SOC, Op_RegF, 22, f22->as_VMReg()->next()); ++reg_def F23 ( SOC, SOC, Op_RegF, 23, f23->as_VMReg()); ++reg_def F23_H ( SOC, SOC, Op_RegF, 23, f23->as_VMReg()->next()); ++reg_def F24 ( SOC, SOC, Op_RegF, 24, f24->as_VMReg()); ++reg_def F24_H ( SOC, SOC, Op_RegF, 24, f24->as_VMReg()->next()); ++reg_def F25 ( SOC, SOC, Op_RegF, 25, f25->as_VMReg()); ++reg_def F25_H ( SOC, SOC, Op_RegF, 25, f25->as_VMReg()->next()); ++reg_def F26 ( SOC, SOC, Op_RegF, 26, f26->as_VMReg()); ++reg_def F26_H ( SOC, SOC, Op_RegF, 26, f26->as_VMReg()->next()); ++reg_def F27 ( SOC, SOC, Op_RegF, 27, f27->as_VMReg()); ++reg_def F27_H ( SOC, SOC, Op_RegF, 27, f27->as_VMReg()->next()); ++reg_def F28 ( SOC, SOC, Op_RegF, 28, f28->as_VMReg()); ++reg_def F28_H ( SOC, SOC, Op_RegF, 28, f28->as_VMReg()->next()); ++reg_def F29 ( SOC, SOC, Op_RegF, 29, f29->as_VMReg()); ++reg_def F29_H ( SOC, SOC, Op_RegF, 29, f29->as_VMReg()->next()); ++reg_def F30 ( SOC, SOC, Op_RegF, 30, f30->as_VMReg()); ++reg_def F30_H ( SOC, SOC, Op_RegF, 30, f30->as_VMReg()->next()); ++reg_def F31 ( SOC, SOC, Op_RegF, 31, f31->as_VMReg()); ++reg_def F31_H ( SOC, SOC, Op_RegF, 31, f31->as_VMReg()->next()); ++ ++ ++// ---------------------------- ++// Special Registers ++// Condition Codes Flag Registers ++// swjdk11 flag reg is GP ++reg_def SW64_FLAG (SOC, SOC, Op_RegFlags, 29, as_Register(29)->as_VMReg()); ++ ++//S2 is used for get_thread(S2) ++//S5 is uesd for heapbase of compressed oop ++alloc_class chunk0( ++ S0, S0_H, ++ S1, S1_H, ++ S3, S3_H, ++ S4, S4_H, ++ S5, S5_H, ++ S2, S2_H, ++ T2, T2_H, ++ T3, T3_H, ++ //T11, T11_H, jzy use rscratch3 ++ T12, T12_H, ++ T1, T1_H, // inline_cache_reg ++ A5, A5_H, ++ A4, A4_H, ++ V0, V0_H, ++ A3, A3_H, ++ A2, A2_H, ++ A1, A1_H, ++ A0, A0_H, ++ T0, T0_H, ++ T4, T4_H, ++ T5, T5_H, ++ T6, T6_H, ++ T7, T7_H, ++ T8, T8_H, ++ T9, T9_H, ++ T10, T10_H, ++ GP, GP_H, ++ RA, RA_H, ++ AT, AT_H, ++ SP, SP_H, // stack_pointer ++ FP, FP_H // frame_pointer ++ ); ++ ++alloc_class chunk1( F0, F0_H, ++ F1, F1_H, ++ F2, F2_H, ++ F3, F3_H, ++ F4, F4_H, ++ F5, F5_H, ++ F6, F6_H, ++ F7, F7_H, ++ F8, F8_H, ++ F9, F9_H, ++ F10, F10_H, ++ F11, F11_H, ++ F20, F20_H, ++ F21, F21_H, ++ F22, F22_H, ++ F23, F23_H, ++ F24, F24_H, ++ F25, F25_H, ++ F26, F26_H, ++ F27, F27_H, ++ F28, F28_H, ++ F19, F19_H, ++ F18, F18_H, ++ F17, F17_H, ++ F16, F16_H, ++ F15, F15_H, ++ F14, F14_H, ++ F13, F13_H, ++ F12, F12_H, ++ F29, F29_H, ++ F30, F30_H, ++ F31, F31_H); ++ ++alloc_class chunk2(SW64_FLAG); ++ ++reg_class s_reg( S0, S1, S2, S3, S4, S5 ); ++reg_class s0_reg( S0 ); ++reg_class s1_reg( S1 ); ++reg_class s2_reg( S2 ); ++reg_class s3_reg( S3 ); ++reg_class s4_reg( S4 ); ++reg_class s5_reg( S5 ); ++ ++//reg_class t_reg( T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 ); //jzy ++reg_class t_reg( T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T12 ); ++reg_class t0_reg( T0 ); ++reg_class t1_reg( T1 ); ++reg_class t2_reg( T2 ); ++reg_class t3_reg( T3 ); ++reg_class t4_reg( T4 ); ++reg_class t5_reg( T5 ); ++reg_class t6_reg( T6 ); ++reg_class t7_reg( T7 ); ++reg_class t8_reg( T8 ); ++reg_class t9_reg( T9 ); ++reg_class t10_reg( T10 ); ++//reg_class t11_reg( T11 ); ++reg_class t12_reg( T12 ); ++ ++reg_class a_reg( A0, A1, A2, A3, A4, A5 ); ++reg_class a0_reg( A0 ); ++reg_class a1_reg( A1 ); ++reg_class a2_reg( A2 ); ++reg_class a3_reg( A3 ); ++reg_class a4_reg( A4 ); ++reg_class a5_reg( A5 ); ++ ++reg_class v0_reg( V0 ); ++ ++reg_class sp_reg( SP, SP_H ); ++reg_class fp_reg( FP, FP_H ); ++ ++reg_class sw64_flags(SW64_FLAG); ++ ++reg_class v0_long_reg( V0, V0_H ); ++ ++reg_class t0_long_reg( T0, T0_H ); ++reg_class t1_long_reg( T1, T1_H ); ++reg_class t2_long_reg( T2, T2_H ); ++reg_class t3_long_reg( T3, T3_H ); ++reg_class t4_long_reg( T4, T4_H ); ++reg_class t5_long_reg( T5, T5_H ); ++reg_class t6_long_reg( T6, T6_H ); ++reg_class t7_long_reg( T7, T7_H ); ++reg_class t8_long_reg( T8, T8_H ); ++reg_class t9_long_reg( T9, T9_H ); ++reg_class t10_long_reg( T10, T10_H ); ++//reg_class t11_long_reg( T11, T11_H ); jzy ++reg_class t12_long_reg( T12, T12_H ); ++ ++reg_class a0_long_reg( A0, A0_H ); ++reg_class a1_long_reg( A1, A1_H ); ++reg_class a2_long_reg( A2, A2_H ); ++reg_class a3_long_reg( A3, A3_H ); ++reg_class a4_long_reg( A4, A4_H ); ++reg_class a5_long_reg( A5, A5_H ); ++ ++reg_class s0_long_reg( S0, S0_H ); ++reg_class s1_long_reg( S1, S1_H ); ++reg_class s2_long_reg( S2, S2_H ); ++reg_class s3_long_reg( S3, S3_H ); ++reg_class s4_long_reg( S4, S4_H ); ++reg_class s5_long_reg( S5, S5_H ); ++ ++//TODO:order is OK? jzy ++//TODO:no S2 & S5 jzy ++//NO T12? ++//reg_class int_reg( S1, S0, S4, S3, T11, T2, T3, T1, A5, A4, V0, A3, A2, A1, A0, T0, T4, T5, T6, T7, T8, T9, T10 ); jzy ++reg_class int_reg( S1, S0, S4, S3, T2, T3, T1, A5, A4, V0, A3, A2, A1, A0, T0, T4, T5, T6, T7, T8, T9, T10 ); ++//TODO:no S2 & S5 jzy ++//NO T12? ++//reg_class no_Ax_int_reg( S1, S0, S4, S3, T11, T2, T3, T1, V0, T0, T4, T5, T6, T7, T8, T9, T10 ); jzy ++reg_class no_Ax_int_reg( S1, S0, S4, S3, T2, T3, T1, V0, T0, T4, T5, T6, T7, T8, T9, T10 ); ++//TODO: no S2 & S5 ++reg_class any_reg( // without FP ++ S1, S1_H, ++ S0, S0_H, ++ S4, S4_H, ++ S3, S3_H, ++ T11, T11_H, ++ T2, T2_H, ++ T3, T3_H, ++ T1, T1_H, ++ A5, A5_H, ++ A4, A4_H, ++ A3, A3_H, ++ A2, A2_H, ++ A1, A1_H, ++ A0, A0_H, ++ T0, T0_H, ++ T4, T4_H, ++ T5, T5_H, ++ T6, T6_H, ++ T7, T7_H, ++ T8, T8_H, ++ T9, T9_H, ++ T10, T10_H, ++ S2, S2_H, // TLS thread ++ S5, S5_H, // heapbase ++ V0, V0_H, ++ RA, RA_H, ++ T12, T12_H, ++ AT, AT_H, ++ GP, GP_H, ++ SP, SP_H, ++); ++reg_class ptr_reg( ++ S1, S1_H, ++ S0, S0_H, ++ S4, S4_H, ++ S3, S3_H, ++ //T11, T11_H, jzy ++ T2, T2_H, ++ T3, T3_H, ++ T1, T1_H, ++ A5, A5_H, ++ A4, A4_H, ++ A3, A3_H, ++ A2, A2_H, ++ A1, A1_H, ++ A0, A0_H, ++ T0, T0_H, ++ T4, T4_H, ++ T5, T5_H, ++ T6, T6_H, ++ T7, T7_H, ++ T8, T8_H, ++ T9, T9_H, ++ T10, T10_H, ++ V0, V0_H ++ ); ++//TODO:who no T11? what perpose of T11? jzy ++reg_class no_T11_p_reg( ++ S1, S1_H, ++ S0, S0_H, ++ S4, S4_H, ++ S3, S3_H, ++ T2, T2_H, ++ T3, T3_H, ++ T1, T1_H, ++ A5, A5_H, ++ A4, A4_H, ++ A3, A3_H, ++ A2, A2_H, ++ A1, A1_H, ++ A0, A0_H, ++ T0, T0_H, ++ T4, T4_H, ++ T5, T5_H, ++ T6, T6_H, ++ T7, T7_H, ++ T8, T8_H, ++ T9, T9_H, ++ T10, T10_H, ++ V0, V0_H ++ ); ++ ++reg_class long_reg( ++ S1, S1_H, ++ S0, S0_H, ++ S4, S4_H, ++ S3, S3_H, ++ //T11, T11_H, jzy ++ T2, T2_H, ++ T3, T3_H, ++ T1, T1_H, ++ A5, A5_H, ++ A4, A4_H, ++ A3, A3_H, ++ A2, A2_H, ++ A1, A1_H, ++ A0, A0_H, ++ T0, T0_H, ++ T4, T4_H, ++ T5, T5_H, ++ T6, T6_H, ++ T7, T7_H, ++ T8, T8_H, ++ T9, T9_H, ++ T10, T10_H, ++ V0, V0_H ++ ); ++ ++ ++// Floating point registers. ++//2017/9/6 zyh: F28&F29 are used as temporary registers in float cmp instructs ++reg_class flt_reg( 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); ++reg_class dbl_reg( F0, F0_H, ++ F1, F1_H, ++ F2, F2_H, ++ F3, F3_H, ++ F4, F4_H, ++ F5, F5_H, ++ F6, F6_H, ++ F7, F7_H, ++ F8, F8_H, ++ F9, F9_H, ++ F10, F10_H, ++ F11, F11_H, ++ F12, F12_H, ++ F13, F13_H, ++ F14, F14_H, ++ F15, F15_H, ++ F16, F16_H, ++ F17, F17_H, ++ F18, F18_H, ++ F19, F19_H, ++ F20, F20_H, ++ F21, F21_H, ++ F22, F22_H, ++ F23, F23_H, ++ F24, F24_H, ++ F25, F25_H, ++ F26, F26_H, ++ F27, F27_H, ++// F28, F28_H, ++// F29, F29_H ++ ); ++ ++reg_class flt_arg0( F16 ); ++reg_class dbl_arg0( F16, F16_H ); ++reg_class dbl_arg1( F17, F17_H ); ++reg_class dbl_tmp_f27( F27, F27_H ); ++reg_class dbl_tmp_f28( F28, F28_H ); ++reg_class dbl_tmp_f29( F29, F29_H ); ++reg_class dbl_tmp_f30( F30, F30_H ); ++ ++%} ++ ++//----------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 %{ ++ //int_def DEFAULT_COST ( 100, 100); ++ int_def HUGE_COST (1000000, 1000000); ++ int_def INSN_COST ( 100, 100); ++ ++ // Memory refs are twice as expensive as run-of-the-mill. ++ int_def MEMORY_REF_COST ( 200, INSN_COST * 2); ++ // Branches are even more expensive. ++ int_def BRANCH_COST ( 300, INSN_COST * 3); ++ // we use jr instruction to construct call, so more expensive ++ int_def CALL_COST ( 500, INSN_COST * 5); ++ int_def VOLATILE_REF_COST ( 1000, INSN_COST * 10); //not in 8?? CHECK djx ++%} ++ ++ ++//----------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. ++ ++#if INCLUDE_ZGC ++#include "gc/z/zBarrierSetAssembler.hpp" ++#endif ++#include "opto/machnode.hpp" ++#include "asm/macroAssembler.hpp" ++#include "gc/shared/cardTable.hpp" ++#include "gc/shared/cardTableBarrierSet.hpp" ++#include "gc/shared/collectedHeap.hpp" ++#include "opto/addnode.hpp" ++ ++class NativeJump; ++ ++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() { ++ // NativeCall instruction size is the same as NativeJump. ++ // exception handler starts out as jump and can be patched to ++ // a call be deoptimization. (4932387) ++ // Note that this value is also credited (in output.cpp) to ++ // the size of the code section. ++ int size = NativeJump::instruction_size; ++// int size = NativeCall::instruction_size; ++ return align_up(size, 16);//need align_up? jzy ++ } ++ ++ static uint size_deopt_handler() { ++ int size = NativeCall::instruction_size; // BytesPerInstWord; //li48(4) + call(1) ++ return align_up(size, 16);//need align_up? jzy ++ } ++ ++}; ++ ++ bool is_CAS(int opcode); ++ bool unnecessary_release(const Node *barrier); ++ // predicate controlling translation of StoreCM ++ bool unnecessary_storestore(const Node *storecm); ++ ++%} // end source_hpp ++ ++source %{ ++ ++ ++#define __ _masm. ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++ ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++ // is_CAS(int opcode) ++ // ++ // return true if opcode is one of the possible CompareAndSwapX ++ // values otherwise false. ++ ++bool is_CAS(int opcode) ++{ ++ switch(opcode) { ++ // We handle these ++ case Op_CompareAndSwapI: ++ case Op_CompareAndSwapL: ++ case Op_CompareAndSwapP: ++ case Op_CompareAndSwapN: ++ case Op_GetAndSetI: ++ case Op_GetAndSetL: ++ case Op_GetAndSetP: ++ case Op_GetAndSetN: ++ case Op_GetAndAddI: ++ case Op_GetAndAddL: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool unnecessary_release(const Node *n) ++{ ++ assert((n->is_MemBar() && ++ n->Opcode() == Op_MemBarRelease), ++ "expecting a release membar"); ++ ++ MemBarNode *barrier = n->as_MemBar(); ++ ++ if (!barrier->leading()) { ++ return false; ++ } else { ++ Node* trailing = barrier->trailing_membar(); ++ MemBarNode* trailing_mb = trailing->as_MemBar(); ++ assert(trailing_mb->trailing(), "Not a trailing membar?"); ++ assert(trailing_mb->leading_membar() == n, "inconsistent leading/trailing membars"); ++ ++ Node* mem = trailing_mb->in(MemBarNode::Precedent); ++ if (!mem->is_Store()) { ++ assert(mem->is_LoadStore(), ""); ++ assert(trailing_mb->Opcode() == Op_MemBarAcquire, ""); ++ return is_CAS(mem->Opcode()); ++ } ++ } ++ ++ return false; ++} ++ ++bool unnecessary_storestore(const Node *storecm) ++{ ++ assert(storecm->Opcode() == Op_StoreCM, "expecting a StoreCM"); ++ ++ // we need to generate a dmb ishst between an object put and the ++ // associated card mark when we are using CMS without conditional ++ // card marking ++ ++ if (UseConcMarkSweepGC && !UseCondCardMark) { ++ return false; ++ } ++ ++ // a storestore is unnecesary in all other cases ++ ++ return true; ++} ++ ++// Emit exception handler code. ++// Stuff framesize into a register and call a VM stub routine. ++ int HandlerImpl::emit_exception_handler(CodeBuffer & cbuf) { ++ // Note that the code buffer's insts_mark is always relative to insts. ++ // That's why we must use the macroassembler to generate a handler. ++ 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(); ++ ++ __ block_comment("; emit_exception_handler"); ++ ++ //cbuf.set_insts_mark(); ++ //__ relocate(relocInfo::runtime_call_type); ++ //__ patchable_jump((address)(OptoRuntime::exception_blob()->entry_point())); ++ __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); ++ __ align(16); ++ assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); ++ __ end_a_stub(); ++ return offset; ++ // return 0; ++ } ++ ++// Emit deopt handler code. ++int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { ++ ++ // Note that the code buffer's insts_mark is always relative to insts. ++ // That's why we must use the macroassembler to generate a handler. ++ 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 ++ } ++ //__ stop("TODO:not check jzy(emit_deopt_handler)"); ++ int offset = __ offset(); ++ address the_pc = (address) __ pc(); ++ __ block_comment("; emit_deopt_handler"); ++ if(UseAddpi){ ++ __ addpi(-1, RA); ++ }else{ ++ __ br(RA, 0); ++ __ subptr(RA, BytesPerInstWord, RA);//point to the begin of deopt ++ } ++ __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); ++ __ align(16); ++ assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); ++ __ end_a_stub(); ++ return offset; ++} ++ ++ ++//============================================================================= ++ ++/* ++ // Float masks come from different places depending on platform. ++#ifdef _LP64 ++ static address float_signmask() { return StubRoutines::x86::float_sign_mask(); } ++ static address float_signflip() { return StubRoutines::x86::float_sign_flip(); } ++ static address double_signmask() { return StubRoutines::x86::double_sign_mask(); } ++ static address double_signflip() { return StubRoutines::x86::double_sign_flip(); } ++#else ++ static address float_signmask() { return (address)float_signmask_pool; } ++ static address float_signflip() { return (address)float_signflip_pool; } ++ static address double_signmask() { return (address)double_signmask_pool; } ++ static address double_signflip() { return (address)double_signflip_pool; } ++#endif ++*/ ++ ++ ++const bool Matcher::match_rule_supported(int opcode) { ++ if (!has_match_rule(opcode)) ++ return false; ++ ++ switch (opcode) { ++ //Op_CountLeadingZerosI Op_CountLeadingZerosL can be deleted, all MIPS CPUs support clz & dclz. ++ case Op_CountLeadingZerosI: ++ case Op_CountLeadingZerosL: ++ if (!UseCountLeadingZerosInstruction) ++ return false; ++ break; ++ case Op_CountTrailingZerosI: ++ case Op_CountTrailingZerosL: ++ if (!UseCountTrailingZerosInstruction) ++ return false; ++ break; ++ } ++ ++ return true; // Per default match rules are supported. ++} ++ ++ const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { ++ // 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); ++ /*if (ret_value) { ++ switch (opcode) { ++ case Op_AddVB: ++ case Op_SubVB: ++ if ((vlen == 64) && (VM_Version::supports_avx512bw() == false)) ++ ret_value = false; ++ break; ++ case Op_URShiftVS: ++ case Op_RShiftVS: ++ case Op_LShiftVS: ++ case Op_MulVS: ++ case Op_AddVS: ++ case Op_SubVS: ++ if ((vlen == 32) && (VM_Version::supports_avx512bw() == false)) ++ ret_value = false; ++ break; ++ case Op_CMoveVF: ++ if (vlen != 8) ++ ret_value = false; ++ break; ++ case Op_CMoveVD: ++ if (vlen != 4) ++ ret_value = false; ++ break; ++ } ++ }*/ ++ ++ return ret_value; // Per default match rules are supported. ++} ++ ++const bool Matcher::has_predicated_vectors(void) { ++ bool ret_value = false; ++ /*if (UseAVX > 2) { ++ ret_value = VM_Version::supports_avx512vl(); ++ }*/ ++ ++ return ret_value; ++} ++ ++const int Matcher::float_pressure(int default_pressure_threshold) { ++ int float_pressure_threshold = default_pressure_threshold; ++ /* ++#ifdef _LP64 ++ if (UseAVX > 2) { ++ // Increase pressure threshold on machines with AVX3 which have ++ // 2x more XMM registers. ++ float_pressure_threshold = default_pressure_threshold * 2; ++ } ++#endif ++ */ ++ return float_pressure_threshold; ++} ++ ++// Max vector size in bytes. 0 if not supported. ++const int Matcher::vector_width_in_bytes(BasicType bt) { ++ /*assert(is_java_primitive(bt), "only primitive type vectors"); ++ if (UseSSE < 2) return 0; ++ // SSE2 supports 128bit vectors for all types. ++ // AVX2 supports 256bit vectors for all types. ++ // AVX2/EVEX supports 512bit vectors for all types. ++ int size = (UseAVX > 1) ? (1 << UseAVX) * 8 : 16; ++ // AVX1 supports 256bit vectors only for FLOAT and DOUBLE. ++ if (UseAVX > 0 && (bt == T_FLOAT || bt == T_DOUBLE)) ++ size = (UseAVX > 2) ? 64 : 32; ++ if (UseAVX > 2 && (bt == T_BYTE || bt == T_SHORT || bt == T_CHAR)) ++ size = (VM_Version::supports_avx512bw()) ? 64 : 32; ++ // Use flag to limit vector size. ++ size = MIN2(size,(int)MaxVectorSize); ++ // Minimum 2 values in vector (or 4 for bytes). ++ switch (bt) { ++ case T_DOUBLE: ++ case T_LONG: ++ if (size < 16) return 0; ++ break; ++ case T_FLOAT: ++ case T_INT: ++ if (size < 8) return 0; ++ break; ++ case T_BOOLEAN: ++ if (size < 4) return 0; ++ break; ++ case T_CHAR: ++ if (size < 4) return 0; ++ break; ++ case T_BYTE: ++ if (size < 4) return 0; ++ break; ++ case T_SHORT: ++ if (size < 4) return 0; ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ return size;*/ ++ return 0; ++} ++ ++// 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. ++} ++ ++// Vector ideal reg ++const uint Matcher::vector_ideal_reg(int size) { ++ assert(MaxVectorSize == 8, ""); ++ switch(size) { ++ case 8: return Op_VecD; ++ } ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++// Only lowest bits of xmm reg are used for vector shift count. ++const uint Matcher::vector_shift_count_ideal_reg(int size) { ++ fatal("vector shift is not supported"); ++ return Node::NotAMachineReg; ++} ++ ++// SW64 supports misaligned vectors store/load? FIXME ++const bool Matcher::misaligned_vectors_ok() { ++ return false; ++ //return !AlignVector; // can be changed by flag ++} ++ ++// SW64 doesn't support AES intrinsics ++const bool Matcher::pass_original_key_for_aes() { ++ return false; ++} ++ ++ ++const bool Matcher::convi2l_type_required = true; ++ ++// Should the Matcher clone shifts on addressing modes, expecting them ++// to be subsumed into complex addressing expressions or compute them ++// into registers? ++bool Matcher::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) { ++} ++/* ++// Helper methods for MachSpillCopyNode::implementation(). ++static int vec_mov_helper(CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo, ++ int src_hi, int dst_hi, uint ireg, outputStream* st) { ++ // In 64-bit VM size calculation is very complex. Emitting instructions ++ // into scratch buffer is used to get size in 64-bit VM. ++ /* ++ LP64_ONLY( assert(!do_size, "this method calculates size only for 32-bit VM"); ) ++ assert(ireg == Op_VecS || // 32bit vector ++ (src_lo & 1) == 0 && (src_lo + 1) == src_hi && ++ (dst_lo & 1) == 0 && (dst_lo + 1) == dst_hi, ++ "no non-adjacent vector moves" ); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ int offset = __ offset(); ++ switch (ireg) { ++ case Op_VecS: // copy whole register ++ case Op_VecD: ++ case Op_VecX: ++#ifndef _LP64 ++ __ movdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); ++#else ++ if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { ++ __ movdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); ++ } else { ++ __ vextractf32x4(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo]), 0x0); ++ } ++#endif ++ break; ++ case Op_VecY: ++#ifndef _LP64 ++ __ vmovdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); ++#else ++ if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { ++ __ vmovdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); ++ } else { ++ __ vextractf64x4(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo]), 0x0); ++ } ++#endif ++ break; ++ case Op_VecZ: ++ __ evmovdquq(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo]), 2); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ int size = __ offset() - offset; ++#ifdef ASSERT ++ // VEX_2bytes prefix is used if UseAVX > 0, so it takes the same 2 bytes as SIMD prefix. ++ assert(!do_size || size == 4, "incorrect size calculattion"); ++#endif ++ return size; ++#ifndef PRODUCT ++ } else if (!do_size) { ++ switch (ireg) { ++ case Op_VecS: ++ case Op_VecD: ++ case Op_VecX: ++ st->print("movdqu %s,%s\t# spill",Matcher::regName[dst_lo],Matcher::regName[src_lo]); ++ break; ++ case Op_VecY: ++ case Op_VecZ: ++ st->print("vmovdqu %s,%s\t# spill",Matcher::regName[dst_lo],Matcher::regName[src_lo]); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++#endif ++ } ++ // VEX_2bytes prefix is used if UseAVX > 0, and it takes the same 2 bytes as SIMD prefix. ++ return (UseAVX > 2) ? 6 : 4; ++ ++ return 0; ++} ++ ++static int vec_spill_helper(CodeBuffer *cbuf, bool do_size, bool is_load, ++ int stack_offset, int reg, uint ireg, outputStream* st) { ++ // In 64-bit VM size calculation is very complex. Emitting instructions ++ // into scratch buffer is used to get size in 64-bit VM. ++ /* ++ LP64_ONLY( assert(!do_size, "this method calculates size only for 32-bit VM"); ) ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ int offset = __ offset(); ++ if (is_load) { ++ switch (ireg) { ++ case Op_VecS: ++ __ movdl(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); ++ break; ++ case Op_VecD: ++ __ movq(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); ++ break; ++ case Op_VecX: ++#ifndef _LP64 ++ __ movdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); ++#else ++ if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { ++ __ movdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); ++ } else { ++ __ vpxor(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), 2); ++ __ vinsertf32x4(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset),0x0); ++ } ++#endif ++ break; ++ case Op_VecY: ++#ifndef _LP64 ++ __ vmovdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); ++#else ++ if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { ++ __ vmovdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); ++ } else { ++ __ vpxor(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), 2); ++ __ vinsertf64x4(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset),0x0); ++ } ++#endif ++ break; ++ case Op_VecZ: ++ __ evmovdquq(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset), 2); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { // store ++ switch (ireg) { ++ case Op_VecS: ++ __ movdl(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); ++ break; ++ case Op_VecD: ++ __ movq(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); ++ break; ++ case Op_VecX: ++#ifndef _LP64 ++ __ movdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); ++#else ++ if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { ++ __ movdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); ++ } ++ else { ++ __ vextractf32x4(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg]), 0x0); ++ } ++#endif ++ break; ++ case Op_VecY: ++#ifndef _LP64 ++ __ vmovdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); ++#else ++ if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { ++ __ vmovdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); ++ } ++ else { ++ __ vextractf64x4(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg]), 0x0); ++ } ++#endif ++ break; ++ case Op_VecZ: ++ __ evmovdquq(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg]), 2); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } ++ int size = __ offset() - offset; ++#ifdef ASSERT ++ int offset_size = (stack_offset == 0) ? 0 : ((stack_offset < 0x80) ? 1 : (UseAVX > 2) ? 6 : 4); ++ // VEX_2bytes prefix is used if UseAVX > 0, so it takes the same 2 bytes as SIMD prefix. ++ assert(!do_size || size == (5+offset_size), "incorrect size calculattion"); ++#endif ++ return size; ++#ifndef PRODUCT ++ } else if (!do_size) { ++ if (is_load) { ++ switch (ireg) { ++ case Op_VecS: ++ st->print("movd %s,[rsp + %d]\t# spill", Matcher::regName[reg], stack_offset); ++ break; ++ case Op_VecD: ++ st->print("movq %s,[rsp + %d]\t# spill", Matcher::regName[reg], stack_offset); ++ break; ++ case Op_VecX: ++ st->print("movdqu %s,[rsp + %d]\t# spill", Matcher::regName[reg], stack_offset); ++ break; ++ case Op_VecY: ++ case Op_VecZ: ++ st->print("vmovdqu %s,[rsp + %d]\t# spill", Matcher::regName[reg], stack_offset); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } else { // store ++ switch (ireg) { ++ case Op_VecS: ++ st->print("movd [rsp + %d],%s\t# spill", stack_offset, Matcher::regName[reg]); ++ break; ++ case Op_VecD: ++ st->print("movq [rsp + %d],%s\t# spill", stack_offset, Matcher::regName[reg]); ++ break; ++ case Op_VecX: ++ st->print("movdqu [rsp + %d],%s\t# spill", stack_offset, Matcher::regName[reg]); ++ break; ++ case Op_VecY: ++ case Op_VecZ: ++ st->print("vmovdqu [rsp + %d],%s\t# spill", stack_offset, Matcher::regName[reg]); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } ++#endif ++ } ++ bool is_single_byte = false; ++ int vec_len = 0; ++ if ((UseAVX > 2) && (stack_offset != 0)) { ++ int tuple_type = Assembler::EVEX_FVM; ++ int input_size = Assembler::EVEX_32bit; ++ switch (ireg) { ++ case Op_VecS: ++ tuple_type = Assembler::EVEX_T1S; ++ break; ++ case Op_VecD: ++ tuple_type = Assembler::EVEX_T1S; ++ input_size = Assembler::EVEX_64bit; ++ break; ++ case Op_VecX: ++ break; ++ case Op_VecY: ++ vec_len = 1; ++ break; ++ case Op_VecZ: ++ vec_len = 2; ++ break; ++ } ++ is_single_byte = Assembler::query_compressed_disp_byte(stack_offset, true, vec_len, tuple_type, input_size, 0); ++ } ++ int offset_size = 0; ++ int size = 5; ++ if (UseAVX > 2 ) { ++ if (VM_Version::supports_avx512novl() && (vec_len == 2)) { ++ offset_size = (stack_offset == 0) ? 0 : ((is_single_byte) ? 1 : 4); ++ size += 2; // Need an additional two bytes for EVEX encoding ++ } else if (VM_Version::supports_avx512novl() && (vec_len < 2)) { ++ offset_size = (stack_offset == 0) ? 0 : ((stack_offset <= 127) ? 1 : 4); ++ } else { ++ offset_size = (stack_offset == 0) ? 0 : ((is_single_byte) ? 1 : 4); ++ size += 2; // Need an additional two bytes for EVEX encodding ++ } ++ } else { ++ offset_size = (stack_offset == 0) ? 0 : ((stack_offset <= 127) ? 1 : 4); ++ } ++ // VEX_2bytes prefix is used if UseAVX > 0, so it takes the same 2 bytes as SIMD prefix. ++ return size+offset_size; ++ return 0; ++} ++*/ ++static inline jint replicate4_imm(int con, int width) { ++ // Load a constant of "width" (in bytes) and replicate it to fill 32bit. ++ assert(width == 1 || width == 2, "only byte or short types here"); ++ int bit_width = width * 8; ++ jint val = con; ++ val &= (1 << bit_width) - 1; // mask off sign bits ++ while(bit_width < 32) { ++ val |= (val << bit_width); ++ bit_width <<= 1; ++ } ++ return val; ++} ++ ++static inline jlong replicate8_imm(int con, int width) { ++ // Load a constant of "width" (in bytes) and replicate it to fill 64bit. ++ assert(width == 1 || width == 2 || width == 4, "only byte, short or int types here"); ++ int bit_width = width * 8; ++ jlong val = con; ++ val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits ++ while(bit_width < 64) { ++ val |= (val << bit_width); ++ bit_width <<= 1; ++ } ++ return val; ++} ++//============================================================================= ++#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 { ++ MacroAssembler _masm(&cbuf); ++ int i = 0; ++ for(i = 0; i < _count; i++) ++ __ nop(); ++} ++ ++uint MachNopNode::size(PhaseRegAlloc *) const { ++ return 4 * _count; ++} ++ ++const Pipeline* MachNopNode::pipeline() const { ++ return MachNode::pipeline_class(); ++} ++ ++#ifndef PRODUCT ++ void MachBreakpointNode::format(PhaseRegAlloc*, outputStream* st) const { ++ st->print("# breakpoint"); ++ } ++#endif ++ ++ void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc* ra_) const { ++ MacroAssembler _masm(&cbuf); ++ //__ stop("breakpoint! ");// stop is ok ?? lsp ++ __ block_comment("execute breakpoint"); ++ __ int3(); ++ } ++ ++ uint MachBreakpointNode::size(PhaseRegAlloc* ra_) const { ++ return MachNode::size(ra_); ++ } ++ ++#define RELOC_IMM64 Assembler::imm_operand ++#define RELOC_DISP32 Assembler::disp32_operand ++/* ++#define __ _masm. ++ ++static bool generate_vzeroupper(Compile* C) { ++ return (VM_Version::supports_vzeroupper() && (C->max_vector_size() > 16 || C->clear_upper_avx() == true)) ? true: false; // Generate vzeroupper ++} ++ ++static int clear_avx_size() { ++ return generate_vzeroupper(Compile::current()) ? 3: 0; // vzeroupper ++}*/ ++ ++// !!!!! Special hack to get all types of calls to specify the byte offset ++// from the start of the call to the point where the return address ++// will point. ++int MachCallStaticJavaNode::ret_addr_offset() ++{ ++// warning("TODO:MachCallStaticJavaNode::ret_addr_offset(), check lsp"); ++ if (SafePatch) { ++ assert(NativeCall::instruction_size == 24, "in MachCallStaticJavaNode::ret_addr_offset"); ++ } else { ++ assert(NativeCall::instruction_size == 20, "in MachCallStaticJavaNode::ret_addr_offset"); // don't consider setfpec1 ++ } ++ return NativeCall::instruction_size; ++} ++ ++int MachCallDynamicJavaNode::ret_addr_offset() ++{ ++ //TODO:warning("TODO:MachCallDynamicJavaNode::ret_addr_offset(), check lsp"); ++ //ldi IC_Klass, ++ //sll IC_Klass, ++ //ldih IC_Klass ++ //ldi IC_Klass // refer to MacroAssembler::ic_call(address entry) ++ ++ //ldi T12 ++ //sll T12 ++ //ldih T12 ++ //ldi T12 ++ //call T12 ++ //nop ++ if (SafePatch) { ++ assert(NativeCall::instruction_size == 24, "in MachCallStaticJavaNode::ret_addr_offset"); ++ } else { ++ assert(NativeCall::instruction_size == 20, "in MachCallStaticJavaNode::ret_addr_offset"); // don't consider setfpec1 ++ } ++ return 4 * BytesPerInstWord + NativeCall::instruction_size; ++} ++ ++int MachCallRuntimeNode::ret_addr_offset() { ++ if (SafePatch) { ++ assert(NativeCall::instruction_size == 24, "in MachCallRuntimeNode::ret_addr_offset()"); ++ } else { ++// warning("TODO:MachCallRuntimeNode::ret_addr_offset(), check lsp");// need adjust for enc_class Java_To_Runtime ? lsp ++ assert(NativeCall::instruction_size == 20, "in MachCallRuntimeNode::ret_addr_offset()"); ++ } ++ return 4 * BytesPerInstWord + NativeCall::instruction_size; // don't consider setfpec1 ++} ++ ++// Indicate if the safepoint node needs the polling page as an input. ++// Since SW64 doesn't have absolute addressing, it needs. ++bool SafePointNode::needs_polling_address_input() ++{ ++ //TODO:warning("TODO:SafePointNode::needs_polling_address_input(), check lsp"); ++ return true; ++// return SafepointMechanism::uses_thread_local_poll() || Assembler::is_polling_page_far(); ++} ++ ++// ++// Compute padding required for nodes which need alignment ++// ++ ++// no use in sw8!! CHECK djx ++// The address of the call instruction needs to be 4-byte aligned to ++// ensure that it does not span a cache line so that it can be patched. ++int CallStaticJavaDirectNode::compute_padding(int current_offset) const ++{ ++// warning("TODO:CallStaticJavaDirectNode::compute_padding, check lsp"); ++ return align_up(current_offset, alignment_required()) - current_offset; ++// return 0; ++} ++ ++// The address of the call instruction needs to be 4-byte aligned to ++// ensure that it does not span a cache line so that it can be patched. ++int CallDynamicJavaDirectNode::compute_padding(int current_offset) const ++{ ++// warning("TODO:CallDynamicJavaDirectNode::compute_padding, check lsp"); ++ current_offset += 4 * BytesPerInstWord; //skip li48 ++ return align_up(current_offset, alignment_required()) - current_offset; ++// return 0; ++} ++ ++//swjdk8 has it use for CallLeafNoFPDirect ins_alignment(16) lsp ++//int CallLeafNoFPDirectNode::compute_padding(int current_offset) const { ++// return round_to(current_offset, alignment_required()) - current_offset; ++//} ++// ++//use for CallRuntimeDirect ins_alignment(16) ++//int CallLeafDirectNode::compute_padding(int current_offset) const { ++// return round_to(current_offset, alignment_required()) - current_offset; ++//} ++// ++// use for CallRuntimeDirect ins_alignment(16) ++//int CallRuntimeDirectNode::compute_padding(int current_offset) const { ++// return round_to(current_offset, alignment_required()) - current_offset; ++//} ++ ++//============================================================================= ++const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty; ++ ++int Compile::ConstantTable::calculate_table_base_offset() const { ++ return 0; // absolute addressing, no 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 { ++ // Empty encoding ++ } ++ ++uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const { ++ return 0; ++} ++ ++#ifndef PRODUCT ++void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { ++ st->print("# MachConstantBaseNode (empty encoding)"); ++} ++#endif ++ ++ ++//============================================================================= ++#ifndef PRODUCT ++void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { ++ Compile* C = ra_->C; ++ ++ int framesize = C->frame_size_in_bytes(); ++ int bangsize = C->bang_size_in_bytes(); ++ assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); ++ ++ // 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 of0fc1ecaa6b7d ++ // stack. But the stack safety zone should account for that. ++ // See bugs 4446381, 4468289, 4497237.0fc1ecaa6b7d ++ if (C->need_stack_bang(bangsize)) { ++ st->print_cr("# stack bang %d", bangsize); st->print("\t"); ++ } ++ ++ st->print("\tsubptr esp, %d, esp",framesize); ++ st->print("\tstl ra, %d(esp) @ MachPrologNode\n\t", framesize - wordSize); ++ st->print("\tstl rfp, %d(esp) \n\t", framesize - wordSize*2); ++ if (PreserveFramePointer) { ++ st->print("\taddptr esp, %d, rfp \n\t", framesize - wordSize*2); ++ } ++ ++} ++#endif ++ ++void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { ++ Compile* C = ra_->C; ++ MacroAssembler _masm(&cbuf); ++ ++ int framesize = C->frame_size_in_bytes(); ++ int bangsize = C->bang_size_in_bytes(); ++ ++ assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); ++ ++ ++ if (C->need_stack_bang(bangsize)) { ++ __ generate_stack_overflow_check(bangsize); ++ ++ } ++ __ subptr(esp, framesize, esp); ++ __ stl(RA, framesize - wordSize, esp); ++ __ stl(rfp, framesize - wordSize*2, esp); ++ ++ if (PreserveFramePointer) ++ __ addptr(esp, framesize - wordSize*2, rfp); ++ __ nop(); //Make enough room for patch_verified_entry() ++ __ nop(); ++ ++ C->set_frame_complete(cbuf.insts_size()); ++ if (C->has_mach_constant_base_node()) { ++ // NOTE: We set the table base offset here because users might be ++ // emitted before MachConstantBaseNode. ++ Compile::ConstantTable& constant_table = C->constant_table(); ++ constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); ++ } ++} ++ ++uint MachPrologNode::size(PhaseRegAlloc* ra_) const ++{ ++ return MachNode::size(ra_); // too many variables; just compute it ++ // the hard way ++} ++ ++int MachPrologNode::reloc() const ++{ ++ return 0; // a large enough number ++} ++ ++//============================================================================= ++#ifndef PRODUCT ++void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const ++{ ++ Compile* C = ra_->C; ++// if (generate_vzeroupper(C)) { ++// st->print("vzeroupper"); ++// st->cr(); st->print("\t"); ++// } ++ int framesize = C->frame_size_in_bytes(); ++ assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); ++// // Remove word for return adr already pushed ++// // and RBP ++// framesize -= 2*wordSize; ++ ++ st->print("\tldl RA, %d, esp # Restore RA ", framesize - wordSize); ++ st->cr(); st->print("\t"); ++ st->print("\tldl rfp, %d, esp # Restore rfp ", framesize - wordSize*2); ++ st->cr(); st->print("\t"); ++ st->print("addptr esp, %d, esp # Rlease stack @ MachEpilogNode",framesize); ++ st->cr(); st->print("\t"); ++ ++ if (do_polling() && C->is_method_compilation()) { ++ st->print("\t"); ++ if (SafepointMechanism::uses_thread_local_poll()) { ++ st->print_cr("ldl rscratch3, poll_offset[rthread] #polling_page_address\n\t" ++ "ldw rscratch3, [rscratch2_AT]\n\t" ++ "# Safepoint: poll for GC"); ++ } else { ++ st->print_cr("mov_immediate64 rscratch3, #offset_to_poll_page\n\t" ++ "ldw rscratch3, [rscratch3]\n\t" ++ "# Safepoint: poll for GC"); ++ } ++ } ++} ++#endif ++ ++void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const ++{ ++ Compile* C = ra_->C; ++ MacroAssembler _masm(&cbuf); ++ ++ int framesize = C->frame_size_in_bytes(); ++ assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); ++ ++ // Note that VerifyStackAtCalls' Majik cookie does not change the frame size popped here ++ ++ __ ldl(RA, framesize - wordSize, esp); ++ __ ldl(rfp, framesize - wordSize * 2, esp); ++ __ addptr(esp, framesize, esp); ++ ++ if (StackReservedPages > 0 && C->has_reserved_stack_access()) { ++ __ reserved_stack_check(); ++ } ++ ++ if (do_polling() && C->is_method_compilation()) { ++ MacroAssembler _masm(&cbuf); ++// __ stop("TODO:check why rscratch2_AT? jzy"); ++ if (SafepointMechanism::uses_thread_local_poll()) { ++ __ ldl(rscratch3, Address(rthread, Thread::polling_page_offset())); ++ __ relocate(relocInfo::poll_return_type); ++ __ ldw(rscratch3, Address(rscratch3, 0)); ++ } else { ++ AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type); ++ __ mov_immediate64(rscratch3, (long)os::get_polling_page()); ++ __ relocate(relocInfo::poll_return_type); ++ __ ldw(rscratch3, Address(rscratch3, 0)); ++ } ++ } ++} ++ ++uint MachEpilogNode::size(PhaseRegAlloc* ra_) const ++{ ++ return MachNode::size(ra_); // too many variables; just compute it ++ // the hard way ++} ++ ++int MachEpilogNode::reloc() const ++{ ++// tty->print_cr(">>>>MachEpilog"); while(1); ++ return 2; // a large enough number ++} ++ ++const Pipeline* MachEpilogNode::pipeline() const ++{ ++ return MachNode::pipeline_class(); ++} ++ ++int MachEpilogNode::safepoint_offset() const ++{ ++ return 0; ++} ++ ++//============================================================================= ++ ++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; ++} ++ ++// Next two methods are shared by 32- and 64-bit VM. They are defined in x86.ad. ++/*static int vec_mov_helper(CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo, ++ int src_hi, int dst_hi, uint ireg, outputStream* st); ++ ++static int vec_spill_helper(CodeBuffer *cbuf, bool do_size, bool is_load, ++ int stack_offset, int reg, uint ireg, outputStream* st);*/ ++ ++static void vec_stack_to_stack_helper(CodeBuffer *cbuf, int src_offset, ++ int dst_offset, uint ireg, outputStream* st) { ++ /*if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ switch (ireg) { ++ case Op_VecS: ++ __ movq(Address(rsp, -8), rax); ++ __ movl(rax, Address(rsp, src_offset)); ++ __ movl(Address(rsp, dst_offset), rax); ++ __ movq(rax, Address(rsp, -8)); ++ break; ++ case Op_VecD: ++ __ pushq(Address(rsp, src_offset)); ++ __ popq (Address(rsp, dst_offset)); ++ break; ++ case Op_VecX: ++ __ pushq(Address(rsp, src_offset)); ++ __ popq (Address(rsp, dst_offset)); ++ __ pushq(Address(rsp, src_offset+8)); ++ __ popq (Address(rsp, dst_offset+8)); ++ break; ++ case Op_VecY: ++ __ vmovdqu(Address(rsp, -32), xmm0); ++ __ vmovdqu(xmm0, Address(rsp, src_offset)); ++ __ vmovdqu(Address(rsp, dst_offset), xmm0); ++ __ vmovdqu(xmm0, Address(rsp, -32)); ++ break; ++ case Op_VecZ: ++ __ evmovdquq(Address(rsp, -64), xmm0, 2); ++ __ evmovdquq(xmm0, Address(rsp, src_offset), 2); ++ __ evmovdquq(Address(rsp, dst_offset), xmm0, 2); ++ __ evmovdquq(xmm0, Address(rsp, -64), 2); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++#ifndef PRODUCT ++ } else { ++ switch (ireg) { ++ case Op_VecS: ++ st->print("movq [rsp - #8], rax\t# 32-bit mem-mem spill\n\t" ++ "movl rax, [rsp + #%d]\n\t" ++ "movl [rsp + #%d], rax\n\t" ++ "movq rax, [rsp - #8]", ++ src_offset, dst_offset); ++ break; ++ case Op_VecD: ++ st->print("pushq [rsp + #%d]\t# 64-bit mem-mem spill\n\t" ++ "popq [rsp + #%d]", ++ src_offset, dst_offset); ++ break; ++ case Op_VecX: ++ st->print("pushq [rsp + #%d]\t# 128-bit mem-mem spill\n\t" ++ "popq [rsp + #%d]\n\t" ++ "pushq [rsp + #%d]\n\t" ++ "popq [rsp + #%d]", ++ src_offset, dst_offset, src_offset+8, dst_offset+8); ++ break; ++ case Op_VecY: ++ st->print("vmovdqu [rsp - #32], xmm0\t# 256-bit mem-mem spill\n\t" ++ "vmovdqu xmm0, [rsp + #%d]\n\t" ++ "vmovdqu [rsp + #%d], xmm0\n\t" ++ "vmovdqu xmm0, [rsp - #32]", ++ src_offset, dst_offset); ++ break; ++ case Op_VecZ: ++ st->print("vmovdqu [rsp - #64], xmm0\t# 512-bit mem-mem spill\n\t" ++ "vmovdqu xmm0, [rsp + #%d]\n\t" ++ "vmovdqu [rsp + #%d], xmm0\n\t" ++ "vmovdqu xmm0, [rsp - #64]", ++ src_offset, dst_offset); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++#endif ++ }*/ ++} ++ ++uint MachSpillCopyNode::implementation(CodeBuffer* cbuf, ++ PhaseRegAlloc* ra_, ++ bool do_size, ++ outputStream* st) const { ++ assert(cbuf != NULL || st != NULL, "sanity"); ++ // Get registers to move ++ OptoReg::Name src_second = ra_->get_reg_second(in(1)); ++ OptoReg::Name src_first = ra_->get_reg_first(in(1)); ++ OptoReg::Name dst_second = ra_->get_reg_second(this); ++ OptoReg::Name dst_first = ra_->get_reg_first(this); ++ ++ 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" ); ++ // Generate spill code! ++ int size = 0; ++ if (src_first == dst_first && src_second == dst_second) { ++ // Self copy, no move ++ return 0; ++ } ++ if (bottom_type()->isa_vect() != NULL) { ++ uint ireg = ideal_reg(); ++ assert((src_first_rc != rc_int && dst_first_rc != rc_int), "sanity"); ++ assert((ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY || ireg == Op_VecZ ), "sanity"); ++ if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { ++ // mem -> mem ++ int src_offset = ra_->reg2offset(src_first); ++ int dst_offset = ra_->reg2offset(dst_first); ++ vec_stack_to_stack_helper(cbuf, src_offset, dst_offset, ireg, st); ++ } else if (src_first_rc == rc_float && dst_first_rc == rc_float ) { ++ //vec_mov_helper(cbuf, false, src_first, dst_first, src_second, dst_second, ireg, st); ++ } else if (src_first_rc == rc_float && dst_first_rc == rc_stack ) { ++ int stack_offset = ra_->reg2offset(dst_first); ++ //vec_spill_helper(cbuf, false, false, stack_offset, src_first, ireg, st); ++ } else if (src_first_rc == rc_stack && dst_first_rc == rc_float ) { ++ int stack_offset = ra_->reg2offset(src_first); ++ //vec_spill_helper(cbuf, false, true, stack_offset, dst_first, ireg, st); ++ } else { ++ ShouldNotReachHere(); ++ } ++ return 0; ++ } ++ if (src_first_rc == rc_stack) { ++ // mem -> ++ if (dst_first_rc == rc_stack) { ++ // mem -> mem ++ assert(src_second != dst_first, "overlap"); ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ int src_offset = ra_->reg2offset(src_first); ++ int dst_offset = ra_->reg2offset(dst_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ ldl(rscratch3, Address(esp, src_offset)); ++ __ stl(rscratch3, Address(esp, dst_offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("ldl rscratch3, [esp + #%d]\t# 64-bit mem-mem spill 1\n\t" ++ "stl rscratch3, [esp + #%d]", ++ src_offset, dst_offset); ++ } ++#endif ++ } ++ size += 8; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ // No pushl/popl, so: ++ int src_offset = ra_->reg2offset(src_first); ++ int dst_offset = ra_->reg2offset(dst_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ ldw(rscratch3, Address(esp, src_offset)); ++ __ stw(rscratch3, Address(esp, dst_offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("ldw rscratch3, [esp + #%d] spill 2\n\t" ++ "stw rscratch3, [esp + #%d]\n\t", ++ src_offset, dst_offset); ++ } ++#endif ++ } ++ size += 8; ++ } ++ return size; ++ } else if (dst_first_rc == rc_int) { ++ // mem -> gpr ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ int offset = ra_->reg2offset(src_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ ldl(as_Register(Matcher::_regEncode[dst_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("ldl %s, [esp + #%d]\t# spill 3", ++ Matcher::regName[dst_first], ++ offset); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ int offset = ra_->reg2offset(src_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ if (this->ideal_reg() == Op_RegI) ++ __ ldw(as_Register(Matcher::_regEncode[dst_first]), Address(esp, offset)); ++ else ++ __ ldwu(as_Register(Matcher::_regEncode[dst_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ if (this->ideal_reg() == Op_RegI) ++ st->print("ldw %s, [esp + #%d]\t# spill 4", ++ Matcher::regName[dst_first], ++ offset); ++ else ++ st->print("ldwu %s, [esp + #%d]\t# spill 5", ++ Matcher::regName[dst_first], ++ offset); ++ } ++#endif ++ } ++ if (this->ideal_reg() == Op_RegI) { ++ size += 4; ++ } else { ++ size += 8; ++ } ++ } ++ return size; ++ } else if (dst_first_rc == rc_float) { ++ // mem-> xmm ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ int offset = ra_->reg2offset(src_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ fldd( as_FloatRegister(Matcher::_regEncode[dst_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("fldd %s, [esp + #%d]\t# spill 6", ++ Matcher::regName[dst_first], ++ offset); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ int offset = ra_->reg2offset(src_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ flds( as_FloatRegister(Matcher::_regEncode[dst_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("flds %s, [esp + #%d]\t# spill 7", ++ Matcher::regName[dst_first], ++ offset); ++ } ++#endif ++ } ++ size += 4; ++ } ++ return size; ++ } ++ } else if (src_first_rc == rc_int) { ++ // gpr -> ++ if (dst_first_rc == rc_stack) { ++ // gpr -> mem ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ int offset = ra_->reg2offset(dst_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ stl(as_Register(Matcher::_regEncode[src_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("stl %s, [esp + #%d] # spill 8", ++ Matcher::regName[src_first], ++ offset); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ int offset = ra_->reg2offset(dst_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ stw(as_Register(Matcher::_regEncode[src_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if (!do_size) { ++ if (size != 0) st->print("\n\t"); ++ st->print("stw %s, [esp + #%d]\t# spill 9", ++ Matcher::regName[src_first], offset); ++ } ++#endif ++ } ++ size += 4; ++ } ++ return size; ++ } else if (dst_first_rc == rc_int) { ++ // gpr -> gpr ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ movl(as_Register(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("movl %s <-- %s\t# spill 10", ++ Matcher::regName[dst_first], ++ Matcher::regName[src_first]); ++ } ++#endif ++ } ++ size += 4; ++ return size; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ if (this->ideal_reg() == Op_RegI) ++ __ movws(as_Register(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); ++ else ++ __ movl(as_Register(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); ++#ifndef PRODUCT ++ } else { ++ if (!do_size) { ++ if (size != 0) st->print("\n\t"); ++ st->print("move(32-bit) %s <-- %s\t# spill 11", ++ Matcher::regName[dst_first], ++ Matcher::regName[src_first]); ++ } ++#endif ++ } ++ size += 4; ++ return size; ++ } ++ } else if (dst_first_rc == rc_float) { ++ // gpr -> xmm ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ ifmovd(as_Register(Matcher::_regEncode[src_first]), as_FloatRegister(Matcher::_regEncode[dst_first])); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("ifmovd %s, %s\t# spill 12", ++ Matcher::regName[src_first], ++ Matcher::regName[dst_first]); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ ifmovs( as_Register(Matcher::_regEncode[src_first]), as_FloatRegister(Matcher::_regEncode[dst_first]) ); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("ifmovs %s, %s\t# spill 13", ++ Matcher::regName[src_first], ++ Matcher::regName[dst_first]); ++ } ++#endif ++ } ++ size += 4; ++ } ++ return size; ++ } ++ } else if (src_first_rc == rc_float) { ++ // xmm -> ++ if (dst_first_rc == rc_stack) { ++ // xmm -> mem ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ int offset = ra_->reg2offset(dst_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ fstd( as_FloatRegister(Matcher::_regEncode[src_first]), Address(esp, offset) ); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("fstd %s, [esp + #%d]\t# spill 14", ++ Matcher::regName[src_first], ++ offset); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ int offset = ra_->reg2offset(dst_first); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ fsts(as_FloatRegister(Matcher::_regEncode[src_first]), Address(esp, offset)); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("fsts %s, [esp + #%d]\t# spill 15", ++ Matcher::regName[src_first], ++ offset); ++ } ++#endif ++ } ++ size += 4; ++ } ++ return size; ++ } else if (dst_first_rc == rc_int) { ++ // xmm -> gpr ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ fimovd( as_FloatRegister(Matcher::_regEncode[src_first]), as_Register(Matcher::_regEncode[dst_first])); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("fimovd %s, %s\t# spill 16", ++ Matcher::regName[src_first], ++ Matcher::regName[dst_first]); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ fimovs( as_FloatRegister(Matcher::_regEncode[src_first]), as_Register(Matcher::_regEncode[dst_first])); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("fimovs %s, %s\t# spill 17", ++ Matcher::regName[src_first], ++ Matcher::regName[dst_first]); ++ } ++#endif ++ } ++ size += 4; ++ } ++ return size; ++ } else if (dst_first_rc == rc_float) { ++ // xmm -> xmm ++ if ((src_first & 1) == 0 && src_first + 1 == src_second && ++ (dst_first & 1) == 0 && dst_first + 1 == dst_second) { ++ // 64-bit ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ mov_d( as_FloatRegister(Matcher::_regEncode[dst_first]), as_FloatRegister(Matcher::_regEncode[src_first])); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("mov_d %s <-- %s\t# spill 18", ++ Matcher::regName[dst_first], ++ Matcher::regName[src_first]); ++ } ++#endif ++ } ++ size += 4; ++ } else { ++ // 32-bit ++ assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); ++ assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); ++ if (cbuf) { ++ MacroAssembler _masm(cbuf); ++ __ mov_s( as_FloatRegister(Matcher::_regEncode[dst_first]), as_FloatRegister(Matcher::_regEncode[src_first])); ++#ifndef PRODUCT ++ } else { ++ if(!do_size){ ++ if (size != 0) st->print("\n\t"); ++ st->print("mov_s %s <-- %s\t# spill 19", ++ Matcher::regName[dst_first], ++ Matcher::regName[src_first]); ++ } ++#endif ++ } ++ size += 4; ++ } ++ return size; ++ } ++ } ++ ++ assert(0," foo "); ++ Unimplemented(); ++ return size; ++} ++ ++#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 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("addl esp, %d, %s \t# box lock@BoxLockNode", offset, Matcher::regName[reg]); ++} ++#endif ++ ++void BoxLockNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const ++{ ++ MacroAssembler _masm(&cbuf); ++ int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); ++ int reg = ra_->get_encode(this); ++ /*if (Assembler::operand_valid_for_simple_type_instruction_immediate(offset)) { ++ __ addl(esp, offset, as_Register(reg)); ++ } else { ++ __ addptr(esp, offset, as_Register(reg)); ++ }*/ ++ __ addptr(esp, offset, as_Register(reg)); ++} ++ ++uint BoxLockNode::size(PhaseRegAlloc *ra_) const ++{ ++ //int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); ++ //return Assembler::operand_valid_for_simple_type_instruction_immediate(offset) ? 4 : 8; ++ return 8; ++} ++ ++//============================================================================= ++#ifndef PRODUCT ++void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const ++{ ++ if (UseCompressedClassPointers) { ++ st->print_cr("movl rscratch3, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); ++ st->print_cr("\tdecode_klass_not_null rscratch4, rscratch4"); ++ st->print_cr("\tcmpeq iCache_v0, rscratch4\t # Inline cache check"); ++ } else { ++ st->print_cr("\tcmpeq iCache_v0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t" ++ "# Inline cache check"); ++ } ++ st->print_cr("\tjne SharedRuntime::_ic_miss_stub"); ++ st->print_cr("\tnop\t# nops to align entry point"); ++} ++#endif ++ ++void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc * ra_) const { ++ MacroAssembler _masm(&cbuf); ++ int ic_reg = Matcher::inline_cache_reg_encode();//sw64 inline_cache_reg(V0); ++ Register receiver = j_rarg0; ++ Register iCache = as_Register(ic_reg); ++ ++ Label skip; ++ __ load_klass(rscratch4, receiver); ++ __ cmpptr(rscratch4, iCache); ++ __ jcc(Assembler::equal, skip); ++ __ relocate(relocInfo::runtime_call_type); ++ __ patchable_jump((address)SharedRuntime::get_ic_miss_stub()); ++ __ align(CodeEntryAlignment); ++ __ bind(skip); ++} ++ ++uint MachUEPNode::size(PhaseRegAlloc* ra_) const ++{ ++ return MachNode::size(ra_); // too many variables; just compute it ++ // the hard way ++} ++ ++ ++//============================================================================= ++ ++int Matcher::regnum_to_fpu_offset(int regnum) ++{ ++ return regnum - 32; // The FP registers are in the second chunk ++} ++ ++// This is UltraSparc specific, true just means we have fast l2f 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. ++ // On 86 a branch displacement is calculated relative to address ++ // of a next instruction. ++// offset -= br_size; ++// ++// // the short version of jmpConUCF2 contains multiple branches, ++// // making the reach slightly less ++// if (rule == jmpConUCF2_rule) ++// return (-126 <= offset && offset <= 125); ++// return (-128 <= offset && offset <= 127); ++ Unimplemented(); ++ return false; ++} ++ ++const bool Matcher::isSimpleConstant64(jlong value) { ++ // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. ++ //return value == (int) value; // Cf. storeImmL and immL32. ++ ++ // Probably always true, even if a temp register is required. ++ return true; ++} ++ ++// The ecx parameter to rep stosq for the ClearArray node is in words. ++const bool Matcher::init_array_count_is_in_bytes = false; ++ ++// No additional cost for CMOVL. ++const int Matcher::long_cmove_cost() { return 0; } ++ ++// No CMOVF/CMOVD with SSE2 ++const int Matcher::float_cmove_cost() { return 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; ++ ++bool Matcher::narrow_oop_use_complex_address() { ++ assert(UseCompressedOops, "only for compressed oops code"); ++// return (LogMinObjAlignmentInBytes <= 3); ++ //Unimplemented(); ++ return false; ++} ++ ++bool Matcher::narrow_klass_use_complex_address() { ++ assert(UseCompressedClassPointers, "only for compressed klass code"); ++// return (LogKlassAlignmentInBytes <= 3); ++ //Unimplemented(); ++ return false; ++} ++ ++bool Matcher::const_oop_prefer_decode() { ++ // Prefer ConN+DecodeN over ConP. ++ return true; ++} ++ ++bool Matcher::const_klass_prefer_decode() { ++ // TODO: Either support matching DecodeNKlass (heap-based) in operand ++ // or condisider the following: ++ // Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode. ++ //return Universe::narrow_klass_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; // XXX in sw8 is false! CHECK djx ++ ++// 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 = false; //in sw8 is false! CHECK djx ++ ++// No-op on amd64 ++void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {} ++ ++// Advertise here if the CPU requires explicit rounding operations to ++// implement the UseStrictFP mode. ++const bool Matcher::strict_fp_requires_explicit_rounding = true; ++ ++// Are floats conerted to double when stored to stack during deoptimization? ++// On x64 it is stored without convertion so we can use normal access. ++bool Matcher::float_in_double() { return true; } //swjdk8 is return true lsp?? ++ ++// Do ints take an entire long register or just half? ++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 ) { ++ /* Refer to: [sharedRuntime_sw64.cpp] SharedRuntime::java_calling_convention() */ ++ if ( /* reg == T0_num || reg == T0_H_num ++ || */ reg == A0_num || reg == A0_H_num ++ || reg == A1_num || reg == A1_H_num ++ || reg == A2_num || reg == A2_H_num ++ || reg == A3_num || reg == A3_H_num ++ || reg == A4_num || reg == A4_H_num ++ || reg == A5_num || reg == A5_H_num ) ++ return true; ++ ++ if ( reg == F16_num || reg == F16_H_num ++ || reg == F17_num || reg == F17_H_num ++ || reg == F18_num || reg == F18_H_num ++ || reg == F19_num || reg == F19_H_num ++ || reg == F20_num || reg == F20_H_num ++ || reg == F21_num || reg == F21_H_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) { ++ // In 64 bit mode a code which use multiply when ++ // devisor is constant is faster than hardware ++ // DIV instruction (it uses MulHiL). ++ return false; ++ } ++ ++ // Register for DIVI projection of divmodI ++RegMask Matcher::divI_proj_mask() { ++ // return INT_RAX_REG_mask(); ++ Unimplemented(); ++ return 0; ++ } ++ ++ // Register for MODI projection of divmodI ++RegMask Matcher::modI_proj_mask() { ++ // return INT_RDX_REG_mask(); ++ Unimplemented(); ++ return 0; ++ } ++ ++ // Register for DIVL projection of divmodL ++RegMask Matcher::divL_proj_mask() { ++ // return LONG_RAX_REG_mask(); ++ Unimplemented(); ++ return 0; ++ } ++ ++ // Register for MODL projection of divmodL ++RegMask Matcher::modL_proj_mask() { ++ // return LONG_RDX_REG_mask(); ++ Unimplemented(); ++ return 0; ++ } ++ ++// Register for saving SP into on method handle invokes. Not used on x86_64. ++const RegMask Matcher::method_handle_invoke_SP_save_mask() { ++// return NO_REG_mask(); ++ //warning("TODO:Matcher::method_handle_invoke_SP_save_mask(), check lsp"); ++ return FP_REG_mask(); ++} ++ ++%} ++ ++//----------ENCODING BLOCK----------------------------------------------------- ++// This block specifies the encoding classes used by the compiler to output ++// byte streams. Encoding classes generate functions which are called 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. They use the ++// ins_encode keyword to specify their encoding class (which must be one of ++// the class names 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 load_N_enc (rRegN dst, memory mem) %{ ++ MacroAssembler _masm(&cbuf); ++ int dst = $dst$$reg; ++ ++ relocInfo::relocType disp_reloc = $mem->disp_reloc(); ++ assert(disp_reloc == relocInfo::none, "cannot have disp"); ++ __ ldwu($dst$$Register, $mem$$Address); ++ %} ++ ++enc_class load_P_enc(rRegP dst, memory mem) %{ ++ MacroAssembler _masm(&cbuf); ++ int dst = $dst$$reg; ++ ++ relocInfo::relocType disp_reloc = $mem->disp_reloc(); ++ assert(disp_reloc == relocInfo::none, "cannot have disp"); ++ __ ldptr($dst$$Register, $mem$$Address); ++%} ++ ++ enc_class sw64_Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime, Java_To_Runtime_Leaf ++ MacroAssembler _masm(&cbuf); ++ //__ stop("TODO:not check lsp(Java_To_Runtime)"); ++// // This is the instruction starting address for relocation info. ++ ++// // the return address is store@(-1)SP by convention on mips, ++// // but we don't have this convention. ++// // so we have to store the pc into last_java_frame by ourself before calling into runtime ++ address addr = (address)$meth$$method; ++ Label retaddr; ++ int offset = __ offset(); ++ //assert( rscratch3 != T12, "rscratch3 can not is T12!" ); ++ __ block_comment(";;execute sw64_Java_To_Runtime"); ++ __ set_last_Java_frame(esp, noreg, retaddr, rscratch3, rscratch2_AT); ++ //lsp: same to swjdk8, different form aarch64, need to store retaddr in stack?? ++ __ call(AddressLiteral(addr, relocInfo::runtime_call_type),&retaddr);// need to check lsp!! ++ //assert(__ offset() - offset <= (int) ret_addr_offset(), "overflow"); ++ ++ //__ mov_immediate64(pv, (intptr_t)addr); ++ //__ push_RA_call(pv); ++ %} ++// ++ ++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. ++ MacroAssembler _masm(&cbuf); ++ ++ ++ //__ stop("TODO:not check lsp(Java_Static_Call)"); ++ cbuf.set_insts_mark();//TODO:relate to relocate? jzy ++ ++ address addr = (address)$meth$$method; ++ address call; ++ if (!_method) { ++ // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. ++ //__ call(AddressLiteral(addr, relocInfo::runtime_call_type)); ++ __ relocate(relocInfo::runtime_call_type); ++ __ patchable_call((address)($meth$$method)); ++ } 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); ++ __ relocate(rspec); ++ __ patchable_call((address)($meth$$method)); ++ ++ // Emit stubs for static call. ++ address mark = cbuf.insts_mark(); ++ address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); ++ if (stub == NULL) { ++ ciEnv::current()->record_failure("CodeCache is full"); ++ return; ++ } ++#if INCLUDE_AOT ++ CompiledStaticCall::emit_to_aot_stub(cbuf, mark); ++#endif ++ } ++ %} ++ ++ ++enc_class call_epilog() %{ ++ MacroAssembler _masm(&cbuf); ++ if (VerifyStackAtCalls) { ++ Unimplemented(); ++// Label L; ++// MacroAssembler _masm(&cbuf); ++// int framesize = ra_->C->frame_size_in_bytes(); ++// __ addl(esp, framesize, rscratch2_AT); ++// __ cmpptr(rscratch2_AT, rfp); ++// __ jcc(Assembler::equal, L); ++// __ stop("VerifyStackAtCalls failed"); ++// __ BIND(L); ++ } ++ %} ++ // ++ // [Ref: LIR_Assembler::ic_call() ] ++ // ++enc_class Java_Dynamic_Call (method meth) %{ ++ MacroAssembler _masm(&cbuf); ++ __ block_comment("Java_Dynamic_Call"); ++ __ ic_call((address)$meth$$method, resolved_method_index(cbuf)); ++%} ++ ++ ++enc_class Set_Flags_After_Fast_Lock_Unlock(FlagsReg cr) %{ ++// Register flags = $cr$$Register; ++// Label L; ++// ++// MacroAssembler _masm(&cbuf); ++// ++// __ addu(flags, R0, R0); ++// __ beq(AT, L); ++// __ move(flags, 0xFFFFFFFF); ++// __ BIND(L); ++%} ++ ++ enc_class enc_PartialSubtypeCheck(rRegP result, rRegP sub, rRegP super) %{ ++ Register result = $result$$Register; ++ Register sub = $sub$$Register; ++ Register super = $super$$Register; ++ Register length = rscratch3; ++ Label miss; ++// ++// // result may be the same as sub ++// // 47c B40: # B21 B41 <- B20 Freq: 0.155379 ++// // 47c partialSubtypeCheck result=S1, sub=S1, super=S3, length=S0 ++// // 4bc mov S2, NULL #@loadConP ++// // 4c0 beq S1, S2, B21 #@branchConP P=0.999999 C=-1.000000 ++// // ++ MacroAssembler _masm(&cbuf); ++ Label done; ++ __ check_klass_subtype_slow_path(sub, super, length, noreg, ++ NULL, &miss, ++ /*set_cond_codes:*/ true); ++ // Refer to X86_64's RDI ++ __ movl(result, R0); ++ __ beq_l(R0, done); ++ ++ __ BIND(miss); ++ __ movl(result, 1); ++ __ BIND(done); ++ %} ++ ++%} ++ ++ ++//---------SW64 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 SharedInfo::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 ++// | | old | | 3 ++// | | SP-+--------+----> Matcher::_old_SP, even aligned ++// v | | ret | 3 return address ++// Owned by +--------+ ++// Self | pad2 | 2 pad to align old SP ++// | +--------+ 1 ++// | | locks | 0 ++// | +--------+----> SharedInfo::stack0, even 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 new | | ++// Callee 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 nessecary 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. ++// Note 4: For I2C adapters, the incoming FP may not meet the minimum stack ++// alignment. Region 11, pad1, may be dynamically extended so that ++// SP meets the minimum alignment. ++ ++ ++frame ++%{ ++// What direction does stack grow in (assumed to be same for C & Java) ++ stack_direction(TOWARDS_LOW); ++ ++ // These three registers define part of the calling convention ++ // between compiled code and the interpreter. ++ inline_cache_reg(V0); // Inline Cache Register x86 is rax, sw64 is v0 check lsp? ++ interpreter_method_oop_reg(S3); // Method Oop Register when ++ // calling interpreter ++ ++ // Optional: name the operand used by cisc-spilling to access ++ // [stack_pointer + offset] ++ cisc_spilling_operand_name(indOffset32); ++ ++ // Number of stack slots consumed by locking an object ++ sync_stack_slots(2); ++ ++ // Compiled code's Frame Pointer ++ frame_pointer(SP); ++ ++ // Interpreter stores its frame pointer in a register which is ++ // stored to the stack by I2CAdaptors. ++ // I2CAdaptors convert from interpreted java to compiled java. ++ interpreter_frame_pointer(FP); ++ ++ // Stack alignment requirement ++ stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes) TODO:check jzy ++ ++ // 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. sw64 needs two slots for ++ // return address and fp. ++ in_preserve_stack_slots(4);//to check lsp ++ ++ // 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. ++ varargs_C_out_slots_killed(frame::arg_reg_save_area_bytes/BytesPerInt); ++ ++ // 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. ++ // Ret Addr is on stack in slot 0 if no locks or verification or alignment. ++ // Otherwise, it is above the locks and verification slot and alignment word ++ //return_addr(STACK -1+ round_to(1+VerifyStackAtCalls+Compile::current()->memb()*Compile::current()->sync_stack_slots(),WordsPerLong)); ++ return_addr(REG RA); // to check lsp ++// return_addr(STACK - 2 + ++// align_up((Compile::current()->in_preserve_stack_slots() + ++// Compile::current()->fixed_slots()), ++// stack_alignment_in_slots())); ++ ++ // Body of function which returns an integer array locating ++ // arguments either in registers or in stack slots. Passed an array ++ // of ideal registers called "sig" and a "length" count. Stack-slot ++ // offsets are based on outgoing arguments, i.e. a CALLER setting up ++ // arguments for a CALLEE. Incoming stack arguments are ++ // automatically biased by the preserve_stack_slots field above. ++ ++ calling_convention ++ %{ ++ // No difference between ingoing/outgoing just pass false ++ SharedRuntime::java_calling_convention(sig_bt, regs, length, false); ++ %} ++ ++ c_calling_convention ++ %{ ++ // This is obviously always outgoing ++ (void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length); ++ %} ++ ++ ++ // Location of C & interpreter return values ++ // register(s) contain(s) return value for Op_StartI2C and Op_StartOSR. ++ // SEE Matcher::match. ++ // Location of compiled Java return values. Same as C for now. ++ return_value %{ ++ assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" ); ++ ++ static const int lo[Op_RegL + 1] = { // enum name ++ 0, // Op_Node ++ 0, // Op_Set ++ V0_num, // Op_RegN ++ V0_num, // Op_RegI ++ V0_num, // Op_RegP ++ F0_num, // Op_RegF ++ F0_num, // Op_RegD ++ V0_num // Op_RegL ++ }; ++ ++ static const int hi[Op_RegL + 1] = { // enum name ++ 0, // Op_Node ++ 0, // Op_Set ++ OptoReg::Bad, // Op_RegN ++ OptoReg::Bad, // Op_RegI ++ V0_H_num, // Op_RegP ++ OptoReg::Bad, // Op_RegF ++ F0_H_num, // Op_RegD ++ V0_H_num // Op_RegL ++ }; ++ ++ return OptoRegPair(hi[ideal_reg], lo[ideal_reg]); ++ %} ++ ++%} ++ ++//----------ATTRIBUTES--------------------------------------------------------- ++//----------Operand Attributes------------------------------------------------- ++op_attrib op_cost(0); // Required cost attribute ++ ++//----------Instruction Attributes--------------------------------------------- ++ins_attrib ins_cost(100); // Required cost attribute ++ins_attrib ins_size(32); // Required size attribute (in bits) ++ins_attrib ins_pc_relative(0); // Required PC Relative flag ++ins_attrib ins_short_branch(0); // Required flag: is this instruction a ++ // non-matching short branch variant of some ++ // long branch? ++ins_attrib ins_alignment(4); // Required alignment attribute (must be a power of 2) ++ // specifies the alignment that some part of the instruction (not ++ // necessarily the start) requires. If > 1, a compute_padding() ++ // function must be provided for the instruction ++ ++//----------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. ++ ++// Vectors ++operand vecD() %{ ++ constraint(ALLOC_IN_RC(dbl_reg)); ++ match(VecD); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++// Flags register, used as output of compare instructions ++operand rFlagsReg() %{ ++ constraint(ALLOC_IN_RC(sw64_flags)); ++ match(RegFlags); ++ ++ format %{ "RFLAGS" %} ++ interface(REG_INTER); ++%} ++ ++// Flags register, used as output of compare instructions ++operand rFlagsRegU() %{ ++ constraint(ALLOC_IN_RC(sw64_flags)); ++ match(RegFlags); ++ ++ format %{ "RFLAGS_U" %} ++ interface(REG_INTER); ++%} ++ ++operand immI_MaxI() %{ ++ predicate(n->get_int() == 2147483647); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI16_sub() %{ ++ predicate((-32767 <= n->get_int()) && (n->get_int() <= 32768)); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immU8() %{ ++ predicate( n->get_int() >= 0 && n->get_int() <= 255 ); ++ match(ConI); ++ op_cost(0); ++ ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI_le_4() ++%{ ++ predicate(n->get_int() <= 4); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++ ++// Pointer for polling page ++operand immP_poll() %{ ++ predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page()); ++ match(ConP); ++ op_cost(0); ++ ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immL16() %{ ++ predicate((-32768 <= n->get_long()) && (n->get_long() <= 32767)); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immL16_sub() %{ ++ predicate((-32767 <= n->get_long()) && (n->get_long() <= 32768)); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++//----------Simple Operands---------------------------------------------------- ++// Immediate Operands ++// Integer Immediate ++operand immI() ++%{ ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for test vs zero ++operand immI0() ++%{ ++ predicate(n->get_int() == 0); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for increment ++operand immI1() ++%{ ++ predicate(n->get_int() == 1); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI_2() ++%{ ++ predicate(n->get_int() == 2); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI_3() ++%{ ++ predicate(n->get_int() == 3); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for decrement ++operand immI_M1() ++%{ ++ predicate(n->get_int() == -1); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Valid scale values for addressing modes ++operand immI2() ++%{ ++ predicate(0 <= n->get_int() && (n->get_int() <= 3)); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI8() ++%{ ++ predicate((-0x80 <= n->get_int()) && (n->get_int() < 0x80)); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI16() ++%{ ++ predicate((-32768 <= n->get_int()) && (n->get_int() <= 32767)); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Int Immediate non-negative ++operand immU31() ++%{ ++ predicate(n->get_int() >= 0); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for long shifts ++operand immI_32() ++%{ ++ predicate( n->get_int() == 32 ); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for long shifts ++operand immI_64() ++%{ ++ predicate( n->get_int() == 64 ); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Pointer Immediate ++operand immP() ++%{ ++ match(ConP); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// NULL Pointer Immediate ++operand immP0() ++%{ ++ predicate(n->get_ptr() == 0); ++ match(ConP); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Pointer Immediate ++operand immN() %{ ++ match(ConN); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immNKlass() %{ ++ match(ConNKlass); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// NULL Pointer Immediate ++operand immN0() %{ ++ predicate(n->get_narrowcon() == 0); ++ match(ConN); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immP31() ++%{ ++ predicate(n->as_Type()->type()->reloc() == relocInfo::none ++ && (n->get_ptr() >> 31) == 0); ++ match(ConP); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++ ++// Long Immediate ++operand immL() ++%{ ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immUL8() %{ ++ predicate( n->get_long() >= 0 && n->get_long() <= 255 ); ++ match(ConL); ++ op_cost(0); ++ ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Long Immediate 32-bit unsigned ++operand immUL32() ++%{ ++ predicate(n->get_long() == (unsigned int) (n->get_long())); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Long Immediate 32-bit signed ++operand immL32() ++%{ ++ predicate(n->get_long() == (int) (n->get_long())); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Long Immediate zero ++operand immL0() ++%{ ++ predicate(n->get_long() == 0L); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for increment ++operand immL1() ++%{ ++ predicate(n->get_long() == 1); ++ match(ConL); ++ ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for decrement ++operand immL_M1() ++%{ ++ predicate(n->get_long() == -1); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Long Immediate: the value 10 ++operand immL10() ++%{ ++ predicate(n->get_long() == 10); ++ match(ConL); ++ ++ 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); ++%} ++ ++// Float Immediate zero ++operand immF0() ++%{ ++ predicate(jint_cast(n->getf()) == 0); ++ match(ConF); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Float Immediate ++operand immF() ++%{ ++ match(ConF); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Double Immediate zero ++operand immD0() ++%{ ++ predicate(jlong_cast(n->getd()) == 0); ++ match(ConD); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Double Immediate ++operand immD() ++%{ ++ match(ConD); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Immediates for special shifts (sign extend) ++ ++// Constants for increment ++operand immI_16() ++%{ ++ predicate(n->get_int() == 16); ++ match(ConI); ++ op_cost(0); ++ ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++operand immI_24() ++%{ ++ predicate(n->get_int() == 24); ++ match(ConI); ++ op_cost(0); ++ ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for byte-wide masking ++operand immI_255() ++%{ ++ predicate(n->get_int() == 255); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for short-wide masking ++operand immI_65535() ++%{ ++ predicate(n->get_int() == 65535); ++ match(ConI); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for byte-wide masking ++operand immL_255() ++%{ ++ predicate(n->get_long() == 255); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Constant for short-wide masking ++operand immL_65535() ++%{ ++ predicate(n->get_long() == 65535); ++ match(ConL); ++ ++ op_cost(0); ++ format %{ %} ++ interface(CONST_INTER); ++%} ++ ++// Register Operands ++// Integer Register ++operand rRegI() ++%{ ++ constraint(ALLOC_IN_RC(int_reg)); ++ match(RegI); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand t10_RegI() %{ ++ constraint(ALLOC_IN_RC(t10_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "T10" %} ++ interface(REG_INTER); ++%} ++ ++//operand t11_RegI() %{ ++// constraint(ALLOC_IN_RC(t11_reg)); ++// match(RegI); ++// match(rRegI); ++// ++// format %{ "T11" %} ++// interface(REG_INTER); ++// %} ++ ++operand a0_RegI() %{ ++ constraint(ALLOC_IN_RC(a0_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "A0" %} ++ interface(REG_INTER); ++%} ++ ++operand a1_RegI() %{ ++ constraint(ALLOC_IN_RC(a1_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "A1" %} ++ interface(REG_INTER); ++%} ++ ++operand a2_RegI() %{ ++ constraint(ALLOC_IN_RC(a2_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "A2" %} ++ interface(REG_INTER); ++%} ++ ++operand a3_RegI() %{ ++ constraint(ALLOC_IN_RC(a3_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "A3" %} ++ interface(REG_INTER); ++%} ++ ++operand a4_RegI() %{ ++ constraint(ALLOC_IN_RC(a4_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "A4" %} ++ interface(REG_INTER); ++%} ++ ++operand v0_RegI() ++%{ ++ constraint(ALLOC_IN_RC(v0_reg)); ++ match(RegI); ++ match(rRegI); ++ ++ format %{ "V0" %} ++ interface(REG_INTER); ++%} ++ ++operand rRegN() %{ ++ constraint(ALLOC_IN_RC(int_reg)); ++ match(RegN); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand v0_RegN() %{ ++ constraint(ALLOC_IN_RC(v0_reg)); ++ match(RegN); ++ match(rRegN); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand t10_RegN() %{ ++ constraint(ALLOC_IN_RC(t10_reg)); ++ match(RegN); ++ match(rRegN); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++// Pointer Register ++operand any_RegP() %{ ++ constraint(ALLOC_IN_RC(any_reg)); ++ match(RegP); ++ match(a0_RegP); ++ match(s2_RegP); ++ match(rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand rRegP() %{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(RegP); ++ match(a0_RegP); ++ match(s2_RegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++//TODO:why no T11 jzy ++operand no_T11_rRegP() %{ ++ constraint(ALLOC_IN_RC(no_T11_p_reg)); ++ match(RegP); ++ match(rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand s2_RegP() ++%{ ++ constraint(ALLOC_IN_RC(s2_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand s3_RegP() ++%{ ++ constraint(ALLOC_IN_RC(s3_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand t8_RegP() ++%{ ++ constraint(ALLOC_IN_RC(t8_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand t9_RegP() ++%{ ++ constraint(ALLOC_IN_RC(t9_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand t10_RegP() ++%{ ++ constraint(ALLOC_IN_RC(t10_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand a0_RegP() ++%{ ++ constraint(ALLOC_IN_RC(a0_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand a1_RegP() ++%{ ++ constraint(ALLOC_IN_RC(a1_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand a2_RegP() ++%{ ++ constraint(ALLOC_IN_RC(a2_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand a3_RegP() ++%{ ++ constraint(ALLOC_IN_RC(a3_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand a4_RegP() ++%{ ++ constraint(ALLOC_IN_RC(a4_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++ ++operand a5_RegP() ++%{ ++ constraint(ALLOC_IN_RC(a5_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand v0_RegP() ++%{ ++ constraint(ALLOC_IN_RC(v0_long_reg)); ++ match(RegP); ++ match(rRegP); ++ match(no_T11_rRegP); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand rRegL() %{ ++ constraint(ALLOC_IN_RC(long_reg)); ++ match(RegL); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand v0_RegL() %{ ++ constraint(ALLOC_IN_RC(v0_long_reg)); ++ match(RegL); ++ match(rRegL); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand t9_RegL() %{ ++ constraint(ALLOC_IN_RC(t9_long_reg)); ++ match(RegL); ++ match(rRegL); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++// Float register operands ++operand regF() %{ ++ constraint(ALLOC_IN_RC(flt_reg)); ++ match(RegF); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++// Double register operands ++operand regD() %{ ++ constraint(ALLOC_IN_RC(dbl_reg)); ++ match(RegD); ++ ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++operand f27_RegD() ++%{ ++ constraint(ALLOC_IN_RC(dbl_tmp_f27)); ++ match(RegD); ++ op_cost(0); ++ format %{ %} ++ interface(REG_INTER); ++%} ++operand f28_RegD() ++%{ ++ constraint(ALLOC_IN_RC(dbl_tmp_f28)); ++ match(RegD); ++ op_cost(0); ++ format %{ %} ++ interface(REG_INTER); ++%} ++operand f29_RegD() ++%{ ++ constraint(ALLOC_IN_RC(dbl_tmp_f29)); ++ match(RegD); ++ op_cost(0); ++ format %{ %} ++ interface(REG_INTER); ++%} ++operand f30_RegD() ++%{ ++ constraint(ALLOC_IN_RC(dbl_tmp_f30)); ++ match(RegD); ++ op_cost(0); ++ format %{ %} ++ interface(REG_INTER); ++%} ++ ++ ++//----------Memory Operands---------------------------------------------------- ++// Direct Memory Operand ++// operand direct(immP addr) ++// %{ ++// match(addr); ++ ++// format %{ "[$addr]" %} ++// interface(MEMORY_INTER) %{ ++// base(0xFFFFFFFF); ++// index(0x4); ++// scale(0x0); ++// disp($addr); ++// %} ++// %} ++ ++// Indirect Memory Operand ++operand indirect(any_RegP reg) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(reg); ++ ++ format %{ "[$reg] @ indirect" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index(0x1e); ++ scale(0x0); ++ disp(0x0); ++ %} ++%} ++ ++// Indirect Memory Plus Short Offset Operand ++operand indOffset16(any_RegP reg, immL16 off) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP reg off); ++ ++ format %{ "[$reg + $off (16-bit)] @ indOffset16" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index(0x1e); ++ scale(0x0); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Plus Long Offset Operand ++//operand indOffset32(rRegP reg, immL32 off) ++//%{ ++// constraint(ALLOC_IN_RC(ptr_reg)); ++// match(AddP reg off); ++// ++// format %{ "[$reg + $off (32-bit)]" %} ++// interface(MEMORY_INTER) %{ ++// base($reg); ++// index(0x1e); ++// scale(0x0); ++// disp($off); ++// %} ++//%} ++ ++// Indirect Memory Plus Index Register Plus Offset Operand ++operand indIndexOffset(any_RegP reg, rRegL lreg, immL16 off) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (AddP reg lreg) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $lreg]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale(0x0); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Plus Index Register Plus Offset Operand ++operand indIndex(any_RegP reg, rRegL lreg) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP reg lreg); ++ ++ op_cost(10); ++ format %{"[$reg + $lreg]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale(0x0); ++ disp(0x0); ++ %} ++%} ++ ++// Indirect Memory Times Scale Plus Index Register ++operand indIndexScale(any_RegP reg, rRegL lreg, immI2 scale) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP reg (LShiftL lreg scale)); ++ ++ op_cost(10); ++ format %{"[$reg + $lreg << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale($scale); ++ disp(0x0); ++ %} ++%} ++ ++operand indPosIndexScale(any_RegP reg, rRegI idx, immI2 scale) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ predicate(n->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); ++ match(AddP reg (LShiftL (ConvI2L idx) scale)); ++ ++ op_cost(10); ++ format %{"[$reg + pos $idx << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($idx); ++ scale($scale); ++ disp(0x0); ++ %} ++%} ++ ++// Indirect Memory Times Scale Plus Index Register Plus Offset Operand ++operand indIndexScaleOffset(any_RegP reg, immL16 off, rRegL lreg, immI2 scale) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (AddP reg (LShiftL lreg scale)) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $lreg << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale($scale); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Plus Positive Index Register Plus Offset Operand ++operand indPosIndexOffset(any_RegP reg, immL16 off, rRegI idx) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ predicate(n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); ++ match(AddP (AddP reg (ConvI2L idx)) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $idx]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($idx); ++ scale(0x0); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand ++operand indPosIndexScaleOffset(any_RegP reg, immL16 off, rRegI idx, immI2 scale) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ predicate(n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); ++ match(AddP (AddP reg (LShiftL (ConvI2L idx) scale)) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $idx << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($idx); ++ scale($scale); ++ disp($off); ++ %} ++%} ++ ++// Indirect Narrow Oop Plus Offset Operand ++// Note: x86 architecture doesn't support "scale * index + offset" without a base ++// we can't free r12 even with Universe::narrow_oop_base() == NULL. TODO:why r12? jzy ++//lsp todo check sw is s5?? ++operand indCompressedOopOffset(rRegN reg, immL16 off) %{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_shift() == Address::times_8)); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (DecodeN reg) off); ++ ++ op_cost(10); ++ format %{"[S5 + $reg << 3 + $off] (compressed oop addressing)" %} ++ interface(MEMORY_INTER) %{ ++ base(0xe); // S5 fo SW64 ++ index($reg); ++ scale(0x3); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Operand ++operand indirectNarrow(rRegN reg) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(DecodeN reg); ++ ++ format %{ "[$reg]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index(0x1e); ++ scale(0x0); ++ disp(0x0); ++ %} ++%} ++ ++// Indirect Memory Plus Short Offset Operand ++operand indOffset16Narrow(rRegN reg, immL16 off) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (DecodeN reg) off); ++ ++ format %{ "[$reg + $off (16-bit)]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index(0x1e); ++ scale(0x0); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Plus Long Offset Operand ++//operand indOffset32Narrow(rRegN reg, immL32 off) ++//%{ ++// predicate(Universe::narrow_oop_shift() == 0); ++// constraint(ALLOC_IN_RC(ptr_reg)); ++// match(AddP (DecodeN reg) off); ++// ++// format %{ "[$reg + $off (32-bit)]" %} ++// interface(MEMORY_INTER) %{ ++// base($reg); ++// index(0x1e); ++// scale(0x0); ++// disp($off); ++// %} ++//%} ++ ++// Indirect Memory Plus Index Register Plus Offset Operand ++operand indIndexOffsetNarrow(rRegN reg, rRegL lreg, immL16 off) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (AddP (DecodeN reg) lreg) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $lreg]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale(0x0); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Plus Index Register Plus Offset Operand ++operand indIndexNarrow(rRegN reg, rRegL lreg) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (DecodeN reg) lreg); ++ ++ op_cost(10); ++ format %{"[$reg + $lreg]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale(0x0); ++ disp(0x0); ++ %} ++%} ++ ++// Indirect Memory Times Scale Plus Index Register ++operand indIndexScaleNarrow(rRegN reg, rRegL lreg, immI2 scale) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (DecodeN reg) (LShiftL lreg scale)); ++ ++ op_cost(10); ++ format %{"[$reg + $lreg << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale($scale); ++ disp(0x0); ++ %} ++%} ++ ++// Indirect Memory Times Scale Plus Index Register Plus Offset Operand ++operand indIndexScaleOffsetNarrow(rRegN reg, immL16 off, rRegL lreg, immI2 scale) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ match(AddP (AddP (DecodeN reg) (LShiftL lreg scale)) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $lreg << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($lreg); ++ scale($scale); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Times Plus Positive Index Register Plus Offset Operand ++operand indPosIndexOffsetNarrow(rRegN reg, immL16 off, rRegI idx) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ predicate(Universe::narrow_oop_shift() == 0 && n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); ++ match(AddP (AddP (DecodeN reg) (ConvI2L idx)) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $idx]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($idx); ++ scale(0x0); ++ disp($off); ++ %} ++%} ++ ++// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand ++operand indPosIndexScaleOffsetNarrow(rRegN reg, immL16 off, rRegI idx, immI2 scale) ++%{ ++ constraint(ALLOC_IN_RC(ptr_reg)); ++ predicate(Universe::narrow_oop_shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); ++ match(AddP (AddP (DecodeN reg) (LShiftL (ConvI2L idx) scale)) off); ++ ++ op_cost(10); ++ format %{"[$reg + $off + $idx << $scale]" %} ++ interface(MEMORY_INTER) %{ ++ base($reg); ++ index($idx); ++ scale($scale); ++ disp($off); ++ %} ++%} ++ ++//----------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 stackSlotP(sRegP reg) ++%{ ++ constraint(ALLOC_IN_RC(stack_slots)); ++ // No match rule because this operand is only generated in matching ++ ++ format %{ "[$reg]" %} ++ interface(MEMORY_INTER) %{ ++ base(0x1e); // SP ++ index(0x1e); // No Index ++ scale(0x0); // No Scale ++ disp($reg); // Stack Offset ++ %} ++%} ++ ++operand stackSlotI(sRegI reg) ++%{ ++ constraint(ALLOC_IN_RC(stack_slots)); ++ // No match rule because this operand is only generated in matching ++ ++ format %{ "[$reg]" %} ++ interface(MEMORY_INTER) %{ ++ base(0x1e); // SP ++ index(0x1e); // No Index ++ scale(0x0); // No Scale ++ disp($reg); // Stack Offset ++ %} ++%} ++ ++operand stackSlotF(sRegF reg) ++%{ ++ constraint(ALLOC_IN_RC(stack_slots)); ++ // No match rule because this operand is only generated in matching ++ ++ format %{ "[$reg]" %} ++ interface(MEMORY_INTER) %{ ++ base(0x1e); // SP ++ index(0x1e); // No Index ++ scale(0x0); // No Scale ++ disp($reg); // Stack Offset ++ %} ++%} ++ ++operand stackSlotD(sRegD reg) ++%{ ++ constraint(ALLOC_IN_RC(stack_slots)); ++ // No match rule because this operand is only generated in matching ++ ++ format %{ "[$reg]" %} ++ interface(MEMORY_INTER) %{ ++ base(0x1e); // SP ++ index(0x1e); // No Index ++ scale(0x0); // No Scale ++ disp($reg); // Stack Offset ++ %} ++%} ++ ++operand stackSlotL(sRegL reg) ++%{ ++ constraint(ALLOC_IN_RC(stack_slots)); ++ // No match rule because this operand is only generated in matching ++ ++ format %{ "[$reg]" %} ++ interface(MEMORY_INTER) %{ ++ base(0x1e); // SP ++ index(0x1e); // No Index ++ scale(0x0); // No Scale ++ disp($reg); // Stack Offset ++ %} ++%} ++ ++//----------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. ++ ++// Comparision Code ++operand cmpOp() %{ ++ match(Bool); ++ ++ format %{ "" %} ++ interface(COND_INTER) %{ ++ equal(0x4, "e"); ++ not_equal(0x5, "ne"); ++ less(0xC, "l"); ++ greater_equal(0xD, "ge"); ++ less_equal(0xE, "le"); ++ greater(0xF, "g"); ++ overflow(0x0, "o"); ++ no_overflow(0x1, "no"); ++ %} ++%} ++ ++// Comparison Code, unsigned compare. Used by FP also, with ++// C2 (unordered) turned into GT or LT already. The other bits ++// C0 and C3 are turned into Carry & Zero flags. ++operand cmpOpU() %{ ++ match(Bool); ++ ++ format %{ "" %} ++ interface(COND_INTER) %{ ++ equal(0x4, "e"); ++ not_equal(0x5, "ne"); ++ less(0x2, "b"); ++ greater_equal(0x3, "nb"); ++ less_equal(0x6, "be"); ++ greater(0x7, "nbe"); ++ overflow(0x0, "o"); ++ no_overflow(0x1, "no"); ++ %} ++%} ++ ++ ++//----------OPERAND CLASSES---------------------------------------------------- ++// Operand Classes are groups of operands that are used as 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, indOffset16, indIndexOffset, indIndex, indIndexScale, indIndexScaleOffset, ++ indPosIndexScale, indPosIndexOffset, indPosIndexScaleOffset, ++ indCompressedOopOffset, ++ indirectNarrow, indOffset16Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, indIndexScaleOffsetNarrow, ++ indPosIndexOffsetNarrow, indPosIndexScaleOffsetNarrow); ++ ++//----------PIPELINE----------------------------------------------------------- ++// Rules which define the behavior of the target architectures pipeline. ++pipeline %{ ++ ++//----------ATTRIBUTES--------------------------------------------------------- ++attributes %{ ++ fixed_size_instructions; // Fixed size instructions ++ branch_has_delay_slot; // branch have delay slot in gs2 ++ max_instructions_per_bundle = 1; // 1 instruction per bundle ++ max_bundles_per_cycle = 4; // Up to 4 bundles per cycle ++ bundle_unit_size=4; ++ 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( MachNop ); ++ %} ++ ++ //----------RESOURCES---------------------------------------------------------- ++ // Resources are the functional units available to the machine ++ ++ resources(D1, D2, D3, D4, DECODE = D1 | D2 | D3| D4, ALU1, ALU2, ALU = ALU1 | ALU2, FPU1, FPU2, FPU = FPU1 | FPU2, MEM, BR); ++ ++ //----------PIPELINE DESCRIPTION----------------------------------------------- ++ // Pipeline Description specifies the stages in the machine's pipeline ++ ++ // IF: fetch ++ // ID: decode ++ // RD: read ++ // CA: caculate ++ // WB: write back ++ // CM: commit ++ ++ pipe_desc(IF, ID, RD, CA, WB, CM); ++ ++ ++ //----------PIPELINE CLASSES--------------------------------------------------- ++ // Pipeline Classes describe the stages in which input and output are ++ // referenced by the hardware pipeline. ++ ++ //No.1 Integer ALU reg-reg operation : dst <-- reg1 op reg2 ++ pipe_class ialu_regI_regI(rRegI dst, rRegI src1, rRegI src2) %{ ++ single_instruction; ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write)+1; ++ DECODE : ID; ++ ALU : CA; ++ %} ++ ++ //No.19 Integer mult operation : dst <-- reg1 mult reg2 ++ pipe_class ialu_mult(rRegI dst, rRegI src1, rRegI src2) %{ ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write)+5; ++ DECODE : ID; ++ ALU2 : CA; ++ %} ++ ++ pipe_class mulL_reg_reg(rRegL dst, rRegL src1, rRegL src2) %{ ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write)+10; ++ DECODE : ID; ++ ALU2 : CA; ++ %} ++ ++ pipe_class ialu_mult_imm(rRegI dst, rRegI src1, immU8 src2) %{ ++ src1 : RD(read); ++ dst : WB(write)+5; ++ DECODE : ID; ++ ALU2 : CA; ++ %} ++ ++ pipe_class mulL_reg_imm(rRegL dst, rRegL src1, immUL8 src2) %{ ++ src1 : RD(read); ++ dst : WB(write)+10; ++ DECODE : ID; ++ ALU2 : CA; ++ %} ++ ++ //No.19 Integer div operation : dst <-- reg1 div reg2 ++ pipe_class ialu_div(rRegI dst, rRegI src1, rRegI src2) %{ ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write)+10; ++ DECODE : ID; ++ ALU2 : CA; ++ %} ++ ++ //No.19 Integer mod operation : dst <-- reg1 mod reg2 ++ pipe_class ialu_mod(rRegI dst, rRegI src1, rRegI src2) %{ ++ instruction_count(2); ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write)+10; ++ DECODE : ID; ++ ALU2 : CA; ++ %} ++ ++ //No.15 Long ALU reg-reg operation : dst <-- reg1 op reg2 ++ pipe_class ialu_regL_regL(rRegL dst, rRegL src1, rRegL src2) %{ ++ instruction_count(2); ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ ALU : CA; ++ %} ++ ++ //No.18 Long ALU reg-imm operation : dst <-- reg1 op immUL8 ++ pipe_class ialu_regL_imm(rRegL dst, rRegL src) %{ ++ instruction_count(2); ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ ALU : CA; ++ %} ++ ++ //No.18 Long ALU reg-imm16 operation : dst <-- reg1 op imm16 ++ pipe_class ialu_regL_imm16(rRegL dst, rRegL src) %{ ++ instruction_count(2); ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ ALU : CA; ++ %} ++ ++ //no.16 load Long from memory : ++ pipe_class ialu_loadL(rRegL dst, memory mem) %{ ++ instruction_count(2); ++ mem : RD(read); ++ dst : WB(write)+5; ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ //No.17 Store Long to Memory : ++ pipe_class ialu_storeL(rRegL src, memory mem) %{ ++ instruction_count(2); ++ mem : RD(read); ++ src : RD(read); ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ //No.2 Integer ALU reg-imm16 operation : dst <-- reg1 op imm16 ++ pipe_class ialu_regI_imm16(rRegI dst, rRegI src) %{ ++ single_instruction; ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ ALU : CA; ++ %} ++ ++ //No.3 Integer move operation : dst <-- reg ++ pipe_class ialu_regI_mov(rRegI dst, rRegI src) %{ ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ ALU : CA; ++ %} ++ ++ //No.4 No instructions : do nothing ++ pipe_class empty( ) %{ ++ instruction_count(0); ++ %} ++ ++ //No.5 UnConditional branch ++ pipe_class pipe_jmp( label labl ) %{ ++ multiple_bundles; ++ DECODE : ID; ++ BR : RD; ++ %} ++ ++ //No.6 ALU Conditional branch : ++ pipe_class pipe_alu_branch(rRegI src1, rRegI src2, label labl ) %{ ++ multiple_bundles; ++ src1 : RD(read); ++ src2 : RD(read); ++ DECODE : ID; ++ BR : RD; ++ %} ++ ++ //no.7 load integer from memory : ++ pipe_class ialu_reg_mem(rRegI dst, memory mem) %{ ++ mem : RD(read); ++ dst : WB(write)+3; ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ //No.8 Store Integer to Memory : ++ pipe_class ialu_storeI(rRegI src, memory mem) %{ ++ mem : RD(read); ++ src : RD(read); ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ ++ //No.10 Floating FPU reg-reg operation : dst <-- reg1 op reg2 ++ pipe_class fpu_regF_regF(regF dst, regF src1, regF src2) %{ ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ FPU : CA; ++ %} ++ ++ //No.22 Floating div operation : dst <-- reg1 div reg2 ++ pipe_class fpu_div(regF dst, regF src1, regF src2) %{ ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ FPU2 : CA; ++ %} ++ ++ pipe_class fcvt_I2D(regD dst, rRegI src) %{ ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ FPU1 : CA; ++ %} ++ ++ pipe_class fcvt_D2I(rRegI dst, regD src) %{ ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ FPU1 : CA; ++ %} ++ ++ pipe_class pipe_mfc1(rRegI dst, regD src) %{ ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ pipe_class pipe_mtc1(regD dst, rRegI src) %{ ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ MEM : RD(5); ++ %} ++ ++ //No.23 Floating sqrt operation : dst <-- reg1 sqrt reg2 ++ pipe_class fpu_sqrt(regF dst, regF src1, regF src2) %{ ++ multiple_bundles; ++ src1 : RD(read); ++ src2 : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ FPU2 : CA; ++ %} ++ ++ //No.11 Load Floating from Memory : ++ pipe_class fpu_loadF(regF dst, memory mem) %{ ++ instruction_count(1); ++ mem : RD(read); ++ dst : WB(write)+3; ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ //No.12 Store Floating to Memory : ++ pipe_class fpu_storeF(regF src, memory mem) %{ ++ instruction_count(1); ++ mem : RD(read); ++ src : RD(read); ++ DECODE : ID; ++ MEM : RD; ++ %} ++ ++ //No.13 FPU Conditional branch : ++ pipe_class pipe_fpu_branch(regF src1, regF src2, label labl ) %{ ++ multiple_bundles; ++ src1 : RD(read); ++ src2 : RD(read); ++ DECODE : ID; ++ BR : RD; ++ %} ++ ++//No.14 Floating FPU reg operation : dst <-- op reg ++ pipe_class fpu1_regF(regF dst, regF src) %{ ++ src : RD(read); ++ dst : WB(write); ++ DECODE : ID; ++ FPU : CA; ++ %} ++ ++ pipe_class long_memory_op() %{ ++ instruction_count(10); multiple_bundles; force_serialization; ++ fixed_latency(30); ++ %} ++ ++ pipe_class simple_call() %{ ++ instruction_count(10); multiple_bundles; force_serialization; ++ fixed_latency(200); ++ BR : RD; ++ %} ++ ++ pipe_class call() %{ ++ instruction_count(10); multiple_bundles; force_serialization; ++ fixed_latency(200); ++ %} ++ ++ //FIXME: ++ //No.9 Piple slow : for multi-instructions ++ pipe_class pipe_slow( ) %{ ++ instruction_count(20); ++ force_serialization; ++ multiple_bundles; ++ fixed_latency(50); ++ %} ++ ++%} ++ ++ ++//----------INSTRUCTIONS------------------------------------------------------- ++// ++// match -- States which machine-independent subtree may be replaced ++// by this instruction. ++// ins_cost -- The estimated cost of this instruction is used by instruction ++// selection to identify a minimum cost tree of machine ++// instructions that matches a tree of machine-independent ++// instructions. ++// format -- A string providing the disassembly for this instruction. ++// The value of an instruction's operand may be inserted ++// by referring to it with a '$' prefix. ++// opcode -- Three instruction opcodes may be provided. These are referred ++// to within an encode class as $primary, $secondary, and $tertiary ++// rrspectively. The primary opcode is commonly used to ++// indicate the type of machine instruction, while secondary ++// and tertiary are often used for prefix options or addressing ++// modes. ++// ins_encode -- A list of encode classes with parameters. The encode class ++// name must have been defined in an 'enc_class' specification ++// in the encode section of the architecture description. ++ ++//-------- only swjdk8-------- ++instruct s4AddLp(rRegP dst, rRegI index, immI_2 dis, rRegP base) %{ ++ match(Set dst (AddP base (LShiftL (ConvI2L index) dis))); ++ ins_cost(10); ++ format %{ " s4addl $index,$base,$dst @ s4AddLp " %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register op1 = $index$$Register; ++ Register op2 = $base$$Register; ++ __ s4addl(op1, op2, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++instruct s8AddLp(rRegP dst, rRegI index, immI_3 scale, rRegP base) %{ ++ match(Set dst (AddP base (LShiftL (ConvI2L index) scale))); ++ ins_cost(10); ++ format %{ " s8addl $index,$base,$dst @ s8AddLp " %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register op1 = $index$$Register; ++ Register op2 = $base$$Register; ++ __ s8addl(op1, op2, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++instruct s4AddWp(rRegI dst, rRegI index, immI_2 scale, rRegI base) %{ ++ match(Set dst (AddI base (LShiftI index scale))); ++ ins_cost(10); ++ format %{ " s4addw $index,$base,$dst @ s4AddWp " %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register op1 = $index$$Register; ++ Register op2 = $base$$Register; ++ __ s4addw(op1, op2, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++instruct s8AddWp(rRegI dst, rRegI index, immI_3 scale, rRegI base) %{ ++ match(Set dst (AddI base (LShiftI index scale))); ++ ins_cost(10); ++ format %{ " s8addw $index,$base,$dst @ s8AddWp " %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register op1 = $index$$Register; ++ Register op2 = $base$$Register; ++ __ s8addw(op1, op2, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++//---------------------- ++ ++//----------Load/Store/Move Instructions--------------------------------------- ++//----------Load Instructions-------------------------------------------------- ++ ++// Load Byte (8 bit signed) ++instruct loadB(rRegI dst, memory mem) ++%{ ++ match(Set dst (LoadB mem)); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# byte\t@loadB\n\t" ++ "\tsextb $dst, $dst" ++ %} ++ ++ ins_encode %{ ++ __ ldbu ($dst$$Register, $mem$$Address); ++ __ sextb($dst$$Register, $dst$$Register); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Byte (8 bit signed) into Long Register ++instruct loadB2L(rRegL dst, memory mem) ++%{ ++ match(Set dst (ConvI2L (LoadB mem))); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# byte -> long\t@loadB2L\n\t" ++ "\tsextb $dst, $dst" %} ++ ++ ins_encode %{ ++ __ ldbu ($dst$$Register, $mem$$Address); ++ __ sextb($dst$$Register, $dst$$Register); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Byte (8 bit UNsigned) ++instruct loadUB(rRegI dst, memory mem) ++%{ ++ match(Set dst (LoadUB mem)); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# ubyte\t@loadUB" %} ++ ++ ins_encode %{ ++ __ ldbu($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Byte (8 bit UNsigned) into Long Register ++instruct loadUB2L(rRegL dst, memory mem) ++%{ ++ match(Set dst (ConvI2L (LoadUB mem))); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# ubyte -> long\t@loadUB2L" %} ++ ++ ins_encode %{ ++ __ ldbu($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register ++instruct loadUB2L_immI(rRegL dst, memory mem, immI mask) %{ ++ match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); ++ //effect(KILL cr); ++ ++ format %{ "ldbu $dst, $mem\t# ubyte & 32-bit mask -> long\t@loadUB2L_immI\n\t" ++ "andw $dst, right_n_bits($mask, 8)" %} ++ ins_encode %{ ++ Register Rdst = $dst$$Register; ++ __ ldbu(Rdst, $mem$$Address); ++ __ andw(Rdst, $mask$$constant & right_n_bits(8), Rdst); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Short (16 bit signed) ++instruct loadS(rRegI dst, memory mem) ++%{ ++ match(Set dst (LoadS mem)); ++ ++ ins_cost(125); ++ format %{ "ldhu $dst, $mem\t# short\t@loadS\n\t" ++ "sexth $dst, $dst" %} ++ ++ ins_encode %{ ++ __ ldhu ($dst$$Register, $mem$$Address); ++ __ sexth($dst$$Register, $dst$$Register); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Short (16 bit signed) to Byte (8 bit signed) ++instruct loadS2B(rRegI dst, memory mem, immI_24 twentyfour) %{ ++ match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour)); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# short -> byte\t@loadS2B\n\t" ++ "sextb $dst, $dst" %} ++ ins_encode %{ ++ __ ldbu ($dst$$Register, $mem$$Address); ++ __ sextb($dst$$Register, $dst$$Register); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Short (16 bit signed) into Long Register ++instruct loadS2L(rRegL dst, memory mem) ++%{ ++ match(Set dst (ConvI2L (LoadS mem))); ++ ++ ins_cost(125); ++ format %{ "ldhu $dst, $mem\t# short\t@loadS2L\n\t" ++ "sexth $dst, $dst" %} ++ ++ ins_encode %{ ++ __ ldhu ($dst$$Register, $mem$$Address); ++ __ sexth($dst$$Register, $dst$$Register); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Short/Char (16 bit UNsigned) ++instruct loadUS(rRegI dst, memory mem) ++%{ ++ match(Set dst (LoadUS mem)); ++ ++ ins_cost(125); ++ format %{ "ldhu $dst, $mem\t# ushort/char\t@loadUS" %} ++ ++ ins_encode %{ ++ __ ldhu($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed) ++instruct loadUS2B(rRegI dst, memory mem, immI_24 twentyfour) %{ ++ match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour)); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# ushort -> byte\t@loadUS2B\n\t" ++ "sextb $dst, $mem" %} ++ ins_encode %{ ++ __ ldbu ($dst$$Register, $mem$$Address); ++ __ sextb($dst$$Register, $dst$$Register); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Short/Char (16 bit UNsigned) into Long Register ++instruct loadUS2L(rRegL dst, memory mem) ++%{ ++ match(Set dst (ConvI2L (LoadUS mem))); ++ ++ ins_cost(125); ++ format %{ "ldhu $dst, $mem\t# ushort/char -> long\t@loadUS2L" %} ++ ++ ins_encode %{ ++ __ ldhu($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Short/Char (16 bit UNsigned) with mask 0xFF into Long Register ++instruct loadUS2L_immI_255(rRegL dst, memory mem, immI_255 mask) %{ ++ match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); ++ ++ format %{ "ldbu $dst, $mem\t# ushort/char & 0xFF -> long\t@loadUS2L_immI_255" %} ++ ins_encode %{ ++ __ ldbu($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Short/Char (16 bit UNsigned) with 32-bit mask into Long Register ++instruct loadUS2L_immI(rRegL dst, memory mem, immI mask) %{ ++ match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); ++ //effect(KILL cr); ++ ++ format %{ "ldhu $dst, $mem\t# ushort/char & 32-bit mask -> long\t@loadUS2L_immI\n\t" ++ "andw $dst, right_n_bits($mask, 16), $dst" %} ++ ins_encode %{ ++ Register Rdst = $dst$$Register; ++ __ ldhu(Rdst, $mem$$Address); ++ __ andw(Rdst, $mask$$constant & right_n_bits(16), Rdst); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer ++instruct loadI(rRegI dst, memory mem) ++%{ ++ match(Set dst (LoadI mem)); ++ ++ ins_cost(125); ++ format %{ "ldws $dst, $mem\t# int\t@loadI" %} ++ ++ ins_encode %{ ++ __ ldws($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer (32 bit signed) to Byte (8 bit signed) ++instruct loadI2B(rRegI dst, memory mem, immI_24 twentyfour) %{ ++ match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour)); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# int -> byte\t@loadI2B\n\t" ++ "sextb $dst, $dst" %} ++ ins_encode %{ ++ __ ldbu($dst$$Register, $mem$$Address); ++ __ sextb($dst$$Register, $dst$$Register); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer (32 bit signed) to Unsigned Byte (8 bit UNsigned) ++instruct loadI2UB(rRegI dst, memory mem, immI_255 mask) %{ ++ match(Set dst (AndI (LoadI mem) mask)); ++ ++ ins_cost(125); ++ format %{ "ldbu $dst, $mem\t# int -> ubyte\t@loadI2UB" %} ++ ins_encode %{ ++ __ ldbu($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer (32 bit signed) to Short (16 bit signed) ++instruct loadI2S(rRegI dst, memory mem, immI_16 sixteen) %{ ++ match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen)); ++ ++ ins_cost(125); ++ format %{ "ldhu $dst, $mem\t# int -> short\t@loadI2S\n\t" ++ "sexth $dst, $dst" %} ++ ins_encode %{ ++ __ ldhu ($dst$$Register, $mem$$Address); ++ __ sexth($dst$$Register, $dst$$Register); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer (32 bit signed) to Unsigned Short/Char (16 bit UNsigned) ++instruct loadI2US(rRegI dst, memory mem, immI_65535 mask) %{ ++ match(Set dst (AndI (LoadI mem) mask)); ++ ++ ins_cost(125); ++ format %{ "ldhu $dst, $mem\t# int -> ushort/char\t@loadI2US" %} ++ ins_encode %{ ++ __ ldhu($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer into Long Register ++instruct loadI2L(rRegL dst, memory mem) ++%{ ++ match(Set dst (ConvI2L (LoadI mem))); ++ ++ ins_cost(100); ++ format %{ "ldws $dst, $mem\t# int -> long\t@loadI2L" %} ++ ++ ins_encode %{ ++ __ ldws($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer with mask 0xFF into Long Register ++instruct loadI2L_immI_255(rRegL dst, memory mem, immI_255 mask) %{ ++ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); ++ ++ format %{ "ldbu $dst, $mem\t# int & 0xFF -> long\t@loadI2L_immI_255" %} ++ ins_encode %{ ++ __ ldbu($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer with mask 0xFFFF into Long Register ++instruct loadI2L_immI_65535(rRegL dst, memory mem, immI_65535 mask) %{ ++ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); ++ ++ format %{ "ldhu $dst, $mem\t# int & 0xFFFF -> long\t@loadI2L_immI_65535" %} ++ ins_encode %{ ++ __ ldhu($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Integer with a 31-bit mask into Long Register TODO:jzy mask length s is OK? andw's immediate length -si 8-bit ++instruct loadI2L_immU31(rRegL dst, memory mem, immU31 mask) %{ ++ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); ++ //effect(KILL cr); ++ ++ format %{ "ldwu $dst, $mem\t# int & 31-bit mask -> long\t@loadI2L_immU31\n\t" ++ "andw $dst, $mask, $dst" %} ++ ins_encode %{ ++ Register Rdst = $dst$$Register; ++ __ ldw(Rdst, $mem$$Address); ++ __ andw(Rdst, $mask$$constant, Rdst); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Unsigned Integer into Long Register ++instruct loadUI2L(rRegL dst, memory mem, immL_32bits mask) ++%{ ++ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); ++ ++ ins_cost(125); ++ format %{ "ldwu $dst, $mem\t# uint -> long\t@loadUI2L" %} ++ ++ ins_encode %{ ++ __ ldwu($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Long ++//TODO implicit null check LSP ++instruct loadL(rRegL dst, memory mem) ++%{ ++ match(Set dst (LoadL mem)); ++ ++ ins_cost(125); ++ format %{ "ldl $dst, $mem\t# long\t@loadL" %} ++ ++ ins_encode %{ ++ __ ldl($dst$$Register, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++// Load Long - UNaligned ++instruct loadL_unaligned(rRegL dst, memory mem) ++%{ ++ match(Set dst (LoadL_unaligned mem)); ++ ++ // FIXME: Need more effective ldl/ldr ++ ins_cost(450); ++ format %{ "loadL_unaligned $dst, $mem #@loadL_unaligned" %} ++ ins_encode %{ ++ __ ldl($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe( ialu_loadL ); ++%} ++ ++// Load Range ++//TODO CHECK LSP ++instruct loadRange(rRegI dst, memory mem) ++%{ ++ match(Set dst (LoadRange mem)); ++ ++ ins_cost(125); // XXX ++ format %{ "ldws $dst, $mem\t# range\t@loadRange" %} ++ ins_encode %{ ++ __ ldws($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++// Load Pointer ++instruct loadP(rRegP dst, memory mem) ++%{ ++ match(Set dst (LoadP mem)); ++ ++ ins_cost(125); // XXX ++ format %{ "ldptr $dst, $mem\t# ptr\t@loadP" %} ++ ins_encode (load_P_enc(dst, mem)); ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++// Load Compressed Pointer ++instruct loadN(rRegN dst, memory mem) ++%{ ++ match(Set dst (LoadN mem)); ++ ++ ins_cost(125); // XXX ++ format %{ "ldwu $dst, $mem\t# compressed ptr\t@loadN" %} ++ ins_encode (load_N_enc(dst, mem)); ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++ ++// Load Klass Pointer ++instruct loadKlass(rRegP dst, memory mem) ++%{ ++ match(Set dst (LoadKlass mem)); ++ ++ ins_cost(125); // XXX ++ format %{ "ldptr $dst, $mem\t# class\t@loadKlass" %} ++ ins_encode (load_P_enc(dst, mem)); ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++// Load narrow Klass Pointer ++instruct loadNKlass(rRegN dst, memory mem) ++%{ ++ match(Set dst (LoadNKlass mem)); ++ ++ ins_cost(125); // XXX ++ format %{ "ldwu $dst, $mem\t# compressed klass ptr\t@loadNKlass" %} ++ ins_encode (load_N_enc(dst, mem)); ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++// Load Float ++instruct loadF(regF dst, memory mem) ++%{ ++ match(Set dst (LoadF mem)); ++ //effect(KILL rscratch1_GP); ++ ++ ins_cost(145); // XXX ++ format %{ "load_float $dst, $mem\t# float\t@loadF" %} ++ ins_encode %{ ++ __ load_float($dst$$FloatRegister, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++// Load Float TODO:jzy 4 bytes? ++instruct MoveF2VL(regF dst, regF src) %{ ++ match(Set dst src); ++ format %{ "fcpys $src, $src, $dst\t! load float (4 bytes)\t@MoveF2VL" %} ++ ins_encode %{ ++ __ fcpys($src$$FloatRegister, $src$$FloatRegister, $dst$$FloatRegister); ++ %} ++ ins_pipe( fpu_regF_regF ); ++%} ++ ++// Load Float TODO: jzy need this? ++instruct MoveVL2F(regF dst, regF src) %{ ++ match(Set dst src); ++ format %{ "fcpys $src, $src, $dst\t! load float (4 bytes)\t@MoveVL2F" %} ++ ins_encode %{ ++ __ fcpys($src$$FloatRegister, $src$$FloatRegister, $dst$$FloatRegister); ++ %} ++ ins_pipe( fpu_regF_regF); ++%} ++ ++// Load Double ++/*instruct loadD_partial(regD dst, memory mem) ++%{ ++// predicate(!UseXmmLoadAndClearUpper); ++ match(Set dst (LoadD mem)); ++ ++ ins_cost(145); // XXX ++ format %{ "movlpd $dst, $mem\t# double" %} ++ ins_encode %{ ++// __ movdbl($dst$$XMMRegister, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); // XXX ++%}*/ ++ ++instruct loadD(regD dst, memory mem) ++%{ ++// predicate(UseXmmLoadAndClearUpper); ++ match(Set dst (LoadD mem)); ++ ++ ins_cost(145); // XXX ++ format %{ "load_double $dst, $mem\t# double\t@loadD" %} ++ ins_encode %{ ++ __ load_double($dst$$FloatRegister, $mem$$Address); ++ %} ++ ins_pipe(ialu_reg_mem); // XXX ++%} ++ ++instruct loadD_unaligned(regD dst, memory mem ) %{ ++ match(Set dst (LoadD_unaligned mem)); ++ ins_cost(250); ++ // FIXME: Need more effective ldl/ldr ++ ins_encode %{ ++ __ load_double($dst$$FloatRegister, $mem$$Address); ++ %} ++ ins_pipe( ialu_reg_mem ); ++%} ++ ++// Load Double ++// TODO CHECK LSP ++instruct MoveD2VL(regD dst, regD src) %{ ++ match(Set dst src); ++ format %{ "fcpys $src, $src, $dst\t! load double (8 bytes)\t@MoveD2VL" %} ++ ins_encode %{ ++ __ fcpys($src$$FloatRegister, $src$$FloatRegister, $dst$$FloatRegister); ++ %} ++ ins_pipe( fpu_regF_regF ); ++%} ++ ++// Load Double ++// TODO CHECK LSP ++instruct MoveVL2D(regD dst, regD src) %{ ++ match(Set dst src); ++ format %{ "fcpys $src, $src, $dst\t! load double (8 bytes)\t@MoveVL2D" %} ++ ins_encode %{ ++ __ fcpys($src$$FloatRegister, $src$$FloatRegister, $dst$$FloatRegister); ++ %} ++ ins_pipe( fpu_regF_regF ); ++%} ++ ++// Load Effective Address ++instruct leaP16(rRegP dst, indOffset16 mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); // XXX ++ format %{ "lea $dst, $mem\t# ptr 16\t@leaP16" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); //TODO check ++%} ++ ++//instruct leaP32(rRegP dst, indOffset32 mem) ++//%{ ++// match(Set dst mem); ++// ++// ins_cost(110); ++// format %{ "lea $dst, $mem\t# ptr 32\t@leaP32" %} ++// ins_encode %{ ++// __ lea($dst$$Register, $mem$$Address); ++// %} ++// ins_pipe(ialu_regI_mov);//TODO check ++//%} ++ ++instruct leaPIdxOff(rRegP dst, indIndexOffset mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxoff\t@leaPIdxOff" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPIdxScale(rRegP dst, indIndexScale mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxscale\t@leaPIdxScale" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPPosIdxScale(rRegP dst, indPosIndexScale mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxscale\t@leaPPosIdxScale" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxscaleoff\t@leaPIdxScaleOff" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPPosIdxOff(rRegP dst, indPosIndexOffset mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr posidxoff\t@leaPPosIdxOff" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) ++%{ ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr posidxscaleoff\t@leaPPosIdxScaleOff" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++// Load Effective Address which uses Narrow (32-bits) oop ++instruct leaPCompressedOopOffset(rRegP dst, indCompressedOopOffset mem) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_shift() != 0)); ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr compressedoopoff32\t@leaPCompressedOopOffset" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaP16Narrow(rRegP dst, indOffset16Narrow mem) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst mem); ++ ++ ins_cost(110); // XXX ++ format %{ "lea $dst, $mem\t# ptr off8narrow\t@leaP8Narrow" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++//instruct leaP32Narrow(rRegP dst, indOffset32Narrow mem) ++//%{ ++// predicate(Universe::narrow_oop_shift() == 0); ++// match(Set dst mem); ++// ++// ins_cost(110); ++// format %{ "lea $dst, $mem\t# ptr off32narrow\t@leaP32Narrow" %} ++// ins_encode %{ ++// __ lea($dst$$Register, $mem$$Address); ++// %} ++// ins_pipe(ialu_regI_mov); ++//%} ++ ++instruct leaPIdxOffNarrow(rRegP dst, indIndexOffsetNarrow mem) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxoffnarrow\t@leaPIdxOffNarrow" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPIdxScaleNarrow(rRegP dst, indIndexScaleNarrow mem) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxscalenarrow\t@leaPIdxScaleNarrow" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPIdxScaleOffNarrow(rRegP dst, indIndexScaleOffsetNarrow mem) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr idxscaleoffnarrow\t@leaPIdxScaleOffNarrow" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPPosIdxOffNarrow(rRegP dst, indPosIndexOffsetNarrow mem) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr posidxoffnarrow\t@leaPPosIdxOffNarrow" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst mem); ++ ++ ins_cost(110); ++ format %{ "lea $dst, $mem\t# ptr posidxscaleoffnarrow\t@leaPPosIdxScaleOffNarrow" %} ++ ins_encode %{ ++ __ lea($dst$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct loadConI(rRegI dst, immI src) ++%{ ++ match(Set dst src); ++ ++ format %{ "mov_immediate32s $dst, $src\t# int\t@loadConI" %} ++ ins_encode %{ ++ __ mov_immediate32s($dst$$Register, $src$$constant); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct loadConI0(rRegI dst, immI0 src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(50); ++ format %{ "movl $dst, R0\t# int\t@loadConI0" %} ++ ins_encode %{ ++ __ movl($dst$$Register, R0); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct loadConL(rRegL dst, immL src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(150); ++ format %{ "mov_immediate64 $dst, $src\t# long\t@loadConL" %} ++ ins_encode %{ ++ __ mov_immediate64($dst$$Register, $src$$constant); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct loadConL0(rRegL dst, immL0 src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(50); ++ format %{ "movl $dst, R0\t# int\t@loadConL0" %} ++ ins_encode %{ ++ __ movl($dst$$Register, R0); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++//instruct loadConUL32(rRegL dst, immUL32 src) ++//%{ ++// match(Set dst src); ++// ++// ins_cost(60); ++// format %{ "mov_immediate32u $dst, $src\t# long (unsigned 32-bit)\t@loadConUL32" %} ++// ins_encode %{ ++// __ mov_immediate32u($dst$$Register, $src$$constant); ++// %} ++// ins_pipe(ialu_regL_regL); ++//%} ++ ++ ++instruct loadConL32(rRegL dst, immL32 src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(70); ++ format %{ "mov_immediate32s $dst, $src\t# long (32-bit)\t@loadConL32" %} ++ ins_encode %{ ++ __ mov_immediate32s($dst$$Register, (int)$src$$constant); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++//use in swjdk8 need to check lsp? ++instruct loadConL16(rRegL dst, immL16 src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(70); ++ format %{ "ldi $dst, $src, R0\t# long (16-bit)\t@loadConL16" %} ++ ins_encode %{ ++ __ ldi($dst$$Register, (int)$src$$constant, R0); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct loadConP(rRegP dst, immP con) %{ ++ match(Set dst con); ++ ++ format %{ "mov_immediate64 $dst, $con\t# ptr\t@loadConP" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ long* value = (long*)$con$$constant; ++ ++ if($con->constant_reloc() == relocInfo::metadata_type){ ++ int klass_index = __ oop_recorder()->find_index((Klass*)value); ++ RelocationHolder rspec = metadata_Relocation::spec(klass_index); ++ ++ __ relocate(rspec); ++ __ prepare_patch_li48(dst, (long)value); ++ }else if($con->constant_reloc() == relocInfo::oop_type){ ++ int oop_index = __ oop_recorder()->find_index((jobject)value); ++ RelocationHolder rspec = oop_Relocation::spec(oop_index); ++ ++ __ relocate(rspec); ++ __ prepare_patch_li48(dst, (long)value); ++ } else if ($con->constant_reloc() == relocInfo::none) { ++ __ mov_immediate64(dst, (long)value); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); // XXX ++%} ++ ++instruct loadConP0(rRegP dst, immP0 src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(50); ++ format %{ "movl $dst, R0\t# ptr\t@loadConP0" %} ++ ins_encode %{ ++ __ movl($dst$$Register, R0); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct loadConP31(rRegP dst, immP31 src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(60); ++ format %{ "mov_immediate32u $dst, $src\t# ptr (positive 32-bit)\t@loadConP31" %} ++ ins_encode %{ ++ __ mov_immediate32u($dst$$Register, $src$$constant); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct loadConP_poll(rRegP dst, immP_poll src) %{ ++ match(Set dst src); ++ ++ ins_cost(50); ++ format %{ "mov_immediate64 $dst, $src #@loadConP_poll" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ intptr_t value = (intptr_t)$src$$constant; ++ ++ __ mov_immediate64(dst, (long)value); ++ %} ++ ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++instruct loadConF(regF dst, immF con) %{ ++ match(Set dst con); ++ ins_cost(125); ++ format %{ "load_float $dst, [$constantaddress]\t# load from constant table: float=$con\t@loadConF" %} ++ ins_encode %{ ++ __ load_float($dst$$FloatRegister, $constantaddress($con)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++//TODO:jzy which is immN0? ++instruct loadConN0(rRegN dst, immN0 src) %{ ++ match(Set dst src); ++ ++ format %{ "movl $dst, $src\t# compressed NULL ptr\t@loadConN0" %} ++ ins_encode %{ ++ __ movl($dst$$Register, R0); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++//TODO:jzy compressed ptr? ++instruct loadConN(rRegN dst, immN src) %{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "set_narrow_oop $dst, $src\t# compressed ptr\t@loadConN" %} ++ ins_encode %{ ++ address con = (address)$src$$constant; ++ if (con == NULL) { ++ ShouldNotReachHere(); ++ } else { ++ __ set_narrow_oop($dst$$Register, (jobject)$src$$constant); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); // XXX ++%} ++ ++instruct loadConNKlass(rRegN dst, immNKlass src) %{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "set_narrow_klass $dst, $src\t# compressed klass ptr\t@loadConNKlass" %} ++ ins_encode %{ ++ address con = (address)$src$$constant; ++ if (con == NULL) { ++ ShouldNotReachHere(); ++ } else { ++ __ set_narrow_klass($dst$$Register, (Klass*)$src$$constant); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); // XXX ++%} ++ ++instruct loadConF0(regF dst, immF0 src) ++%{ ++ match(Set dst src); ++ ins_cost(100); ++ ++ format %{ "fcpys f31, f31, $dst\t# float 0.0\t@loadConF0" %} ++ ins_encode %{ ++ __ fcpys(f31, f31, $dst$$FloatRegister); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// Use the same format since predicate() can not be used here. ++instruct loadConD(regD dst, immD con) %{ ++ match(Set dst con); ++ ins_cost(125); ++ format %{ "load_double $dst, [$constantaddress]\t# load from constant table: double=$con\t@loadConD" %} ++ ins_encode %{ ++ __ load_double($dst$$FloatRegister, $constantaddress($con)); ++ %} ++ ins_pipe(fpu_loadF); ++%} ++ ++instruct loadConD0(regD dst, immD0 src) ++%{ ++ match(Set dst src); ++ ins_cost(100); ++ ++ format %{ "fcpys f31, f31, $dst\t# double 0.0\t@loadConD0" %} ++ ins_encode %{ ++ __ fcpys(f31, f31, $dst$$FloatRegister); ++ %} ++ ins_pipe(fpu_loadF); ++%} ++ ++instruct loadSSI(rRegI dst, stackSlotI src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "ldws $dst, $src\t# int stk\t@loadSSI" %} ++ ins_encode %{ ++ __ ldws($dst$$Register, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++instruct loadSSL(rRegL dst, stackSlotL src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "ldl $dst, $src\t# long stk\t@loadSSL" %} ++ ins_encode %{ ++ __ ldl($dst$$Register, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++instruct loadSSP(rRegP dst, stackSlotP src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "ldl $dst, $src\t# ptr stk\t@loadSSP" %} ++ ins_encode %{ ++ __ ldl($dst$$Register, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++ ++instruct loadSSF(regF dst, stackSlotF src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "load_float $dst, $src\t# float stk\t@loadSSF" %} ++ ins_encode %{ ++ __ load_float($dst$$FloatRegister, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++// Use the same format since predicate() can not be used here. ++instruct loadSSD(regD dst, stackSlotD src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(125); ++ format %{ "load_double $dst, $src\t# double stk\t@loadSSD" %} ++ ins_encode %{ ++ __ load_double($dst$$FloatRegister, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++// Prefetch instructions for allocation. ++// Must be safe to execute with invalid address (cannot fault). ++ ++instruct prefetchAlloc( memory mem ) %{ ++ predicate(AllocatePrefetchInstr==3); ++ match(PrefetchAllocation mem); ++ ins_cost(125); ++ ++ format %{ "PREFETCHW $mem\t# Prefetch allocation into level 1 cache and mark modified" %} ++ ins_encode %{ ++// __ prefetchw($mem$$Address); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct prefetchAllocNTA( memory mem ) %{ ++ predicate(AllocatePrefetchInstr==0); ++ match(PrefetchAllocation mem); ++ ins_cost(125); ++ ++ format %{ "PREFETCHNTA $mem\t# Prefetch allocation to non-temporal cache for write" %} ++ ins_encode %{ ++ Register dst = R0; ++ __ load_float(f31, $mem$$Address); // fillde ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct prefetchAllocT0( memory mem ) %{ ++ predicate(AllocatePrefetchInstr==1); ++ match(PrefetchAllocation mem); ++ ins_cost(125); ++ ++ format %{ "PREFETCHT0 $mem\t# Prefetch allocation to level 1 and 2 caches for write" %} ++ ins_encode %{ ++// __ prefetcht0($mem$$Address); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct prefetchAllocT2( memory mem ) %{ ++ predicate(AllocatePrefetchInstr==2); ++ match(PrefetchAllocation mem); ++ ins_cost(125); ++ ++ format %{ "PREFETCHT2 $mem\t# Prefetch allocation to level 2 cache for write" %} ++ ins_encode %{ ++// __ prefetcht2($mem$$Address); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++//----------Store Instructions------------------------------------------------- ++ ++// Store Byte ++instruct storeB(memory mem, rRegI src) ++%{ ++ match(Set mem (StoreB mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "stb $src, $mem\t# byte\t@storeB" %} ++ ins_encode %{ ++ __ stb($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++// Store Char/Short ++instruct storeC(memory mem, rRegI src) ++%{ ++ match(Set mem (StoreC mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "sth $src, $mem\t# char/short\t@storeC" %} ++ ins_encode %{ ++ __ sth($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++// Store Integer ++instruct storeI(memory mem, rRegI src) ++%{ ++ match(Set mem (StoreI mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "stw $src, $mem\t# int\t@storeI" %} ++ ++ ins_encode %{ ++ __ stw($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++// Store Long ++//TODO implicit null check LSP ++instruct storeL(memory mem, rRegL src) ++%{ ++ match(Set mem (StoreL mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "stl $src, $mem\t# long\t@storeL" %} ++ ++ ins_encode %{ ++ __ stl($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); // XXX ++%} ++ ++// Store Pointer ++instruct storeP(memory mem, any_RegP src) ++%{ ++ match(Set mem (StoreP mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "stl $src, $mem\t# ptr\t@storeP" %} ++ ins_encode %{ ++ __ stl($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeImmP0(memory mem, immP0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreP mem zero)); ++ ++ ins_cost(125); // XXX ++ format %{ "stl S5, $mem\t# ptr (r12_heapbase==0)\t@storeImmP0" %} ++ ++ ins_encode %{ ++//TODO:where set r12_heapbase? jzy ++ __ stl(r12_heapbase, $mem$$Address); ++ %} ++ ++ ins_pipe(ialu_storeI); ++%} ++ ++/*no immdiate operand in swjdk8 ++// Store NULL Pointer, mark word, or other simple pointer constant. TODO:jzy immP31 is NULL ++instruct storeImmP(memory mem, immP31 src) ++%{ ++ match(Set mem (StoreP mem src)); ++ ++ ins_cost(150); // XXX ++ format %{"movwu rscratch3, $src\t# ptr\t@storeImmP" ++ "stl rscratch3, $mem" %} ++ ++ ins_encode %{ ++ __ mov_immediate32(rscratch3, $src$$constant); ++ __ stl(rscratch3, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%}*/ ++ ++// Store Compressed Pointer ++instruct storeN(memory mem, rRegN src) ++%{ ++ match(Set mem (StoreN mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "stw $src, $mem\t# compressed ptr\t@storeN" %} ++ ins_encode %{ ++ __ stw($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeNKlass(memory mem, rRegN src) ++%{ ++ match(Set mem (StoreNKlass mem src)); ++ ++ ins_cost(125); // XXX ++ format %{ "stw $src, $mem\t# compressed klass ptr\t@storeNKlass" %} ++ ins_encode %{ ++ __ stw($src$$Register, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeImmN0(memory mem, immN0 zero) ++%{ ++ predicate(Universe::narrow_oop_base() == NULL && Universe::narrow_klass_base() == NULL); ++ match(Set mem (StoreN mem zero)); ++ ++ ins_cost(125); // XXX ++ format %{ "stw $mem, r12_heapbase\t# compressed ptr (R12_heapbase==0)\t@storeImmN0" %} ++ ins_encode %{ ++ __ stw(r12_heapbase, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++/*no immdiate operand in swjdk8 ++instruct storeImmN(memory mem, immN src) ++%{ ++ match(Set mem (StoreN mem src)); ++ ++ ins_cost(150); // XXX ++ format %{ "set_narrow_oop $src, $mem\t# compressed ptr\t@storeImmN" %} ++ ins_encode %{ ++ address con = (address)$src$$constant; ++ if (con == NULL) { ++ __ stw(R0, $mem$$Address); ++ } else { ++ __ set_narrow_oop($mem$$Address, (jobject)$src$$constant); ++ } ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeImmNKlass(memory mem, immNKlass src) ++%{ ++ match(Set mem (StoreNKlass mem src)); ++ ++ ins_cost(150); // XXX ++ format %{ "set_narrow_klass $src, $mem\t# compressed klass ptr\t@storeImmNKlass" %} ++ ins_encode %{ ++ __ set_narrow_klass($mem$$Address, (Klass*)$src$$constant); ++ %} ++ ins_pipe(ialu_storeI); ++%}*/ ++ ++// Store Integer Immediate ++instruct storeImmI0(memory mem, immI0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreI mem zero)); ++ ++ ins_cost(125); // XXX ++ format %{ "stw r12_heapbase, $mem\t# int (r12_heapbase==0)\t@storeImmI0" %} ++ ins_encode %{ ++ __ stw(r12_heapbase, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++/*no immdiate operand in swjdk8 ++instruct storeImmI(memory mem, immI src) ++%{ ++ match(Set mem (StoreI mem src)); ++ ++ ins_cost(150); ++ format %{ "movwu rscratch3, $src\t# int\t@storeImmI\n\t" ++ "stw rscratch3, $mem" %} ++ ++ ins_encode %{ ++ __ mov_immediate32(rscratch3, $src$$constant); ++ __ stw(rscratch3, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%}*/ ++ ++// Store Long Immediate ++//TODO implicit null check LSP ++instruct storeImmL0(memory mem, immL0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreL mem zero)); ++ ++ ins_cost(125); // XXX ++ format %{ "stl r12_heapbase, $mem\t# long (r12_heapbase==0)\t@storeImmL0" %} ++ ins_encode %{ ++ __ stl(r12_heapbase, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++/*no immdiate operand in swjdk8 ++instruct storeImmL(memory mem, immL32 src) ++%{ ++ match(Set mem (StoreL mem src)); ++ ++ ins_cost(150); ++ format %{ "movws rscratch3, $src\t# long\t@storeImmL\n\t" ++ "stl rscratch3, $mem" %} ++ ins_encode %{ ++ __ movws(rscratch3, (u_int32_t)$src$$constant); ++ __ stl(rscratch3, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%}*/ ++ ++// Store Short/Char Immediate ++instruct storeImmC0(memory mem, immI0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreC mem zero)); ++ ++ ins_cost(125); // XXX ++ format %{ "sth r12_heapbase, $mem\t# short/char (r12_heapbase==0)\t@storeImmC0" %} ++ ins_encode %{ ++ __ sth(r12_heapbase, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++/*no immdiate operand in swjdk8 ++instruct storeImmI16(memory mem, immI16 src) ++%{ ++// predicate(UseStoreImmI16); ++ match(Set mem (StoreC mem src)); ++ ++ ins_cost(150); ++ format %{ "ldi rscratch3, $src\t# short/char\t@storeImmI16\n\t" ++ "sth rscratch3, $mem" %} ++ ins_encode %{ ++ __ ldi(rscratch3, $src$$constant, R0); ++ __ sth(rscratch3, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%}*/ ++ ++// Store Byte Immediate ++instruct storeImmB0(memory mem, immI0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreB mem zero)); ++ ++ ins_cost(125); // XXX ++ format %{ "stb r12_heapbase, $mem\t# short/char (r12_heapbase==0)\t@storeImmB0" %} ++ ins_encode %{ ++ __ stb(r12_heapbase, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++/*no immdiate operand in swjdk8 ++instruct storeImmB(memory mem, immI8 src) ++%{ ++ match(Set mem (StoreB mem src)); ++ ++ ins_cost(150); // XXX ++ format %{ "ldi rscratch3, $src\t# byte\t@storeImmB\n\t" ++ "stb rscratch3, $mem" %} ++ ins_encode %{ ++ __ ldi(rscratch3, $src$$constant, R0); ++ __ stb(rscratch3, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%}*/ ++ ++// Store CMS card-mark Immediate ++instruct storeImmCM0(memory mem, immI0 zero) ++%{ ++ match(Set mem (StoreCM mem zero)); ++ predicate(unnecessary_storestore(n)); ++ ++ ins_cost(125); // XXX ++ format %{ "stb R0, $mem\t# CMS card-mark byte 0\t@storeImmCM0" %} ++ ++ ins_encode %{ ++ __ stb(R0, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeImmCM0_ordered(memory mem, immI0 src) ++%{ ++ match(Set mem (StoreCM mem src)); ++ ++ ins_cost(150); // XXX ++ format %{ "stb R0, $mem\t# CMS card-mark byte 0\t@storeImmCM0 MEMB" %} ++ ++ ins_encode %{ ++ if(UseWmemb) ++ __ wmemb(); ++ else ++ __ memb(); ++ __ stb(R0, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++// Store Float ++instruct storeF(memory mem, regF src) ++%{ ++ match(Set mem (StoreF mem src)); ++ ++ ins_cost(95); // XXX ++ format %{ "store_float $src, $mem\t# float\t@storeF" %} ++ ins_encode %{ ++ __ store_float($src$$FloatRegister, $mem$$Address); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++// Store immediate Float value (it is faster than store from XMM register) ++instruct storeF0(memory mem, immF0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreF mem zero)); ++ ++ ins_cost(25); // XXX ++ format %{ "store_float f31, $mem\t# float 0. (r12_heapbase==0)\t@storeF0" %} ++ ++ ins_encode %{ ++ __ store_float(f31, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++/*no immdiate operand in swjdk8 ++//TODO:it's ok todo this ? jzy ++instruct storeF_imm(memory mem, immF src) ++%{ ++ match(Set mem (StoreF mem src)); ++ ++ ins_cost(50); ++ format %{ "mov_immdiate32 rscratch3, $src\t# float\t@storeF_imm\n\t" ++ "stw rscratch3, $mem\t# float" %} ++ ++ ins_encode %{ ++ __ mov_immediate32(rscratch3, $src$$constant); ++ __ stw(rscratch3, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++*/ ++// Store Double ++instruct storeD(memory mem, regD src) ++%{ ++ match(Set mem (StoreD mem src)); ++ ++ ins_cost(95); // XXX ++ format %{ "store_double $src, $mem\t# double\t@storeD" %} ++ ins_encode %{ ++ __ store_double($src$$FloatRegister, $mem$$Address); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++// Store immediate double 0.0 (it is faster than store from XMM register) TODO:is zero? jzy ++instruct storeD0_imm(memory mem, immD0 src) ++%{ ++ predicate(!UseCompressedOops || (Universe::narrow_oop_base() != NULL));// lsp todo check ++ match(Set mem (StoreD mem src)); ++ ++ ins_cost(50); ++ format %{ "store_double f31, $mem\t# double 0.\t@storeD0_imm" %} ++ ++ ins_encode %{ ++ __ store_double(f31, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeD0(memory mem, immD0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set mem (StoreD mem zero)); ++ ++ ins_cost(25); // XXX ++ format %{ "store_double f31, $mem\t# double 0. \t@storeD0" %} ++ ++ ins_encode %{ ++ __ store_double(f31, $mem$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeSSI(stackSlotI dst, rRegI src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(100); ++ format %{ "stw $src, $dst\t# int stk\t@storeSSI" %} ++ ++ ins_encode %{ ++ __ stw($src$$Register, $dst$$Address); ++ %} ++ ins_pipe( ialu_storeI ); ++%} ++ ++instruct storeSSL(stackSlotL dst, rRegL src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(100); ++ format %{ "stl $src, $dst\t# long stk\t@storeSSL" %} ++ ++ ins_encode %{ ++ __ stl($src$$Register, $dst$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeSSP(stackSlotP dst, rRegP src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(100); ++ format %{ "stl $src, $dst\t# ptr stk\t@storeSSP" %} ++ ++ ins_encode %{ ++ __ stl($src$$Register, $dst$$Address); ++ %} ++ ins_pipe(ialu_storeI); ++%} ++ ++instruct storeSSF(stackSlotF dst, regF src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(95); // XXX ++ format %{ "store_float $src, $dst\t# float stk\t@storeSSF" %} ++ ins_encode %{ ++ __ store_float($src$$FloatRegister, Address(esp, $dst$$disp)); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct storeSSD(stackSlotD dst, regD src) ++%{ ++ match(Set dst src); ++ ++ ins_cost(95); // XXX ++ format %{ "store_double $src, $dst\t# double stk\t@storeSSD" %} ++ ins_encode %{ ++ __ store_double($src$$FloatRegister, Address(esp, $dst$$disp)); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++//----------BSWAP Instructions------------------------------------------------- ++instruct bytes_reverse_int(rRegI dst) %{ ++ match(Set dst (ReverseBytesI dst)); ++ ++ format %{ "bswapw $dst @bytes_reverse_int" %} ++ //opcode(0x0F, 0xC8); /*Opcode 0F /C8 */ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ __ swap(dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct bytes_reverse_long(rRegL dst) %{ ++ match(Set dst (ReverseBytesL dst)); ++ ++ format %{ "bswapl $dst @bytes_reverse_long" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ if(UseSW8A) { ++ __ revbl(dst, dst); ++ } else { ++ int zap1 = 0x1; ++ int zap2 = 0x80; ++ int count = 0x38; ++ int zap3 = 0x7E; ++ //__ stop("bytes_reverse_long"); ++ assert(dst != rscratch3 && dst != rscratch2_AT, "dst should not equal to AT and rscratch3"); ++ __ slll(dst, count, rscratch3); ++ __ srll(dst, count, rscratch2_AT); ++ __ bis(rscratch3, rscratch2_AT, rscratch2_AT); ++ __ zapnot(dst, zap3, dst);//set the highest and lowest bit to zero ++ __ bis(dst, rscratch2_AT, dst); ++ ++ for(int i=1; i<4; i++){ ++ zap1 = zap1<<1; ++ zap2 = zap2>>1; ++ count = count - 16; ++ zap3 = 0xff - zap1 -zap2; ++ __ zapnot(dst, zap1, rscratch3); ++ __ slll(rscratch3, count, rscratch3); ++ __ zapnot(dst, zap2, rscratch2_AT); ++ __ srll(rscratch2_AT, count, rscratch2_AT); ++ __ bis(rscratch3, rscratch2_AT, rscratch2_AT); ++ __ zapnot(dst, zap3, dst); ++ __ bis(dst, rscratch2_AT, dst); ++ } ++ } ++ %} ++ ins_pipe( pipe_slow); ++%} ++ ++instruct bytes_reverse_unsigned_short(rRegI dst) %{ ++ match(Set dst (ReverseBytesUS dst)); ++ ++ format %{ "zapnot $dst, #0x3, $dst $dst @bytes_reverse_unsigned_short\n\t" ++ "huswap $dst" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ __ zapnot(dst, 0x3, dst); ++ __ huswap(dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct bytes_reverse_short(rRegI dst) %{ ++ match(Set dst (ReverseBytesS dst)); ++ ++ format %{ "zapnot $dst, #0x3, $dst $dst @bytes_reverse_unsigned_short\n\t" ++ "hswap $dst" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ __ zapnot(dst, 0x3, dst); ++ __ hswap(dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++//---------- Zeros Count Instructions ------------------------------------------ ++// CountLeadingZerosINode CountTrailingZerosINode ++instruct countLeadingZerosI(rRegI dst, rRegI src) %{ ++ predicate(UseCountLeadingZerosInstruction); ++ match(Set dst (CountLeadingZerosI src)); ++ ++ format %{ "CTLZ $dst, $dst #@countLeadingZerosI" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ zapnot(src, 0xf, dst); ++ __ ctlz(dst, dst); ++ __ subw(dst, 32, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++instruct countLeadingZerosL(rRegI dst, rRegL src) %{ ++ predicate(UseCountLeadingZerosInstruction); ++ match(Set dst (CountLeadingZerosL src)); ++ ++ format %{ "CTLZ $src,$dst #@countLeadingZerosL" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ ctlz(src, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct countTrailingZerosI(rRegI dst, rRegI src) %{ ++ predicate(UseCountTrailingZerosInstruction); ++ match(Set dst (CountTrailingZerosI src)); ++ ++ format %{ "CTTZ $src, $dst\n\t #@countTrailingZerosI"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ slll(src, 32, dst); ++ __ cttz(dst, dst); ++ __ subw(dst, 32, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++instruct countTrailingZerosL(rRegI dst, rRegL src) %{ ++ predicate(UseCountTrailingZerosInstruction); ++ match(Set dst (CountTrailingZerosL src)); ++ ++ format %{ "CTTZ $src,$dst #@countTrailingZerosL" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ cttz(src, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++ ++//---------- Population Count Instructions ------------------------------------- ++ ++instruct popCountI(rRegI dst, rRegI src) %{ ++ predicate(UsePopCountInstruction); ++ match(Set dst (PopCountI src)); ++ ++ format %{ "popcnt $dst, $src" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ zapnot(src, 0xf, dst); ++ __ ctpop(dst, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++/* memory operands no use in sw64 ++instruct popCountI_mem(rRegI dst, memory mem) %{ ++ predicate(UsePopCountInstruction); ++ match(Set dst (PopCountI (LoadI mem))); ++ ++ format %{ "popcnt $dst, $mem" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ ++ __ ldw(rscratch2_AT, $mem$$Address); ++ __ zapnot(rscratch2_AT, 0xf, dst); ++ __ ctpop(dst, dst); ++ %} ++ ins_pipe(ialu_reg_mem); ++%}*/ ++ ++// Note: Long.bitCount(long) returns an int. ++instruct popCountL(rRegI dst, rRegL src) %{ ++ predicate(UsePopCountInstruction); ++ match(Set dst (PopCountL src)); ++ ++ format %{ "CTPOP $dst, $src" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ ctpop(src, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++/* memory operands no use in sw64 ++// Note: Long.bitCount(long) returns an int. ++instruct popCountL_mem(rRegI dst, memory mem) %{ ++ predicate(UsePopCountInstruction); ++ match(Set dst (PopCountL (LoadL mem))); ++ ++ format %{ "popcnt $dst, $mem" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ ++ __ ldl(rscratch2_AT, $mem$$Address); ++ __ ctpop(rscratch2_AT, dst); ++ %} ++ ins_pipe(ialu_reg_mem); ++%}*/ ++ ++//----------MemBar Instructions----------------------------------------------- ++// Memory barrier flavors ++ ++instruct membar_acquire() %{ ++ match(MemBarAcquire); ++ ins_cost(0); ++ ++ size(4); ++ format %{ "MEMBAR-acquire @ membar_acquire" %} ++ ins_encode %{ ++ if (UseNecessaryMembar) { ++ __ memb(); ++ } ++ %} ++ ins_pipe(empty); ++%} ++ ++instruct load_fence() %{ ++ match(LoadFence); ++ ins_cost(400); ++ ++ format %{ "MEMBAR @ load_fence" %} ++ ins_encode %{ ++ __ memb(); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct membar_acquire_lock() %{ ++ match(MemBarAcquireLock); ++ ins_cost(0); ++ ++ size(0); ++ format %{ "MEMBAR-acquire (acquire as part of CAS in prior FastLock so empty encoding) @ membar_acquire_lock" %} ++ ins_encode(); ++ ins_pipe(empty); ++%} ++ ++instruct unnecessary_membar_release() %{ ++ predicate(unnecessary_release(n)); ++ match(MemBarRelease); ++ ins_cost(0); ++ ++ format %{ "membar_release (elided)" %} ++ ++ ins_encode %{ ++ __ block_comment("membar_release (elided)"); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct membar_release() %{ ++ match(MemBarRelease); ++ match(StoreFence); ++ ins_cost(400);//0 ++ ++ format %{ "MEMBAR-release StoreFence @ membar_release" %} ++ ++ ins_encode %{ ++// // Attention: DO NOT DELETE THIS GUY! ++ __ memb(); ++ %} ++ ++ ins_pipe(pipe_slow); ++%} ++ ++instruct membar_release_lock() %{ ++ match(MemBarReleaseLock); ++ ins_cost(0); ++ ++ size(0); ++ format %{ "MEMBAR-release-lock (release in FastUnlock so empty) @ membar_release_lock" %} ++ ins_encode(); ++ ins_pipe(empty); ++%} ++ ++instruct membar_volatile() %{ ++ match(MemBarVolatile); ++ ins_cost(400); ++ ++ format %{ "MEMBAR-volatile" %} ++ ins_encode %{ ++ if( !os::is_MP() ) return; // Not needed on single CPU ++ __ memb(); ++ ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++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) @ unnecessary_membar_volatile" %} ++ ins_encode( ); ++ ins_pipe(empty); ++%} ++ ++instruct membar_storestore() %{ ++ match(MemBarStoreStore); ++ ++ ins_cost(0); ++ size(4); ++ format %{ "MEMBAR-storestore @ membar_storestore" %} ++ ins_encode %{ ++ if (UseWmemb && UseNecessaryMembar) { ++ __ wmemb(); ++ } else if (UseNecessaryMembar) { ++ __ memb(); ++ } ++ %} ++ ins_pipe(empty); ++%} ++ ++//----------Move Instructions-------------------------------------------------- ++ ++instruct castX2P(rRegP dst, rRegL src) ++%{ ++ match(Set dst (CastX2P src)); ++ ++ format %{ "movl $dst, $src\t# long->ptr @castX2P" %} ++ ins_encode %{ ++ Register src = $src$$Register; ++ Register dst = $dst$$Register; ++ ++ if(src != dst) ++ __ movl(dst, src); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++instruct castP2X(rRegL dst, rRegP src) ++%{ ++ match(Set dst (CastP2X src)); ++ ++ format %{ "movl $dst, $src\t# ptr -> long@castP2X" %} ++ ins_encode %{ ++ Register src = $src$$Register; ++ Register dst = $dst$$Register; ++ ++ if(src != dst); ++ __ movl(dst, src); ++ %} ++ ins_pipe(ialu_regI_mov); ++%} ++ ++// Convert oop into int for vectors alignment masking ++instruct convP2I(rRegI dst, rRegP src) ++%{ ++ match(Set dst (ConvL2I (CastP2X src))); ++ ++ format %{ "movwu $dst, $src\t# ptr -> int" %} ++ ins_encode %{ ++ __ movwu($dst$$Register, $src$$Register); //LSP CHECK?? OK ++ %} ++ ins_pipe(ialu_regI_regI); // XXX ++%} ++ ++// Convert compressed oop into int for vectors alignment masking ++// in case of 32bit oops (heap < 4Gb). ++instruct convN2I(rRegI dst, rRegN src) ++%{ ++ predicate(Universe::narrow_oop_shift() == 0); ++ match(Set dst (ConvL2I (CastP2X (DecodeN src)))); ++ ++ format %{ "movwu $dst, $src\t# compressed ptr -> int" %} ++ ins_encode %{ ++ __ movwu($dst$$Register, $src$$Register);//LSP CHECK?? OK ++ %} ++ ins_pipe(ialu_regI_regI); // XXX ++%} ++ ++// Convert oop pointer into compressed form ++instruct encodeHeapOop(rRegN dst, rRegP src) %{ ++ predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); ++ match(Set dst (EncodeP src)); ++// effect(KILL cr); ++ format %{ "encode_heap_oop $dst,$src" %} ++ ins_encode %{ ++ Register s = $src$$Register; ++ Register d = $dst$$Register; ++// __ movl(d, s); ++ __ encode_heap_oop(d, s); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct encodeHeapOop_not_null(rRegN dst, rRegP src) %{ ++ predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); ++ match(Set dst (EncodeP src)); ++ format %{ "encode_heap_oop_not_null $dst,$src" %} ++ ins_encode %{ ++ __ encode_heap_oop_not_null($dst$$Register, $src$$Register); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct decodeHeapOop(rRegP dst, rRegN src) %{ ++ predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && ++ n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); ++ match(Set dst (DecodeN src)); ++// effect(KILL cr); ++ format %{ "decode_heap_oop $dst,$src" %} ++ ins_encode %{ ++ Register s = $src$$Register; ++ Register d = $dst$$Register; ++// __ movl(d, s); ++ __ decode_heap_oop(d, s); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct decodeHeapOop_not_null(rRegP dst, rRegN src) %{ ++ predicate(n->bottom_type()->is_ptr()->ptr() == TypePtr::NotNull || ++ n->bottom_type()->is_ptr()->ptr() == TypePtr::Constant); ++ match(Set dst (DecodeN src)); ++ format %{ "decode_heap_oop_not_null $dst,$src" %} ++ ins_encode %{ ++ Register s = $src$$Register; ++ Register d = $dst$$Register; ++ if (s != d) { ++ __ decode_heap_oop_not_null(d, s); ++ } else { ++ __ decode_heap_oop_not_null(d); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct encodeKlass_not_null(rRegN dst, rRegP src) %{ ++ match(Set dst (EncodePKlass src)); ++// effect(KILL cr); ++ format %{ "encode_klass_not_null $dst,$src" %} ++ ins_encode %{ ++ __ encode_klass_not_null($dst$$Register, $src$$Register); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct decodeKlass_not_null(rRegP dst, rRegN src) %{ ++ match(Set dst (DecodeNKlass src)); ++// effect(KILL cr); ++ format %{ "decode_klass_not_null $dst,$src" %} ++ ins_encode %{ ++ Register s = $src$$Register; ++ Register d = $dst$$Register; ++ if (s != d) { ++ __ decode_klass_not_null(d, s); ++ } else { ++ __ decode_klass_not_null(d); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++/* ++ ++//----------Conditional Move--------------------------------------------------- ++// Jump ++// dummy instruction for generating temp registers ++instruct jumpXtnd_offset(rRegL switch_val, immI2 shift, rRegI dest) %{ ++ match(Jump (LShiftL switch_val shift)); ++ ins_cost(350); ++ predicate(false); ++ effect(TEMP dest); ++ ++ format %{ "leaq $dest, [$constantaddress]\n\t" ++ "jmp [$dest + $switch_val << $shift]\n\t" %} ++ ins_encode %{ ++ // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 ++ // to do that and the compiler is using that register as one it can allocate. ++ // So we build it all by hand. ++ // Address index(noreg, switch_reg, (Address::ScaleFactor)$shift$$constant); ++ // ArrayAddress dispatch(table, index); ++ Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant); ++ __ lea($dest$$Register, $constantaddress); ++ __ jmp(dispatch); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++ ++instruct jumpXtnd_addr(rRegL switch_val, immI2 shift, immL32 offset, rRegI dest) %{ ++ match(Jump (AddL (LShiftL switch_val shift) offset)); ++ ins_cost(350); ++ effect(TEMP dest); ++ ++ format %{ "leaq $dest, [$constantaddress]\n\t" ++ "jmp [$dest + $switch_val << $shift + $offset]\n\t" %} ++ ins_encode %{ ++ // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 ++ // to do that and the compiler is using that register as one it can allocate. ++ // So we build it all by hand. ++ // Address index(noreg, switch_reg, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant); ++ // ArrayAddress dispatch(table, index); ++ Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant); ++ __ lea($dest$$Register, $constantaddress); ++ __ jmp(dispatch); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++ ++instruct jumpXtnd(rRegL switch_val, rRegI dest) %{ ++ match(Jump switch_val); ++ ins_cost(350); ++ effect(TEMP dest); ++ ++ format %{ "leaq $dest, [$constantaddress]\n\t" ++ "jmp [$dest + $switch_val]\n\t" %} ++ ins_encode %{ ++ // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 ++ // to do that and the compiler is using that register as one it can allocate. ++ // So we build it all by hand. ++ // Address index(noreg, switch_reg, Address::times_1); ++ // ArrayAddress dispatch(table, index); ++ Address dispatch($dest$$Register, $switch_val$$Register, Address::times_1); ++ __ lea($dest$$Register, $constantaddress); ++ __ jmp(dispatch); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++*/ ++ ++// Conditional move ++instruct cmovI_cmpI_reg_reg(rRegI dst, rRegI src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, int @cmovI_cmpI_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpI_reg_imm(rRegI dst, immU8 src, rRegI tmp1, rRegI tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveI (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ins_cost(80); ++ format %{ ++ "cmovI$cop $dst, $src\t# signed, int @cmovI_cmpI_reg_imm" ++ %} ++ ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2, rcc); ++ __ selne(rcc, src, dst, dst); ++ ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct cmovI_cmpL_reg_reg(rRegI dst, rRegI src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, int @cmovI_cmpL_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpL_reg_imm(rRegI dst, immU8 src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, int @cmovI_cmpL_reg_imm" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpN_reg_reg(rRegI dst, rRegI src, rRegN tmp1, rRegN tmp2, cmpOpU cop) %{ ++ match(Set dst (CMoveI (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# unsigned, int @cmovI_cmpN_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpN_reg_imm(rRegI dst, immU8 src, rRegN tmp1, rRegN tmp2, cmpOpU cop) %{ ++ match(Set dst (CMoveI (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# unsigned, int @cmovI_cmpN_reg_imm" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpP_reg_reg(rRegI dst, rRegI src, rRegP tmp1, rRegP tmp2, cmpOpU cop) %{ ++ match(Set dst (CMoveI (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# unsigned, int @cmovI_cmpP_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2, rcc); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpP_reg_imm(rRegI dst, immU8 src, rRegP tmp1, rRegP tmp2, cmpOpU cop) %{ ++ match(Set dst (CMoveI (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# unsigned, int @cmovI_cmpP_reg_imm" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2, rcc); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpU_reg_reg(rRegI dst, rRegI src, rRegI tmp1, rRegI tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpU tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, int @cmovI_cmpU_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpU_reg_imm(rRegI dst, immU8 src, rRegI tmp1, rRegI tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpU tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, int @cmovI_cmpU_reg_imm" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_cmpD_reg_reg(rRegI dst, rRegI src, regD tmp1, regD tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveI (Binary cop (CmpD tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, ptr @cmovI_cmpD_reg_reg" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovI_cmpD_reg_imm(rRegI dst, immU8 src, regD tmp1, regD tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveI (Binary cop (CmpD tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, ptr @cmovI_cmpD_reg_imm" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovI_cmpF_reg_reg(rRegI dst, rRegI src, regF tmp1, regF tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveI (Binary cop (CmpF tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, ptr @cmovI_cmpF_reg_reg" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovI_cmpF_reg_imm(rRegI dst, immU8 src, regF tmp1, regF tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveI (Binary cop (CmpF tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovI$cop $dst, $src\t# signed, ptr @cmovI_cmpF_reg_imm" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++/* ++instruct cmovI_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ ++ match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); ++ ins_cost(200); ++ expand %{ ++ cmovI_regU(cop, cr, dst, src); ++ %} ++%} ++*/ ++/* memory operands no need for SW64 ++// Conditional move ++instruct cmovI_mem1(rRegI dst, memory src, rRegI tmp1, rRegI tmp2, cmpOp cop, rFlagsReg cr) %{ ++ match(Set dst (CMoveI (Binary cop (CmpI tmp1 tmp2)) (Binary dst (LoadI src)))); ++ effect(KILL cr); ++ ins_cost(250); // XXX ++ format %{ "cmovl$cop $dst, $src\t# signed, int" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldw(rscratch3, src); ++ __ cmpws(flag, op1, op2, cr); ++ __ selne(cr, rscratch3, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_mem2(rRegI dst, memory src, rRegL tmp1, rRegL tmp2, cmpOp cop) %{ ++ match(Set dst (CMoveI (Binary cop (CmpL tmp1 tmp2)) (Binary dst (LoadI src)))); ++ ++ ins_cost(250); // XXX ++ format %{ "cmovl$cop $dst, $src\t# signed, int" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldw(rscratch2_AT, src); ++ __ cmpls(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// Conditional move ++instruct cmovI_memU1(rRegI dst, memory src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpN tmp1 tmp2)) (Binary dst (LoadI src)))); ++ ++ ins_cost(250); // XXX ++ format %{ "cmovl$cop $dst, $src\t# unsigned, int" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldw(rscratch2_AT, src); ++ __ cmpwu(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovI_memU2(rRegI dst, memory src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveI (Binary cop (CmpN tmp1 tmp2)) (Binary dst (LoadI src)))); ++ ++ ins_cost(250); // XXX ++ format %{ "cmovl$cop $dst, $src\t# unsigned, int" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldw(rscratch2_AT, src); ++ __ cmplu(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%}*/ ++/* ++instruct cmovI_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, memory src) %{ ++ match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); ++ ins_cost(250); ++ expand %{ ++ cmovI_memU(cop, cr, dst, src); ++ %} ++%} ++*/ ++ ++// Conditional move ++instruct cmovN_cmpI_reg_reg(rRegN dst, rRegN src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# signed, compressed ptr @cmovN_cmpI_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovN_cmpI_reg_imm(rRegN dst, immU8 src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# signed, compressed ptr @cmovN_cmpI_reg_imm" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovN_cmpL_reg_reg(rRegN dst, rRegN src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# signed, compressed ptr @cmovN_cmpL_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovN_cmpU_reg_reg(rRegN dst, rRegN src, rRegI tmp1, rRegI tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpU tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# signed, compressed ptr @cmovN_cmpU_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// Conditional move ++instruct cmovN_cmpN_reg_reg(rRegN dst, rRegN src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# unsigned, compressed ptr @cmovN_cmpN_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovN_cmpN_reg_imm(rRegN dst, immU8 src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# unsigned, compressed ptr @cmovN_cmpN_reg_imm" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovN_cmpP_reg_reg(rRegN dst, rRegN src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# unsigned, compressed ptr @cmovN_cmpP_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovN_cmpP_reg_imm(rRegN dst, immU8 src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveN (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovN$cop $dst, $src\t# unsigned, compressed ptr @cmovN_cmpP_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant & ((1<<8)-1); ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++/* ++instruct cmovN_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ ++ match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); ++ ins_cost(200); ++ expand %{ ++ cmovN_regU(cop, cr, dst, src); ++ %} ++%} ++*/ ++ ++// Conditional move ++instruct cmovP_cmpI_reg_reg(rRegP dst, rRegP src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# signed, ptr @cmovP_cmpI_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovP_cmpU_reg_reg(rRegP dst, rRegP src, rRegI tmp1, rRegI tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpU tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# signed, ptr @cmovP_cmpU_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovP_cmpF_reg_reg(rRegP dst, rRegP src, regF tmp1, regF tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveP (Binary cop (CmpF tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# signed, ptr @cmovP_cmpF_reg_reg" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovs(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovs(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovP_cmpD_reg_reg(rRegP dst, rRegP src, regD tmp1, regD tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveP (Binary cop (CmpD tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# signed, ptr @cmovP_cmpD_reg_reg" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++ ++instruct cmovP_cmpL_reg_reg(rRegP dst, rRegP src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# signed, ptr @cmovP_cmpL_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++// Conditional move ++instruct cmovP_cmpN_reg_reg(rRegP dst, rRegP src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# unsigned, ptr @cmovP_cmpN_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovP_cmpP_reg_reg(rRegP dst, rRegP src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovP$cop $dst, $src\t# unsigned, ptr @cmovP_cmpP_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2 ); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++/* ++instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ ++ match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); ++ ins_cost(200); ++ expand %{ ++ cmovP_regU(cop, cr, dst, src); ++ %} ++%} ++ ++// DISABLED: Requires the ADLC to emit a bottom_type call that ++// correctly meets the two pointer arguments; one is an incoming ++// register but the other is a memory operand. ALSO appears to ++// be buggy with implicit null checks. ++//*/ ++ ++/* memory operands no need for SW64 ++// Conditional move ++instruct cmovP_mem1(rRegP dst, memory src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpI tmp1 tmp2)) (Binary dst (LoadP src)))); ++ ins_cost(250); ++ format %{ "CMOV$cop $dst,$src\t# ptr" %} ++ opcode(0x0F,0x40); ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmpws(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct cmovP_mem2(rRegP dst, memory src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpL tmp1 tmp2)) (Binary dst (LoadP src)))); ++ ins_cost(250); ++ format %{ "CMOV$cop $dst,$src\t# ptr" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmpls(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++// Conditional move ++instruct cmovP_memU1(rRegP dst, memory src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpN tmp1 tmp2)) (Binary dst (LoadP src)))); ++ ins_cost(250); ++ format %{ "CMOV$cop $dst,$src\t# ptr" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmpwu(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct cmovP_memU2(rRegP dst, memory src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveP (Binary cop (CmpP tmp1 tmp2)) (Binary dst (LoadP src)))); ++ ins_cost(250); ++ format %{ "CMOV$cop $dst,$src\t# ptr" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmplu(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++*/ ++ ++instruct cmovL_cmpI_reg_reg(rRegL dst, rRegL src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, long @cmovL_cmpI_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpI_reg_imm(rRegL dst, immU8 src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, long @cmovL_cmpI_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpL_reg_reg(rRegL dst, rRegL src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, long@cmovL_cmpL_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpL_reg_imm(rRegL dst, immU8 src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, long@cmovL_cmpL_reg_imm" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpF_reg_reg(rRegL dst, rRegL src, regF tmp1, regF tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveL (Binary cop (CmpF tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, ptr @cmovL_cmpF_reg_reg" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovs(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovs(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ fimovs(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpD_reg_reg(rRegL dst, rRegL src, regD tmp1, regD tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveL (Binary cop (CmpD tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, ptr @cmovL_cmpD_reg_reg" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpD_reg_imm(rRegL dst, immU8 src, regD tmp1, regD tmp2, cmpOp cop ) %{ ++ match(Set dst (CMoveL (Binary cop (CmpD tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# signed, ptr @cmovL_cmpD_reg_imm" %} ++ ins_encode%{ ++ FloatRegister op1 = $tmp1$$FloatRegister; ++ FloatRegister op2 = $tmp2$$FloatRegister; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ selne(rcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ fimovd(FcmpRES, rcc); ++ __ seleq(rcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpU_reg_reg(rRegL dst, rRegL src, rRegI tmp1, rRegI tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpU tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# unsigned, long @cmovL_cmpU_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpN_reg_reg(rRegL dst, rRegL src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# unsigned, long @cmovL_cmpN_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpN_reg_imm(rRegL dst, immU8 src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# unsigned, long @cmovL_cmpN_reg_imm" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ int src = $src$$constant; ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_cmpP_reg_reg(rRegL dst, rRegL src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovL$cop $dst, $src\t# unsigned, long @cmovL_cmpP_reg_reg" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2); ++ __ selne(rcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++/* ++instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ ++ match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); ++ ins_cost(200); ++ expand %{ ++ cmovL_regU(cop, cr, dst, src); ++ %} ++%} ++*/ ++/* memory operands no need for SW64 ++instruct cmovL_mem1(rRegL dst, memory src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpI tmp1 tmp2)) (Binary dst (LoadL src)))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovq$cop $dst, $src\t# signed, long" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmpws(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_mem2(rRegL dst, memory src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpL tmp1 tmp2)) (Binary dst (LoadL src)))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovq$cop $dst, $src\t# signed, long" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmpls(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_memU1(rRegL dst, memory src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpN tmp1 tmp2)) (Binary dst (LoadL src)))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovq$cop $dst, $src\t# unsigned, long" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmpwu(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct cmovL_memU2(rRegL dst, memory src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveL (Binary cop (CmpP tmp1 tmp2)) (Binary dst (LoadL src)))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovq$cop $dst, $src\t# unsigned, long" %} ++ ins_encode%{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int flag = $cop$$cmpcode; ++ __ ldl(rscratch2_AT, src); ++ __ cmplu(flag, op1, op2, rscratch1_GP); ++ __ selne(rscratch1_GP, rscratch2_AT, dst, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%}*/ ++/* ++instruct cmovL_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, memory src) %{ ++ match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); ++ ins_cost(200); ++ expand %{ ++ cmovL_memU(cop, cr, dst, src); ++ %} ++%} ++*/ ++instruct cmovF_cmpI_reg_reg(regF dst, regF src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveF (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovF$cop $dst, $src\t# signed, float @cmovF_cmpI_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ ifmovd(rcc, fcc); ++ __ fselne(fcc, src, dst, dst); ++ ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovF_cmpL_reg_reg(regF dst, regF src, rRegL tmp1, rRegL tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveF (Binary cop (CmpL tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovF$cop $dst, $src\t# @cmovF_cmpL_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmpls(flag, op1, op2); ++ __ ifmovd(rcc, fcc); ++ __ fselne(fcc, src, dst, dst); ++ ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovF_cmpF_reg_reg(regF dst, regF src, regF tmp1, regF tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveF (Binary cop (CmpF tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovF$cop $dst, $src\t# @cmovF_cmpF_reg_reg" %} ++ ins_encode %{ ++ FloatRegister op1 = as_FloatRegister($tmp1$$reg); ++ FloatRegister op2 = as_FloatRegister($tmp2$$reg); ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ } ++ ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++ //no in sw8 ?? TODO djx ++instruct cmovF_cmpU_reg_reg(regF dst, regF src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveF (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovF$cop $dst, $src\t# @cmovF_cmpU_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ ifmovd(rcc, fcc); ++ __ fselne(fcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++ //no in sw8 ?? TODO djx ++instruct cmovF_cmpP_reg_reg(regF dst, regF src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveF (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovF$cop $dst, $src\t# @cmovF_cmpP_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2); ++ __ ifmovd(rcc, fcc); ++ __ fselne(fcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++/* ++instruct cmovF_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regF dst, regF src) %{ ++ match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); ++ ins_cost(200); ++ expand %{ ++ cmovF_regU(cop, cr, dst, src); ++ %} ++%} ++*/ ++ ++instruct cmovD_cmpI_reg_reg(regD dst, regD src, rRegI tmp1, rRegI tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveD (Binary cop (CmpI tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovD$cop $dst, $src\t# @cmovD_cmpI_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmpws(flag, op1, op2); ++ __ ifmovd(rcc, fcc); ++ __ fselne(fcc, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovD_cmpD_reg_reg(regD dst, regD src, regD tmp1, regD tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveD (Binary cop (CmpD tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovD$cop $dst, $src\t# @cmovD_cmpD_reg_reg" %} ++ ins_encode %{ ++ FloatRegister op1 = as_FloatRegister($tmp1$$reg); ++ FloatRegister op2 = as_FloatRegister($tmp2$$reg); ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovD_cmpF_reg_reg(regD dst, regD src, regF tmp1, regF tmp2, cmpOp cop) ++%{ ++ match(Set dst (CMoveD (Binary cop (CmpF tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovD$cop $dst, $src\t# @cmovD_cmpF_reg_reg" %} ++ ins_encode %{ ++ FloatRegister op1 = as_FloatRegister($tmp1$$reg); ++ FloatRegister op2 = as_FloatRegister($tmp2$$reg); ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ fselne(fcc, src, dst, dst); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ fseleq(fcc, src, dst, dst); ++ break; ++ } ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovD_cmpN_reg_reg(regD dst, regD src, rRegN tmp1, rRegN tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveD (Binary cop (CmpN tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovD$cop $dst, $src\t# @cmovD_cmpN_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmpwu(flag, op1, op2); ++ __ ifmovd(rcc, FcmpRES); ++ __ fselne(FcmpRES, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct cmovD_cmpP_reg_reg(regD dst, regD src, rRegP tmp1, rRegP tmp2, cmpOpU cop) ++%{ ++ match(Set dst (CMoveD (Binary cop (CmpP tmp1 tmp2)) (Binary dst src))); ++ ++ ins_cost(200); // XXX ++ format %{ "cmovD$cop $dst, $src\t# @cmovD_cmpP_reg_reg" %} ++ ins_encode %{ ++ Register op1 = $tmp1$$Register; ++ Register op2 = $tmp2$$Register; ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ int flag = $cop$$cmpcode; ++ __ cmplu(flag, op1, op2); ++ __ ifmovd(rcc, FcmpRES); ++ __ fselne(FcmpRES, src, dst, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++/* ++instruct cmovD_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regD dst, regD src) %{ ++ match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); ++ ins_cost(200); ++ expand %{ ++ cmovD_regU(cop, cr, dst, src); ++ %} ++%} ++*/ ++//----------Arithmetic Instructions-------------------------------------------- ++//----------Addition Instructions---------------------------------------------- ++ ++instruct addI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (AddI src1 src2)); ++ ++ format %{ "addw $src1, $src2, $dst\t# int @addI_rReg" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ __ addw(src1, src2, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++instruct addI_rReg_imm(rRegI dst, rRegI src1, immU8 src2) ++%{ ++ match(Set dst (AddI src1 src2)); ++ ins_cost(80); ++ format %{ "addw $src1, $src2, $dst\t# int @addI_rReg_imm" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ int imm = $src2$$constant; ++ ++ __ addw(src1, imm, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++/*memory operands no need for SW64 ++instruct addI_rReg_mem(rRegI dst, rRegI src1, memory src2) ++%{ ++ match(Set dst (AddI src1 (LoadI src2))); ++ ++ ins_cost(150); // XXX ++ format %{ "ldw $dst, $src2\t# int @addI_rReg_mem\n\t" ++ "addw $src1, $dst, $dst"%} ++ ins_encode %{ ++ __ ldw($dst$$Register, $src2$$Address); ++ __ addw($src1$$Register, rscratch2_AT, $dst$$Register); ++ %} ++// ins_pipe( ialu_reg_mem ); ++%} ++ ++instruct addI_mem_rReg(memory dst, rRegI src) ++%{ ++ match(Set dst (StoreI dst (AddI (LoadI dst) src))); ++ ++ ins_cost(150); // XXX ++ format %{ "ldw rscratch1_GP, $dst\t# int @addI_mem_rReg\n\t" ++ "addw rscratch1_GP, $src, rscratch1_GP\n\t" ++ "stw rscratch1_GP, $dst"%} ++ ins_encode %{ ++ __ ldw(rscratch1_GP, $dst$$Address); ++ __ addw(rscratch1_GP, $src$$Register, rscratch1_GP); ++ __ stw(rscratch1_GP, $dst$$Address); ++ %} ++// ins_pipe(ialu_mem_reg); ++%} ++ ++instruct addI_mem_imm(memory dst, immI src) ++%{ ++ match(Set dst (StoreI dst (AddI (LoadI dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ "addw $dst, $src\t# int @addI_mem_imm" %} ++ ins_encode %{ ++ int imm = $src$$constant; ++ ++ __ ldw(rscratch2_AT, $dst$$Address); ++ if(MacroAssembler::is_uimm8(imm)) { ++ __ addw(rscratch2_AT, imm, rscratch2_AT); ++ } else { ++ __ mov_immediate32(rscratch1_GP, imm); ++ __ addw(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ } ++ __ stw(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe(ialu_mem_imm); ++%}*/ ++ ++instruct incI_rReg(rRegI dst, rRegI src1, immI1 src2) ++%{ ++ match(Set dst (AddI src1 src2)); ++ ins_cost(60); ++ format %{ "addw $src1, #1, $dst\t# int @incI_rReg" %} ++ ins_encode %{ ++ __ addw($src1$$Register, 1, $dst$$Register); ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/*memory operands no need for SW64 ++instruct incI_mem(memory dst, immI1 src) ++%{ ++ match(Set dst (StoreI dst (AddI (LoadI dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ "ldw rscratch2_AT, $dst\t# int @incI_mem\n\t" ++ "addw rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldw(rscratch2_AT, $dst$$Address); ++ __ addw(rscratch2_AT, 1, rscratch2_AT); ++ __ stw(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// XXX why does that use AddI ++instruct decI_rReg(rRegI dst, rRegI src1, immI_M1 src2) ++%{ ++ match(Set dst (AddI src1 src2)); ++ ins_cost(60); ++ format %{ "subw $src1, #1, $dst\t# int @decI_rReg" %} ++ ins_encode %{ ++ __ subw($src1$$Register, 1, $dst$$Register); ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/*memory operands no need for SW64 ++// XXX why does that use AddI ++instruct decI_mem(memory dst, immI_M1 src) ++%{ ++ match(Set dst (StoreI dst (AddI (LoadI dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ "ldw rscratch2_AT, $dst\t# int @decI_mem\n\t" ++ "subw rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldw(rscratch2_AT, $dst$$Address); ++ __ subw(rscratch2_AT, 1, rscratch2_AT); ++ __ stw(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// the same as addI_rReg_imm ++//instruct leaI_rReg_immI(rRegI dst, rRegI src0, immI src1) ++//%{ ++// match(Set dst (AddI src0 src1)); ++// ++// ins_cost(110); ++// format %{ "addw $src0, $src1, $dst\t# int @leaI_rReg_immI" %} ++// ins_encode %{ ++// Register dst = $dst$$Register; ++// Register src = $src0$$Register; ++// int imm = $src1$$constant; ++// ++// if(MacroAssembler::is_uimm8(imm)) { ++// __ addw(src, imm, dst); ++// } else { ++// __ mov_immediate32(rscratch2_AT, imm); ++// __ addw(src, rscratch2_AT, dst); ++// } ++// %} ++// ins_pipe(ialu_regL_imm16); ++//%} ++ ++instruct addL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (AddL src1 src2)); ++ ++ format %{ "addl $src1, $src2, $dst\t# long @addL_rReg" %} ++ ins_encode %{ ++ __ addl($src1$$Register, $src2$$Register, $dst$$Register); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct addL_rReg_imm(rRegL dst, rRegL src1, immU8 src2) ++%{ ++ match(Set dst (AddL src1 src2)); ++ ins_cost(80); ++ format %{ "addptr $src1, $src2, $dst\t# long @addL_rReg_imm" %} ++ ins_encode %{ ++ __ addl($src1$$Register, (int)$src2$$constant, $dst$$Register); ++ %} ++ ins_pipe( ialu_regL_imm ); ++%} ++ ++/*memory operands no need for SW64 ++instruct addL_rReg_mem(rRegL dst, rRegL src1, memory src2) ++%{ ++ match(Set dst (AddL src1 (LoadL src2))); ++ ++ ins_cost(125); // XXX ++ format %{ "ldl $dst, $src2\t# long @addL_rReg_mem\n\t" ++ "addl src1, $dst, $dst"%} ++ ins_encode %{ ++ __ ldl($dst$$Register, $src2$$Address); ++ __ addl($src1$$Register, $dst$$Register, $dst$$Register); ++ %} ++ //ins_pipe(ialu_reg_mem); ++%} ++ ++instruct addL_mem_rReg(memory dst, rRegL src) ++%{ ++ match(Set dst (StoreL dst (AddL (LoadL dst) src))); ++ ++ ins_cost(150); // XXX ++ format %{ "ldl rscratch2_AT, $dst\t# long @addL_mem_rReg\n\t" ++ "addl rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $dst$$Address); ++ __ addl(rscratch2_AT, $src$$Register, rscratch2_AT); ++ __ stl(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe(ialu_mem_reg); ++%} ++ ++instruct addL_mem_imm(memory dst, immL32 src) ++%{ ++ match(Set dst (StoreL dst (AddL (LoadL dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ "ldl rscratch2_AT, $dst\t# long @addL_mem_imm\n\t" ++ "addptr rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $dst$$Address); ++ __ addptr(rscratch2_AT, (int)$src$$constant, rscratch2_AT); ++ __ stl(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++instruct incL_rReg(rRegL dst, rRegL src1, immL1 src2) ++%{ ++ match(Set dst (AddL src1 src2)); ++ ins_cost(40); ++ format %{ "addl $src1, #1, $dst\t# int @incL_rReg" %} ++ ins_encode %{ ++ __ addl($src1$$Register, 1, $dst$$Register); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/*memory operands no need for SW64 ++instruct incL_mem(memory dst, immL1 src) ++%{ ++ match(Set dst (StoreL dst (AddL (LoadL dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ "ldl rscratch2_AT, $dst\t# long @incL_mem\n\t" ++ "addl rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $dst$$Address); ++ __ addl(rscratch2_AT, 1, rscratch2_AT); ++ __ stl(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// XXX why does that use AddL ++instruct decL_rReg(rRegL dst, rRegL src1, immL_M1 src2) ++%{ ++ match(Set dst (AddL src1 src2)); ++ ins_cost(60); ++ format %{ "subl $src1, #1, $dst\t# int @decL_rReg" %} ++ ins_encode %{ ++ __ subl($src1$$Register, 1, $dst$$Register); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/*memory operands no need for SW64 ++// XXX why does that use AddL ++instruct decL_mem(memory dst, immL_M1 src) ++%{ ++ match(Set dst (StoreL dst (AddL (LoadL dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ "ldl rscratch2_AT, $dst\t# int @decL_mem\n\t" ++ "subl rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $dst$$Address); ++ __ subl(rscratch2_AT, 1, rscratch2_AT); ++ __ stl(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++//the same as addL_rReg_imm ++//instruct leaL_rReg_immL(rRegL dst, rRegL src0, immL32 src1) ++//%{ ++// match(Set dst (AddL src0 src1)); ++// ++// ins_cost(110); ++// format %{ "addptr $src0, $src1, $dst\t# long @leaL_rReg_immL" %} ++// ins_encode %{ ++// __ addptr($src0$$Register, (int)$src1$$constant, $dst$$Register); ++// %} ++// ins_pipe(ialu_regL_regL); ++//%} ++ ++instruct addP_rReg(rRegP dst, rRegP src1, rRegP src2) ++%{ ++ match(Set dst (AddP src1 src2)); ++ ++ format %{ "addl $src1, $src2, $dst\t# ptr @addP_rReg" %} ++ ins_encode %{ ++ __ addl($src1$$Register, $src2$$Register, $dst$$Register); ++ %} ++ ins_pipe(ialu_regL_regL); //in 8 this is ialu_regI_regI?? TODO djx ++%} ++ ++instruct addP_reg_reg(rRegP dst, rRegP src1, rRegL src2) %{ ++ match(Set dst (AddP src1 src2)); ++ ++ format %{ "addl $src1, $src2, $dst #@addP_reg_reg" %} ++ ins_encode %{ ++ __ addl($src1$$Register, $src2$$Register, $dst$$Register); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++instruct addP_rReg_imm(rRegP dst, rRegP src1, immUL8 src2) ++%{ ++ match(Set dst (AddP src1 src2)); ++ ins_cost(40); ++ format %{ "addptr $src1, $src2, $dst\t# long @addP_rReg_imm" %} ++ ins_encode %{ ++ __ addl($src1$$Register, (int)$src2$$constant, $dst$$Register); ++ %} ++ ins_pipe( ialu_regL_imm ); ++%} ++ ++//the same as addP_rReg_imm ++// XXX addP mem ops ???? ++ ++//instruct leaP_rReg_imm(rRegP dst, rRegP src0, immL32 src1) ++//%{ ++// match(Set dst (AddP src0 src1)); ++// ++// ins_cost(110); ++// format %{ "addptr $src0, $src1, $dst\t# long @leaP_rReg_imm" %} ++// ins_encode %{ ++// __ addptr($src0$$Register, (int)$src1$$constant, $dst$$Register); ++// %} ++//// ins_pipe(ialu_reg_reg); ++//%} ++ ++instruct checkCastPP(rRegP dst) ++%{ ++ match(Set dst (CheckCastPP dst)); ++ ++ size(0); //?? TODO djx ++ format %{ "#checkcastPP of $dst (empty encoding)\t# @chekCastPP" %} ++ ins_encode( /*empty encoding*/ ); ++ ins_pipe( empty ); ++%} ++ ++instruct castPP(rRegP dst) ++%{ ++ match(Set dst (CastPP dst)); ++ ++ size(0); ++ format %{ "#castPP of $dst (empty encoding)\t# @castPP" %} ++ ins_encode(/* empty encoding */); ++ ins_pipe(empty); ++%} ++ ++instruct castII(rRegI dst) ++%{ ++ match(Set dst (CastII dst)); ++ ++ size(0); ++ format %{ "#castII of $dst (empty encoding)\t# @castII" %} ++ ins_encode( /*empty encoding*/ ); ++ ins_cost(0); ++ ins_pipe( empty ); ++%} ++ ++ ++// LoadP-locked same as a regular LoadP when used with compare-swap ++instruct loadPLocked(rRegP dst, memory mem) ++%{ ++ match(Set dst (LoadPLocked mem)); ++ ++ ins_cost(125); ++ format %{ "ldptr $dst, $mem #@loadPLocked" %} ++ ins_encode (load_P_enc(dst, mem)); ++ ins_pipe( ialu_reg_mem ); ++%} ++/* ++// Conditional-store of the updated heap-top. ++// Used during allocation of the shared heap. ++// Sets flags (EQ) on success. Implemented with a CMPXCHG on Intel. ++ ++instruct storePConditional(memory heap_top_ptr, ++ rax_RegP oldval, rRegP newval, ++ rFlagsReg cr) ++%{ ++ match(Set cr (StorePConditional heap_top_ptr (Binary oldval newval))); ++ ++ format %{ "cmpxchgq $heap_top_ptr, $newval\t# (ptr) " ++ "If rax == $heap_top_ptr then store $newval into $heap_top_ptr" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem_wide(newval, heap_top_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, heap_top_ptr)); ++ ins_pipe(pipe_cmpxchg); ++%} ++ ++// Conditional-store of an int value. ++// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG. ++instruct storeIConditional(memory mem, rax_RegI oldval, rRegI newval, rFlagsReg cr) ++%{ ++ match(Set cr (StoreIConditional mem (Binary oldval newval))); ++ effect(KILL oldval); ++ ++ format %{ "cmpxchgl $mem, $newval\t# If rax == $mem then store $newval into $mem" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem(newval, mem), ++ OpcP, OpcS, ++ reg_mem(newval, mem)); ++ ins_pipe(pipe_cmpxchg); ++%} ++ ++// Conditional-store of a long value. ++// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG. ++instruct storeLConditional(memory mem, rax_RegL oldval, rRegL newval, rFlagsReg cr) ++%{ ++ match(Set cr (StoreLConditional mem (Binary oldval newval))); ++ effect(KILL oldval); ++ ++ format %{ "cmpxchgq $mem, $newval\t# If rax == $mem then store $newval into $mem" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem_wide(newval, mem), ++ OpcP, OpcS, ++ reg_mem(newval, mem)); ++ ins_pipe(pipe_cmpxchg); ++%} ++ ++ ++// XXX No flag versions for CompareAndSwap{P,I,L} because matcher can't match them ++instruct compareAndSwapP(rRegI res, ++ memory mem_ptr, ++ rax_RegP oldval, rRegP newval, ++ rFlagsReg cr) ++%{ ++ predicate(VM_Version::supports_cx8()); ++ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); ++ match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ ++ format %{ "cmpxchgq $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" ++ "sete $res\n\t" ++ "movzbl $res, $res" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem_wide(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr), ++ REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete ++ REX_reg_breg(res, res), // movzbl ++ Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndSwapL(rRegI res, ++ memory mem_ptr, ++ rax_RegL oldval, rRegL newval, ++ rFlagsReg cr) ++%{ ++ predicate(VM_Version::supports_cx8()); ++ match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); ++ match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ ++ format %{ "cmpxchgq $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" ++ "sete $res\n\t" ++ "movzbl $res, $res" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem_wide(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr), ++ REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete ++ REX_reg_breg(res, res), // movzbl ++ Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndSwapI(rRegI res, ++ memory mem_ptr, ++ rax_RegI oldval, rRegI newval, ++ rFlagsReg cr) ++%{ ++ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); ++ match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ ++ format %{ "cmpxchgl $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" ++ "sete $res\n\t" ++ "movzbl $res, $res" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr), ++ REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete ++ REX_reg_breg(res, res), // movzbl ++ Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndSwapB(rRegI res, ++ memory mem_ptr, ++ rax_RegI oldval, rRegI newval, ++ rFlagsReg cr) ++%{ ++ match(Set res (CompareAndSwapB mem_ptr (Binary oldval newval))); ++ match(Set res (WeakCompareAndSwapB mem_ptr (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ ++ format %{ "cmpxchgb $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" ++ "sete $res\n\t" ++ "movzbl $res, $res" %} ++ opcode(0x0F, 0xB0); ++ ins_encode(lock_prefix, ++ REX_breg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr), ++ REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete ++ REX_reg_breg(res, res), // movzbl ++ Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndSwapS(rRegI res, ++ memory mem_ptr, ++ rax_RegI oldval, rRegI newval, ++ rFlagsReg cr) ++%{ ++ match(Set res (CompareAndSwapS mem_ptr (Binary oldval newval))); ++ match(Set res (WeakCompareAndSwapS mem_ptr (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ ++ format %{ "cmpxchgw $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" ++ "sete $res\n\t" ++ "movzbl $res, $res" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ SizePrefix, ++ REX_reg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr), ++ REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete ++ REX_reg_breg(res, res), // movzbl ++ Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndSwapN(rRegI res, ++ memory mem_ptr, ++ rax_RegN oldval, rRegN newval, ++ rFlagsReg cr) %{ ++ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); ++ match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ ++ format %{ "cmpxchgl $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" ++ "sete $res\n\t" ++ "movzbl $res, $res" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr), ++ REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete ++ REX_reg_breg(res, res), // movzbl ++ Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndExchangeB( ++ memory mem_ptr, ++ rax_RegI oldval, rRegI newval, ++ rFlagsReg cr) ++%{ ++ match(Set oldval (CompareAndExchangeB mem_ptr (Binary oldval newval))); ++ effect(KILL cr); ++ ++ format %{ "cmpxchgb $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} ++ opcode(0x0F, 0xB0); ++ ins_encode(lock_prefix, ++ REX_breg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr) // lock cmpxchg ++ ); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndExchangeS( ++ memory mem_ptr, ++ rax_RegI oldval, rRegI newval, ++ rFlagsReg cr) ++%{ ++ match(Set oldval (CompareAndExchangeS mem_ptr (Binary oldval newval))); ++ effect(KILL cr); ++ ++ format %{ "cmpxchgw $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ SizePrefix, ++ REX_reg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr) // lock cmpxchg ++ ); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndExchangeI( ++ memory mem_ptr, ++ rax_RegI oldval, rRegI newval, ++ rFlagsReg cr) ++%{ ++ match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); ++ effect(KILL cr); ++ ++ format %{ "cmpxchgl $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr) // lock cmpxchg ++ ); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndExchangeL( ++ memory mem_ptr, ++ rax_RegL oldval, rRegL newval, ++ rFlagsReg cr) ++%{ ++ predicate(VM_Version::supports_cx8()); ++ match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); ++ effect(KILL cr); ++ ++ format %{ "cmpxchgq $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem_wide(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr) // lock cmpxchg ++ ); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndExchangeN( ++ memory mem_ptr, ++ rax_RegN oldval, rRegN newval, ++ rFlagsReg cr) %{ ++ match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); ++ effect(KILL cr); ++ ++ format %{ "cmpxchgl $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr) // lock cmpxchg ++ ); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct compareAndExchangeP( ++ memory mem_ptr, ++ rax_RegP oldval, rRegP newval, ++ rFlagsReg cr) ++%{ ++ predicate(VM_Version::supports_cx8()); ++ match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); ++ effect(KILL cr); ++ ++ format %{ "cmpxchgq $mem_ptr,$newval\t# " ++ "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} ++ opcode(0x0F, 0xB1); ++ ins_encode(lock_prefix, ++ REX_reg_mem_wide(newval, mem_ptr), ++ OpcP, OpcS, ++ reg_mem(newval, mem_ptr) // lock cmpxchg ++ ); ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddB_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ ++ predicate(n->as_LoadStore()->result_not_used()); ++ match(Set dummy (GetAndAddB mem add)); ++ effect(KILL cr); ++ format %{ "ADDB [$mem],$add" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ addb($mem$$Address, $add$$constant); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddB( memory mem, rRegI newval, rFlagsReg cr) %{ ++ match(Set newval (GetAndAddB mem newval)); ++ effect(KILL cr); ++ format %{ "XADDB [$mem],$newval" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ xaddb($mem$$Address, $newval$$Register); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddS_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ ++ predicate(n->as_LoadStore()->result_not_used()); ++ match(Set dummy (GetAndAddS mem add)); ++ effect(KILL cr); ++ format %{ "ADDW [$mem],$add" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ addw($mem$$Address, $add$$constant); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddS( memory mem, rRegI newval, rFlagsReg cr) %{ ++ match(Set newval (GetAndAddS mem newval)); ++ effect(KILL cr); ++ format %{ "XADDW [$mem],$newval" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ xaddw($mem$$Address, $newval$$Register); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddI_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ ++ predicate(n->as_LoadStore()->result_not_used()); ++ match(Set dummy (GetAndAddI mem add)); ++ effect(KILL cr); ++ format %{ "ADDL [$mem],$add" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ addl($mem$$Address, $add$$constant); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddI( memory mem, rRegI newval, rFlagsReg cr) %{ ++ match(Set newval (GetAndAddI mem newval)); ++ effect(KILL cr); ++ format %{ "XADDL [$mem],$newval" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ xaddl($mem$$Address, $newval$$Register); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddL_no_res( memory mem, Universe dummy, immL32 add, rFlagsReg cr) %{ ++ predicate(n->as_LoadStore()->result_not_used()); ++ match(Set dummy (GetAndAddL mem add)); ++ effect(KILL cr); ++ format %{ "ADDQ [$mem],$add" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ addq($mem$$Address, $add$$constant); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xaddL( memory mem, rRegL newval, rFlagsReg cr) %{ ++ match(Set newval (GetAndAddL mem newval)); ++ effect(KILL cr); ++ format %{ "XADDQ [$mem],$newval" %} ++ ins_encode %{ ++ if (os::is_MP()) { __ lock(); } ++ __ xaddq($mem$$Address, $newval$$Register); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xchgB( memory mem, rRegI newval) %{ ++ match(Set newval (GetAndSetB mem newval)); ++ format %{ "XCHGB $newval,[$mem]" %} ++ ins_encode %{ ++ __ xchgb($newval$$Register, $mem$$Address); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xchgS( memory mem, rRegI newval) %{ ++ match(Set newval (GetAndSetS mem newval)); ++ format %{ "XCHGW $newval,[$mem]" %} ++ ins_encode %{ ++ __ xchgw($newval$$Register, $mem$$Address); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xchgI( memory mem, rRegI newval) %{ ++ match(Set newval (GetAndSetI mem newval)); ++ format %{ "XCHGL $newval,[$mem]" %} ++ ins_encode %{ ++ __ xchgl($newval$$Register, $mem$$Address); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xchgL( memory mem, rRegL newval) %{ ++ match(Set newval (GetAndSetL mem newval)); ++ format %{ "XCHGL $newval,[$mem]" %} ++ ins_encode %{ ++ __ xchgq($newval$$Register, $mem$$Address); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xchgP( memory mem, rRegP newval) %{ ++ match(Set newval (GetAndSetP mem newval)); ++ format %{ "XCHGQ $newval,[$mem]" %} ++ ins_encode %{ ++ __ xchgq($newval$$Register, $mem$$Address); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++ ++instruct xchgN( memory mem, rRegN newval) %{ ++ match(Set newval (GetAndSetN mem newval)); ++ format %{ "XCHGL $newval,$mem]" %} ++ ins_encode %{ ++ __ xchgl($newval$$Register, $mem$$Address); ++ %} ++ ins_pipe( pipe_cmpxchg ); ++%} ++*/ ++ ++// lsp check the T11 register? replace to t12?? ++instruct partialSubtypeCheck( rRegP result, no_T11_rRegP sub, no_T11_rRegP super) %{ ++ match(Set result (PartialSubtypeCheck sub super)); ++ //effect(KILL tmp); ++ ins_cost(1100); // slightly larger than the next version ++ format %{ "partialSubtypeCheck result=$result, sub=$sub, super=$super, tmp=rscratch3 " %} ++ ++ ins_encode( enc_PartialSubtypeCheck(result, sub, super) ); ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct storePConditional(indirect mem, v0_RegP oldval, rRegP newval, rFlagsReg cr) %{ ++ match(Set cr(StorePConditional mem(Binary oldval newval))); ++ effect(KILL oldval); ++ //size(56); ++ format %{ "StorePConditional cmpxchg $mem, $newval\t# If $oldval == $mem then store $newval into $mem" %} ++ ins_encode %{ ++ Register oldval = $oldval$$Register; ++ Register newval = $newval$$Register; ++ Register cr = $cr$$Register; ++ ++ __ storeLcon(oldval, $mem$$Address, newval); ++ //__ movl(cr, AT); ++ ++ %} ++ ins_pipe(long_memory_op); ++%} ++ ++// Conditional-store of an int value. ++// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG on Intel. ++instruct storeIConditional(indirect mem, v0_RegI oldval, rRegI newval, rFlagsReg cr) %{ ++ match(Set cr(StoreIConditional mem(Binary oldval newval))); ++ effect(KILL oldval); ++ format %{ "CMPXCHG32 $newval, $mem, $oldval \t# @storeIConditional" %} ++ ++ ins_encode %{ ++ Register oldval = $oldval$$Register; ++ Register newval = $newval$$Register; ++ Register cr = $cr$$Register; ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding storeIConditional"); ++ __ storeIcon(oldval, $mem$$Address, newval); ++ //__ movl(cr, AT); ++ %} ++ ins_pipe(long_memory_op); ++ %} ++ ++ ++ // Conditional-store of a long value. ++ // ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG. ++ ++instruct storeLConditional(indirect mem, v0_RegL oldval, rRegL newval, rFlagsReg cr) %{ ++ match(Set cr(StoreLConditional mem (Binary oldval newval))); ++ effect(KILL oldval);//TODO:kill oldval? jzy ++ //size(56); ++ format %{ "StoreLConditional cmpxchg $mem, $newval\t# If $oldval == $mem then store $newval into $mem" %} ++ ins_encode %{ ++ Register oldval = $oldval$$Register; ++ Register newval = $newval$$Register; ++ Register cr = $cr$$Register; ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding storeLConditional"); ++ ++ __ storeLcon(oldval, $mem$$Address, newval); ++ ++ %} ++ ins_pipe(long_memory_op); ++ %} ++ ++//FIXME: ++instruct compareAndSwapP( rRegI res, indirect mem, v0_RegP oldval, rRegP newval, rFlagsReg cr) %{ ++ match(Set res (CompareAndSwapP mem (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ //size(60); ++ format %{ ++ "CMPXCHG $newval, $mem, $oldval @ compareAndSwapP\n\t" ++ "If $oldval == $mem then store $newval into $mem\n\t" ++ "sete $res " ++ %} ++ ins_encode %{ ++ Register newval = $newval$$Register; ++ Register oldval = $oldval$$Register; ++ Register res = $res$$Register; ++// Address addr($mem_ptr$$Register, 0); ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding compareAndSwapP"); ++ //SizedScope sc(&_masm, 100); ++ __ cmpxchg(newval, $mem$$Address, oldval); ++ __ seleq(rcc, 1, R0, res); ++ %} ++ ins_pipe( long_memory_op ); ++%} ++ ++ ++instruct compareAndSwapL( rRegI res, indirect mem, v0_RegL oldval, rRegL newval, rFlagsReg cr) %{ ++ //predicate(VM_Version::supports_cx8()); ++ match(Set res (CompareAndSwapL mem (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++// effect(TEMP tmpt10, USE_KILL oldval); ++ //size(60); //TODO: ZHJ20180613 ++ format %{ ++ "CMPXCHG $newval, $mem, $oldval @ compareAndSwapL\n\t" ++ "If $oldval == $mem then store $newval into $mem\n\t" ++ "sete $res " ++ %} ++ ins_encode %{ ++ Register newval = $newval$$Register; ++ Register oldval = $oldval$$Register; ++ Register res = $res$$Register; ++// Address addr($mem_ptr$$Register, 0); ++ ++ //SizedScope sc(&_masm, 100); ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding compareAndSwapL"); ++ __ cmpxchg(newval, $mem$$Address, oldval); ++ __ seleq(rcc, 1, R0, res); ++ %} ++ ins_pipe( long_memory_op ); ++%} ++ ++instruct compareAndSwapI( rRegI res, indirect mem, v0_RegI oldval, rRegI newval, rFlagsReg cr) %{ ++ match(Set res (CompareAndSwapI mem (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ //size(60); ++// match(CompareAndSwapI mem_ptr (Binary oldval newval)); ++ format %{ ++ "CMPXCHG32 $newval, $mem, $oldval @ compareAndSwapI\n\t" ++ "If $oldval == $mem then store $newval into $mem\n\t" ++ "sete $res " ++ %} ++ ins_encode %{ ++ Register newval = $newval$$Register; ++ Register oldval = $oldval$$Register; ++ Register res = $res$$Register; ++// Address addr($mem_ptr$$Register, 0); ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding compareAndSwapI"); ++ ++ //SizedScope sc(&_masm, 100); ++ __ cmpxchg32(newval, $mem$$Address, oldval); ++ __ seleq(rcc, 1, R0, res); ++ %} ++ ins_pipe( long_memory_op ); ++%} ++ ++instruct compareAndSwapN( rRegI res, indirect mem, v0_RegN oldval, rRegN newval, rFlagsReg cr) %{ ++ match(Set res (CompareAndSwapN mem (Binary oldval newval))); ++ effect(KILL cr, KILL oldval); ++ //effect(KILL cr, USE_KILL oldval); ++// effect(TEMP tmpT10, USE_KILL oldval); ++ //size(64); ++ format %{ ++ "CMPXCHG32 $newval, $mem, $oldval @ compareAndSwapI\n\t" ++ "If $oldval == $mem then store $newval into $mem\n\t" ++ "sete $res" ++ %} ++ ins_encode %{ ++ Register newval = $newval$$Register; ++ Register oldval = $oldval$$Register; ++ Register res = $res$$Register; ++// Address addr($mem_ptr$$Register, 0); ++// Label L; ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding compareAndSwapN"); ++ // cmpxchg32 is implemented with ll/sc, which will do sign extension. ++ // Thus, we should extend oldval's sign for correct comparision. ++ ++ // __ stop("?compareAndSwapN jzy"); ++ __ addw(oldval, 0, oldval); ++ __ cmpxchg32(newval, $mem$$Address, oldval); ++// __ selne(AT, 1, AT, res); ++ __ seleq(rcc, 1, R0, res); ++ %} ++ ins_pipe( long_memory_op ); ++%} ++ ++instruct getAndAddI(indirect mem, rRegI add, rRegI val, rFlagsReg cr) %{ ++ // predicate( n->get_int() == 1 && n->get_int() == -1); ++ // val = *mem & *mem = *mem + add ++ match(Set val (GetAndAddI mem add)); ++ effect(KILL cr); ++ format %{ "xaddI [$mem],$add\t@getAndAddI" %} ++ ins_encode %{ ++ Register base = as_Register($mem$$base); ++ int disp = $mem$$disp; ++ Register value = $val$$Register; ++ Register add = $add$$Register; ++ Label again; ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding getAndAddI"); ++ SizedScope sc(&_masm, 40); ++ if(UseSW8A) { ++ __ BIND(again); ++ __ lldw(AT, disp, base); ++ __ addw(AT, add, GP); ++ __ lstw(GP, disp, base); ++ __ beq_l(GP, again); ++ __ movl(value, AT); ++ } else { ++ __ BIND(again); ++ __ lldw(AT, disp, base); ++ __ ldi(GP, 1, R0); ++ __ wr_f(GP); ++ __ addw(AT, add, GP); ++ __ align(8); // must align ++ __ lstw(GP, disp, base); ++ __ rd_f(GP); ++ __ beq_l(GP, again); ++ __ movl(value, AT); ++ } ++ %} ++ ins_pipe( long_memory_op ); ++%} ++ ++instruct getAndAddL( indirect mem, rRegL add, rRegL val, rFlagsReg cr) %{ ++ // val = *mem & *mem = *mem + add ++ match(Set val (GetAndAddL mem add)); ++ effect(KILL cr); ++ format %{ "xaddL [$mem],$add\t@ getAndAddL" %} ++ ins_encode %{ ++ Register base = as_Register($mem$$base); ++ int disp = $mem$$disp; ++ Register value = $val$$Register; ++ Register add = $add$$Register; ++ Label again; ++ guarantee($mem$$index == sp->encoding() && $mem$$disp == 0, "impossible encoding getAndAddL"); ++ SizedScope sc(&_masm, 40); ++ if(UseSW8A) { ++ __ BIND(again); ++ __ lldl(AT, disp, base); ++ __ addl( AT, add, GP); ++ __ lstl(GP, disp, base); ++ __ beq_l(GP, again); ++ __ movl(value, AT); ++ } else { ++ __ BIND(again); ++ __ lldl(AT, disp, base); ++ __ ldi(GP, 1, R0); ++ __ wr_f(GP); ++ __ addl( AT, add, GP); ++ __ align(8); // must align ++ __ lstl(GP, disp, base); ++ __ rd_f(GP); ++ __ beq_l(GP, again); ++ __ movl(value, AT); ++ } ++ %} ++ ins_pipe( long_memory_op ); ++%} ++//----------Subtraction Instructions------------------------------------------- ++ ++// Integer Subtraction Instructions ++instruct subI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (SubI src1 src2)); ++ ++ format %{ "subw $src1, $src2, $dst\t# int\t@subI_rReg" %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ ++ __ subw(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct subI_rReg_imm(rRegI dst, rRegI src1, immU8 src2) ++%{ ++ match(Set dst (SubI src1 src2)); ++ ins_cost(80); ++ format %{ "subw $src1, $src2, $dst\t# int\t@subI_rReg_imm" %} ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ int imm = $src2$$constant; ++ ++ __ subw(src1, imm, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++/* memory operands no need for SW64 ++instruct subI_rReg_mem(rRegI dst, memory src1, rRegI src2) ++%{ ++ match(Set dst (SubI src2 (LoadI src1))); ++ ++ ins_cost(125); ++ format %{ ++ "ldw $dst, $src1\t# int\t@subI_rReg_mem\n\t" ++ "subw $src2, $dst, $dst" ++ %} ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldw(dst, src1); ++ __ subw(src2, dst, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct subI_mem_rReg(memory dst, rRegI src) ++%{ ++ match(Set dst (StoreI dst (SubI (LoadI dst) src))); ++ ++ ins_cost(150); ++ format %{ ++ "ldw rscratch2_AT, $dst\t# int\t@subI_mem_rReg\n\t" ++ "subw rscratch2_AT, $src, $dst\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ Register src = $src$$Register; ++ __ ldw(rscratch2_AT, dst); ++ __ subw(rscratch2_AT, src, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%} ++ ++instruct subI_mem_imm(memory dst, immI src) ++%{ ++ match(Set dst (StoreI dst (SubI (LoadI dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ ++ "ldw rscratch2_AT, $dst\t# int\t@subI_mem_imm\n\t" ++ "subw rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst" ++ %} ++ ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ int src = $src$$constant; ++ __ ldw(rscratch2_AT, dst); ++ __ subw(rscratch2_AT, src, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++instruct subL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (SubL src1 src2)); ++ ++ format %{ "subl $src1, $src2, $dst\t# long\t@subL_rReg" %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ __ subl(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct subL_rReg_imm(rRegI dst, rRegI src1, immUL8 src2) ++%{ ++ match(Set dst (SubL src1 src2)); ++ ++ format %{"subl $src1, $src2, $dst\t# long\t@subL_rReg_imm" %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ int src2 = $src2$$constant; ++ ++ __ subl(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/* memory operands no need for SW64 ++instruct subL_rReg_mem(rRegL dst, rRegL src1, memory src2) ++%{ ++ match(Set dst (SubL src1 (LoadL src2))); ++ ++ ins_cost(125); ++ format %{ ++ "ldl rscratch2_AT, $src2\t# long\t@subL_rReg_mem\n\t" ++ "subl $src1, rscratch2_AT, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst" ++ %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Address src2 = $src2$$Address; ++ __ ldl(rscratch2_AT, src2); ++ __ subl(src1, rscratch2_AT, dst); ++ %} ++ //ins_pipe(ialu_reg_mem); ++%} ++ ++instruct subL_mem_rReg(memory dst, rRegL src) ++%{ ++ match(Set dst (StoreL dst (SubL (LoadL dst) src))); ++ ++ ins_cost(150); ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@subL_mem_rReg\n\t" ++ "subl rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst" ++ %} ++ ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ Register src = $src$$Register; ++ __ ldl(rscratch2_AT, dst); ++ __ subl(rscratch2_AT, src, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%} ++ ++instruct subL_mem_imm(memory dst, immL32 src) ++%{ ++ match(Set dst (StoreL dst (SubL (LoadL dst) src))); ++ ++ ins_cost(125); // XXX ++ format %{ ++ "ldptr rscratch2_AT, $dst\t# long\t@subL_mem_imm\n\t" ++ "subptr rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stptr rscratch2_AT, $dst" ++ %} ++ ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ int src = $src$$constant; ++ __ ldl(rscratch2_AT, dst); ++ __ mov_immediate32s(rscratch1_GP, src); //lsp to check sign-extend?? ++ __ subl(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Subtract from a pointer ++// XXX hmpf??? ++instruct subP_rReg(rRegP dst, rRegP src1, rRegI src2, immI0 zero) ++%{ ++ match(Set dst (AddP src1 (SubI zero src2))); ++ ++ format %{ "subw R0, $src2, $dst\t# ptr - int\t@subP_rReg\n\t" ++ "addl $src1, $dst, $dst" ++ %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ __ subw(R0, src2, dst); ++ __ addl(src1, dst, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct negI_rReg(rRegI dst, rRegI src, immI0 zero) ++%{ ++ match(Set dst (SubI zero src)); ++ ++ format %{ "subw R0, $src,$dst\t# int\t@negI_rReg" %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ subw(R0, src, dst); ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/* memory operands no need for SW64 ++instruct negI_mem(memory dst, immI0 zero) ++%{ ++ match(Set dst (StoreI dst (SubI zero (LoadI dst)))); ++ ++ format %{ "ldw rscratch2_AT, $dst\t# int\t@negI_mem\n\t" ++ "subw R0, rscratch2_AT, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ __ ldw(rscratch2_AT, dst); ++ __ subw(R0, rscratch2_AT, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_reg); ++%}*/ ++ ++instruct negL_rReg(rRegL dst, rRegL src, immL0 zero) ++%{ ++ match(Set dst (SubL zero src)); ++ ++ format %{ "subl R0, $src, $dst\t# long \t@negL_rReg" %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ subl(R0, src, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/* memory operands no need for SW64 ++instruct negL_mem(memory dst, immL0 zero) ++%{ ++ match(Set dst (StoreL dst (SubL zero (LoadL dst)))); ++ ++ format %{ "ldl rscratch2_AT, $dst\t# long\t@negL_mem\n\t" ++ "subl R0, rscratch2_AT, rscratch2_AT\n\t" ++ "stl( rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ __ ldl(rscratch2_AT, dst); ++ __ subl(R0, rscratch2_AT, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_reg); ++%}*/ ++ ++ ++//----------Multiplication/Division Instructions------------------------------- ++// Integer Multiplication Instructions ++// Multiply Register ++ ++instruct mulI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (MulI src1 src2)); ++ ++ ins_cost(300); ++ format %{ "mulw $src1, $src2, $dst\t# int @mulI_rReg" %} ++ ins_encode %{ ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ Register dst = $dst$$Register; ++ ++ __ mulw(src1, src2, dst); ++ %} ++ ins_pipe( ialu_mult ); ++%} ++ ++instruct mulI_rReg_imm(rRegI dst, rRegI src, immU8 imm) ++%{ ++ match(Set dst (MulI src imm)); ++ ++ ins_cost(300); ++ format %{ "mulw $src, $dst, $dst \t# int @mulI_rReg_imm\n\t" %} ++ ins_encode %{ ++ Register src1 = $src$$Register; ++ int src2 = $imm$$constant; ++ Register dst = $dst$$Register; ++ __ mulw(src1, src2, dst); ++ %} ++ ins_pipe( ialu_mult_imm ); ++%} ++ ++/* memory operands no need for SW64 ++instruct mulI_mem(rRegI dst, memory src1, rRegI src2) ++%{ ++ match(Set dst (MulI src2 (LoadI src1))); ++ ++ ins_cost(350); ++ format %{ "ldw $dst, $src1\t# int @mulI_mem \n\t" ++ "mulw $dst, $src2, $dst" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldw(dst, src1); ++ __ mulw(src2, dst, dst); ++ %} ++// ins_pipe(ialu_reg_mem_alu0); ++%} ++ ++instruct mulI_mem_imm(rRegI dst, memory src, immI imm) ++%{ ++ match(Set dst (MulI (LoadI src) imm)); ++ ++ ins_cost(300); ++ format %{ "ldw rscratch2_AT, $src, $imm\t# int @mulI_mem_imm \n\t" ++ "mov_immediate32 rscratch1_GP, $imm\n\t" ++ "mulw rscratch2_AT, $imm, $dst"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int val = $imm$$constant; ++ __ ldw(rscratch2_AT, src); ++ __ mov_immediate32(rscratch1_GP, val); ++ __ mulw(rscratch2_AT, rscratch1_GP, dst); ++ %} ++// ins_pipe(ialu_reg_mem_alu0); ++%}*/ ++ ++instruct mulL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (MulL src1 src2)); ++ ++ ins_cost(300); ++ format %{ "mull $src1, $src2, $dst\t# long @mulL_rReg" %} ++ ins_encode %{ ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ Register dst = $dst$$Register; ++ ++ __ mull(src1, src2, dst); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct mulL_rReg_imm(rRegL dst, rRegL src, immUL8 imm) ++%{ ++ match(Set dst (MulL src imm)); ++ ++ ins_cost(300); ++ format %{ "mull $src, $imm, $dst \t# long\t@mulL_rReg_imm\n\t" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int imm = $imm$$constant; ++ ++ __ mull(src, imm, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++/* memory operands no need for SW64 ++instruct mulL_mem(rRegL dst, memory src1, rRegL src2) ++%{ ++ match(Set dst (MulL src2 (LoadL src1))); ++ ++ ins_cost(350); ++ format %{ "ldptr $dst, $src1 \t# long\t@mulL_mem\n\t" ++ "mull $src2, $dst, $dst" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldptr(dst, src1); ++ __ mull(src2, dst, dst); ++ %} ++// ins_pipe(ialu_reg_mem_alu0); ++%} ++ ++instruct mulL_mem_imm(rRegL dst, memory src, immL32 imm) ++%{ ++ match(Set dst (MulL (LoadL src) imm)); ++ ++ ins_cost(300); ++ format %{ "ldptr $dst, $src\t# long\t@mulL_mem_imm\n\t" ++ "mov_immediate32 rscratch1_GP, $imm\n\t" ++ "mull $dst, rscratch1_GP, $dst"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ int val = $imm$$constant; ++ __ ldptr(dst, src); ++ __ mov_immediate32s(rscratch1_GP, val); ++ __ mull(dst, rscratch1_GP, dst); ++ %} ++// ins_pipe(ialu_reg_mem_alu0); ++%}*/ ++ ++/*sw have no such instruct ++instruct mulHiL_rReg(rdx_RegL dst, no_rax_RegL src, rax_RegL rax)//??todo ++%{ ++ match(Set dst (MulHiL src rax)); ++ ++ ins_cost(300); ++ format %{ "imulq RDX:RAX, RAX, $src\t# mulhi" %} ++ ins_encode %{ ++// (REX_reg_wide(src), OpcP, reg_opc(src)); ++ %} ++// ins_pipe(ialu_reg_reg_alu0); ++%} ++*/ ++ ++instruct divI_rReg(rRegI dst, rRegI src, rRegI div) ++%{ ++ match(Set dst (DivI src div)); ++ ++ ins_cost(30*100+10*100); // XXX ++ format %{ "divI $src, $div $dst @divI_rReg" %}//TODO: How to represent the logic written below?jx ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register div = $div$$Register; ++ //__ stop("divI_rReg"); ++ ++ if (UseSW8A) { ++ __ corrected_idivw(src, div, dst); ++ } else if (FastIntDiv) { ++ __ idiv_sw(src, div, dst); ++ } else { ++ __ saveTRegisters(); ++ if(src == A0){ ++ __ movl(rscratch3, src); ++ __ movl(A0, div); ++ __ movl(A1, rscratch3); ++ }else{ ++ __ movl(A0, div); ++ __ movl(A1, src); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::sdiv), 2); ++ __ movl(pv, V0); ++ __ restoreTRegisters(); ++ __ movl(dst, pv); ++ } ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct divL_rReg(rRegL dst, rRegL src, rRegL div) ++%{ ++ match(Set dst (DivL src div)); ++ ++ ins_cost(30*100+10*100); // XXX ++ format %{ "divL $src $div $dst @divL_rReg" %}//TODO: How to represent the logic written below?jx ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register div = $div$$Register; ++ if (UseSW8A) { ++ __ corrected_idivl(src, div, dst); ++ } else if (FastLongDiv) { ++ Label ldiv, exit; ++ //AT does not need to be saved(in pushad function) before calling ++ //since it has been defined as NS ++ __ slll(dst, 0xb, rscratch3); //logically left shift 11-bit ++ __ sral(rscratch3, 0xb, rscratch3); //arithmetically right shift 11-bit ++ ++ // when 1 was put in 53 bit-position, ++ // the result would be different from the original one ++ ++ // which means when the value of op1 is [0xFFE0000000000000, 0x20000000000000], ++ // the result would be different after slll and sral ++ // why?jx ++ __ cmpeq(dst, rscratch3, rscratch3); ++ ++ __ bne_l(rscratch3, ldiv); ++ ++ __ saveTRegisters(); ++ if(src == A0){ ++ __ movl(pv, src); ++ __ movl(A0, div); ++ __ movl(A1, pv); ++ }else{ ++ __ movl(A0, div); ++ __ movl(A1, src); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv), 2); ++ __ movl(pv, V0); ++ __ restoreTRegisters(); ++ __ movl(dst, pv); ++ __ beq_l(R0, exit); ++ ++ __ BIND(ldiv); ++ __ ldiv_sw(src, div, dst); ++ ++ __ BIND(exit); ++ } else { ++ __ saveTRegisters(); ++ if(src == A0){ ++ __ movl(rscratch3, src); ++ __ movl(A0, div); ++ __ movl(A1, rscratch3); ++ }else{ ++ __ movl(A0, div); ++ __ movl(A1, src); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv), 2); ++ __ movl(pv, V0); ++ __ restoreTRegisters(); ++ __ movl(dst, pv); ++ } ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++ ++ ++//----------------------------------------------------------------------------- ++ ++instruct modI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (ModI src1 src2)); ++ ++ ins_cost(300); // XXX ++ format %{ "modi $src1, $src2, $dst @ modI_rReg" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++// __ stop("modI_rReg"); ++ ++ if (UseSW8A) { ++ __ remw(src1, src2, dst); ++ } else if (FastIntRem) { ++ __ irem_sw(src1, src2, dst); ++ } else { ++ __ saveTRegisters(); ++ if(src1 == A0){ ++ __ movl(pv, src1); ++ __ movl(A0, src2); ++ __ movl(A1, pv); ++ }else{ ++ __ movl(A0, src2); ++ __ movl(A1, src1); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::srem), 2); ++ __ movl(pv, V0); ++ __ restoreTRegisters(); ++ __ movl(dst, pv); ++ } ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++instruct modL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (ModL src1 src2)); ++ ++ ins_cost(300); // XXX ++ format %{ "modL $src1, $src2, $dst\t@modL_rReg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src1 = as_Register($src1$$reg); ++ Register src2 = as_Register($src2$$reg); ++ ++ if (UseSW8A) { ++ __ reml(src1, src2, dst); ++ } else if (FastLongRem) { ++ Label lrem, exit; ++// Register tem = operand; ++ ++ __ slll(src1, 0xb, rscratch3); ++ __ sral(rscratch3, 0xb, rscratch3); ++ __ cmpeq(src1, rscratch3, rscratch3); ++ __ bne_l(rscratch3, lrem); ++ ++ __ saveTRegisters(); ++ if(src1 == A0){ ++ __ movl(rscratch3, src1); ++ __ movl(A0, src2); ++ __ movl(A1, rscratch3); ++ }else{ ++ __ movl(A0, src2); ++ __ movl(A1, src1); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem), 2); ++ __ movl(pv, V0); ++ __ restoreTRegisters(); ++ __ movl(dst, pv); ++ __ beq_l(R0, exit); ++ ++ __ BIND(lrem); ++ __ lrem_sw(src1, src2, dst); ++ ++ __ BIND(exit); ++ } else { ++ __ saveTRegisters(); ++ if(src1 == A0){ ++ __ movl(rscratch3, src1); ++ __ movl(A0, src2); ++ __ movl(A1, rscratch3); ++ }else{ ++ __ movl(A0, src2); ++ __ movl(A1, src1); ++ } ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem), 2); ++ __ movl(pv, V0); ++ __ restoreTRegisters(); ++ __ movl(dst, pv); ++ } ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++/*No need for SW64 ++// Integer Shift Instructions ++// Shift Left by one ++instruct salI_rReg_1(rRegI dst, rRegI src, immI1 shift) ++%{ ++ match(Set dst (LShiftI src shift)); ++ ++ format %{ "slll $src, #1, $dst\t# @salI_rReg_1" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ slll(src, 1, dst); ++ __ addw(dst, R0, dst);//lsp to check ok?? ++ ++ %} ++ ins_pipe(ialu_regI_imm); ++%}*/ ++ ++/* memory operands no need for SW64 ++// Shift Left by one ++instruct salI_mem_1(memory dst, immI1 shift) ++%{ ++ match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); ++ ++ format %{ "ldw rscratch2_AT, $dst\t# @salI_mem_1\n\t" ++ "slll rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst" %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ __ ldw(rscratch2_AT, dst); ++ __ slll(rscratch2_AT, 1, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Shift Left by 8-bit immediate ++instruct salI_rReg_imm(rRegI dst, rRegI src, immU8 shift) ++%{ ++ match(Set dst (LShiftI src shift)); ++ ins_cost(80); ++ format %{ "slll $src, $shift�x1f, $dst\t# @salI_rReg_imm\n\t" ++ "addw $dst, #0, $dst" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int shamt = $shift$$constant; ++ ++ if(UseSW8A) { ++ __ sllw(src, shamt, dst); ++ } else { ++ __ slll(src, shamt&0x1f, dst); ++ __ addw(dst, 0, dst); ++ } ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/* memory operands no need for SW64 ++// Shift Left by 8-bit immediate ++instruct salI_mem_imm(memory dst, immI8 shift) ++%{ ++ match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); ++ ++ format %{ "ldw rscratch2_AT, $dst\t# @salI_mem_imm\n\t" ++ "slll rscratch2_AT, $shift�x1f, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" %}//?shift ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int shamt = $shift$$constant; ++ __ ldw(rscratch2_AT, dst); ++ __ slll(rscratch2_AT, shamt&0x1f, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%} ++*/ ++// Shift Left by variable//sny reg_reg ++instruct salI_rReg_CL(rRegI dst, rRegI src, rRegI shift) ++%{ ++ match(Set dst (LShiftI src shift)); ++ ++ format %{ ++ "and_ins $shift, #0x1f, rscratch3\t #@salI_rReg_CL\n\t" ++ "slll $src, rscratch3, $dst\n\t" ++ "movws $dst, $dst" ++ %}//?shift ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register shamt = $shift$$Register; ++ if (UseSW8A) { ++ __ sllw(src, shamt, dst); ++ } else { ++ __ and_ins(shamt, 0x1f, rscratch3);//31(0x1f) ++ __ slll(src, rscratch3, dst); ++ __ movws(dst, dst);// Do we need this operation?jx lsp?? ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++/* memory operands no need for SW64 ++// Shift Left by variable ++instruct salI_mem_CL(memory dst, rRegI shift) ++%{ ++ match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); ++ ++ format %{ ++ "ldw rscratch2_AT, $dst\t #@salI_mem_CL\n\t" ++ "and_ins $shift, 0x1f, $shift\n\t" ++ "slll rscratch2_AT, $shift, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Register shamt = $shift$$Register; ++ Address dst = $dst$$Address; ++ __ ldw(rscratch2_AT, dst); ++ __ and_ins(shamt, 0x1f, shamt); ++ __ slll(rscratch2_AT, shamt, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%} ++*/ ++ ++/* no need for SW64 ++// Arithmetic shift right by one ++instruct sarI_rReg_1(rRegI dst, rRegI src, immI1 shift) ++%{ ++ match(Set dst (RShiftI src shift)); ++ ++ format %{ "sral $src, #1, $dst\t #@sarI_rReg_1" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ sral(src, 1, dst); ++ %} ++ ins_pipe(ialu_regI_imm); ++%}*/ ++ ++/* memory operands no need for SW64 ++// Arithmetic shift right by one ++instruct sarI_mem_1(memory dst, immI1 shift) ++%{ ++ match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); ++ ++ format %{ ++ "ldw rscratch2_AT, $dst\t #@sarI_mem_1\n\t" ++ "sral rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ ++ __ ldw(rscratch2_AT, dst); ++ __ sral(rscratch2_AT, 1, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Arithmetic Shift Right by 8-bit immediate ++instruct sarI_rReg_imm(rRegI dst, rRegI src, immU8 shift) ++%{ ++ match(Set dst (RShiftI src shift)); ++ ++ format %{ ++ "sral $src, $shift&0x1f, $dst\t #@sarI_rReg_imm" ++ %} ++ ++ ins_encode %{ ++ Register src = $src$$Register; ++ Register dst = $dst$$Register; ++ int shamt = $shift$$constant; ++ if(UseSW8A) { ++ __ sraw(src, shamt, dst); ++ } else { ++ __ sral(src, shamt&0x1f, dst); ++ } ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/* memory operands no need for SW64 ++// Arithmetic Shift Right by 8-bit immediate ++instruct sarI_mem_imm(memory dst, immI8 shift) ++%{ ++ match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); ++ ++ format %{ ++ "ldw rscratch2_AT, $dst\t #@sarI_mem_imm\n\t" ++ "sral rscratch2_AT, $shift&0x1f, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int shamt = $shift$$constant; ++ __ ldw(rscratch2_AT, dst); ++ __ sral(rscratch2_AT, shamt&0x1f, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Arithmetic Shift Right by variable ++instruct sarI_rReg_CL(rRegI dst, rRegI src, rRegI shift) ++%{ ++ match(Set dst (RShiftI src shift)); ++ ++ format %{ ++ "and_ins $shift, #31, rscratch3\t #@sarI_rReg_CL\n\t\t" ++ "sral $src, rscratch3, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register shamt = $shift$$Register; ++ if(UseSW8A) { ++ __ sraw(src, shamt, dst); ++ } else { ++ __ and_ins(shamt, 0x1f, rscratch3); ++ __ sral(src, rscratch3, dst); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++/* memory operands no need for SW64 ++// Arithmetic Shift Right by variable ++instruct sarI_mem_CL(memory dst, rRegI shift) ++%{ ++ match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); ++ ++ format %{ ++ "ldw rscratch2_AT, $dst\t #@sarI_mem_CL\n\t" ++ "and_ins $shift, #31, $shift\n\t" ++ "sral rscratch2_AT, $shift, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Register shamt = $shift$$Register; ++ Address dst = $dst$$Address; ++ __ ldw(rscratch2_AT, dst); ++ __ and_ins(shamt, 31, shamt); ++ __ sral(rscratch2_AT, shamt, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%}*/ ++ ++/* no need for SW54 ++// Logical shift right by one ++instruct shrI_rReg_1(rRegI dst, rRegI src, immI1 shift) ++%{ ++ match(Set dst (URShiftI src shift)); ++ ++ format %{ "srll $src, #1, $dst\t #@shrI_rReg_1" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ srll(src, 1, dst); ++ %} ++ ins_pipe(ialu_regI_imm); ++%}*/ ++ ++/* memory operands no need for SW64 ++// Logical shift right by one ++instruct shrI_mem_1(memory dst, immI1 shift) ++%{ ++ match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); ++ ++ format %{ "ldw rscratch2_AT, $dst\t #@shrI_mem_1\n\t" ++ "srll rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ __ ldw(rscratch2_AT, dst); ++ __ srll(rscratch2_AT, 0x1, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Logical Shift Right by 8-bit immediate ++instruct shrI_rReg_imm(rRegI dst, rRegI src, immU8 shift) ++%{ ++ match(Set dst (URShiftI src shift)); ++ ++ format %{ "srll $src, $shift�x1f, $dst\t #@shrI_rReg_imm" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int shamt = $shift$$constant; ++ if(UseSW8A) { ++ __ srlw(src, shamt, dst); ++ } else { ++ __ zapnot(src, 0xf, dst); ++ __ srll(dst, shamt&0x1f, dst); ++ __ addw(dst, 0x0, dst); //need to CHECK lsp ++ } ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/* memory operands no need for SW64 ++// Logical Shift Right by 8-bit immediate ++instruct shrI_mem_imm(memory dst, immI8 shift) ++%{ ++ match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); ++ ++ format %{ "ldw rscratch2_AT, $dst\t #@shrI_mem_imm\n\t" ++ "srll rscratch2_AT, $shift�x1f, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst, rscratch1_GP" %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int shamt = $shift$$constant; ++ __ ldw(rscratch2_AT, dst); ++ __ srll(rscratch2_AT, shamt&0x1f, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Logical Shift Right by variable ++instruct shrI_rReg_CL(rRegI dst, rRegI src, rRegI shift) ++%{ ++ match(Set dst (URShiftI src shift)); ++ ++ format %{ ++ "and_ins $shift, 0x1f, rscratch3\t #@shrI_rReg_CL\n\t\t" ++ "movwu $dst, $src\n\t\t" ++ "srll $dst, rscratch3, $dst\n\t\t" ++ "movws $dst, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register shamt = $shift$$Register; ++ if(UseSW8A) { ++ __ srlw(src, shamt, dst); ++ } else { ++ __ and_ins(shamt, 0x1f, rscratch3); ++ __ movwu(dst, src); //need to Check lsp ++ __ srll(dst, rscratch3, dst); ++ __ movws(dst, dst); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++/* memory operands no need for SW64 ++// Logical Shift Right by variable ++instruct shrI_mem_CL(memory dst, rRegI shift) ++%{ ++ match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); ++ ++ format %{ "shrl #@shrI_mem_CL" %} ++ ++ ins_encode %{ ++ Register shamt = $shift$$Register; ++ Address dst = $dst$$Address; ++ __ ldw(rscratch2_AT, dst); ++ __ and_ins(shamt, 0x1f, shamt); ++ __ srll(rscratch2_AT, shamt, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%}*/ ++ ++/* No need for SW64 ++// Long Shift Instructions ++// Shift Left by one ++instruct salL_rReg_1(rRegL dst, rRegL src, immI1 shift) ++%{ ++ match(Set dst (LShiftL src shift)); ++ ++ format %{ "slll $src, $shift, $dst\t #@salL_rReg_1 " %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ slll(src, 1, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%}*/ ++ ++/* memory operands no need for SW64 ++// Shift Left by one ++instruct salL_mem_1(memory dst, immI1 shift) ++%{ ++ match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); ++ ++ format %{ "salq #@salL_mem_1" %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ __ ldl(rscratch2_AT, dst); ++ __ slll(rscratch2_AT, 1, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Shift Left by 8-bit immediate ++instruct salL_rReg_imm(rRegL dst, rRegL src, immU8 shift) ++%{ ++ match(Set dst (LShiftL src shift)); ++ ins_cost(80); ++ format %{ "slll $src, $shift, $dst #@salL_rReg_imm" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int shamt = $shift$$constant; ++ ++ __ slll(src, shamt&0x3f, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/* memory operands no need for SW64 ++// Shift Left by 8-bit immediate ++instruct salL_mem_imm(memory dst, immI8 shift) ++%{ ++ match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); ++ ++ format %{ "salq #@salL_mem_imm" %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int shamt = $shift$$constant; ++ __ ldl(rscratch2_AT, dst); ++ __ slll(rscratch2_AT, shamt&0x3f, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Shift Left by variable ++instruct salL_rReg_CL(rRegL dst, rRegL src, rRegI shift) ++%{ ++ match(Set dst (LShiftL src shift)); ++ ins_cost(80); ++ format %{ "slll $src $shift, $dst #@salL_rReg_CL" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register shamt = $shift$$Register; ++ //__ and_ins(shamt, 0x3f, shamt); ++ __ slll(src, shamt, dst); ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++/* memory operands no need for SW64 ++// Shift Left by variable ++instruct salL_mem_CL(memory dst, rRegI shift) ++%{ ++ match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); ++ ++ format %{ "salq #@salL_mem_CL" %} ++ ++ ins_encode %{ ++ Register shamt = $shift$$Register; ++ Address dst = $dst$$Address; ++ __ ldl(rscratch2_AT, dst); ++ __ and_ins(shamt, 0x3f, shamt); ++ __ slll(rscratch2_AT, shamt, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%} ++// No need for SW64 ++// Arithmetic shift right by one ++instruct sarL_rReg_1(rRegL dst, rRegL src, immI1 shift) ++%{ ++ match(Set dst (RShiftL src shift)); ++ ++ format %{ "sral $src, #1, $dst\t# long\t@sarL_rReg_1" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ sral(src, 1, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++// memory operands no need for SW64 ++// Arithmetic shift right by one ++instruct sarL_mem_1(memory dst, immI1 shift) ++%{ ++ match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); ++ ++ ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@sarL_mem_1\n\t" ++ "sral rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ ++ __ ldl(rscratch2_AT, dst); ++ __ sral(rscratch2_AT, 1, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Arithmetic Shift Right by 8-bit immediate ++instruct sarL_rReg_imm(rRegL dst, rRegL src, immU8 shift) ++%{ ++ match(Set dst (RShiftL src shift)); ++ ins_cost(80); ++ format %{ "sral $src, $shift, $dst\t# long\t@sarL_rReg_imm" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int value = $shift$$constant; ++ ++ __ sral(src, value, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/* memory operands no need for SW64 ++// Arithmetic Shift Right by 8-bit immediate ++instruct sarL_mem_imm(memory dst, immI8 shift) ++%{ ++ match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); ++ ++ ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@sarL_mem_imm\n\t" ++ "sral rscratch2_AT, $shift, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int value = $shift$$constant; ++ ++ __ ldl(rscratch2_AT, dst); ++ __ sral(rscratch2_AT, value, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Arithmetic Shift Right by variable ++instruct sarL_rReg_CL(rRegL dst, rRegL src, rRegI shift) ++%{ ++ match(Set dst (RShiftL src shift)); ++ ++ format %{ "sral $src, $shift, $dst\t# long\t@sarL_rReg_CL" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register shift = $shift$$Register; ++ ++ __ sral(src, shift, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++/* memory operands no need for SW64 ++// Arithmetic Shift Right by variable ++instruct sarL_mem_CL(memory dst, rRegI shift) ++%{ ++ match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); ++ ++ ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@sarL_mem_CL\n\t" ++ "sral rscratch2_AT, $shift, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ Register shift = $shift$$Register; ++ ++ __ ldl(rscratch2_AT, dst); ++ __ sral(rscratch2_AT, shift, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%} ++ ++// No need for SW64 ++// Logical shift right by one ++instruct shrL_rReg_1(rRegL dst, rRegL src, immI1 shift) ++%{ ++ match(Set dst (URShiftL src shift)); ++ ++ format %{ "srll $src, #1, $dst\t# long\t@shrL_rReg_1\n\t" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ srll(src, 1, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++// memory operands no need for SW64 ++// Logical shift right by one ++instruct shrL_mem_1(memory dst, immI1 shift) ++%{ ++ match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); ++ ++ ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@shrL_mem_1\n\t" ++ "srll rscratch2_AT, #1, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ ++ __ ldl(rscratch2_AT, dst); ++ __ srll(rscratch2_AT, 1, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Logical Shift Right by 8-bit immediate ++instruct shrL_rReg_imm(rRegL dst, rRegL src, immU8 shift) ++%{ ++ match(Set dst (URShiftL src shift)); ++ ins_cost(80); ++ format %{ "srll $src, $shift�x3f, $dst\t# long\t@shrL_rReg_imm" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int shamt = $shift$$constant; ++ __ srll(src, shamt&0x3f, dst); ++ %} ++ ins_pipe(ialu_regL_imm); ++%} ++ ++/* memory operands no need for SW64 ++// Logical Shift Right by 8-bit immediate ++instruct shrL_mem_imm(memory dst, immI8 shift) ++%{ ++ match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); ++ ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@shrL_mem_imm\n\t" ++ "srll rscratch2_AT, $shift�x3f, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int shamt = $shift$$constant; ++ __ ldl(rscratch2_AT, dst); ++ __ srll(rscratch2_AT, shamt&0x3f, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_imm); ++%}*/ ++ ++// Logical Shift Right by variable ++instruct shrL_rReg_CL(rRegL dst, rRegL src, rRegI shift) ++%{ ++ match(Set dst (URShiftL src shift)); ++ ++ format %{ ++ "srll $src, $shift, $dst\t# long\t@shrL_rReg_CL" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ Register shift = $shift$$Register; ++ ++ //__ and_ins(shift, 0x3f, shift);TODO: ++ __ srll(src, shift, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++/* memory operands no need for SW64 ++// Logical Shift Right by variable ++instruct shrL_mem_CL(memory dst, rRegI shift) ++%{ ++ match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); ++ ++ ++ format %{ ++ "ldl rscratch2_AT, $dst\t# long\t@shrL_mem_CL\n\t" ++ "and_ins $shift, #0x3f, $shift\n\t" ++ "srll rscratch2_AT, $shift, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst, rscratch1_GP" ++ %} ++ ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ Register shift = $shift$$Register; ++ ++ __ ldl(rscratch2_AT, dst); ++ __ and_ins(shift, 0x3f, shift); ++ __ srll(rscratch2_AT, shift, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ //ins_pipe(ialu_mem_reg); ++%}*/ ++ ++ ++// Logical Shift Right by 24, followed by Arithmetic Shift Left by 24. ++// This idiom is used by the compiler for the i2b bytecode. ++instruct i2b(rRegI dst, rRegI src, immI_24 twentyfour) ++%{ ++ match(Set dst (RShiftI (LShiftI src twentyfour) twentyfour)); ++ ++ format %{ "sextb $src, $dst\t#@i2b" %} ++ ++ ins_encode %{ ++ Register src = $src$$Register; ++ Register dst = $dst$$Register; ++ ++ __ sextb(src, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++// Logical Shift Right by 16, followed by Arithmetic Shift Left by 16. ++// This idiom is used by the compiler the i2s bytecode. ++instruct i2s(rRegI dst, rRegI src, immI_16 sixteen) ++%{ ++ match(Set dst (RShiftI (LShiftI src sixteen) sixteen)); ++ ++ format %{ "sexth $src, $dst\t#@i2s" %} ++ ++ ins_encode %{ ++ Register src = $src$$Register; ++ Register dst = $dst$$Register; ++ ++ __ sexth(src, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++/* Rotate shift No need for SW64 ?? ++// ROL/ROR instructions ++ ++// ROL expand ++instruct rolI_rReg_imm1(rRegI dst, immI1 lshift, immI_M1 rshift) %{ ++ match(Set dst (OrI (LShiftI dst lshift) (URShiftI dst rshift))); ++ format %{ "roll #@rolI_rReg_imm1" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++// int lshift = $lshift$$constant; ++// int rshift = $rshift$$constant; ++ __ slll(dst, 0x1, rscratch2_AT); ++ __ srll(dst, 0x1F, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ ++ %} ++ //ins_pipe(ialu_reg); ++%} ++ ++/*--x86 does not provide any match rule, compiling error---*/ ++// end of ROL expand ++ ++// Rotate Left by one ++//instruct rolI_rReg_i1(rRegI dst, immI1 lshift, immI_M1 rshift) ++//%{ ++// match(Set dst (OrI (LShiftI dst lshift) (URShiftI dst rshift))); ++// ++// expand %{ ++// //rolI_rReg_imm1(dst, cr); ++// %} ++//%} ++ ++// Rotate Left by 8-bit immediate ++instruct rolI_rReg_i8(rRegI dst, immI8 lshift, immI8 rshift) ++%{ ++ predicate((0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x1f)) && UseSW8A); ++ match(Set dst (OrI (LShiftI dst lshift) (URShiftI dst rshift))); ++ format %{ "rolw $dst, $dst, $lshift #@rolI_rReg_i8" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ int lshift = $lshift$$constant; ++ int rshift = $rshift$$constant; ++ if(UseSW8A) { ++ __ rolw(dst, lshift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++// Rotate Left by variable ++instruct rolI_rReg_Var_C0(rRegI dst, rRegI shift, immI0 zero) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrI (LShiftI dst shift) (URShiftI dst (SubI zero shift)))); ++ format %{ "rolw $dst, $dst, $shift #@rolI_rReg_Var_C0" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ rolw(dst, shift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++// Rotate Left by variable ++instruct rolI_rReg_Var_C32(rRegI dst, rRegI shift, immI_32 c32) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrI (LShiftI dst shift) (URShiftI dst (SubI c32 shift)))); ++ format %{ "rolw $dst, $dst, $shift #@rolI_rReg_Var_C32" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ rolw(dst, shift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct rolAddI_rReg_i8(rRegI dst, immI8 lshift, immI8 rshift) ++%{ ++ predicate((0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x1f)) && UseSW8A); ++ match(Set dst (AddI (LShiftI dst lshift) (URShiftI dst rshift))); ++ format %{ "rolw $dst, $dst, $lshift #@rolAddI_rReg_i8" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ int lshift = $lshift$$constant; ++ int rshift = $rshift$$constant; ++ if(UseSW8A) { ++ __ rolw(dst, lshift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++// ROR expand ++/*---x86 does not provide any match rule, compiling error---*/ ++/* ++instruct rorI_rReg_imm1(rRegI dst) ++%{ ++ ++ format %{ "rorl $dst" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ __ srll(dst, 0x1, rscratch2_AT); ++ __ slll(dst, 0x1F, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg); ++%} ++ ++// Rotate Right by 8-bit immediate ++instruct rorI_rReg_i8(rRegI dst, immI8 rshift, immI8 lshift) ++%{ ++ predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x1f)); ++ match(Set dst (OrI (URShiftI dst rshift) (LShiftI dst lshift))); ++ format %{ "rorl #@rorI_rReg_i8" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ int rshift = $rshift$$constant; ++ int lshift = $lshift$$constant; ++ __ srll(dst, rshift, rscratch2_AT); ++ __ slll(dst, lshift, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg); ++%} ++// end of ROR expand ++ ++// Rotate Right by one ++//instruct rorI_rReg_i1(rRegI dst, immI1 rshift, immI_M1 lshift) ++//%{ ++// match(Set dst (OrI (URShiftI dst rshift) (LShiftI dst lshift))); ++// ++// expand %{ ++// //rorI_rReg_imm1(dst, cr); ++// %} ++//%} ++ ++// Rotate Right by 8-bit immediate ++//instruct rorI_rReg_i8(rRegI dst, immI8 rshift, immI8 lshift) ++//%{ ++// predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x1f)); ++// match(Set dst (OrI (URShiftI dst rshift) (LShiftI dst lshift))); ++// ++// expand %{ ++// //rorI_rReg_imm8(dst, rshift, cr); ++// %} ++//%} ++*/ ++// Rotate Right by variable ++instruct rorI_rReg_Var_C0(rRegI dst, rRegI shift, immI0 zero) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrI (URShiftI dst shift) (LShiftI dst (SubI zero shift)))); ++ format %{ "rorw $dst, $dst, 0 - $shift #@rorI_rReg_Var_C0" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ and_ins(shift, 0x1f, rscratch1_GP); ++ __ subw(R0, rscratch1_GP, rscratch1_GP); ++ __ rolw(dst, rscratch1_GP, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++// Rotate Right by variable ++instruct rorI_rReg_Var_C32(rRegI dst, rRegI shift, immI_32 c32) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrI (URShiftI dst shift) (LShiftI dst (SubI c32 shift)))); ++ format %{ "rorw $dst, $dst, 32 - $shift #@rorI_rReg_Var_C32" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ and_ins(shift, 0x1f, rscratch1_GP); ++ __ subw(R0, rscratch1_GP, rscratch1_GP); ++ __ rolw(dst, rscratch1_GP, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++/* ++// for long rotate ++// ROL expand ++instruct rolL_rReg_imm1(rRegL dst) %{ ++ ++ format %{ ++ "slll $dst, 1, rscratch2_AT\t#long\t@rolL_rReg_imm1\n\t" ++ "srll $dst, 63, rscratch1_GP\n\t" ++ "or_ins rscratch2_AT, rscratch1_GP, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ ++ __ slll(dst, 1, rscratch2_AT); ++ __ srll(dst, 63, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ ++ %} ++ //ins_pipe(ialu_reg); ++%} ++ ++instruct rolL_rReg_CL(rRegL dst, rRegI shift) %{ ++// format %{ ++// "andw $shift, #0x1f, $shift\t#long\t@rolL_rReg_CL\n\t" ++// "mov_immediate32 rscratch2_AT, #64\n\t" ++// "subw rscratch2_AT, $shift, rscratch1_GP\n\t" ++// "mov_immediate64 rscratch2_AT, 0xffffffffffffffff\n\t" ++// "slll rscratch2_AT, rscratch1_GP, rscratch2_AT\n\t" ++// "and_ins $src, rscratch2_AT, rscratch2_AT\n\t" ++// "srll rscratch2_AT, rscratch1_GP, rscratch2_AT\n\t" ++// "slll $src, $shift, $dst\n\t" ++// "or_ins $dst, rscratch2_AT, $dst" ++// %} ++ format %{ "rolL_rReg_CL\t#@rolL_rReg_CL\n\t" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ ++ __ andw(shift, 0x1f, shift); ++ __ slll(dst, shift, rscratch2_AT); ++ __ mov_immediate32(rscratch1_GP, 64); ++ __ subw(rscratch1_GP, shift, rscratch1_GP); ++ __ srll(dst, rscratch1_GP, rscratch1_GP); ++ ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg_reg); ++%} ++// end of ROL expand ++ ++// Rotate Left by one ++instruct rolL_rReg_i1(rRegL dst, immI1 lshift, immI_M1 rshift) ++%{ ++ match(Set dst (OrL (LShiftL dst lshift) (URShiftL dst rshift))); ++ ++ expand %{ ++ rolL_rReg_imm1(dst); ++ %} ++%} ++*/ ++// Rotate Left by 8-bit immediate ++instruct rolL_rReg_i8(rRegL dst, immI8 lshift, immI8 rshift) ++%{ ++ predicate((0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x3f)) && UseSW8A); ++ match(Set dst (OrL (LShiftL dst lshift) (URShiftL dst rshift))); ++ format %{ "roll $dst, $dst, $lshift #@rolL_rReg_i8" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ int lshift = $lshift$$constant; ++ int rshift = $rshift$$constant; ++ if(UseSW8A) { ++ __ roll(dst, lshift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++// Rotate Left by variable ++instruct rolL_rReg_Var_C0(rRegL dst, rRegI shift, immI0 zero) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrL (LShiftL dst shift) (URShiftL dst (SubI zero shift)))); ++ format %{ "roll $dst, $dst, $shift #@rolL_rReg_Var_C0" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ roll(dst, shift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++// Rotate Left by variable ++instruct rolL_rReg_Var_C64(rRegL dst, rRegI shift, immI_64 c64) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrL (LShiftL dst shift) (URShiftL dst (SubI c64 shift)))); ++ format %{ "roll $dst, $dst, $shift #@rolL_rReg_Var_C64" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ roll(dst, shift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct rolAddL_rReg_i8(rRegL dst, immI8 lshift, immI8 rshift) ++%{ ++ predicate((0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x3f)) && UseSW8A); ++ match(Set dst (AddL (LShiftL dst lshift) (URShiftL dst rshift))); ++ format %{ "roll $dst, $dst, $lshift #@rolAddL_rReg_i8" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ int lshift = $lshift$$constant; ++ int rshift = $rshift$$constant; ++ if(UseSW8A) { ++ __ roll(dst, lshift, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++/* ++// ROR expand ++instruct rorL_rReg_imm1(rRegL dst) ++%{ ++ format %{ ++ "srll $dst, #1, rscratch2_AT\t#@rorL_rReg_imm1\n\t" ++ "slll $dst, #63, rscratch1_GP\n\t" ++ "or_ins rscratch2_AT, rscratch1_GP, $dst" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ ++ __ srll(dst, 1, rscratch2_AT); ++ __ slll(dst, 63, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg); ++%} ++*/ ++/* The following two methods cannot be implemented since there are no match rules*/ ++/* ++instruct rorL_rReg_imm8(rRegL dst, immI8 shift) ++%{ ++ ++ format %{ "rorq $dst, $shift" %} ++ ++ ins_encode%{ ++ Register dst = $dst$$Register; ++ int shift = $rshift$$constant; ++ ++ __ srll(dst, shift, rscratch2_AT); ++ __ slll(dst, 64-shift, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg); ++%} ++ ++instruct rorL_rReg_CL(rRegL dst, rRegI shift) ++%{ ++ ++ format %{ "rorq $dst, $shift" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ ++ __ srll(dst, shift, rscratch2_AT); ++ __ mov_immediate32(rscratch1_GP, 64); ++ __ subw(rscratch1_GP, shift, rscratch1_GP); ++ __ slll(dst, rscratch1_GP, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg_reg); ++%} ++*/ ++/* ++// end of ROR expand ++ ++// Rotate Right by one ++instruct rorL_rReg_i1(rRegL dst, immI1 rshift, immI_M1 lshift) ++%{ ++ match(Set dst (OrL (URShiftL dst rshift) (LShiftL dst lshift))); ++ ++ expand %{ ++ rorL_rReg_imm1(dst); ++ %} ++%} ++ ++// Rotate Right by 8-bit immediate ++instruct rorL_rReg_i8(rRegL dst, rRegL src, immI8 rshift, immI8 lshift) ++%{ ++ predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x3f)); ++ match(Set dst (OrL (URShiftL src rshift) (LShiftL src lshift))); ++//instruct rorL_rReg_imm8(rRegL dst, rRegL src, immI8 shift) ++//%{ ++ format %{ ++ "srll $dst, $rshift, rscratch2_AT\t#@rorL_rReg_i8\n\t" ++ "slll $dst, 64-rshift, rscratch1_GP\n\t" ++ "or_ins rscratch2_AT, rscratch1_GP, $dst" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ int shift = $rshift$$constant; ++ ++ __ srll(dst, shift, rscratch2_AT); ++ __ slll(dst, 64-shift, rscratch1_GP); ++ __ or_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ //ins_pipe(ialu_reg); ++%} ++*/ ++// Rotate Right by variable ++instruct rorL_rReg_Var_C0(rRegL dst, rRegI shift, immI0 zero) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrL (URShiftL dst shift) (LShiftL dst (SubI zero shift)))); ++ format %{ "rorl $dst, $dst, 0 - $shift #@rorL_rReg_Var_C0" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ and_ins(shift, 0x3f, rscratch1_GP); ++ __ subw(R0, rscratch1_GP, rscratch1_GP); ++ __ roll(dst, rscratch1_GP, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++instruct rorL_rReg_Var_C64(rRegL dst, rRegI shift, immI_64 c64) ++%{ ++ predicate(UseSW8A); ++ match(Set dst (OrL (URShiftL dst shift) (LShiftL dst (SubI c64 shift)))); ++ format %{ "rorl $dst, $dst, 64 - $shift #@rorL_rReg_Var_C64" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register shift = $shift$$Register; ++ if(UseSW8A) { ++ __ and_ins(shift, 0x3f, rscratch1_GP); ++ __ subw(R0, rscratch1_GP, rscratch1_GP); ++ __ roll(dst, rscratch1_GP, dst); ++ } else { ++ Unimplemented(); ++ } ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++ ++// Logical Instructions ++ ++// Integer Logical Instructions ++ ++// And Instructions ++// And Register with Register ++instruct andI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (AndI src1 src2)); ++ ++ format %{ ++ "and_ins $src1, $src2, $dst\t# int @andI_rReg" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ __ and_ins(src1, src2, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++/* sw8 ++instruct andI_Reg_Reg(rRegI dst, rRegI src1, rRegI src2) %{ ++ match(Set dst (AndI src1 src2)); ++ ++ format %{ "and $dst, $src1, $src2 #@andI_Reg_Reg" %} ++ ins_encode %{ ++// Register dst = $dst$$Register; ++// Register src1 = $src1$$Register; ++// Register src2 = $src2$$Register; ++// __ andr(dst, src1, src2); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++*/ ++/* TODO no in jdk8 ++// And Register with Immediate 255 ++instruct andI_rReg_imm255(rRegI dst, rRegI src1, immI_255 src2) ++%{ ++ match(Set dst (AndI src1 src2)); ++ ++ format %{ "and_ins $src1, #255, $dst\t# int & 0xFF @andI_rReg_imm255"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ __ and_ins(src1, 255, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++// And Register with Immediate 255 and promote to long ++instruct andI2L_rReg_imm255(rRegI dst, rRegI src, immI_255 mask) ++%{ ++ match(Set dst (ConvI2L (AndI src mask))); ++ ++ format %{ "and_ins $src, #255, $dst\t# int & 0xFF -> long @andI2L_rReg_imm255"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ and_ins(src, 255, dst); ++// __ sextb(src, dst); //TODO CHECK LSP I2L signed extend ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++*/ ++// And Register with Immediate 65535 ++instruct andI_rReg_imm65535(rRegI dst, rRegI src1, immI_65535 src2) ++%{ ++ match(Set dst (AndI src1 src2)); ++ ins_cost(40); ++ format %{ "zapnot $src1, #3, $dst\t# int & 0xFFFF @andI_rReg_imm65535"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src1$$Register; ++ __ zapnot(src, 0x3, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++/* TODO no in jdk8 ++// And Register with Immediate 65535 and promote to long ++instruct andI2L_rReg_imm65535(rRegI dst, rRegI src, immI_65535 mask) ++%{ ++ match(Set dst (ConvI2L (AndI src mask))); ++ ++ format %{ "zapnot $src, #3, $dst\t# int & 0xFFFF -> long @andI2L_rReg_imm65535"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ zapnot(src, 0x3, dst); ++// __ sexth(dst, dst); // TODO CHECK lsp I2L signed extend? ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++*/ ++// And Register with Immediate ++instruct andI_rReg_imm(rRegI dst, rRegI src1, immU8 src2) ++%{ ++ match(Set dst (AndI src1 src2)); ++ ins_cost(60); ++ format %{ "andw $src1, $src2, $dst\t# int @andI_rReg_imm"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src1$$Register; ++ int val = $src2$$constant; ++ __ and_ins(src, val, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++/* ++instruct andI_Reg_immI(rRegI dst, rRegI src1, immI src2) %{ ++ match(Set dst (AndI src1 src2)); ++ ++ format %{ "and $dst, $src1, $src2 #@andI_Reg_immI" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src1$$Register; ++ int val = $src2$$constant; ++ ++ __ mov_immediate32(AT, val); ++ __ and_ins(src, AT, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++*/ ++ ++/* memory operands no need for SW64 ++// And Register with Memory ++instruct andI_rReg_mem(rRegI dst, memory src1, rRegI src2) ++%{ ++ match(Set dst (AndI src2 (LoadI src1))); ++ ++// ins_cost(125);//todo ++ format %{ "ldw rscratch3, $src1\t# int @andI_rReg_mem\n\t" ++ "andw rscratch3, $src2, $dst" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldw(rscratch3, src1); ++ __ andw(rscratch3, src2, dst); ++ %} ++// ins_pipe(ialu_reg_mem); ++%} ++ ++// And Memory with Register ++instruct andI_mem_rReg(memory dst, rRegI src) ++%{ ++ match(Set dst (StoreI dst (AndI (LoadI dst) src))); ++ ++ ins_cost(150);//todo ++ format %{ "ldw rscratch3, $dst\t# int @andI_mem_rReg\n\t" ++ "and_ins rscratch3, $src, rscratch2_AT\n\t" ++ "stw rscratch3, $dst" %} ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ Register src = $src$$Register; ++ __ ldw(rscratch3, dst); ++ __ and_ins(src, rscratch3, rscratch3); ++ __ stw(rscratch3, dst); ++ ++ %} ++// ins_pipe(ialu_mem_reg); ++%} ++ ++// And Memory with Immediate ++instruct andI_mem_imm(memory dst, immI src) ++%{ ++ match(Set dst (StoreI dst (AndI (LoadI dst) src))); ++ ++ ins_cost(125);//todo ++ format %{ "ldw rscratch2_AT, $dst\t# int @andI_mem_imm\n\t" ++ "movws rscratch2_AT, $src, rscratch2_AT\n\t" ++ "and_ins rscratch2_AT, rscratch1_GP, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst" %} ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int val = $src$$constant; ++ __ ldw(rscratch1_GP, dst); ++ __ movws(rscratch2_AT, val); ++ __ and_ins(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ ++ %} ++// ins_pipe(ialu_mem_imm); ++%} ++ ++// BMI1 instructions ++instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1) %{ ++ match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ "ldw rscratch2_AT, $src2\t# @andnI_rReg_rReg_mem\n\t" ++ "ornot R0, $src1, rscratch1_GP\n\t" ++ "andw rscratch1_GP, rscratch2_AT, $dst" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Address src2 = $src2$$Address; ++ int val = $minus_1$$constant; ++ __ ldw(rscratch2_AT, src2); ++ __ ornot(R0, src1, rscratch1_GP); ++ __ andw(rscratch1_GP, rscratch2_AT, dst); ++ %} ++// ins_pipe(ialu_reg_mem); ++%}*/ ++/*no need in swjdk8 ++instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1) %{ ++ match(Set dst (AndI (XorI src1 minus_1) src2)); ++// predicate(UseBMI1Instructions); ++ ++ format %{ "ornot R0, $src1, rscratch3 \t# @andnI_rReg_rReg_rReg\n\t" ++ "andw rscratch3, $src2, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ ++ __ ornot(R0, src1, rscratch3); ++ __ andw(rscratch3, src2, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++// TODO CHECK lsp: instruct name blsiI needed to be changed?? ++instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI0 imm_zero) %{ ++ match(Set dst (AndI (SubI imm_zero src) src)); ++// predicate(UseBMI1Instructions); ++ ++ format %{ "subw R0, $src, rscratch3\t# @blsiI_rReg_rReg\n\t" ++ "andw rscratch3, $src, $dst"%} ++ ++ ins_encode %{ ++// __ blsil($dst$$Register, $src$$Register); ++ __ subw(R0, $src$$Register, rscratch3); ++ __ andw(rscratch3, $src$$Register, $dst$$Register); ++ %} ++// ins_pipe(ialu_reg); ++%}*/ ++/* memory operands no need for SW64 ++instruct blsiI_rReg_mem(rRegI dst, memory src, immI0 imm_zero) %{ ++ match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ "ldw rscratch2_AT, $src\t# @blsiI_rReg_mem\n\t" ++ "subw R0, rscratch2_AT, rscratch1_GP\n\t" ++ "andw rscratch1_GP, rscratch2_AT, $dst"%} ++ ++ ins_encode %{ ++// __ blsil($dst$$Register, $src$$Address); ++ __ ldw(rscratch2_AT, $src$$Address); ++ __ subw(R0, rscratch2_AT, rscratch1_GP); ++ __ andw(rscratch1_GP, rscratch2_AT, $dst$$Register); ++ %} ++// ins_pipe(ialu_reg_mem); ++%} ++ ++instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1) ++%{ ++ match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ "ldw rscratch2_AT, $src\t# @blsmskI_rReg_mem\n\t" ++ "subw rscratch2_AT, #1, rscratch1_GP\n\t" ++ "xorw rscratch1_GP, rscratch2_AT, $dst"%} ++ ++ ins_encode %{ ++// __ blsmskl($dst$$Register, $src$$Address); ++ __ ldw(rscratch2_AT, $src$$Address); ++ __ subw(rscratch2_AT, 1, rscratch1_GP); ++ __ xorw(rscratch1_GP, rscratch2_AT, $dst$$Register); ++ %} ++// ins_pipe(ialu_reg_mem); ++%}*/ ++ ++/* no need in swjdk8 ++instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1) ++%{ ++ match(Set dst (XorI (AddI src minus_1) src)); ++// predicate(UseBMI1Instructions); ++ ++ format %{ "subw $src, #1, rscratch3\t# @blsmskI_rReg_rReg\n\t" ++ "xorw rscratch3, $src, $dst"%} ++ ++ ins_encode %{ ++// __ blsmskl($dst$$Register, $src$$Register); ++ __ subw($src$$Register, 1, rscratch3); ++ __ xorw(rscratch3, $src$$Register, $dst$$Register); ++ %} ++ ++// ins_pipe(ialu_reg); ++%} ++ ++instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1) ++%{ ++ match(Set dst (AndI (AddI src minus_1) src) ); ++// predicate(UseBMI1Instructions); ++ ++ format %{ "subw $src, #1, rscratch3\t# @blsrI_rReg_rReg\n\t" ++ "andw rscratch3, $src, $dst"%} ++ ++ ins_encode %{ ++// __ blsrl($dst$$Register, $src$$Register); ++ __ subw($src$$Register, 1, rscratch3); ++ __ andw(rscratch3, $src$$Register, $dst$$Register); ++ %} ++ ++// ins_pipe(ialu_reg_mem); ++%} ++*/ ++/* memory operands no need for SW64 ++instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1) ++%{ ++ match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ "ldw rscratch2_AT, $src\t# @blsmskI_rReg_mem\n\t" ++ "subw rscratch2_AT, #1, rscratch1_GP\n\t" ++ "andw rscratch2_AT, rscratch1_GP, $dst"%} ++ ++ ins_encode %{ ++// __ blsrl($dst$$Register, $src$$Address); ++ __ ldw(rscratch2_AT, $src$$Address); ++ __ subw(rscratch2_AT, 1, rscratch1_GP); ++ __ andw(rscratch2_AT, rscratch1_GP, $dst$$Register); ++ %} ++ ++// ins_pipe(ialu_reg); ++%}*/ ++ ++// Or Instructions ++// Or Register with Register ++instruct orI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (OrI src1 src2)); ++ ++ format %{ ++ "bis $src1, $src2, $dst\t# int @orI_rReg" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ //__ stop("orI_rReg");//TODO ++ __ bis(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++ ++// Or Register with Immediate ++instruct orI_rReg_imm(rRegI dst, rRegI src1, immU8 src2) ++%{ ++ match(Set dst (OrI src1 src2)); ++ ins_cost(60); ++ format %{ "bis $src1, $src2, $dst\t# int @orI_rReg_imm" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ int src2 = $src2$$constant; ++ //__ stop("orI_rReg_imm");//TODO ++ __ bis(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ ++/* memory operands no need for SW64 ++// Or Register with Memory ++instruct orI_rReg_mem(rRegI dst, memory src1, rRegI src2) ++%{ ++ match(Set dst (OrI src2 (LoadI src1))); ++ ++ ins_cost(125); ++ format %{ ++ "ldw rscratch2_AT, $src1\t# int @orI_rReg_mem\n\t" ++ "orw $src2, rscratch2_AT, $dst" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldw(rscratch2_AT, src1); ++ __ orw(src2, rscratch2_AT, dst); ++ %} ++ ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ ++// Or Memory with Register ++instruct orI_mem_rReg(memory dst, rRegI src) ++%{ ++ match(Set dst (StoreI dst (OrI (LoadI dst) src))); ++ ++ ins_cost(150); ++ format %{ ++ "ldw rscratch2_AT, $dst\t# int @orI_mem_rReg\n\t" ++ "orw $src, rscratch2_AT, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst" ++ %} ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ Register src = $src$$Register; ++ __ ldw(rscratch2_AT, dst); ++ __ bis(rscratch2_AT, src, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ ++// Or Memory with Immediate ++instruct orI_mem_imm(memory dst, immI src) ++%{ ++ match(Set dst (StoreI dst (OrI (LoadI dst) src))); ++ ++ ins_cost(125); ++ format %{ ++ "ldw rscratch2_AT, $dst\t# int @orI_mem_imm\n\t" ++ "movws rscratch1_GP, $src\n\t" ++ "bis rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst" ++ %} ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int src = $src$$constant; ++ __ ldw(rscratch2_AT, dst); ++ __ movws(rscratch1_GP, src); ++ __ bis(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ __ stw(rscratch2_AT, dst, rscratch1_GP); ++ %} ++ ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%}*/ ++ ++// Xor Instructions ++// Xor Register with Register ++instruct xorI_rReg(rRegI dst, rRegI src1, rRegI src2) ++%{ ++ match(Set dst (XorI src1 src2)); ++// ins_cost(60); ++ ++ format %{ ++ "xor_ins $src1, $src2, $dst\t# int @xorI_rReg" ++ %} ++ ins_encode %{ ++ //__ stop("xorI_rReg"); TODO:jzy ++ __ xor_ins($src1$$Register, $src2$$Register, $dst$$Register); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++/* TODO no in jdk8 ++// Xor Register with Immediate -1 ++instruct xorI_rReg_im1(rRegI dst, rRegI src, immI_M1 imm) %{ ++ match(Set dst (XorI src imm)); ++ ins_cost(60); ++ ++ format %{ "ornot R0, $src, $dst\t# int @xorI_rReg_im1\n\t" ++ "zapnot $dst, 0xf, $dst"%} ++ ins_encode %{ ++ __ ornot(R0, $src$$Register, $dst$$Register); ++// __ zapnot($dst$$Register, 0xf, $dst$$Register);//?? ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++*/ ++// Xor Register with Immediate ++instruct xorI_rReg_imm(rRegI dst, rRegI src1, immU8 src2) ++%{ ++ match(Set dst (XorI src1 src2)); ++ ins_cost(60); ++ ++ format %{ "xor_ins $src1, $src2, $dst\t# int @xorI_rReg_imm\n\t" %} ++ ins_encode %{ ++ //__ stop("xorI_rReg_imm"); TODO:jzy ++ __ xor_ins($src1$$Register, $src2$$constant, $dst$$Register); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++/* memory operands no need for SW64 ++// Xor Register with Memory ++instruct xorI_rReg_mem(rRegI dst, rRegI src1, memory src2) ++%{ ++ match(Set dst (XorI src1 (LoadI src2))); ++ ins_cost(125); ++ ++ format %{ "ldw rscratch2_AT, $src2\t# int @xorI_rReg_mem\n\t" ++ "xorw $src1, rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldw(rscratch2_AT, $src2$$Address); ++ __ xorw($src1$$Register, rscratch2_AT, $dst$$Register); ++ %} ++// ins_pipe( ialu_reg_mem ); ++%} ++ ++// Xor Memory with Register ++instruct xorI_mem_rReg(memory dst, rRegI src) ++%{ ++ match(Set dst (StoreI dst (XorI (LoadI dst) src))); ++ ins_cost(150); ++ ++ format %{ "ldw rscratch2_AT, $dst\t# int @xorI_rReg_mem\n\t" ++ "xor_ins rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldw(rscratch2_AT, $dst$$Address); ++ __ xor_ins(rscratch2_AT, $src$$Register, rscratch2_AT); ++ __ stw(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe( ialu_reg_mem ); ++%} ++ ++// Xor Memory with Immediate ++instruct xorI_mem_imm(memory dst, immI src) ++%{ ++ match(Set dst (StoreI dst (XorI (LoadI dst) src))); ++ ins_cost(125); ++ ++ format %{ "ldw rscratch2_AT, $dst\t# int @xorI_mem_imm\n\t" ++ "movws rscratch1_GP, $src\n\t" ++ "xor_ins rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stw rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldw(rscratch2_AT, $dst$$Address); ++ __ movws(rscratch1_GP, (int)$src$$constant); ++ __ xor_ins(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ __ stw(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe(ialu_mem_imm); ++%} ++ */ ++ ++ ++// Long Logical Instructions ++ ++// And Instructions ++// And Register with Register ++instruct andL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (AndL src1 src2)); ++ ins_cost(100); ++ format %{ "and_ins $src1, $src2, $dst\t# long @andL_rReg" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ ++ __ and_ins(src1, src2, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++/* TODO no in jdk8 ++// And Register with Immediate 255 ++instruct andL_rReg_imm255(rRegL dst, rRegL src1, immL_255 src2) ++%{ ++ match(Set dst (AndL src1 src2)); ++ ++ format %{ "and_ins $src1, #255, $dst\t# long & 0xFF @andL_rReg_imm_255" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ __ and_ins(src1, 255, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++// And Register with Immediate 65535 ++instruct andL_rReg_imm65535(rRegL dst, rRegL src1, immL_65535 src2) ++%{ ++ match(Set dst (AndL src1 src2)); ++ ++ format %{ "zapnot $src1, 0x3, $dst\t# long & 0xFFFF @andL_rReg_imm65535"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ __ zapnot(src1, 0x3, dst);//TODO CHECK LSP ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++ ++// And Register with Immediate ++instruct andL_rReg_imm(rRegL dst, rRegL src1, immL32 src2) ++%{ ++ match(Set dst (AndL src1 src2)); ++ ++ format %{ "movws $dst, $src2\t# long @andL_rReg_imm\n\t" ++ "and_ins $dst, $src1, $dst"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ int value = $src2$$constant; ++ __ movws(dst, value); ++ __ and_ins(dst, src1, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++*/ ++instruct andL_Reg_Reg_convI2L(rRegL dst, rRegL src1, rRegI src2) %{ ++ match(Set dst (AndL src1 (ConvI2L src2))); ++ format %{ "AND $dst, $src1, $src2 @ andL_Reg_Reg_convI2L\n\t" %} ++ ins_encode %{ ++ Register dst_reg = $dst$$Register; ++ Register src1_reg = $src1$$Register; ++ Register src2_reg = $src2$$Register; ++// __ stop("andL_Reg_Reg_convI2L copy from jdk8 why src2 do not signed extend lsp"); ++ ++ __ and_ins(src1_reg, src2_reg, dst_reg); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++instruct andL_Reg_imm_0_255(rRegL dst, rRegL src1, immUL8 src2) %{ ++ match(Set dst (AndL src1 src2)); ++ ins_cost(60); ++ ++ format %{ "and $dst, $src1, $src2 #@andL2I_Reg_imm_0_255" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src1$$Register; ++ long val = $src2$$constant; ++ ++ __ and_ins(src, val, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++// And Register with Immediate 65535 ++instruct andL_rReg_imm65535(rRegL dst, rRegL src1, immL_65535 src2) ++%{ ++ match(Set dst (AndL src1 src2)); ++ ins_cost(60); ++ format %{ "zapnot $src1, 0x3, $dst\t# long & 0xFFFF @andL_rReg_imm65535"%} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ __ zapnot(src1, 0x3, dst);//TODO CHECK LSP ++ %} ++ ins_pipe(ialu_regI_imm16); ++%} ++instruct andL2I_Reg_imm_0_255(rRegI dst, rRegL src1, immUL8 src2) %{ ++ match(Set dst (ConvL2I (AndL src1 src2))); ++ ins_cost(60); ++ ++ format %{ "and $dst, $src1, $src2 #@andL2I_Reg_imm_0_255" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src1$$Register; ++ long val = $src2$$constant; ++ ++ __ and_ins(src, val, dst); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++/* memory operands no need for SW64 ++// And Register with Memory ++instruct andL_rReg_mem(rRegL dst, memory src1, rRegL src2) ++%{ ++ match(Set dst (AndL src2 (LoadL src1))); ++ ++ ins_cost(125);//todo ++ format %{ ++ "ldl rscratch2_AT, $src1\t# long @andL_rReg_mem\n\t" ++ "and_ins rscratch2_AT, $src2, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldl(rscratch2_AT, src1); ++ __ and_ins(rscratch2_AT, src2, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++// ins_pipe(ialu_reg_mem); ++%} ++ ++// And Memory with Immediate ++instruct andL_mem_imm(memory dst, immL32 src) ++%{ ++ match(Set dst (StoreL dst (AndL (LoadL dst) src))); ++ ++ ins_cost(125);//todo ++ format %{ "ldl rscratch2_AT, $dst\t# long @andL_mem_imm\n\t" ++ "movws rscratch1_GP, $src\n\t" ++ "and_ins rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst" %} ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int val = $src$$constant; ++ __ ldl(rscratch2_AT, dst); ++ __ movws(rscratch1_GP, val); ++ __ and_ins(rscratch1_GP, rscratch2_AT, rscratch2_AT); ++ __ stl(rscratch2_AT, dst); ++ %} ++// ins_pipe(ialu_mem_imm); ++%} ++ ++ ++// BMI1 instructions ++instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1) %{ ++ match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ "ldl rscratch2_AT, $src2\t# @andL_mem_rReg\n\t" ++ "ornot R0, $src1, rscratch3\n\t" ++ "and_ins rscratch3, rscratch2_AT, $dst" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Address src2 = $src2$$Address; ++ __ ldl(rscratch2_AT, src2); ++ __ ornot(R0, src1, rscratch3); ++ __ and_ins(rscratch3, rscratch2_AT, dst); ++ %} ++// ins_pipe(ialu_reg_mem); ++%}*/ ++/* TODO no in jdk8 ++instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1) %{ ++ match(Set dst (AndL (XorL src1 minus_1) src2)); ++// predicate(UseBMI1Instructions); ++ ++ format %{ ++ "ornot R0, $src1, rscratch3\t# @andnL_rReg_rReg_rReg\n\t" ++ "andptr rscratch3, $src2, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $dst$$Register; ++ Register src2 = $dst$$Register; ++ __ ornot(R0, src1, rscratch3); ++ __ andptr(rscratch3, src2, dst); ++ %} ++ ins_pipe(ialu_regL_regL); ++%} ++*/ ++/*no need in swjdk8 ++instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero) %{ ++ match(Set dst (AndL (SubL imm_zero src) src)); ++// predicate(UseBMI1Instructions); ++ ++ format %{ ++ "subptr R0, $src, rscratch3\t# @blsiL_rReg_rReg\n\t" ++ "andptr rscratch3, $src, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ subptr(R0, src, rscratch3); ++ __ andptr(rscratch3, src, dst); ++ %} ++ ins_pipe(ialu_regI_regI); ++%}*/ ++/* memory operands no need for SW64 ++instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero) %{ ++ match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ ++ "ldl rscratch2_AT, $src\t# @blsiL_rReg_rReg\n\t" ++ "subl R0, rscratch2_AT, rscratch3\n\t" ++ "and_ins rscratch3, rscratch2_AT, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ __ ldl(rscratch2_AT, src); ++ __ subl(R0, rscratch2_AT, rscratch3); ++ __ and_ins(rscratch3, rscratch2_AT, dst); ++ %} ++// ins_pipe(ialu_reg_mem); ++%} ++ ++instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1) ++%{ ++ match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ ++ "ldl rscratch2_AT, $src\t# @blsmskL_Reg_mem\n\t" ++ "subl rscratch2_AT, #1, rscratch1_GP\n\t" ++ "xor_ins rscratch2_AT, rscratch1_GP, $dst" ++ %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ __ ldl(rscratch2_AT, src); ++ __ subl(rscratch2_AT, 1, rscratch1_GP); ++ __ xor_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++// ins_pipe(ialu_reg_mem); ++%}*/ ++/*no need in swjdk8 ++instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1) ++%{ ++ match(Set dst (XorL (AddL src minus_1) src)); ++// predicate(UseBMI1Instructions); ++ ++ format %{ "subl $src, #1, rscratch3\t# @blsmskL_rReg_rReg\n\t" ++ "xor_ins rscratch3, $src, $dst" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ __ subl(src, 1, rscratch3); ++ __ xor_ins(rscratch3, src, dst); ++ %} ++ ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1) ++%{ ++ match(Set dst (AndL (AddL src minus_1) src) ); ++// predicate(UseBMI1Instructions); ++ ++ format %{ "subl $src, #1, rscratch3\t# @blsrL_Reg_Reg\n\t" ++ "and_ins rscratch3, $src, $dst" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ subl(src, 1, rscratch3); ++ __ and_ins(rscratch3, src, dst); ++ %} ++ ++ ins_pipe(ialu_regI_regI); ++%}*/ ++/* memory operands no need for SW64 ++instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1) ++%{ ++ match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); ++// predicate(UseBMI1Instructions); ++ ++ ins_cost(125);//todo ++ format %{ "ldl rscratch2_AT, $src\t# @blsrL_rReg_mem\n\t" ++ "subl rscratch2_AT, #1, rscratch1_GP\n\t" ++ "and_ins rscratch2_AT, rscratch1_GP, $dst" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src = $src$$Address; ++ __ ldl(rscratch2_AT, src); ++ __ subl(rscratch2_AT, 1, rscratch1_GP); ++ __ and_ins(rscratch2_AT, rscratch1_GP, dst); ++ %} ++ ++// ins_pipe(ialu_reg); ++%} ++*/ ++// Or Instructions ++// Or Register with Register ++instruct orL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (OrL src1 src2)); ++ ++ format %{ "bis $src1, $src2, $dst\t# @orL_rReg\n\t" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ __ bis(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ ++ ++// Use any_RegP to match R15 (TLS register) without spilling. ++instruct orL_rReg_castP2X(rRegL dst, any_RegP src1, rRegL src2) %{ ++ match(Set dst (OrL src2 (CastP2X src1))); ++ ++ format %{ "bis $src1, $src2, $dst\t# @orL_rReg_castP2X\n\t" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ Register src2 = $src2$$Register; ++ __ bis(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regL_regL);//ins_pipe needs to be changed to a proper one ++%} ++ ++ ++// Or Register with Immediate ++instruct orL_rReg_imm(rRegL dst, rRegL src1, immU8 src2) ++%{ ++ match(Set dst (OrL src1 src2)); ++ ins_cost(80); ++ format %{ ++"movws $dst, $src2, $dst\t# @orL_rReg_imm\n\t" ++"bis $src1, $dst, $dst" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src1 = $src1$$Register; ++ int src2 = $src2$$constant; ++ __ bis(src1, src2, dst); ++ %} ++ ins_pipe(ialu_regL_regL);//ins_pipe needs to be changed to a proper one ++%} ++ ++/* memory operands no need for SW64 ++// Or Register with Memory ++instruct orL_rReg_mem(rRegL dst, memory src1, rRegL src2) ++%{ ++ match(Set dst (OrL src2 (LoadL src1))); ++ ++ ins_cost(125); ++ format %{ ++ "ldptr rscratch2_AT, $src1\t# @orL_rReg_mem\n\t" ++ "bis $src2, rscratch2_AT, $dst" ++ %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Address src1 = $src1$$Address; ++ Register src2 = $src2$$Register; ++ __ ldptr(rscratch2_AT, src1); ++ __ bis(src2, rscratch2_AT, dst); ++ %} ++// ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ ++ ++// Or Memory with Register ++instruct orL_mem_rReg(memory dst, rRegL src) ++%{ ++ match(Set dst (StoreL dst (OrL (LoadL dst) src))); ++ ins_cost(150); ++ format %{ ++ "ldl rscratch2_AT, $dst\t# @orL_mem_rReg\n\t" ++ "bis rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst" ++ %} ++ ins_encode%{ ++ Address dst = $dst$$Address; ++ Register src = $src$$Register; ++ __ ldl(rscratch2_AT, dst); ++ __ bis(rscratch2_AT, src, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++// ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ ++// Or Memory with Immediate ++instruct orL_mem_imm(memory dst, immL32 src) ++%{ ++ match(Set dst (StoreL dst (OrL (LoadL dst) src))); ++ ++ ins_cost(125); ++ format %{ ++ "ldl rscratch2_AT, $dst\t# @orL_mem_imm\n\t" ++ "movws rscratch1_GP, $src\n\t" ++ "bis rscratch2_AT, rscratch1_GP, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst" ++ %} ++ ins_encode %{ ++ Address dst = $dst$$Address; ++ int src = $src$$constant; ++ __ ldl(rscratch2_AT, dst); ++ __ movws(rscratch1_GP, src); ++ __ bis(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ __ stl(rscratch2_AT, dst, rscratch1_GP); ++ %} ++// ins_pipe(ialu_regI_regI);//ins_pipe needs to be changed to a proper one ++%} ++ */ ++ ++ ++// Xor Instructions ++// Xor Register with Register ++instruct xorL_rReg(rRegL dst, rRegL src1, rRegL src2) ++%{ ++ match(Set dst (XorL src1 src2)); ++ ins_cost(60); ++ ++ format %{ "xorptr $src1, $src2, $dst\t# long @xorL_rReg" %} ++ ins_encode %{ ++ __ xorptr($src1$$Register, $src2$$Register, $dst$$Register); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++/* TODO no in jdk8 ++// Xor Register with Immediate -1 ++instruct xorL_rReg_im1(rRegL dst, rRegL src, immL_M1 imm) %{ ++ match(Set dst (XorL src imm)); ++ ins_cost(60); ++ ++ format %{ "ornot R0, $src, $dst\t# long @xorL_rReg_im1" %} ++ ins_encode %{ ++ __ ornot(R0, $src$$Register, $dst$$Register); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++*/ ++// Xor Register with Immediate ++instruct xorL_rReg_imm(rRegL dst, rRegL src1, immU8 src2) ++%{ ++ match(Set dst (XorL src1 src2)); ++ ins_cost(60); ++ ++ format %{ "xor_ins $src1, $src2, $dst\t# long @xorL_rReg_imm\n" %} ++ ins_encode %{ ++ __ xor_ins($src1$$Register, $src2$$constant, $dst$$Register); ++ %} ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++/* memory operands no need for SW64 ++// Xor Register with Memory ++instruct xorL_rReg_mem(rRegL dst, rRegL src1, memory src2) ++%{ ++ match(Set dst (XorL src1 (LoadL src2))); ++ ins_cost(125); ++ ++ format %{ "ldl rscratch2_AT, $src2\t# long @xorL_rReg_mem\n\t" ++ "xor_ins $src1, rscratch2_AT, $dst" %} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $src2$$Address); ++ __ xor_ins($src1$$Register, rscratch2_AT, $dst$$Register); ++ %} ++// ins_pipe( ialu_reg_mem ); ++%} ++ ++// Xor Memory with Register ++instruct xorL_mem_rReg(memory dst, rRegL src) ++%{ ++ match(Set dst (StoreL dst (XorL (LoadL dst) src))); ++ ins_cost(150); ++ ++ format %{ "ldl rscratch2_AT, $src\t# long @xorL_mem_rReg\n\t" ++ "xor_ins $src, rscratch2_AT, $dst\n\t" ++ "stl rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $dst$$Address); ++ __ xor_ins(rscratch2_AT, $src$$Register, rscratch2_AT); ++ __ stl(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe( ialu_reg_mem ); ++%} ++ ++// Xor Memory with Immediate ++instruct xorL_mem_imm(memory dst, immL32 src) ++%{ ++ match(Set dst (StoreI dst (XorL (LoadI dst) src))); ++ ins_cost(125); ++ ++ format %{ "ldl rscratch2_AT, $dst\t# long @xorL_mem_imm\n\t" ++ "movws rscratch1_GP, $src\n\t" ++ "xo_ins rscratch2_AT, $src, rscratch2_AT\n\t" ++ "stl rscratch2_AT, $dst"%} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $dst$$Address); ++ __ movws(rscratch1_GP, (int)$src$$constant); ++ __ xor_ins(rscratch2_AT, rscratch1_GP, rscratch2_AT); ++ __ stl(rscratch2_AT, $dst$$Address, rscratch1_GP); ++ %} ++// ins_pipe( ialu_mem_imm ); ++%} ++ */ ++ ++// Convert Int to Boolean ++instruct convI2B(rRegI dst, rRegI src) ++%{ ++ match(Set dst (Conv2B src)); ++ ++ ins_cost(100); ++ format %{ "selne $src, #1, $src, $dst\t# @ convI2B" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ __ selne(src, 1, src, dst); ++ %} ++ ins_pipe(ialu_regL_regL ); ++%} ++ ++ ++// Convert Pointer to Boolean ++instruct convP2B(rRegI dst, rRegP src) ++%{ ++ match(Set dst (Conv2B src)); ++ ++ format %{ "selne $src, #1, $src, $dst\t# @convP2B" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ __ selne(src, 1, src, dst); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++//lsp if p= max_int(0x7fffffff),jump to Skip Label ++ ++ //Lable Convert ++ __ BIND(Convert); ++ __ fcvtsd(src, temp_float_reg); ++ __ fcvtdl_z(temp_float_reg, temp_float_reg1); ++ __ fcvtlw(temp_float_reg1, temp_float_reg); ++ __ fimovs(temp_float_reg, dst); ++ __ addw(dst, 0, dst); ++ __ beq_l(R0, Done); ++ ++ //Lable Skip ++ __ BIND(Overflow) ++ __ addw(rscratch3, 0, dst); ++ __ BIND(Done); ++ } ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct convF2I_reg_slow( rRegI dst, regF src ) %{ ++ match(Set dst (ConvF2I src)); ++ ins_cost(250); ++ format %{ "convf2i $dst, $src @ convF2I_reg_slow" %} ++ ins_encode %{ ++ Register dreg = $dst$$Register; ++ FloatRegister fval = $src$$FloatRegister; ++ ++ __ pushad(rscratch3); ++ __ mov_s(F16, fval); ++ __ call(RuntimeAddress((CAST_FROM_FN_PTR(address, SharedRuntime::f2i)))); ++ __ movl(rscratch3, V0); ++ __ popad(rscratch3); ++ __ movl(dreg, rscratch3); ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++instruct convF2L_reg_fast( rRegL dst, regF src ) %{ ++ match(Set dst (ConvF2L src)); ++ ins_cost(150); ++ format %{ "convf2l $dst, $src @ convF2L_reg_fast" %} ++ ins_encode %{ ++ if(UseSW8A) { ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ __ cmovdl_z(dst, src); ++ }else { ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = $src$$FloatRegister; ++ Label Convert,Overflow,Done; ++ FloatRegister temp_float_reg = f30; ++ FloatRegister temp_float_reg1 = f28; ++ ++ __ fcmpun(src, src, temp_float_reg); ++ __ ffbne(temp_float_reg, Convert); ++ ++ __ bis (R0, 1, rscratch3); ++ __ slll(rscratch3, 63, rscratch3); ++ ++ __ ifmovd(rscratch3, temp_float_reg); ++ __ fcvtls(temp_float_reg, temp_float_reg1); ++ __ fcmple(src, temp_float_reg1, temp_float_reg); ++ __ ffbne(temp_float_reg, Overflow); //if less than min_long(0x8000000000000000),jump to Skip Lable ++ ++ __ subl(rscratch3, 1, rscratch3); ++ __ ifmovd(rscratch3, temp_float_reg); ++ __ fcvtls(temp_float_reg, temp_float_reg1); ++ __ fcmple(temp_float_reg1,src, temp_float_reg); ++ __ ffbne(temp_float_reg, Overflow); // if >=max_long(0x7fffffffffffffff),jump to Skip Lable ++ ++ //Lable Convert ++ __ BIND(Convert); ++ __ fcvtsd(src, temp_float_reg); ++ __ fcvtdl_z(temp_float_reg, temp_float_reg1); ++ __ fimovd(temp_float_reg1, dst); ++ __ beq_l(R0, Done); ++ ++ //Lable Skip ++ __ BIND(Overflow); ++ __ move(dst, rscratch3); ++ __ BIND(Done); ++ } ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++instruct convF2L_reg_slow( rRegL dst, regF src ) %{ ++ match(Set dst (ConvF2L src)); ++ ins_cost(250); ++ format %{ "convf2l $dst, $src @ convF2L_reg_slow" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ FloatRegister fval = $src$$FloatRegister; ++ //TODO:jzy check usage ++ __ pushad(rscratch3); ++ __ mov_s(F16, fval); ++// __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2l), 1); ++ __ call(RuntimeAddress((CAST_FROM_FN_PTR(address, SharedRuntime::f2l)))); ++ __ movl(rscratch3, V0); ++ __ popad(rscratch3); ++ __ movl(dst, rscratch3); ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct convD2L_reg_fast( rRegL dst, regD src ) %{ ++ match(Set dst (ConvD2L src)); ++ ins_cost(150); ++ format %{ "convD2L $dst, $src @ convD2L_reg_fast" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ FloatRegister temp_float_reg = f30; ++ FloatRegister temp_float_reg1 = f28; ++ assert((temp_float_reg1 != $src$$FloatRegister), "can not use F28"); ++ assert((temp_float_reg1 != $dst$$FloatRegister), "can not use F28"); ++ ++ Label Convert,Overflow,Done; ++ __ fcmpun (src, src, temp_float_reg); ++ __ ffbne (temp_float_reg, Convert); //If Unorder,Jump to Convert Label ++ ++ __ bis (R0, 1, rscratch3); ++ __ slll (rscratch3, 63, rscratch3); ++ ++ __ ifmovd (rscratch3, temp_float_reg); ++ __ fcvtld (temp_float_reg, temp_float_reg1); ++ __ fcmple (src, temp_float_reg1, temp_float_reg); ++ __ ffbne (temp_float_reg, Overflow); //If less than min_long(0x8000000000000000),jump to Skip Label ++ ++ __ subl (rscratch3, 0x1, rscratch3); ++ __ ifmovd (rscratch3, temp_float_reg); ++ __ fcvtld (temp_float_reg, temp_float_reg1); ++ __ fcmple (temp_float_reg1, src, temp_float_reg); ++ __ ffbne (temp_float_reg, Overflow); //If >= max_long(0x7fffffffffffffff),jump to Skip Label ++ ++ //Label Convert ++ __ BIND(Convert); ++ __ fcvtdl_z (src, temp_float_reg);//lx20121018,result is rounded toward zero ++ __ fimovd(temp_float_reg,dst); ++ __ beq_l (R0, Done); ++ //Labe Skip ++ __ BIND(Overflow); ++ __ move(dst,rscratch3); ++ __ BIND(Done); ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++instruct convD2L_reg_slow( rRegL dst, regD src ) %{ ++ match(Set dst (ConvD2L src)); ++ ins_cost(250); ++ format %{ "convD2L $dst, $src @ convD2L_reg_slow" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ ++ __ pushad(rscratch3); ++ __ mov_d(F16, src); ++// __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2l), 1); ++ __ call(RuntimeAddress((CAST_FROM_FN_PTR(address, SharedRuntime::d2l)))); ++ __ movl(rscratch3, V0); ++ __ popad(rscratch3); ++ __ movl(dst, rscratch3); ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++// Convert a double to an int. If the double is a NAN, stuff a zero in instead. ++instruct convD2I_reg_reg_fast( rRegI dst, regD src ) %{ ++ match(Set dst (ConvD2I src)); ++ ++ ins_cost(150); ++ format %{ "convD2I $dst, $src\t# @ convD2I_reg_reg_fast" %} ++ ++ ins_encode %{ ++ if (UseSW8A) { ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ ++ __ cmovdw_z(dst, src); ++ } else { ++ FloatRegister src = $src$$FloatRegister; ++ Register dst = $dst$$Register; ++ FloatRegister temp_float_reg = f30; ++ FloatRegister temp_float_reg1 = f28; ++ FloatRegister tmp = f27; ++ ++ assert( (temp_float_reg1 != src), "can not use F28"); ++ assert( (temp_float_reg != src), "can not use F28"); ++ Label Convert,Overflow,Done; ++ __ fcmpun (src, src, temp_float_reg); ++ __ ffbne (temp_float_reg, Convert); //If Unorder,Jump to Convert Label ++ ++ __ bis (R0, 1, rscratch3); ++ __ slll (rscratch3, 31, rscratch3); ++ __ ifmovs (rscratch3, temp_float_reg); ++ __ fcvtwl (temp_float_reg, temp_float_reg1); ++ __ fcvtld (temp_float_reg1, temp_float_reg); ++ __ fcmple (src, temp_float_reg, temp_float_reg1); ++ __ ffbne (temp_float_reg1, Overflow); //If less than min_int(0x80000000),jump to Skip Label ++ ++ __ subw (rscratch3, 0x1, rscratch3); ++ __ ifmovs (rscratch3, temp_float_reg); ++ __ fcvtwl (temp_float_reg, temp_float_reg1); ++ __ fcvtld (temp_float_reg1, temp_float_reg); ++ __ fcmple (temp_float_reg, src, temp_float_reg1); ++ __ ffbne (temp_float_reg1, Overflow); //If >= max_int(0x7fffffff),jump to Skip Label ++ ++ //Label Convert ++ __ BIND(Convert); ++ __ fcvtdl_z (src, temp_float_reg);//lx20121018,result is rounded toward zero ++ __ fcvtlw (temp_float_reg, tmp); ++ __ fimovs(tmp,dst); ++ __ addw(dst,0,dst); ++ __ beq_l (R0, Done); ++ //Labe Overflow ++ __ BIND(Overflow); ++ __ addw(rscratch3, 0, dst); ++ __ BIND(Done); ++ } ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++instruct convD2I_reg_reg_slow( rRegI dst, regD src ) %{ ++ match(Set dst (ConvD2I src)); ++ ++ ins_cost(250); ++ format %{ "convD2I $dst, $src\t# @ convD2I_reg_reg_slow" %} ++ ++ ins_encode %{ ++ FloatRegister src = $src$$FloatRegister; ++ Register dst = $dst$$Register; ++ ++ __ pushad(rscratch3); ++ __ mov_d(F16, src); ++// __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2i), 1); ++ __ call(RuntimeAddress((CAST_FROM_FN_PTR(address, SharedRuntime::d2i)))); ++ __ movl(rscratch3, V0); ++ __ popad(rscratch3); ++ __ movl(dst, rscratch3); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct convI2F_reg_reg( regF dst, rRegI src ) %{ ++ match(Set dst (ConvI2F src)); ++ format %{ "convi2f $dst, $src @ convI2F_reg" %} ++ ins_encode %{ ++ Register src = $src$$Register; ++ FloatRegister dst = $dst$$FloatRegister; ++ if (UseSW8A) { ++ __ cmovws(dst, src); ++ } else { ++ __ ifmovs(src, f30); ++ __ fcvtwl(f30, f28); ++ __ fcvtls(f28, dst); ++ } ++ %} ++ ++ ins_pipe( fpu_regF_regF ); ++%} ++/* memory operands no need for SW64 ++instruct convI2F_reg_mem(regF dst, memory src) ++%{ ++ match(Set dst (ConvI2F (LoadI src))); ++ ++ format %{ "ldw rscratch1_GP, $src\t# i2f@convI2F_reg_mem\n\t" ++ "convi2f $dst, rscratch1_GP " %} ++ ins_encode %{ ++ FloatRegister dst = $dst$$FloatRegister; ++ __ ldw(rscratch1_GP, $src$$Address); ++ __ ifmovs(rscratch1_GP, f30); ++ __ fcvtwl(f30, f28); ++ __ fcvtls(f28, dst); ++// __ cvtsi2ssl ($dst$$XMMRegister, $src$$Address); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++*/ ++ ++instruct convI2D_reg_reg(regD dst, rRegI src) %{ ++ match(Set dst (ConvI2D src)); ++ format %{ "conI2D $dst, $src @convI2D_reg" %} ++ ins_encode %{ ++ Register src = $src$$Register; ++ FloatRegister dst = $dst$$FloatRegister; ++ if (UseSW8A){ ++ __ cmovwd(dst, src); ++ } else { ++ __ ifmovd(src, f30); ++ __ fcvtld(f30, dst); ++ } ++ %} ++ ins_pipe( fpu_regF_regF ); ++%} ++ ++/* memory operands no need for SW64 ++instruct convI2D_reg_mem(regD dst, memory src) ++%{ ++ match(Set dst (ConvI2D (LoadI src))); ++ format %{ "ldw rscratch1_GP, $src\t# i2d@convI2D_reg_mem\n\t" ++ "conI2D $dst, rscratch1_GP " %} ++ ins_encode %{ ++ Register src = $src$$Register; ++ FloatRegister dst = $dst$$FloatRegister; ++ __ ldw(rscratch1_GP, $src$$Address); ++ __ ifmovd(rscratch1_GP, f30); ++ __ fcvtld(f30, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%}*/ ++/* ++instruct convXI2F_reg(regF dst, rRegI src) ++%{ ++ predicate(UseXmmI2F); ++ match(Set dst (ConvI2F src)); ++ ++ format %{ "movdl $dst, $src\n\t" ++ "cvtdq2psl $dst, $dst\t# i2f" %} ++ ins_encode %{ ++ __ movdl($dst$$XMMRegister, $src$$Register); ++ __ cvtdq2ps($dst$$XMMRegister, $dst$$XMMRegister); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++instruct convXI2D_reg(regD dst, rRegI src) ++%{ ++ predicate(UseXmmI2D); ++ match(Set dst (ConvI2D src)); ++ ++ format %{ "movdl $dst, $src\n\t" ++ "cvtdq2pdl $dst, $dst\t# i2d" %} ++ ins_encode %{ ++ __ movdl($dst$$XMMRegister, $src$$Register); ++ __ cvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++*/ ++instruct convL2F_reg_reg(regF dst, rRegL src) ++%{ ++ match(Set dst (ConvL2F src)); ++ format %{ "convl2f $dst, $src @ convL2F_reg" %} ++ ins_encode %{ ++ FloatRegister dst = $dst$$FloatRegister; ++ Register src = as_Register($src$$reg); ++ if (UseSW8A){ ++ __ cmovls(dst, src); ++ } else { ++ __ ifmovd(src, f30); ++ __ fcvtls(f30, dst); ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++/* memory operands no need for SW64 ++instruct convL2F_reg_mem(regF dst, memory src) ++%{ ++ match(Set dst (ConvL2F (LoadL src))); ++ format %{ "ldl rscratch1_GP, $src\t# l2f@convL2F_reg_mem\n\t" ++ "conI2D $dst, rscratch1_GP " %} ++ ins_encode %{ ++ FloatRegister dst = $dst$$FloatRegister; ++ Register src = as_Register($src$$reg); ++ __ ldl(rscratch1_GP, $src$$Address); ++ __ ifmovd(rscratch1_GP, f30); ++ __ fcvtls(f30, dst); ++// __ cvtsi2ssq ($dst$$XMMRegister, $src$$Address); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ */ ++ ++instruct convL2D_reg_reg(regD dst, rRegL src) ++%{ ++ match(Set dst (ConvL2D src)); ++ ++ format %{ "convL2D $dst, $src @ convL2D_reg" %} ++ ins_encode %{ ++ Register src = as_Register($src$$reg); ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ if (UseSW8A) { ++ __ cmovld(dst, src); ++ } else { ++ __ ifmovd(src, f30); ++ __ fcvtld(f30, dst); ++ } ++ %} ++ ins_pipe(pipe_slow); // XXX ++%} ++ ++/* memory operands no need for SW64 ++instruct convL2D_reg_mem(regD dst, memory src) ++%{ ++ match(Set dst (ConvL2D (LoadL src))); ++ ++ format %{ "convL2D $dst, $src @ convL2D_reg" %} ++ ins_encode %{ ++ Register src = as_Register($src$$reg); ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ __ ldl(rscratch1_GP, $src$$Address); ++ __ ifmovd(rscratch1_GP, f30); ++ __ fcvtld(f30, dst); ++ %} ++ ins_pipe(pipe_slow); // XXX ++%}*/ ++ ++instruct convI2L_reg_reg( rRegL dst, rRegI src) %{ ++ match(Set dst (ConvI2L src)); ++ ++ ins_cost(100); ++ format %{ "movws $dst, $src @ convI2L_reg\t" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ ++ if(dst != src) __ movws(dst, src); ++ %} ++ ins_pipe( ialu_regL_regL ); ++%} ++ ++ ++// instruct convI2L_reg_reg_foo(rRegL dst, rRegI src) ++// %{ ++// match(Set dst (ConvI2L src)); ++// // predicate(_kids[0]->_leaf->as_Type()->type()->is_int()->_lo >= 0 && ++// // _kids[0]->_leaf->as_Type()->type()->is_int()->_hi >= 0); ++// predicate(((const TypeNode*) n)->type()->is_long()->_hi == ++// (unsigned int) ((const TypeNode*) n)->type()->is_long()->_hi && ++// ((const TypeNode*) n)->type()->is_long()->_lo == ++// (unsigned int) ((const TypeNode*) n)->type()->is_long()->_lo); ++ ++// format %{ "movl $dst, $src\t# unsigned i2l" %} ++// ins_encode(enc_copy(dst, src)); ++// // opcode(0x63); // needs REX.W ++// // ins_encode(REX_reg_reg_wide(dst, src), OpcP, reg_reg(dst,src)); ++// ins_pipe(ialu_reg_reg); ++// %} ++ ++ ++// Zero-extend convert int to long ++instruct convI2L_reg_reg_zex(rRegL dst, rRegI src, immL_32bits mask) ++%{ ++ match(Set dst (AndL (ConvI2L src) mask)); ++ ++ format %{ "movwu $dst, $src \t# i2l zero-extend @convI2L_reg_reg_zex" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ __ movwu(dst, src); ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++/* memory operands no need for SW64 ++// Zero-extend convert int to long ++instruct convI2L_reg_mem_zex(rRegL dst, memory src, immL_32bits mask) ++%{ ++ match(Set dst (AndL (ConvI2L (LoadI src)) mask)); ++ ++ format %{ "ldwu $dst, $src\t# i2l zero-extend @convI2L_reg_mem_zex" %} ++ ins_encode %{ ++ __ ldwu($dst$$Register, $src$$Address); ++ %} ++ ins_pipe(pipe_slow); ++%} ++*/ ++ ++instruct zerox_long_reg_reg(rRegL dst, rRegL src, immL_32bits mask) ++%{ ++ match(Set dst (AndL src mask)); ++ format %{ "zapnot $src, 0xf, $dst\t# i2l zero-extend @zerox_long_reg_reg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ __ zapnot(src, 0xf, dst); ++ ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct convL2I2L_reg_reg_zex(rRegL dst, rRegL src, immL_32bits mask) ++%{ ++ match(Set dst (AndL (ConvI2L (ConvL2I src)) mask)); ++ ++ format %{ "zapnot $dst, $src\t# L2I2L zero-extend @ convL2I2L_reg_reg_zex" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ zapnot(src, 0xf, dst); ++ ++ %} ++ ins_pipe(ialu_regI_regI); ++%} ++ ++instruct convL2I2L_reg_reg( rRegL dst, rRegL src ) %{ ++ match(Set dst (ConvI2L (ConvL2I src))); ++ ++ format %{ "addw $dst, $src, 0 @ convL2I2L_reg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ ++ __ addw(src, 0, dst); ++ %} ++ ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++instruct convL2I_reg_reg( rRegI dst, rRegL src ) %{ ++ match(Set dst (ConvL2I src)); ++ ++ format %{ "addw $src, 0, $dst@ convL2I_reg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ Register src = as_Register($src$$reg); ++ ++ __ addw(src, 0, dst); ++ %} ++ ++ ins_pipe( ialu_regI_regI ); ++%} ++ ++ ++instruct MoveF2I_stack_reg(rRegI dst, stackSlotF src) %{ ++ match(Set dst (MoveF2I src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(125); ++ format %{ "ldw $dst, $src\t# @MoveF2I_stack_reg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ __ ldw(dst, Address(esp, $src$$disp));//LSP CHECK sign extend? ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ ++ match(Set dst (MoveI2F src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(125); ++ format %{ "store_float $dst, $src\t# @MoveI2F_stack_reg " %} ++ ins_encode %{ ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ __ store_float(dst, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct MoveD2L_stack_reg(rRegL dst, stackSlotD src) %{ ++ match(Set dst (MoveD2L src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(125); ++ format %{ "movq $dst, $src\t# MoveD2L_stack_reg" %} ++ ins_encode %{ ++ __ ldl($dst$$Register, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct MoveL2D_stack_reg_partial(regD dst, stackSlotL src) %{ ++// predicate(!UseXmmLoadAndClearUpper); ++ match(Set dst (MoveL2D src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(125); ++ format %{ "store_double $dst, $src\t# @MoveI2F_stack_reg"%} ++ ins_encode %{ ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ __ store_double(dst, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++/* ++instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ ++ predicate(UseXmmLoadAndClearUpper); ++ match(Set dst (MoveL2D src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(125); ++ format %{ "movsd $dst, $src\t# MoveL2D_stack_reg" %} ++ ins_encode %{ ++ __ movdbl($dst$$XMMRegister, Address(esp, $src$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++*/ ++ ++instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ ++ match(Set dst (MoveF2I src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(95); // XXX ++ format %{ "store_float $dst, $src\t# MoveF2I_reg_stack" %} ++ ins_encode %{ ++ FloatRegister src = as_FloatRegister($src$$reg); ++ __ store_float(src, Address(esp, $dst$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct MoveI2F_reg_stack(stackSlotF dst, rRegI src) %{ ++ match(Set dst (MoveI2F src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(100); ++ format %{ "stw $src, $dst\t# @MoveI2F_reg_stack" %} ++ ins_encode %{ ++ __ stw( $src$$Register, Address(esp, $dst$$disp)); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ ++ match(Set dst (MoveD2L src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(95); // XXX ++ format %{ "store_double $src, $dst\t# @MoveL2D_reg_stack" %} ++ ins_encode %{ ++ FloatRegister src = as_FloatRegister($src$$reg); ++ __ store_double(src, Address(esp, $dst$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct MoveL2D_reg_stack(stackSlotD dst, rRegL src) %{ ++ match(Set dst (MoveL2D src)); ++ effect(DEF dst, USE src); ++ ++ ins_cost(100); ++ format %{ "stl $src, $dst\t# @MoveL2D_reg_stack" %} ++ ins_encode %{ ++ __ stl($src$$Register, Address(esp, $dst$$disp)); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct MoveF2I_reg_reg(rRegI dst, regF src) %{ ++ match(Set dst (MoveF2I src)); ++ effect(DEF dst, USE src); ++ ins_cost(85); ++ format %{ "MoveF2I $dst, $src @ MoveF2I_reg_reg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ ++ __ fimovs(src, dst); ++ __ addw(dst, 0, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++instruct MoveD2L_reg_reg(rRegL dst, regD src) %{ ++ match(Set dst (MoveD2L src)); ++ effect(DEF dst, USE src); ++ ins_cost(85); ++ format %{ "MoveD2L $dst, $src @ MoveD2L_reg_reg" %} ++ ins_encode %{ ++ Register dst = as_Register($dst$$reg); ++ FloatRegister src = as_FloatRegister($src$$reg); ++ ++ __ fimovd(src, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++ instruct MoveI2F_reg_reg(regF dst, rRegI src) %{ ++ match(Set dst (MoveI2F src)); ++ effect(DEF dst, USE src); ++ ins_cost(85); ++ format %{ "MoveI2F $dst, $src @ MoveI2F_reg_reg" %} ++ ins_encode %{ ++ Register src = as_Register($src$$reg); ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ ++ __ ifmovs(src, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct MoveL2D_reg_reg(regD dst, rRegL src) %{ ++ match(Set dst (MoveL2D src)); ++ effect(DEF dst, USE src); ++ ins_cost(85); ++ format %{ "MoveL2D $dst, $src @ MoveL2D_reg_reg" %} ++ ins_encode %{ ++ FloatRegister dst = as_FloatRegister($dst$$reg); ++ Register src = as_Register($src$$reg); ++ ++ __ ifmovd(src, dst); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++ ++// ======================================================================= ++// fast clearing of an array ++instruct clear_array(rRegL cnt, rRegP base, Universe dummy) %{ ++ match(Set dummy (ClearArray cnt base)); ++ format %{ "CLEAR_ARRAY base = $base, cnt = $cnt # Clear doublewords" %} ++ ins_encode %{ ++ //Assume cnt is the number of bytes in an array to be cleared, ++ //and base points to the starting address of the array. ++ Register base = $base$$Register; ++ Register num = $cnt$$Register; ++ Label Loop, done; ++ ++ __ move(rscratch3, num); /* rscratch3 = words */ ++ __ beq_l(rscratch3, done); ++ __ move(rscratch2_AT, base); ++ ++ __ BIND(Loop); ++ __ stl(R0, Address(rscratch2_AT, 0)); ++ __ addl(rscratch2_AT, wordSize, rscratch2_AT); ++ __ subl(rscratch3, 1, rscratch3); ++ __ bne_l(rscratch3, Loop); ++ __ BIND(done); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++/*TODO:need implement jzy ++instruct string_compareU(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, t8_RegP tmp1, t9_RegL tmp2, rFlagsReg cr) ++%{ ++ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); ++ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); ++ ++ format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} ++ ins_encode %{ ++ // Count is in 8-bit bytes; non-Compact chars are 16 bits. ++ __ string_compare($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, $result$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ fnoreg, fnoreg, fnoreg, StrIntrinsicNode::UU); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_compareL(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, t8_RegP tmp1, t9_RegL tmp2, rFlagsReg cr) ++%{ ++ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); ++ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); ++ ++ format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} ++ ins_encode %{ ++ __ string_compare($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, $result$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ fnoreg, fnoreg, fnoreg, StrIntrinsicNode::LL); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_compareUL(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, t8_RegP tmp1, t9_RegL tmp2, ++ f28_RegD vtmp1, f29_RegD vtmp2, f30_RegD vtmp3, rFlagsReg cr) ++%{ ++ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); ++ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3, ++ USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); ++ ++ format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $vtmp1, $vtmp2, $vtmp3" %} ++ ins_encode %{ ++ __ string_compare($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, $result$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, ++ $vtmp3$$FloatRegister, StrIntrinsicNode::UL); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_compareLU(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, t8_RegP tmp1, t9_RegL tmp2, ++ f28_RegD vtmp1, f29_RegD vtmp2, f30_RegD vtmp3, rFlagsReg cr) ++%{ ++ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); ++ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3, ++ USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); ++ ++ format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $vtmp1, $vtmp2, $vtmp3" %} ++ ins_encode %{ ++ __ string_compare($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, $result$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, ++ $vtmp3$$FloatRegister,StrIntrinsicNode::LU); ++ %} ++ ins_pipe(pipe_slow); ++%}*/ ++/*TODO:need implement jzy ++instruct string_indexofUU(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, rRegI tmp1, rRegI tmp2, rRegI tmp3, ++ rRegI tmp4, rRegI tmp5, rRegI tmp6, rFlagsReg cr) ++%{ ++ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); ++ match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, KILL cr); ++ format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UU)" %} ++ ++ ins_encode %{ ++ __ string_indexof($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register, $tmp4$$Register, ++ $tmp5$$Register, $tmp6$$Register, ++ -1, $result$$Register, StrIntrinsicNode::UU); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_indexofLL(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, rRegI tmp1, rRegI tmp2, rRegI tmp3, ++ rRegI tmp4, rRegI tmp5, rRegI tmp6, rFlagsReg cr) ++%{ ++ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); ++ match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, KILL cr); ++ format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (LL)" %} ++ ++ ins_encode %{ ++ __ string_indexof($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register, $tmp4$$Register, ++ $tmp5$$Register, $tmp6$$Register, ++ -1, $result$$Register, StrIntrinsicNode::LL); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_indexofUL(a1_RegP str1, a2_RegI cnt1, a3_RegP str2, a4_RegI cnt2, ++ a0_RegI result, rRegI tmp1, rRegI tmp2, rRegI tmp3, ++ rRegI tmp4, rRegI tmp5, rRegI tmp6, rFlagsReg cr) ++%{ ++ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); ++ match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, KILL cr); ++ format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UL)" %} ++ ++ ins_encode %{ ++ __ string_indexof($str1$$Register, $str2$$Register, ++ $cnt1$$Register, $cnt2$$Register, ++ $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register, $tmp4$$Register, ++ $tmp5$$Register, $tmp6$$Register, ++ -1, $result$$Register, StrIntrinsicNode::UL); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_indexof_conUU(a1_RegP str1, a4_RegI cnt1, a3_RegP str2, ++ immI_le_4 int_cnt2, a0_RegI result, rRegI tmp1, rRegI tmp2, rRegI tmp3, ++ rRegI tmp4, rFlagsReg cr) ++%{ ++ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); ++ match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); ++ format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UU)" %} ++ ++ ins_encode %{ ++ int icnt2 = (int)$int_cnt2$$constant; ++ __ string_indexof($str1$$Register, $str2$$Register, ++ $cnt1$$Register, zr, ++ $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register, $tmp4$$Register, zr, zr, ++ icnt2, $result$$Register, StrIntrinsicNode::UU); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_indexof_conLL(a1_RegP str1, a4_RegI cnt1, a3_RegP str2, ++ immI_le_4 int_cnt2, a0_RegI result, rRegI tmp1, rRegI tmp2, rRegI tmp3, ++ rRegI tmp4, rFlagsReg cr) ++%{ ++ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); ++ match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); ++ format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (LL)" %} ++ ++ ins_encode %{ ++ int icnt2 = (int)$int_cnt2$$constant; ++ __ string_indexof($str1$$Register, $str2$$Register, ++ $cnt1$$Register, zr, ++ $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register, $tmp4$$Register, zr, zr, ++ icnt2, $result$$Register, StrIntrinsicNode::LL); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_indexof_conUL(a1_RegP str1, a4_RegI cnt1, a3_RegP str2, ++ immI_le_4 int_cnt2, a0_RegI result, rRegI tmp1, rRegI tmp2, rRegI tmp3, ++ rRegI tmp4, rFlagsReg cr) ++%{ ++ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); ++ match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); ++ format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UL)" %} ++ ++ ins_encode %{ ++ int icnt2 = (int)$int_cnt2$$constant; ++ __ string_indexof($str1$$Register, $str2$$Register, ++ $cnt1$$Register, zr, ++ $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register, $tmp4$$Register, zr, zr, ++ icnt2, $result$$Register, StrIntrinsicNode::UL); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_indexofU_char(a1_RegP str1, a2_RegI cnt1, a3_RegI ch, ++ a0_RegI result, rRegI tmp1, rRegI tmp2, ++ rRegI tmp3, rFlagsReg cr) ++%{ ++ match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); ++ effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch, ++ TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ++ ++ format %{ "String IndexOf char[] $str1,$cnt1,$ch -> $result" %} ++ ++ ins_encode %{ ++ __ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, ++ $result$$Register, $tmp1$$Register, $tmp2$$Register, ++ $tmp3$$Register); ++ %} ++ ins_pipe(pipe_slow); ++%}*/ ++//TODO:need implement jzy ++/* ++instruct string_equalsL(a1_RegP str1, a3_RegP str2, a4_RegI cnt, ++ a0_RegI result, rFlagsReg cr) ++%{ ++ 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 cr); ++ ++ format %{ "String Equals $str1,$str2,$cnt -> $result" %} ++ ins_encode %{ ++ // Count is in 8-bit bytes; non-Compact chars are 16 bits. ++ __ string_equals($str1$$Register, $str2$$Register, ++ $result$$Register, $cnt$$Register, 1); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct string_equalsU(a1_RegP str1, a3_RegP str2, a4_RegI cnt, ++ a0_RegI result, rFlagsReg cr) ++%{ ++ predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); ++ match(Set result (StrEquals (Binary str1 str2) cnt)); ++ effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); ++ ++ format %{ "String Equals $str1,$str2,$cnt -> $result" %} ++ ins_encode %{ ++ // Count is in 8-bit bytes; non-Compact chars are 16 bits. ++ __ string_equals($str1$$Register, $str2$$Register, ++ $result$$Register, $cnt$$Register, 2); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct array_equalsB(a1_RegP ary1, a2_RegP ary2, a0_RegI result, ++ a3_RegP tmp1, a4_RegP tmp2, a5_RegP tmp3, ++ t10_RegP tmp, rFlagsReg cr) ++%{ ++ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); ++ match(Set result (AryEq ary1 ary2)); ++ effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ++ ++ format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ++ ins_encode %{ ++ __ arrays_equals($ary1$$Register, $ary2$$Register, ++ $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, ++ $result$$Register, $tmp$$Register, 1); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++instruct array_equalsC(a1_RegP ary1, a2_RegP ary2, a0_RegI result, ++ a3_RegP tmp1, a4_RegP tmp2, a5_RegP tmp3, ++ t10_RegP tmp, rFlagsReg cr) ++%{ ++ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); ++ match(Set result (AryEq ary1 ary2)); ++ effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ++ ++ format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ++ ins_encode %{ ++ __ arrays_equals($ary1$$Register, $ary2$$Register, ++ $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, ++ $result$$Register, $tmp$$Register, 2); ++ %} ++ ins_pipe(pipe_slow); ++%} ++*/ ++instruct has_negatives(a1_RegP ary1, a2_RegI len, v0_RegI result, rFlagsReg cr) ++%{ ++ match(Set result (HasNegatives ary1 len)); ++ effect(USE_KILL ary1, USE_KILL len, KILL cr); ++ format %{ "has negatives byte[] $ary1,$len -> $result" %} ++ ins_encode %{ ++ __ has_negatives($ary1$$Register, $len$$Register, $result$$Register); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++// fast char[] to byte[] compression TODO:jzy ++/*instruct string_compress(a2_RegP src, a1_RegP dst, a3_RegI len, ++ f27_RegD tmp1, f28_RegD tmp2, f29_RegD tmp3, f30_RegD tmp4, ++ a0_RegI result, rFlagsReg cr) ++%{ ++ match(Set result (StrCompressedCopy src (Binary dst len))); ++ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); ++ ++ format %{ "String Compress $src,$dst -> $result // KILL R1, R2, R3, R4" %} ++ ins_encode %{ ++ __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, ++ $tmp1$$FloatRegister, $tmp2$$FloatRegister, ++ $tmp3$$FloatRegister, $tmp4$$FloatRegister, ++ $result$$Register); ++ %} ++ ins_pipe( pipe_slow ); ++%}*/ ++ ++// fast byte[] to char[] inflation TODO:should implement jzy ++/*instruct string_inflate(Universe dummy, a0_RegP src, a1_RegP dst, a2_RegI len, ++ f27_RegD tmp1, f28_RegD tmp2, f29_RegD tmp3, f30_RegD tmp4, rFlagsReg cr) ++%{ ++ match(Set dummy (StrInflatedCopy src (Binary dst len))); ++ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); ++ ++ format %{ "String Inflate $src,$dst // KILL $tmp1, $tmp2" %} ++ ins_encode %{ ++ __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, ++ $tmp1$$FloatRegister, $tmp2$$FloatRegister, $tmp3$$FloatRegister, $tmp4$$Register); ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// encode char[] to byte[] in ISO_8859_1 ++instruct encode_iso_array(a2_RegP src, a1_RegP dst, a3_RegI len, ++ f27_RegD Vtmp1, f28_RegD Vtmp2, f29_RegD Vtmp3, f30_RegD Vtmp4, ++ a0_RegI result, rFlagsReg cr) ++%{ ++ match(Set result (EncodeISOArray src (Binary dst len))); ++ effect(USE_KILL src, USE_KILL dst, USE_KILL len, ++ KILL Vtmp1, KILL Vtmp2, KILL Vtmp3, KILL Vtmp4, KILL cr); ++ ++ format %{ "Encode array $src,$dst,$len -> $result" %} ++ ins_encode %{ ++ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, ++ $result$$Register, $Vtmp1$$FloatRegister, $Vtmp2$$FloatRegister, ++ $Vtmp3$$FloatRegister, $Vtmp4$$FloatRegister); ++ %} ++ ins_pipe( pipe_slow ); ++%}*/ ++ ++/* ++ ++//----------Overflow Math Instructions----------------------------------------- ++ ++instruct overflowAddI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2) ++%{ ++ match(Set cr (OverflowAddI op1 op2)); ++ effect(DEF cr, USE_KILL op1, USE op2); ++ ++ format %{ "addl $op1, $op2\t# overflow check int" %} ++ ++ ins_encode %{ ++ __ addl($op1$$Register, $op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowAddI_rReg_imm(rFlagsReg cr, rax_RegI op1, immI op2) ++%{ ++ match(Set cr (OverflowAddI op1 op2)); ++ effect(DEF cr, USE_KILL op1, USE op2); ++ ++ format %{ "addl $op1, $op2\t# overflow check int" %} ++ ++ ins_encode %{ ++ __ addl($op1$$Register, $op2$$constant); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowAddL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2) ++%{ ++ match(Set cr (OverflowAddL op1 op2)); ++ effect(DEF cr, USE_KILL op1, USE op2); ++ ++ format %{ "addq $op1, $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ addq($op1$$Register, $op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowAddL_rReg_imm(rFlagsReg cr, rax_RegL op1, immL32 op2) ++%{ ++ match(Set cr (OverflowAddL op1 op2)); ++ effect(DEF cr, USE_KILL op1, USE op2); ++ ++ format %{ "addq $op1, $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ addq($op1$$Register, $op2$$constant); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowSubI_rReg(rFlagsReg cr, rRegI op1, rRegI op2) ++%{ ++ match(Set cr (OverflowSubI op1 op2)); ++ ++ format %{ "cmpl $op1, $op2\t# overflow check int" %} ++ ins_encode %{ ++ __ cmpl($op1$$Register, $op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowSubI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2) ++%{ ++ match(Set cr (OverflowSubI op1 op2)); ++ ++ format %{ "cmpl $op1, $op2\t# overflow check int" %} ++ ins_encode %{ ++ __ cmpl($op1$$Register, $op2$$constant); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowSubL_rReg(rFlagsReg cr, rRegL op1, rRegL op2) ++%{ ++ match(Set cr (OverflowSubL op1 op2)); ++ ++ format %{ "cmpq $op1, $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ cmpq($op1$$Register, $op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowSubL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2) ++%{ ++ match(Set cr (OverflowSubL op1 op2)); ++ ++ format %{ "cmpq $op1, $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ cmpq($op1$$Register, $op2$$constant); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowNegI_rReg(rFlagsReg cr, immI0 zero, rax_RegI op2) ++%{ ++ match(Set cr (OverflowSubI zero op2)); ++ effect(DEF cr, USE_KILL op2); ++ ++ format %{ "negl $op2\t# overflow check int" %} ++ ins_encode %{ ++ __ negl($op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowNegL_rReg(rFlagsReg cr, immL0 zero, rax_RegL op2) ++%{ ++ match(Set cr (OverflowSubL zero op2)); ++ effect(DEF cr, USE_KILL op2); ++ ++ format %{ "negq $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ negq($op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg); ++%} ++ ++instruct overflowMulI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2) ++%{ ++ match(Set cr (OverflowMulI op1 op2)); ++ effect(DEF cr, USE_KILL op1, USE op2); ++ ++ format %{ "imull $op1, $op2\t# overflow check int" %} ++ ins_encode %{ ++ __ imull($op1$$Register, $op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg_alu0); ++%} ++ ++instruct overflowMulI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2, rRegI tmp) ++%{ ++ match(Set cr (OverflowMulI op1 op2)); ++ effect(DEF cr, TEMP tmp, USE op1, USE op2); ++ ++ format %{ "imull $tmp, $op1, $op2\t# overflow check int" %} ++ ins_encode %{ ++ __ imull($tmp$$Register, $op1$$Register, $op2$$constant); ++ %} ++ ins_pipe(ialu_reg_reg_alu0); ++%} ++ ++instruct overflowMulL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2) ++%{ ++ match(Set cr (OverflowMulL op1 op2)); ++ effect(DEF cr, USE_KILL op1, USE op2); ++ ++ format %{ "imulq $op1, $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ imulq($op1$$Register, $op2$$Register); ++ %} ++ ins_pipe(ialu_reg_reg_alu0); ++%} ++ ++instruct overflowMulL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2, rRegL tmp) ++%{ ++ match(Set cr (OverflowMulL op1 op2)); ++ effect(DEF cr, TEMP tmp, USE op1, USE op2); ++ ++ format %{ "imulq $tmp, $op1, $op2\t# overflow check long" %} ++ ins_encode %{ ++ __ imulq($tmp$$Register, $op1$$Register, $op2$$constant); ++ %} ++ ins_pipe(ialu_reg_reg_alu0); ++%} ++*/ ++ ++/* Cmpxxx useless in SW64 ++//----------Control Flow Instructions------------------------------------------ ++// Signed compare Instructions ++ ++// XXX more variants!! ++instruct compI_rReg(rFlagsReg cr, rRegI op1, rRegI op2) ++%{ ++ match(Set cr (CmpI op1 op2)); ++ effect(DEF cr, USE op1, USE op2); ++ ++ format %{ "cmpw $op1, $op2\t@compI_rReg" %} ++ ++ ins_encode %{ ++ __ cmpw($op1$$Register, $op2$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_reg); ++%} ++ ++instruct compI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2) ++%{ ++ match(Set cr (CmpI op1 op2)); ++ ++ format %{ "cmpw $op1, $op2\t@compI_rReg_imm" %} ++ ++ ins_encode %{ ++ __ mov_immediate32(rscratch3, $op2$$constant); ++ __ cmpw($op1$$Register, rscratch3, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compI_rReg_mem(rFlagsReg cr, rRegI op1, memory op2) ++%{ ++ match(Set cr (CmpI op1 (LoadI op2))); ++ ++ ins_cost(500); // XXX ++ format %{ "cmpw $op1, $op2\t@compI_rReg_mem" %} ++ ++ ins_encode %{ ++ __ ldws(rscratch2_AT, $op2$$Address); ++ __ cmpw($op1$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testI_reg(rFlagsReg cr, rRegI src, immI0 zero) ++%{ ++ match(Set cr (CmpI src zero)); ++ ++ format %{ "testw $src, $src\t@testI_reg" %} ++ ins_encode %{ ++ __ testw($src$$Register, $src$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct testI_reg_imm(rFlagsReg cr, rRegI src, immI con, immI0 zero) ++%{ ++ match(Set cr (CmpI (AndI src con) zero)); ++ ++ format %{ "testl $src, $con\t@testI_reg_imm" %} ++ ins_encode %{ ++ __ testw($src$$Register, $con$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct testI_reg_mem(rFlagsReg cr, rRegI src, memory mem, immI0 zero) ++%{ ++ match(Set cr (CmpI (AndI src (LoadI mem)) zero)); ++ ++ format %{ "testl $src, $mem\t@testI_reg_mem" %} ++ ins_encode %{ ++ __ ldws(rscratch2_AT, $mem$$Address); ++ __ testw($src$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++// Unsigned compare Instructions; really, same as signed except they ++// produce an rFlagsRegU instead of rFlagsReg. ++instruct compU_rReg(rFlagsRegU cr, rRegI op1, rRegI op2) ++%{ ++ match(Set cr (CmpU op1 op2)); ++ ++ format %{ "cmpw $op1, $op2\t# unsigned\t@compU_rReg" %} ++ ins_encode %{ ++ __ cmpw($op1$$Register, $op2$$Register, $cr$$Register); ++ __ stop("need add unsigned instruct: jzy?"); ++ %} ++ //ins_pipe(ialu_cr_reg_reg); ++%} ++ ++instruct compU_rReg_imm(rFlagsRegU cr, rRegI op1, immI op2) ++%{ ++ match(Set cr (CmpU op1 op2)); ++ ++ format %{ "cmpl $op1, $op2\t# unsigned\t@compU_rReg_imm" %} ++ ins_encode %{ ++ __ mov_immediate32(rscratch2_AT, $op2$$constant); ++ __ cmpw($op1$$Register, rscratch2_AT, $cr$$Register); ++ __ stop("need add unsigned instruct: jzy?"); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compU_rReg_mem(rFlagsRegU cr, rRegI op1, memory op2) ++%{ ++ match(Set cr (CmpU op1 (LoadI op2))); ++ ++ ins_cost(500); // XXX ++ format %{ "cmpl $op1, $op2\t# unsigned\t@compU_rReg_mem" %} ++ ins_encode %{ ++ __ ldws(rscratch2_AT, $op2$$Address); ++ __ cmpw($op1$$Register, rscratch2_AT, $cr$$Register); ++ __ stop("need add unsigned instruct: jzy?"); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++// // // Cisc-spilled version of cmpU_rReg ++// //instruct compU_mem_rReg(rFlagsRegU cr, memory op1, rRegI op2) ++// //%{ ++// // match(Set cr (CmpU (LoadI op1) op2)); ++// // ++// // format %{ "CMPu $op1,$op2" %} ++// // ins_cost(500); ++// // opcode(0x39); ++// // ins_encode( OpcP, reg_mem( op1, op2) ); ++// //%} ++ ++instruct testU_reg(rFlagsRegU cr, rRegI src, immI0 zero) ++%{ ++ match(Set cr (CmpU src zero)); ++ ++ format %{ "testw $src, $src\t# unsigned\t@testU_reg" %} ++ ins_encode %{ ++ __ testw($src$$Register, $src$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compP_rReg(rFlagsRegU cr, rRegP op1, rRegP op2) ++%{ ++ match(Set cr (CmpP op1 op2)); ++ ++ format %{ "cmpptr $op1, $op2\t# ptr\t@compP_rReg" %} ++ ins_encode %{ ++ __ cmpptr($op1$$Register, $op2$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_reg); ++%} ++ ++instruct compP_rReg_mem(rFlagsRegU cr, rRegP op1, memory op2) ++%{ ++ match(Set cr (CmpP op1 (LoadP op2))); ++ ++ ins_cost(500); // XXX ++ format %{ "cmpptr $op1, $op2\t# ptr\t@compP_rReg_mem" %} ++ ins_encode %{ ++ __ ldws(rscratch2_AT, $op2$$Address); ++ __ cmpptr($op1$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++// // // Cisc-spilled version of cmpP_rReg ++// //instruct compP_mem_rReg(rFlagsRegU cr, memory op1, rRegP op2) ++// //%{ ++// // match(Set cr (CmpP (LoadP op1) op2)); ++// // ++// // format %{ "CMPu $op1,$op2" %} ++// // ins_cost(500); ++// // opcode(0x39); ++// // ins_encode( OpcP, reg_mem( op1, op2) ); ++// //%} ++ ++// XXX this is generalized by compP_rReg_mem??? ++// Compare raw pointer (used in out-of-heap check). ++// Only works because non-oop pointers must be raw pointers ++// and raw pointers have no anti-dependencies. ++instruct compP_mem_rReg(rFlagsRegU cr, rRegP op1, memory op2) ++%{ ++ predicate(n->in(2)->in(2)->bottom_type()->reloc() == relocInfo::none);//TODO:jzy? ++ match(Set cr (CmpP op1 (LoadP op2))); ++ ++ format %{ "cmpptr $op1, $op2\t# raw ptr\t@compP_mem_rReg" %} ++ ins_encode %{ ++ __ ldws(rscratch2_AT, $op2$$Address); ++ __ cmpptr($op1$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++// This will generate a signed flags result. This should be OK since ++// any compare to a zero should be eq/neq. ++instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero) ++%{ ++ match(Set cr (CmpP src zero)); ++ ++ format %{ "testptr $src, $src\t# ptr\t@testP_reg" %} ++ ins_encode %{ ++ __ testptr($src$$Register, $src$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++// This will generate a signed flags result. This should be OK since ++// any compare to a zero should be eq/neq. ++instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) ++%{ ++ predicate(!UseCompressedOops || (Universe::narrow_oop_base() != NULL)); ++ match(Set cr (CmpP (LoadP op) zero)); ++ ++ ins_cost(500); // XXX ++ format %{ "testq $op, 0xffffffffffffffff\t# ptr\t@testP_mem" %} ++ ins_encode %{ ++ __ ldptr(rscratch2_AT, $op$$Address); ++ __ testptr(rscratch2_AT, 0xFFFFFFFF, $cr$$Register); ++ __ stop("0xFFFFFFFF or 0xffffffffffffffff jzy?"); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) ++%{ ++ predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL) && (Universe::narrow_klass_base() == NULL)); ++ match(Set cr (CmpP (LoadP mem) zero)); ++ ++ format %{ "cmpq R0, $mem\t# ptr (r12_heapbase==0)\t@testP_mem_reg0" %} ++ ins_encode %{ ++ __ ldptr(rscratch2_AT, $mem$$Address); ++ __ cmpptr(rscratch2_AT, 0, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) ++%{ ++ match(Set cr (CmpN op1 op2)); ++ ++ format %{ "cmpw $op1, $op2\t# compressed ptr\t@compN_rReg" %} ++ ins_encode %{ ++ __ cmpw($op1$$Register, $op2$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_reg); ++%} ++ ++instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) ++%{ ++ match(Set cr (CmpN src (LoadN mem))); ++ ++ format %{ "cmpw $src, $mem\t# compressed ptr\t@compN_rReg_mem" %} ++ ins_encode %{ ++ __ ldwu(rscratch2_AT, $mem$$Address); ++ __ cmpw($src$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ ++ match(Set cr (CmpN op1 op2)); ++ ++ format %{ "cmpw $op1, $op2\t# compressed ptr\t@compN_rReg_imm" %} ++ ins_encode %{ ++ __ cmp_narrow_oop($op1$$Register, (jobject)$op2$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) ++%{ ++ match(Set cr (CmpN src (LoadN mem))); ++ ++ format %{ "cmpw $mem, $src\t# compressed ptr\t@compN_mem_imm" %} ++ ins_encode %{ ++ __ cmp_narrow_oop($mem$$Address, (jobject)$src$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct compN_rReg_imm_klass(rFlagsRegU cr, rRegN op1, immNKlass op2) %{ ++ match(Set cr (CmpN op1 op2)); ++ ++ format %{ "cmpw $op1, $op2\t# compressed klass ptr\t@compN_rReg_imm_klass" %} ++ ins_encode %{ ++ __ cmp_narrow_klass($op1$$Register, (Klass*)$op2$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compN_mem_imm_klass(rFlagsRegU cr, memory mem, immNKlass src) ++%{ ++ match(Set cr (CmpN src (LoadNKlass mem))); ++ ++ format %{ "cmpw $mem, $src\t# compressed klass ptr\t@compN_mem_imm_klass" %} ++ ins_encode %{ ++ __ cmp_narrow_klass($mem$$Address, (Klass*)$src$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ ++ match(Set cr (CmpN src zero)); ++ ++ format %{ "testw $src, $src\t# compressed ptr\t@testN_reg" %} ++ ins_encode %{ __ testw($src$$Register, $src$$Register, $cr$$Register); %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) ++%{ ++ predicate(Universe::narrow_oop_base() != NULL); ++ match(Set cr (CmpN (LoadN mem) zero)); ++ ++ ins_cost(500); // XXX ++ format %{ "testw $mem, 0xffffffff\t# compressed ptr\t@testN_mem" %} ++ ins_encode %{ ++ __ ldwu(rscratch2_AT, $mem$$Address); ++ __ cmpw(rscratch2_AT, (int)0xFFFFFFFF, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) ++%{ ++ predicate(Universe::narrow_oop_base() == NULL && (Universe::narrow_klass_base() == NULL)); ++ match(Set cr (CmpN (LoadN mem) zero)); ++ ++ format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)\t@testN_mem_reg0" %} ++ ins_encode %{ ++ __ ldwu(rscratch2_AT, $mem$$Address); ++ __ cmpw(R0, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++// Yanked all unsigned pointer compare operations. ++// Pointer compares are done with CmpP which is already unsigned. ++ ++instruct compL_rReg(rFlagsReg cr, rRegL op1, rRegL op2) ++%{ ++ match(Set cr (CmpL op1 op2)); ++ ++ format %{ "cmpl $op1, $op2\t@compL_rReg" %} ++ ins_encode %{ ++ __ cmpl($op1$$Register, $op2$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_reg); ++%} ++ ++instruct compL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2) ++%{ ++ match(Set cr (CmpL op1 op2)); ++ ++ format %{ "cmpl $op1, $op2\t@compL_rReg_imm" %} ++ ins_encode %{ ++ __ cmpl($op1$$Register, (int)$op2$$constant, $cr$$Register); ++ __ stop("immL32's length is OK? jzy"); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compL_rReg_mem(rFlagsReg cr, rRegL op1, memory op2) ++%{ ++ match(Set cr (CmpL op1 (LoadL op2))); ++ ++ format %{ "cmpl $op1, $op2\t@compL_rReg_mem" %} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $op2$$Address); ++ __ cmpl($op1$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testL_reg(rFlagsReg cr, rRegL src, immL0 zero) ++%{ ++ match(Set cr (CmpL src zero)); ++ ++ format %{ "testl $src, $src\t@testL_reg" %} ++ ins_encode %{ ++ __ testl($src$$Register, $src$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct testL_reg_imm(rFlagsReg cr, rRegL src, immL32 con, immL0 zero) ++%{ ++ match(Set cr (CmpL (AndL src con) zero)); ++ ++ format %{ "testl $src, $con\t# long\t@testL_reg_imm" %} ++ ins_encode %{ ++ __ testl($src$$Register, (int)$con$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct testL_reg_mem(rFlagsReg cr, rRegL src, memory mem, immL0 zero) ++%{ ++ match(Set cr (CmpL (AndL src (LoadL mem)) zero)); ++ ++ format %{ "testl $src, $mem\t@testL_reg_mem" %} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $mem$$Address); ++ __ testl($src$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testL_reg_mem2(rFlagsReg cr, rRegP src, memory mem, immL0 zero) ++%{ ++ match(Set cr (CmpL (AndL (CastP2X src) (LoadL mem)) zero)); ++ ++ format %{ "testl $src, $mem\t@testL_reg_mem2" %} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $mem$$Address); ++ __ testl($src$$Register, rscratch2_AT, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++*/ ++// Manifest a CmpL result in an integer register. ++// (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0) ++instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2) %{ ++ match(Set dst (CmpL3 src1 src2)); ++ ins_cost(1000); ++ format %{ "cmpL3 $dst, $src1, $src2 @ cmpL3_reg_reg" %} ++ ins_encode %{ ++ Register opr1 = $src1$$Register; ++ Register opr2 = $src2$$Register; ++ Register dst = $dst$$Register; ++ ++ Label done; ++ __ subl(opr1, opr2, rscratch3); ++ __ subl(R0, 1, dst); ++ __ blt_l(rscratch3, done); ++ ++ __ selgt(rscratch3, 1, R0, dst); ++ __ BIND(done); ++ ++// __ cmpl(opr1, opr2, rcc); ++// __ ldi(rscratch3, -1, R0); ++// __ sellt(rcc, rscratch3, R0, dst); ++// __ selgt(rcc, 1, dst, dst); ++ ++ ++// Label done; ++// __ cmplt(opr2, opr1, dst); ++// __ jcc(Assembler::neq, done); ++// __ cmpeq(opr1, opr2, rcc); ++// __ ldi(rscratch3, -1); ++// __ seleq(rcc, rscratch3, R0, dst); ++// __ bind(done); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++// ++// less_rsult = -1 ++// greater_result = 1 ++// equal_result = 0 ++// nan_result = -1 ++// ++instruct cmpF3_reg_reg(rRegI dst, regF src1, regF src2, rFlagsReg cr) %{ ++ match(Set dst (CmpF3 src1 src2)); ++ effect(KILL cr); ++ ++ //ins_cost(1000); ++ format %{ "cmpF3 $dst, $src1, $src2 @ cmpF3_reg_reg" %} ++ ins_encode %{ ++ FloatRegister src1 = as_FloatRegister($src1$$reg); ++ FloatRegister src2 = as_FloatRegister($src2$$reg); ++ Register dst = as_Register($dst$$reg); ++ ++ Label Done; ++ ++ __ ldi(dst, -1, R0); ++ __ c_ole_s(src2, src1); ++ __ fbeq(fcc, 4); ++ ++ __ movl(dst, R0); ++ __ c_eq_s(src1, src2); ++ __ fbne(fcc, 1); ++ __ ldi(dst, 1, R0); ++ ++ __ bind(Done); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct cmpD3_reg_reg(rRegI dst, regD src1, regD src2, rFlagsReg cr) %{ ++ match(Set dst (CmpD3 src1 src2)); ++ effect(KILL cr); ++ ++ //ins_cost(1000); ++ format %{ "cmpD3 $dst, $src1, $src2 @ cmpD3_reg_reg" %} ++ ins_encode %{ ++ FloatRegister src1 = as_FloatRegister($src1$$reg); ++ FloatRegister src2 = as_FloatRegister($src2$$reg); ++ Register dst = as_Register($dst$$reg); ++ ++ Label Done; ++ ++ __ ldi(dst, -1, R0); ++ __ c_ole_d(src2, src1); ++ __ fbeq(fcc, 4); ++ ++ __ movl(dst, R0); ++ __ c_eq_d(src1, src2); ++ __ fbne(fcc, 1); ++ __ ldi(dst, 1, R0); ++ ++ __ bind(Done); ++ %} ++ ins_pipe( pipe_slow ); ++%} ++ ++// Unsigned long compare Instructions; really, same as signed long except they ++// produce an rFlagsRegU instead of rFlagsReg. ++/*instruct compUL_rReg(rFlagsRegU cr, rRegL op1, rRegL op2) ++%{ ++ match(Set cr (CmpUL op1 op2)); ++ ++ format %{ "cmpq $op1, $op2\t# unsigned\t@compUL_rReg" %} ++ ins_encode %{ ++ __ cmpUL($op1$$Register, $op2$$Register, $cr$$Register); ++ %} ++ ins_pipe(ialu_regL_regL); ++%}*/ ++ ++/*Cmpxxx useless in SW64 ++instruct compUL_rReg_imm(rFlagsRegU cr, rRegL op1, immL32 op2) ++%{ ++ match(Set cr (CmpUL op1 op2)); ++ ++ format %{ "cmpl $op1, $op2\t# unsigned\t@compUL_rReg_imm" %} ++ ins_encode %{ ++ __ mov_immediate32(rscratch2_AT, (int)$op2$$constant); ++ __ cmpl($op1$$Register, rscratch2_AT, $cr$$Register); ++ __ stop("need unsigned edition of cmpw/cmpl? jzy"); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compUL_rReg_mem(rFlagsRegU cr, rRegL op1, memory op2) ++%{ ++ match(Set cr (CmpUL op1 (LoadL op2))); ++ ++ format %{ "cmpq $op1, $op2\t# unsigned\t@compUL_rReg_mem" %} ++ ins_encode %{ ++ __ ldl(rscratch2_AT, $op2$$Address); ++ __ cmpl($op1$$Register, rscratch2_AT, $cr$$Register); ++ __ stop("need unsigned edition of cmpw/cmpl? jzy"); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testUL_reg(rFlagsRegU cr, rRegL src, immL0 zero) ++%{ ++ match(Set cr (CmpUL src zero)); ++ ++ format %{ "testq $src, $src\t# unsigned\t@testUL_reg" %} ++ ins_encode %{ ++ __ testl($src$$Register, $src$$Register, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_imm); ++%} ++ ++instruct compB_mem_imm(rFlagsReg cr, memory mem, immI8 imm) ++%{ ++ match(Set cr (CmpI (LoadB mem) imm)); ++ ++ ins_cost(125); ++ format %{ "cmpb $mem, $imm\t@compB_mem_imm" %} ++ ins_encode %{ ++ __ cmpb($mem$$Address, $imm$$constant, $cr$$Register); ++ %} ++ //ins_pipe(ialu_cr_reg_mem); ++%} ++ ++instruct testB_mem_imm(rFlagsReg cr, memory mem, immI8 imm, immI0 zero) ++%{ ++ match(Set cr (CmpI (AndI (LoadB mem) imm) zero)); ++ ++ ins_cost(125); ++ format %{ "testb $mem, $imm\t@testB_mem_imm" %} ++ ins_encode %{ __ testb($mem$$Address, $imm$$constant, $cr$$Register); %} ++ //ins_pipe(ialu_cr_reg_mem); ++%}*/ ++ ++//----------Max and Min-------------------------------------------------------- ++// Min Instructions ++ ++instruct minI_Reg_Reg(rRegI dst, rRegI src) %{ ++ match(Set dst (MinI dst src)); ++ //effect(KILL flags); ++ ins_cost(200); ++ ++ format %{ "MIN $dst, $src @minI_Reg_Reg" %} ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ cmplt(src, dst, rscratch3); ++ __ selne(rscratch3, src, dst, dst); ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++ // Max Register with Register (generic version) ++instruct maxI_Reg_Reg(rRegI dst, rRegI src) %{ ++ match(Set dst (MaxI dst src)); ++ ins_cost(80); ++ ++ format %{ "MAX $dst, $src @maxI_Reg_Reg" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ Register src = $src$$Register; ++ ++ __ cmplt(dst, src, rscratch3); ++ __ selne(rscratch3, src, dst, dst); ++ ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++instruct maxI_Reg_zero(rRegI dst, immI0 zero) %{ ++ match(Set dst (MaxI dst zero)); ++ ins_cost(50); ++ ++ format %{ "MAX $dst, 0 @maxI_Reg_zero" %} ++ ++ ins_encode %{ ++ Register dst = $dst$$Register; ++ ++ __ cmplt(dst, R0, rscratch3); ++ __ selne(rscratch3, R0, dst, dst); ++ ++ %} ++ ++ ins_pipe( pipe_slow ); ++%} ++ ++// ============================================================================ ++// Branch Instructions ++ ++// Jump Direct - Label defines a relative address from JMP+1 ++instruct jmpDir(label labl) ++%{ ++ match(Goto); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "jmp $labl\t@jmpDir" %} ++ //size(5); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jmp(*L); // Always long jump ++ %} ++ ins_pipe(pipe_jmp); //CHECK TODO djx ++ ins_pc_relative(1); ++%} ++ ++// Jump Direct Conditional - Label defines a relative address from Jcc+1 ++instruct jmpLoopEnd(cmpOp cop, rRegI src1, rRegI src2, label labl) %{ ++ match(CountedLoopEnd cop (CmpI src1 src2)); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "J$cop $src1, $src2, $labl\t# Loop end @ jmpLoopEnd" %} ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Register op2 = $src2$$Register; ++ Label *L = $labl$$label; ++ int flag = $cop$$cmpcode; ++ ++// __ cmpl(op1, op2); ++// __ jcc((Assembler::Condition)flag, *L); ++ __ cmpls(flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ins_pipe( pipe_jmp ); ++ ins_pc_relative(1); ++%} ++ ++ instruct jmpLoopEnd_reg_imm16(cmpOp cop, rRegI src1, immI16_sub src2, label labl) %{ ++ match(CountedLoopEnd cop (CmpI src1 src2)); ++ effect(USE labl); ++ ++ ins_cost(150); ++ format %{ "J$cop $src1, $src2, $labl\t# Loop end @ jmpLoopEnd_reg_imm_16_sub" %} ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ int val = $src2$$constant; ++ Label *L = $labl$$label; ++ int flag = $cop$$cmpcode; ++ ++ //__ ldi(rscratch1_GP, -1 * val, op1); ++ //__ jcc((Assembler::Condition)flag, *L, rscratch1_GP); ++ ++ __ cmpw(op1, val); ++ __ jcc((Assembler::Condition)flag, *L); ++ %} ++ ins_pipe( pipe_jmp ); ++ ins_pc_relative(1); ++%} ++ ++ instruct jmpLoopEnd_reg_immI(cmpOp cop, rRegI src1, immI src2, label labl) %{ ++ match(CountedLoopEnd cop (CmpI src1 src2)); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "J$cop $src1, $src2, $labl\t# Loop end @ jmpLoopEnd_reg_immI" %} ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Register op2 = rscratch3; ++ Label *L = $labl$$label; ++ int flag = $cop$$cmpcode; ++ ++ __ mov_immediate32s(op2, $src2$$constant); ++ __ cmpls(flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ins_pipe( pipe_jmp ); ++ ins_pc_relative(1); ++%} ++ ++ instruct jmpLoopEnd_reg_immI0(cmpOp cop, rRegI src1, immI0 src2, label labl) %{ ++ match( CountedLoopEnd cop (CmpI src1 src2) ); ++ effect(USE labl); ++ ins_cost(170); ++ format %{ "J$cop $src1, $src2, $labl\t# Loop end @ jmpLoopEnd_reg_imm0_short" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Label *L = $labl$$label; ++ int flag = $cop$$cmpcode; ++ ++ __ jcc((Assembler::Condition)flag, *L, op1); ++ %} ++ ++ ins_pipe( pipe_jmp ); ++ ins_pc_relative(1); ++//ZLONG ins_short_branch(1); ++%} ++ ++// This match pattern is created for StoreIConditional since I cannot match IfNode without a RegFlags! ++instruct jmpCon_flags(cmpOp cop, rFlagsReg cr, label labl) %{ ++ match(If cop cr); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "J$cop $labl #sw64 uses GP as eflag @jmpCon_flags" %} ++ ++ ins_encode %{ ++ //__ stop("jmpCon_flags is for StoreIConditional?? lsp"); ++ Label *L = $labl$$label; ++ int flag = $cop$$cmpcode; ++ __ jcc((Assembler::Condition)flag, *L); ++ /*switch((Assembler::Condition)flag) ++ { ++ case Assembler::equal: //equal ++ __ bne_l($cr$$Register, *L); ++ break; ++ case Assembler::notEqual: //not equal ++ __ beq_l($cr$$Register, *L); ++ break; ++ default: ++ Unimplemented(); ++ }*/ ++ %} ++ ++ ins_pipe( pipe_jmp ); ++ ins_pc_relative(1); ++%} ++ ++//SW64:OKOK: ++instruct branchConP_zero(cmpOpU cmp, rRegP op1, immP0 zero, label labl) %{ ++ match(If cmp (CmpP op1 zero)); ++ effect(USE labl); ++ ++ ins_cost(180); ++ format %{ "b$cmp $op1, R0, $labl #@branchConP_zero_short" %} ++ ++ ins_encode %{ ++ Register op1 = $op1$$Register; ++ Register op2 = R0; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ jcc((Assembler::Condition)flag, *L, op1); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConN2P_zero_short(cmpOpU cmp, rRegN op1, immP0 zero, label labl) %{ ++ match(If cmp (CmpP (DecodeN op1) zero)); ++ predicate(Universe::narrow_oop_base() == NULL && Universe::narrow_oop_shift() == 0); ++ effect(USE labl); ++ ++ ins_cost(180); ++ format %{ "b$cmp $op1, R0, $labl #@branchConN2P_zero_short" %} ++ ++ ins_encode %{ ++ Register op1 = $op1$$Register; ++ Register op2 = R0; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ //__ stop("why only use beq&bne? sny"); ++ switch((Assembler::Condition)flag) ++ { ++ case Assembler::equal: //equal ++ __ beq_l(op1, *L); ++ break; ++ case Assembler::notEqual: //not_equal ++ __ bne_l(op1, *L); ++ break; ++ default: ++ Unimplemented(); ++ } ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++ ++instruct branchConP_short(cmpOpU cmp, rRegP op1, rRegP op2, label labl) %{ ++ match(If cmp (CmpP op1 op2)); ++// predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf)); ++ effect(USE labl); ++ ++ ins_cost(200); ++ format %{ "b$cmp $op1, $op2, $labl #@branchConP_short" %} ++ ++ ins_encode %{ ++ Register op1 = $op1$$Register; ++ Register op2 = $op2$$Register; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ cmplu(flag, op1, op2); ++ __ bne_l(rcc, *L);//TODO: add default rcc jzy ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct cmpN_null_branch_short(cmpOp cmp, rRegN op1, immN0 null, label labl) %{ ++ match(If cmp (CmpN op1 null)); ++ effect(USE labl); ++ ++ ins_cost(180); ++ format %{ "CMP $op1,0\t! compressed ptr\n\t" ++ "BP$cmp $labl @ cmpN_null_branch_short" %} ++ ins_encode %{ ++ Register op1 = $op1$$Register; ++ Register op2 = R0; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ jcc((Assembler::Condition)flag, *L, op1); ++ %} ++ ++//TODO: pipe_branchP or create pipe_branchN LEE ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct cmpN_reg_branch_short(cmpOpU cmp, rRegN op1, rRegN op2, label labl) %{ ++ match(If cmp (CmpN op1 op2)); ++ effect(USE labl); ++ ++ ins_cost(180); ++ format %{ "CMP $op1,$op2\t! compressed ptr\n\t" ++ "BP$cmp $labl @ cmpN_reg_branch_short" %} ++ ins_encode %{ ++ Register op1 = $op1$$Register; ++ Register op2 = $op2$$Register; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ cmplu(flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConIU_reg_reg_short(cmpOpU cmp, rRegI src1, rRegI src2, label labl) %{ ++ match( If cmp (CmpU src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConIU_reg_reg_short" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Register op2 = $src2$$Register; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++// __ stop("check if op1 & op2 are unsigned //sny"); ++ __ cmplu((Assembler::Condition)flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++ ++instruct branchConIU_reg_imm_short(cmpOpU cmp, rRegI src1, immI src2, label labl) %{ ++ match( If cmp (CmpU src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConIU_reg_imm_short" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ int val = $src2$$constant; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ mov_immediate32s(rscratch3, val); ++ __ cmplu((Assembler::Condition)flag, op1, rscratch3); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++%} ++ ++instruct branchConI_reg_reg_short(cmpOp cmp, rRegI src1, rRegI src2, label labl) %{ ++ match( If cmp (CmpI src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConI_reg_reg_short" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Register op2 = $src2$$Register; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ cmpls(flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++%} ++ ++instruct branchConI_reg_imm0_short(cmpOp cmp, rRegI src1, immI0 src2, label labl) %{ ++ match( If cmp (CmpI src1 src2) ); ++ effect(USE labl); ++ ins_cost(20); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConI_reg_imm0_short" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ jcc((Assembler::Condition)flag, *L, op1); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConI_reg_imm_short(cmpOp cmp, rRegI src1, immI src2, label labl) %{ ++ match( If cmp (CmpI src1 src2) ); ++ effect(USE labl); ++// ins_cost(200); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConI_reg_imm_short" %} ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ int val = $src2$$constant; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ mov_immediate32s(rscratch3, val); ++// __ cmpl(op1, rscratch3); ++// __ jcc((Assembler::Condition)flag, *L); ++ __ cmpls(flag, op1, rscratch3); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConIU_reg_imm0_short(cmpOpU cmp, rRegI src1, immI0 zero, label labl) %{ ++ match( If cmp (CmpU src1 zero) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, zero, $labl #@branchConIU_reg_imm0_short" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++// __ stop("is below necessary? sny"); ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: //equal ++ __ beq_l(op1, *L); ++ break; ++ case Assembler::notEqual: //not_equal ++ __ bne_l(op1, *L); ++ break; ++ case Assembler::above: //above ++ __ bne_l(op1, *L); ++ break; ++ case Assembler::aboveEqual: //above_equal ++ __ beq_l(R0, *L); ++ break; ++ case Assembler::below: //below ++ Unimplemented(); ++ return; ++ break; ++ case Assembler::belowEqual: //below_equal ++ __ beq_l(op1, *L); ++ break; ++ default: ++ Unimplemented(); ++ } ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++//instruct branchConIU_reg_immI16_short(cmpOpU cmp, rRegI src1, immI16_sub src2, label labl) %{ ++// match( If cmp (CmpU src1 src2) ); ++// effect(USE labl); ++// ins_cost(180); ++// format %{ "BR$cmp $src1, $src2, $labl #@branchConIU_reg_immI16_short" %} ++// ++// ins_encode %{ ++// Register op1 = $src1$$Register; ++// int val = $src2$$constant; ++// Label &L = *($labl$$label); ++// int flag = $cmp$$cmpcode; ++// ++// __ ldi(AT, -1 * val, op1); ++// switch(flag) { ++// case 0x04: //equal ++// if (&L) ++// __ beq_l(AT, L); ++// else ++// __ beq(AT, (int)0); ++// break; ++// case 0x05: //not_equal ++// if (&L) ++// __ bne_l(AT, L); ++// else ++// __ bne(AT, (int)0); ++// break; ++// case 0x0F: //above ++// if(&L) ++// __ bgt_l(AT, L); ++// else ++// __ bgt(AT, (int)0); ++// break; ++// case 0x0D: //above_equal ++// if(&L) ++// __ bge_l(AT, L); ++// else ++// __ bge(AT, (int)0); ++// break; ++// case 0x0C: //below ++// if(&L) ++// __ blt_l(AT, L); ++// else ++// __ blt(AT, (int)0); ++// break; ++// case 0x0E: //below_equal ++// if(&L) ++// __ ble_l(AT, L); ++// else ++// __ ble(AT, (int)0); ++// break; ++// default: ++// Unimplemented(); ++// } ++// %} ++// ++// ins_pc_relative(1); ++// ins_pipe( pipe_alu_branch ); ++////ZLONG ins_short_branch(1); ++//%} ++ ++instruct branchConL_regL_regL_short(cmpOp cmp, rRegL src1, rRegL src2, label labl) %{ ++ match( If cmp (CmpL src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConL_regL_regL_short" %} ++// ins_cost(250); ++ ++ ins_encode %{ ++ Register op1 = as_Register($src1$$reg); ++ Register op2 = as_Register($src2$$reg); ++ ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++// __ cmpl(op1, op2); ++// __ jcc((Assembler::Condition)flag, *L); ++ __ cmpls(flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConI_reg_imm16_sub(cmpOp cmp, rRegI src1, immI16_sub src2, label labl) %{ ++ match( If cmp (CmpI src1 src2) ); ++ effect(USE labl); ++// ins_cost(180); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConI_reg_imm16_sub" %} ++ ++ ins_encode %{ ++ Register op1 = $src1$$Register; ++ int val = $src2$$constant; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ //__ ldi(rscratch1_GP, -1 * val, op1); ++ //__ jcc((Assembler::Condition)flag, *L, rscratch1_GP); ++ ++ __ cmpw(op1, val); ++ __ jcc((Assembler::Condition)flag, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++%} ++ ++instruct branchConL_regL_immL0_short(cmpOp cmp, rRegL src1, immL0 zero, label labl) %{ ++ match( If cmp (CmpL src1 zero) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, zero, $labl #@branchConL_regL_immL0_short" %} ++ ins_cost(80); ++ ++ ins_encode %{ ++ Register op1 = as_Register($src1$$reg); ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ jcc((Assembler::Condition)flag, *L, op1); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConL_regL_immL_short(cmpOp cmp, rRegL src1, immL src2, label labl) %{ ++ match( If cmp (CmpL src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConL_regL_immL_short" %} ++// ins_cost(100); ++ ++ ins_encode %{ ++ Register op1 = as_Register($src1$$reg); ++ Register op2 = rscratch2_AT; ++ ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ __ mov_immediate64(op2, $src2$$constant); ++// __ cmpl(op1, op2); ++// __ jcc((Assembler::Condition)flag, *L); ++ __ cmpls(flag, op1, op2); ++ __ bne_l(rcc, *L); ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe( pipe_alu_branch ); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConF_reg_reg_short(cmpOp cmp, regF src1, regF src2, label labl) %{ ++ match( If cmp (CmpF src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConF_reg_reg_short" %} ++ ++ ins_encode %{ ++ FloatRegister op1 = $src1$$FloatRegister; ++ FloatRegister op2 = $src2$$FloatRegister; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ ffbne(FcmpRES, *L); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ ffbeq(FcmpRES, *L); ++ break; ++ case Assembler::greater: ++ __ c_olt_s(op2, op1); ++ __ ffbne(FcmpRES, *L); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_s(op2, op1); ++ __ ffbne(FcmpRES, *L); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_s(op2, op1); ++ __ ffbeq(FcmpRES, *L); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_s(op2, op1); ++ __ ffbeq(FcmpRES, *L); ++ break; ++ } ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe(pipe_slow); ++//ZLONG ins_short_branch(1); ++%} ++ ++instruct branchConD_reg_reg_short(cmpOp cmp, regD src1, regD src2, label labl) %{ ++ match( If cmp (CmpD src1 src2) ); ++ effect(USE labl); ++ format %{ "BR$cmp $src1, $src2, $labl #@branchConD_reg_reg_short" %} ++ ++ ins_encode %{ ++ FloatRegister op1 = $src1$$FloatRegister; ++ FloatRegister op2 = $src2$$FloatRegister; ++ Label * L = $labl$$label; ++ int flag = $cmp$$cmpcode; ++ ++ switch((Assembler::Condition)flag) { ++ case Assembler::equal: ++ __ fcmpeq(op1, op2, fcc); ++ __ ffbne(FcmpRES, *L); ++ break; ++ case Assembler::notEqual: ++ __ fcmpeq(op1, op2, fcc); ++ __ ffbeq(FcmpRES, *L); ++ break; ++ case Assembler::greater: ++ __ c_olt_d(op2, op1); ++ __ ffbne(FcmpRES, *L); ++ break; ++ case Assembler::greaterEqual: ++ __ c_ole_d(op2, op1); ++ __ ffbne(FcmpRES, *L); ++ break; ++ case Assembler::less: ++ __ block_comment("less;;"); ++ __ c_ole_d(op2, op1); ++ __ ffbeq(FcmpRES, *L); ++ break; ++ case Assembler::lessEqual: ++ __ block_comment("lessEqual;;"); ++ __ c_olt_d(op2, op1); ++ __ ffbeq(FcmpRES, *L); ++ break; ++ } ++ %} ++ ++ ins_pc_relative(1); ++ ins_pipe(pipe_slow); ++//ZLONG ins_short_branch(1); ++%} ++ ++// mask version ++// Jump Direct Conditional - Label defines a relative address from Jcc+1 ++/* TODO:jzy what's n->has_vector_mask_set()? ++instruct jmpLoopEnd_and_restoreMask(cmpOp cop, rFlagsReg cr, label labl) ++%{ ++ predicate(n->has_vector_mask_set()); ++ match(CountedLoopEnd cop cr); ++ effect(USE labl); ++ ++ ins_cost(400); ++ format %{ "j$cop $labl\t# loop end\n\t" ++ "restorevectmask \t# vector mask restore for loops" %} ++ size(10); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jcc((Assembler::Condition)($cop$$cmpcode), *L, cr); // Always long jump ++ __ stop("jmpLoopEnd_and_restoreMask stop"); ++ //__ restorevectmask(); ++ %} ++ //ins_pipe(pipe_jcc); ++%} ++ ++// Jump Direct Conditional - Label defines a relative address from Jcc+1 ++instruct jmpLoopEndU_and_restoreMask(cmpOpU cop, rFlagsRegU cmp, label labl) %{ ++ predicate(n->has_vector_mask_set()); ++ match(CountedLoopEnd cop cmp); ++ effect(USE labl); ++ ++ ins_cost(400); ++ format %{ "j$cop,u $labl\t# loop end\n\t" ++ "restorevectmask \t# vector mask restore for loops" %} ++ size(10); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump ++ __ restorevectmask(); ++ %} ++ ins_pipe(pipe_jcc); ++%} ++ ++instruct jmpLoopEndUCF_and_restoreMask(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ ++ predicate(n->has_vector_mask_set()); ++ match(CountedLoopEnd cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,u $labl\t# loop end\n\t" ++ "restorevectmask \t# vector mask restore for loops" %} ++ size(10); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump ++ __ restorevectmask(); ++ %} ++ ins_pipe(pipe_jcc); ++%}*/ ++ ++// Jump Direct Conditional - using unsigned comparison ++instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) %{ ++ match(If cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,us $labl\t@jmpConU" %} ++// size(20); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); // Always long jump ++ %} ++ ins_pipe( pipe_jmp ); ++// ins_pc_relative(1); ++%} ++/* ++instruct jmpConUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ ++ match(If cop cmp); ++ effect(USE labl); ++ ++ ins_cost(200); ++ format %{ "j$cop,u $labl" %} ++ size(6); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump ++ %} ++ ins_pipe(pipe_jcc); ++%} ++ ++instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ ++ match(If cop cmp); ++ effect(USE labl); ++ ++ ins_cost(200); ++ format %{ $$template ++ if ($cop$$cmpcode == Assembler::notEqual) { ++ $$emit$$"jp,u $labl\n\t" ++ $$emit$$"j$cop,u $labl" ++ } else { ++ $$emit$$"jp,u done\n\t" ++ $$emit$$"j$cop,u $labl\n\t" ++ $$emit$$"done:" ++ } ++ %} ++ ins_encode %{ ++ Label* l = $labl$$label; ++ if ($cop$$cmpcode == Assembler::notEqual) { ++ __ jcc(Assembler::parity, *l, false); ++ __ jcc(Assembler::notEqual, *l, false); ++ } else if ($cop$$cmpcode == Assembler::equal) { ++ Label done; ++ __ jccb(Assembler::parity, done); ++ __ jcc(Assembler::equal, *l, false); ++ __ bind(done); ++ } else { ++ ShouldNotReachHere(); ++ } ++ %} ++ ins_pipe(pipe_jcc); ++%} ++*/ ++/* ++// ============================================================================ ++// 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 NZ for a miss or zero for a hit. The ++// encoding ALSO sets flags. ++ ++instruct partialSubtypeCheck(rdi_RegP result, ++ rsi_RegP sub, rax_RegP super, rcx_RegI rcx, ++ rFlagsReg cr) ++%{ ++ match(Set result (PartialSubtypeCheck sub super)); ++ effect(KILL rcx, KILL cr); ++ ++ ins_cost(1100); // slightly larger than the next version ++ format %{ "movq rdi, [$sub + in_bytes(Klass::secondary_supers_offset())]\n\t" ++ "movl rcx, [rdi + Array::length_offset_in_bytes()]\t# length to scan\n\t" ++ "addq rdi, Array::base_offset_in_bytes()\t# Skip to start of data; set NZ in case count is zero\n\t" ++ "repne scasq\t# Scan *rdi++ for a match with rax while rcx--\n\t" ++ "jne,s miss\t\t# Missed: rdi not-zero\n\t" ++ "movq [$sub + in_bytes(Klass::secondary_super_cache_offset())], $super\t# Hit: update cache\n\t" ++ "xorq $result, $result\t\t Hit: rdi zero\n\t" ++ "miss:\t" %} ++ ++ opcode(0x1); // Force a XOR of RDI ++ ins_encode(enc_PartialSubtypeCheck()); ++ ins_pipe(pipe_slow); ++%} ++ ++instruct partialSubtypeCheck_vs_Zero(rFlagsReg cr, ++ rsi_RegP sub, rax_RegP super, rcx_RegI rcx, ++ immP0 zero, ++ rdi_RegP result) ++%{ ++ match(Set cr (CmpP (PartialSubtypeCheck sub super) zero)); ++ effect(KILL rcx, KILL result); ++ ++ ins_cost(1000); ++ format %{ "movq rdi, [$sub + in_bytes(Klass::secondary_supers_offset())]\n\t" ++ "movl rcx, [rdi + Array::length_offset_in_bytes()]\t# length to scan\n\t" ++ "addq rdi, Array::base_offset_in_bytes()\t# Skip to start of data; set NZ in case count is zero\n\t" ++ "repne scasq\t# Scan *rdi++ for a match with rax while cx-- != 0\n\t" ++ "jne,s miss\t\t# Missed: flags nz\n\t" ++ "movq [$sub + in_bytes(Klass::secondary_super_cache_offset())], $super\t# Hit: update cache\n\t" ++ "miss:\t" %} ++ ++ opcode(0x0); // No need to XOR RDI ++ ins_encode(enc_PartialSubtypeCheck()); ++ ins_pipe(pipe_slow); ++%} ++*/ ++// ============================================================================ ++// Branch Instructions -- short offset versions ++// ++// These instructions are used to replace jumps of a long offset (the default ++// match) with jumps of a shorter offset. These instructions are all tagged ++// with the ins_short_branch attribute, which causes the ADLC to suppress the ++// match rules in general matching. Instead, the ADLC generates a conversion ++// method in the MachNode which can be used to do in-place replacement of the ++// long variant with the shorter variant. The compiler will determine if a ++// branch can be taken by the is_short_branch_offset() predicate in the machine ++// specific code section of the file. ++ ++// Jump Direct - Label defines a relative address from JMP+1 ++instruct jmpDir_short(label labl) %{ ++ match(Goto); ++ effect(USE labl); ++ ins_cost(300); ++ format %{ "JMP $labl #@jmpDir" %} ++ ins_encode %{ ++ Label &L = *($labl$$label); ++ if(&L) ++ __ beq_l(R0, L); ++ else ++ ShouldNotReachHere(); ++ %} ++ ins_pipe( pipe_jmp ); ++ ins_pc_relative(1); ++%} ++ ++/* ++// Jump Direct Conditional - Label defines a relative address from Jcc+1 ++instruct jmpCon_short(cmpOp cop, rFlagsReg cr, label labl) %{ ++ match(If cop cr); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,s $labl" %} ++ size(2); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++ ++// Jump Direct Conditional - Label defines a relative address from Jcc+1 ++instruct jmpLoopEnd_short(cmpOp cop, rFlagsReg cr, label labl) %{ ++ match(CountedLoopEnd cop cr); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,s $labl\t# loop end" %} ++ size(2); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++ ++// Jump Direct Conditional - Label defines a relative address from Jcc+1 ++instruct jmpLoopEndU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{ ++ match(CountedLoopEnd cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,us $labl\t# loop end" %} ++ size(2); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++ ++instruct jmpLoopEndUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ ++ match(CountedLoopEnd cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,us $labl\t# loop end" %} ++ size(2); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++ ++// Jump Direct Conditional - using unsigned comparison ++instruct jmpConU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{ ++ match(If cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,us $labl" %} ++ size(2); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++ ++instruct jmpConUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ ++ match(If cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ "j$cop,us $labl" %} ++ size(2); ++ ins_encode %{ ++ Label* L = $labl$$label; ++ __ jccb((Assembler::Condition)($cop$$cmpcode), *L); ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++ ++instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ ++ match(If cop cmp); ++ effect(USE labl); ++ ++ ins_cost(300); ++ format %{ $$template ++ if ($cop$$cmpcode == Assembler::notEqual) { ++ $$emit$$"jp,u,s $labl\n\t" ++ $$emit$$"j$cop,u,s $labl" ++ } else { ++ $$emit$$"jp,u,s done\n\t" ++ $$emit$$"j$cop,u,s $labl\n\t" ++ $$emit$$"done:" ++ } ++ %} ++ size(4); ++ ins_encode %{ ++ Label* l = $labl$$label; ++ if ($cop$$cmpcode == Assembler::notEqual) { ++ __ jccb(Assembler::parity, *l); ++ __ jccb(Assembler::notEqual, *l); ++ } else if ($cop$$cmpcode == Assembler::equal) { ++ Label done; ++ __ jccb(Assembler::parity, done); ++ __ jccb(Assembler::equal, *l); ++ __ bind(done); ++ } else { ++ ShouldNotReachHere(); ++ } ++ %} ++ ins_pipe(pipe_jcc); ++ ins_short_branch(1); ++%} ++*/ ++ ++// ============================================================================ ++// inlined locking and unlocking ++/* ++instruct cmpFastLockRTM(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rdx_RegI scr, rRegI cx1, rRegI cx2) %{ ++ predicate(Compile::current()->use_rtm()); ++ match(Set cr (FastLock object box)); ++ effect(TEMP tmp, TEMP scr, TEMP cx1, TEMP cx2, USE_KILL box); ++ ins_cost(300); ++ format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr,$cx1,$cx2" %} ++ ins_encode %{ ++ __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, ++ $scr$$Register, $cx1$$Register, $cx2$$Register, ++ _counters, _rtm_counters, _stack_rtm_counters, ++ ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), ++ true, ra_->C->profile_rtm()); ++ %} ++ ins_pipe(pipe_slow); ++%}*/ ++instruct cmpFastLock(rFlagsReg cr, rRegP object, s3_RegP box, v0_RegI tmp, rRegP scr) %{ ++ //predicate(!Compile::current()->use_rtm()); ++ match(Set cr (FastLock object box));//TODO:check where use cr? jzy ++ effect(TEMP tmp, TEMP scr, USE_KILL box); ++ ins_cost(300); ++ format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr\t@cmpFastLock" %} ++ ins_encode %{ ++ //__ stop("need check parameters and implements. jzy?"); ++ __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, ++ $scr$$Register, noreg, noreg, _counters, NULL, false, false); ++ %} ++ ins_pipe( pipe_slow ); ++ ins_pc_relative(1); ++%} ++ ++instruct cmpFastUnlock(rFlagsReg cr, rRegP object, v0_RegP box, rRegP tmp) %{ ++ match(Set cr (FastUnlock object box)); ++ effect(TEMP tmp, USE_KILL box); ++ ins_cost(300); ++ format %{ "fastunlock $object,$box\t! kills $box,$tmp\t@cmpFastUnlock" %} ++ ins_encode %{ ++ __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, false); ++ %} ++ ins_pipe( pipe_slow ); ++ ins_pc_relative(1); ++%} ++ ++ ++// ============================================================================ ++// Safepoint Instructions ++/* no need in sw8 ++instruct safePoint_poll(rFlagsReg cr) ++%{ ++ predicate(!Assembler::is_polling_page_far() && SafepointMechanism::uses_global_page_poll()); ++ match(SafePoint); ++ effect(KILL cr); ++ ++ format %{ "testl rax, [rip + #offset_to_poll_page]\t" ++ "# Safepoint: poll for GC" %} ++ ins_cost(125); ++ ins_encode %{ ++ //AddressLiteral addr(os::get_polling_page(), relocInfo::poll_type); ++ //__ testl(rax, addr); ++ __ stop("safePoint_poll unimplement jzy?"); ++ %} ++ ins_pipe(ialu_reg_mem); ++%}*/ ++ ++instruct safePoint_poll_far(rFlagsReg cr, rRegP poll) ++%{ ++// predicate(Assembler::is_polling_page_far() && SafepointMechanism::uses_global_page_poll()); ++ match(SafePoint poll); ++ effect(USE poll); ++ ++ ins_cost(125); ++ format %{ "Safepoint @ [$poll] : poll for GC @ safePoint_poll_reg" %} ++ ++ ins_encode %{ ++ Register poll_reg = $poll$$Register; ++ ++ __ block_comment("Safepoint:"); ++ __ relocate(relocInfo::poll_type); ++ __ ldw(rscratch3, 0, poll_reg); ++ %} ++ ins_pipe(ialu_reg_mem); ++%} ++/* ++instruct safePoint_poll_tls(rFlagsReg cr, t0_RegP poll) ++%{ ++ predicate(SafepointMechanism::uses_thread_local_poll()); ++ match(SafePoint poll); ++ effect(KILL cr, USE poll); ++ ++ format %{ "testl rax, [$poll]\t" ++ "# Safepoint: poll for GC\t@safePoint_poll_tls why rax? jzy" %} ++ ins_cost(125); ++// size(3); ++ ins_encode %{ ++ //__ relocate(relocInfo::poll_type); ++ //address pre_pc = __ pc(); ++ //__ testl(rax, Address($poll$$Register, 0)); ++ //address post_pc = __ pc(); ++ //guarantee(pre_pc[0] == 0x41 && pre_pc[1] == 0x85, "must emit #rex test-ax [reg]"); ++ __ stop("safePoint_poll_tls unimplement jzy?"); ++ %} ++ //ins_pipe(ialu_reg_mem); ++%} ++*/ ++// ============================================================================ ++// Procedure Call/Return Instructions ++// Call Java Static Instruction ++// Note: If this code changes, the corresponding ret_addr_offset() and ++// compute_padding() functions will have to be adjusted. ++instruct CallStaticJavaDirect(method meth) %{ ++ match(CallStaticJava); ++ effect(USE meth); ++ ++ ins_cost(300); ++ format %{ "call,static\t@CallStaticJavaDirect" %} ++ ++ ins_encode(Java_Static_Call(meth), call_epilog); ++ ins_pipe(pipe_slow); ++ ins_alignment(4); ++%} ++ ++// Call Java Dynamic Instruction ++// Note: If this code changes, the corresponding ret_addr_offset() and ++// compute_padding() functions will have to be adjusted. ++instruct CallDynamicJavaDirect(method meth) ++%{ ++ match(CallDynamicJava); ++ effect(USE meth); ++ ++ ins_cost(300); ++ format %{ "movq v0, #Universe::non_oop_word()\t@CallDynamicJavaDirect\n\t" ++ "call,dynamic " %} ++ ins_encode(Java_Dynamic_Call(meth), call_epilog); ++ ins_pipe(pipe_slow); ++ ins_alignment(4); ++%} ++ ++// Call Runtime Instruction ++instruct CallRuntimeDirect(method meth) ++%{ ++ match(CallRuntime); ++ effect(USE meth); ++ ++ ins_cost(300); ++ format %{ "call,runtime\t@CallRuntimeDirect" %} ++ ins_encode(sw64_Java_To_Runtime(meth)); ++ ins_pipe(pipe_slow); ++// ins_alignment(16);//lsp todo check ++%} ++ ++// Call runtime without safepoint ++instruct CallLeafDirect(method meth) ++%{ ++ match(CallLeaf); ++ effect(USE meth); ++ ++ ins_cost(300); ++ format %{ "call_leaf,runtime\t@CallLeafDirect" %} ++ ins_encode(sw64_Java_To_Runtime(meth)); ++ ins_pipe(pipe_slow); ++ ins_pc_relative(1);//lsp todo check ++// ins_alignment(16);//lsp todo check ++%} ++ ++// Call runtime without safepoint ++instruct CallLeafNoFPDirect(method meth) ++%{ ++ match(CallLeafNoFP); ++ effect(USE meth); ++ ++ ins_cost(300); ++ format %{ "call_leaf_nofp,runtime\t@CallLeafNoFPDirect" %} ++ ins_encode(sw64_Java_To_Runtime(meth)); ++ ins_pipe(pipe_slow); ++ ins_pc_relative(1);//lsp todo check ++// ins_alignment(16); ++%} ++ ++// Return Instruction ++// Remove the return address & jump to it. ++// Notice: We always emit a nop after a ret to make sure there is room ++// for safepoint patching ++instruct Ret() ++%{ ++ match(Return); ++ ++ format %{ "ret\t@Ret" %} ++ ++ ins_encode %{ ++ __ ret_sw(); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++ ++// 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(rRegP jump_target, rRegP method_oop) ++%{ ++ match(TailCall jump_target method_oop); ++ ++ ins_cost(300); ++ format %{ "jmp $jump_target\t# rmethod: holds method oop\t@TailCalljmpInd" %} ++ ++ ins_encode %{ ++ Register target = $jump_target$$Register; ++ Register oop = $method_oop$$Register; ++ //__ stop("check parameters jzy?"); ++ // RA will be used in generate_forward_exception() ++// __ push(RA); ++ ++ __ movl(rmethod, oop); ++ __ jmp(target); ++ //__ stop("check parameters jzy?"); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++ ++// Tail Jump; remove the return address; jump to target. ++// TailCall above leaves the return address around. ++instruct tailjmpInd(rRegP jump_target, v0_RegP ex_oop) ++%{ ++ match(TailJump jump_target ex_oop); ++ ++ ins_cost(300); ++ format %{ "Jmp $jump_target ; ex_oop = $ex_oop\t@tailjmpInd" %} ++ ins_encode %{ ++ // V0, c_rarg2 are indicated in: ++ // [stubGenerator_sw64.cpp] generate_forward_exception() ++ // [runtime_sw64.cpp] OptoRuntime::generate_exception_blob() ++ // ++ Register target = $jump_target$$Register; ++ Register oop = $ex_oop$$Register; ++ //Register exception_oop = V0; ++ Register exception_pc = c_rarg2; ++ //__ stop("check tailjmpInd lsp"); ++ __ block_comment(";;tailjmpInd start"); ++ __ movl(exception_pc, RA); ++ //__ movl(rax, oop); // oop is same as exception_oop,both are v0 ++ __ jmp(target); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++ ++// Create exception oop: created by stack-crawling runtime code. ++// Created exception is now available to this handler, and is setup ++// just prior to jumping to this handler. No code emitted. ++instruct CreateException(v0_RegP ex_oop) ++%{ ++ match(Set ex_oop (CreateEx)); ++ ++ size(0); ++ // use the following format syntax ++ format %{ "# exception oop is in v0; 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); ++ ++ // use the following format syntax ++ format %{ "jmp rethrow_stub\t@RethrowException" %} ++ ++ ins_encode %{ ++ //__ stop("check RethrowException lsp"); ++ __ block_comment("@ RethrowException"); ++ cbuf.set_insts_mark(); ++ cbuf.relocate(cbuf.insts_mark(), runtime_call_Relocation::spec()); ++ ++ // call OptoRuntime::rethrow_stub to get the exception handler in parent method ++ __ patchable_jump((address)OptoRuntime::rethrow_stub()); ++ %} ++ ins_pipe(pipe_jmp); ++%} ++ ++instruct ShouldNotReachHere( ) ++%{ ++ match(Halt); ++ ins_cost(300); ++ ++ // Use the following format syntax ++ format %{ "ILLTRAP ;#@ShouldNotReachHere" %} ++ ins_encode %{ ++ // Here we should emit illtrap ! ++ ++ __ stop("in ShoudNotReachHere"); ++ ++ %} ++ ins_pipe( pipe_jmp ); ++%} ++/* ++// ++// Execute ZGC load barrier (strong) slow path ++// ++ ++// When running without XMM regs ++instruct loadBarrierSlowRegNoVec(rRegP dst, memory mem, rFlagsReg cr) %{ ++ ++ match(Set dst (LoadBarrierSlowReg mem)); ++ predicate(MaxVectorSize < 16); ++ ++ effect(DEF dst, KILL cr); ++ ++ format %{"LoadBarrierSlowRegNoVec $dst, $mem" %} ++ ins_encode %{ ++#if INCLUDE_ZGC ++ Register d = $dst$$Register; ++ ZBarrierSetAssembler* bs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ assert(d != r12, "Can't be R12!"); ++ assert(d != r15, "Can't be R15!"); ++ assert(d != rsp, "Can't be RSP!"); ++ ++ __ lea(d, $mem$$Address); ++ __ call(RuntimeAddress(bs->load_barrier_slow_stub(d))); ++#else ++ ShouldNotReachHere(); ++#endif ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// For XMM and YMM enabled processors ++instruct loadBarrierSlowRegXmmAndYmm(rRegP dst, memory mem, rFlagsReg cr, ++ rxmm0 x0, rxmm1 x1, rxmm2 x2,rxmm3 x3, ++ rxmm4 x4, rxmm5 x5, rxmm6 x6, rxmm7 x7, ++ rxmm8 x8, rxmm9 x9, rxmm10 x10, rxmm11 x11, ++ rxmm12 x12, rxmm13 x13, rxmm14 x14, rxmm15 x15) %{ ++ ++ match(Set dst (LoadBarrierSlowReg mem)); ++ predicate((UseSSE > 0) && (UseAVX <= 2) && (MaxVectorSize >= 16)); ++ ++ effect(DEF dst, KILL cr, ++ KILL x0, KILL x1, KILL x2, KILL x3, ++ KILL x4, KILL x5, KILL x6, KILL x7, ++ KILL x8, KILL x9, KILL x10, KILL x11, ++ KILL x12, KILL x13, KILL x14, KILL x15); ++ ++ format %{"LoadBarrierSlowRegXmm $dst, $mem" %} ++ ins_encode %{ ++#if INCLUDE_ZGC ++ Register d = $dst$$Register; ++ ZBarrierSetAssembler* bs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ assert(d != r12, "Can't be R12!"); ++ assert(d != r15, "Can't be R15!"); ++ assert(d != rsp, "Can't be RSP!"); ++ ++ __ lea(d, $mem$$Address); ++ __ call(RuntimeAddress(bs->load_barrier_slow_stub(d))); ++#else ++ ShouldNotReachHere(); ++#endif ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// For ZMM enabled processors ++instruct loadBarrierSlowRegZmm(rRegP dst, memory mem, rFlagsReg cr, ++ rxmm0 x0, rxmm1 x1, rxmm2 x2,rxmm3 x3, ++ rxmm4 x4, rxmm5 x5, rxmm6 x6, rxmm7 x7, ++ rxmm8 x8, rxmm9 x9, rxmm10 x10, rxmm11 x11, ++ rxmm12 x12, rxmm13 x13, rxmm14 x14, rxmm15 x15, ++ rxmm16 x16, rxmm17 x17, rxmm18 x18, rxmm19 x19, ++ rxmm20 x20, rxmm21 x21, rxmm22 x22, rxmm23 x23, ++ rxmm24 x24, rxmm25 x25, rxmm26 x26, rxmm27 x27, ++ rxmm28 x28, rxmm29 x29, rxmm30 x30, rxmm31 x31) %{ ++ ++ match(Set dst (LoadBarrierSlowReg mem)); ++ predicate((UseAVX == 3) && (MaxVectorSize >= 16)); ++ ++ effect(DEF dst, KILL cr, ++ KILL x0, KILL x1, KILL x2, KILL x3, ++ KILL x4, KILL x5, KILL x6, KILL x7, ++ KILL x8, KILL x9, KILL x10, KILL x11, ++ KILL x12, KILL x13, KILL x14, KILL x15, ++ KILL x16, KILL x17, KILL x18, KILL x19, ++ KILL x20, KILL x21, KILL x22, KILL x23, ++ KILL x24, KILL x25, KILL x26, KILL x27, ++ KILL x28, KILL x29, KILL x30, KILL x31); ++ ++ format %{"LoadBarrierSlowRegZmm $dst, $mem" %} ++ ins_encode %{ ++#if INCLUDE_ZGC ++ Register d = $dst$$Register; ++ ZBarrierSetAssembler* bs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ assert(d != r12, "Can't be R12!"); ++ assert(d != r15, "Can't be R15!"); ++ assert(d != rsp, "Can't be RSP!"); ++ ++ __ lea(d, $mem$$Address); ++ __ call(RuntimeAddress(bs->load_barrier_slow_stub(d))); ++#else ++ ShouldNotReachHere(); ++#endif ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// ++// Execute ZGC load barrier (weak) slow path ++// ++ ++// When running without XMM regs ++instruct loadBarrierWeakSlowRegNoVec(rRegP dst, memory mem, rFlagsReg cr) %{ ++ ++ match(Set dst (LoadBarrierSlowReg mem)); ++ predicate(MaxVectorSize < 16); ++ ++ effect(DEF dst, KILL cr); ++ ++ format %{"LoadBarrierSlowRegNoVec $dst, $mem" %} ++ ins_encode %{ ++#if INCLUDE_ZGC ++ Register d = $dst$$Register; ++ ZBarrierSetAssembler* bs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ assert(d != r12, "Can't be R12!"); ++ assert(d != r15, "Can't be R15!"); ++ assert(d != rsp, "Can't be RSP!"); ++ ++ __ lea(d, $mem$$Address); ++ __ call(RuntimeAddress(bs->load_barrier_weak_slow_stub(d))); ++#else ++ ShouldNotReachHere(); ++#endif ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// For XMM and YMM enabled processors ++instruct loadBarrierWeakSlowRegXmmAndYmm(rRegP dst, memory mem, rFlagsReg cr, ++ rxmm0 x0, rxmm1 x1, rxmm2 x2,rxmm3 x3, ++ rxmm4 x4, rxmm5 x5, rxmm6 x6, rxmm7 x7, ++ rxmm8 x8, rxmm9 x9, rxmm10 x10, rxmm11 x11, ++ rxmm12 x12, rxmm13 x13, rxmm14 x14, rxmm15 x15) %{ ++ ++ match(Set dst (LoadBarrierWeakSlowReg mem)); ++ predicate((UseSSE > 0) && (UseAVX <= 2) && (MaxVectorSize >= 16)); ++ ++ effect(DEF dst, KILL cr, ++ KILL x0, KILL x1, KILL x2, KILL x3, ++ KILL x4, KILL x5, KILL x6, KILL x7, ++ KILL x8, KILL x9, KILL x10, KILL x11, ++ KILL x12, KILL x13, KILL x14, KILL x15); ++ ++ format %{"LoadBarrierWeakSlowRegXmm $dst, $mem" %} ++ ins_encode %{ ++#if INCLUDE_ZGC ++ Register d = $dst$$Register; ++ ZBarrierSetAssembler* bs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ assert(d != r12, "Can't be R12!"); ++ assert(d != r15, "Can't be R15!"); ++ assert(d != rsp, "Can't be RSP!"); ++ ++ __ lea(d,$mem$$Address); ++ __ call(RuntimeAddress(bs->load_barrier_weak_slow_stub(d))); ++#else ++ ShouldNotReachHere(); ++#endif ++ %} ++ ins_pipe(pipe_slow); ++%} ++ ++// For ZMM enabled processors ++instruct loadBarrierWeakSlowRegZmm(rRegP dst, memory mem, rFlagsReg cr, ++ rxmm0 x0, rxmm1 x1, rxmm2 x2,rxmm3 x3, ++ rxmm4 x4, rxmm5 x5, rxmm6 x6, rxmm7 x7, ++ rxmm8 x8, rxmm9 x9, rxmm10 x10, rxmm11 x11, ++ rxmm12 x12, rxmm13 x13, rxmm14 x14, rxmm15 x15, ++ rxmm16 x16, rxmm17 x17, rxmm18 x18, rxmm19 x19, ++ rxmm20 x20, rxmm21 x21, rxmm22 x22, rxmm23 x23, ++ rxmm24 x24, rxmm25 x25, rxmm26 x26, rxmm27 x27, ++ rxmm28 x28, rxmm29 x29, rxmm30 x30, rxmm31 x31) %{ ++ ++ match(Set dst (LoadBarrierWeakSlowReg mem)); ++ predicate((UseAVX == 3) && (MaxVectorSize >= 16)); ++ ++ effect(DEF dst, KILL cr, ++ KILL x0, KILL x1, KILL x2, KILL x3, ++ KILL x4, KILL x5, KILL x6, KILL x7, ++ KILL x8, KILL x9, KILL x10, KILL x11, ++ KILL x12, KILL x13, KILL x14, KILL x15, ++ KILL x16, KILL x17, KILL x18, KILL x19, ++ KILL x20, KILL x21, KILL x22, KILL x23, ++ KILL x24, KILL x25, KILL x26, KILL x27, ++ KILL x28, KILL x29, KILL x30, KILL x31); ++ ++ format %{"LoadBarrierWeakSlowRegZmm $dst, $mem" %} ++ ins_encode %{ ++#if INCLUDE_ZGC ++ Register d = $dst$$Register; ++ ZBarrierSetAssembler* bs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); ++ ++ assert(d != r12, "Can't be R12!"); ++ assert(d != r15, "Can't be R15!"); ++ assert(d != rsp, "Can't be RSP!"); ++ ++ __ lea(d,$mem$$Address); ++ __ call(RuntimeAddress(bs->load_barrier_weak_slow_stub(d))); ++#else ++ ShouldNotReachHere(); ++#endif ++ %} ++ ins_pipe(pipe_slow); ++%} ++*/ ++// ============================================================================ ++// This name is KNOWN by the ADLC and cannot be changed. ++// The ADLC forces a 'TypeRawPtr::BOTTOM' output type ++// for this guy. ++instruct tlsLoadP(s2_RegP dst) %{ ++ match(Set dst (ThreadLocal)); ++ effect(DEF dst); ++ ++ size(0); ++ format %{ "# TLS is in S2" %} ++ ins_encode( /*empty encoding*/ ); ++ ins_pipe(empty); ++%} ++/* ++ ++//----------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 == RAX_enc) ++// Only one replacement instruction ++// ++// ---------EXAMPLE---------------------------------------------------------- ++// ++// // pertinent parts of existing instructions in architecture description ++// instruct movI(rRegI dst, rRegI src) ++// %{ ++// match(Set dst (CopyI src)); ++// %} ++// ++// instruct incI_rReg(rRegI dst, immI1 src, rFlagsReg cr) ++// %{ ++// match(Set dst (AddI dst src)); ++// effect(KILL cr); ++// %} ++// ++// // Change (inc mov) to lea ++// peephole %{ ++// // increment preceeded by register-register move ++// peepmatch ( incI_rReg 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 ( leaI_rReg_immI( 0.dst 1.src 0.src ) ); ++// %} ++// ++ ++// Implementation no longer uses movX instructions since ++// machine-independent system no longer uses CopyX nodes. ++// ++// peephole ++// %{ ++// peepmatch (incI_rReg movI); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaI_rReg_immI(0.dst 1.src 0.src)); ++// %} ++ ++// peephole ++// %{ ++// peepmatch (decI_rReg movI); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaI_rReg_immI(0.dst 1.src 0.src)); ++// %} ++ ++// peephole ++// %{ ++// peepmatch (addI_rReg_imm movI); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaI_rReg_immI(0.dst 1.src 0.src)); ++// %} ++ ++// peephole ++// %{ ++// peepmatch (incL_rReg movL); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaL_rReg_immL(0.dst 1.src 0.src)); ++// %} ++ ++// peephole ++// %{ ++// peepmatch (decL_rReg movL); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaL_rReg_immL(0.dst 1.src 0.src)); ++// %} ++ ++// peephole ++// %{ ++// peepmatch (addL_rReg_imm movL); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaL_rReg_immL(0.dst 1.src 0.src)); ++// %} ++ ++// peephole ++// %{ ++// peepmatch (addP_rReg_imm movP); ++// peepconstraint (0.dst == 1.dst); ++// peepreplace (leaP_rReg_imm(0.dst 1.src 0.src)); ++// %} ++ ++// // Change load of spilled value to only a spill ++// instruct storeI(memory mem, rRegI src) ++// %{ ++// match(Set mem (StoreI mem src)); ++// %} ++// ++// instruct loadI(rRegI 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)); ++%} ++ ++peephole ++%{ ++ peepmatch (loadL storeL); ++ peepconstraint (1.src == 0.dst, 1.mem == 0.mem); ++ peepreplace (storeL(1.mem 1.mem 1.src)); ++%} ++ ++//----------SMARTSPILL RULES--------------------------------------------------- ++// These must follow all instruction definitions as they use the names ++// defined in the instructions definitions. ++*/ +diff -uNr openjdk/src/hotspot/cpu/sw64/sw64Test.cpp afu11u/src/hotspot/cpu/sw64/sw64Test.cpp +--- openjdk/src/hotspot/cpu/sw64/sw64Test.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/sw64Test.cpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include ++ ++#include "precompiled.hpp" ++#include "code/codeBlob.hpp" ++#include "asm/macroAssembler.hpp" ++#include "runtime/stubCodeGenerator.hpp" ++ ++// hook routine called during JVM bootstrap to test AArch64 assembler ++ ++extern "C" void entry(CodeBuffer*); ++ ++ ++class X_Generator: public StubCodeGenerator { ++ public: ++ X_Generator(CodeBuffer *c, bool print_code = true) : StubCodeGenerator(c, print_code) {} ++ ++ ++ address generate_getGenerateInfo() { ++ StubCodeMark mark(this, "VM_Version", "getGenerateInfo"); ++ ++# define __ _masm-> ++ address start = __ pc(); ++ ++ __ movl(V0, c_rarg0); // Copy to eax we need a return value anyhow ++ __ xchgptr(V0, Address(c_rarg1, 0)); // automatic LOCK ++ __ ret(); ++ ++# undef __ ++ return start; ++ } ++}; ++ ++void directTestCode() ++{ ++ BufferBlob* b = BufferBlob::create("sw64Test", 500000); ++ CodeBuffer code(b); ++ MacroAssembler _masm(&code); ++ //entry(&code); ++#define _masm __ ++ ++#undef __ ++} ++ ++ ++extern "C" { ++ typedef void (*getGenerateStub_t)(void*); ++} ++static getGenerateStub_t getGenerateStub = NULL; ++ ++void sw64TestHook() ++{ ++#ifdef ASSERT ++ //direct test generatecode ++ { ++ directTestCode(); ++ } ++ ++ //test generation code by StubGenerator ++ { ++ { ++ ResourceMark rm; ++ ++ BufferBlob* stub_blob = BufferBlob::create("sw64TestHook_stub", 500000); ++ if (stub_blob == NULL) { ++ vm_exit_during_initialization("Unable to allocate sw64TestHook_stub"); ++ } ++ ++ CodeBuffer c(stub_blob); ++ X_Generator g(&c, false); ++ getGenerateStub = CAST_TO_FN_PTR(getGenerateStub_t, ++ g.generate_getGenerateInfo()); ++ } ++ ++ address arg0; ++ getGenerateStub_t((void*)arg0); ++ } ++ ++#endif ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/templateInterpreterGenerator_sw64.cpp afu11u/src/hotspot/cpu/sw64/templateInterpreterGenerator_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/templateInterpreterGenerator_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/templateInterpreterGenerator_sw64.cpp 2025-05-09 10:06:54.196292504 +0800 +@@ -0,0 +1,2042 @@ ++/* ++ * 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 "asm/macroAssembler.hpp" ++#include "gc/shared/barrierSetAssembler.hpp" ++#include "interpreter/bytecodeHistogram.hpp" ++#include "interpreter/interp_masm.hpp" ++#include "interpreter/interpreter.hpp" ++#include "interpreter/interpreterRuntime.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/debug.hpp" ++#include "utilities/macros.hpp" ++ ++#define __ _masm-> ++ ++// 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 ++int TemplateInterpreter::InterpreterCodeSize = JVMCI_ONLY(268) NOT_JVMCI(256) * 1024; ++ ++ ++const int method_offset = frame::interpreter_frame_method_offset * wordSize; ++const int bcp_offset = frame::interpreter_frame_bcp_offset * wordSize; ++const int locals_offset = frame::interpreter_frame_locals_offset * wordSize; ++ ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++ ++//----------------------------------------------------------------------------- ++ ++extern "C" void entry(CodeBuffer*); ++ ++//----------------------------------------------------------------------------- ++ ++address TemplateInterpreterGenerator::generate_StackOverflowError_handler() { ++ BLOCK_COMMENT("generate_StackOverflowError_handler enter"); //__ warn("TODO:check function right generate_StackOverflowError_handler jzy "); ++ address entry = __ pc(); ++ Register rax = V0; ++ ++#ifdef ASSERT ++ { ++ Label L; ++ __ lea(rax, Address(rfp, ++ frame::interpreter_frame_monitor_block_top_offset * ++ wordSize)); ++ __ cmpptr(rax, esp); // rax = maximal rsp for current rbp (stack ++ // grows negative) ++ __ jcc(Assembler::aboveEqual, L); // check if frame is complete ++ __ stop ("interpreter frame not set up"); ++ __ bind(L); ++ } ++#endif // ASSERT ++ // Restore bcp under the assumption that the current frame is still ++ // interpreted ++ __ restore_bcp(); ++ ++ // expression stack must be empty before entering the VM if an ++ // exception happened ++ __ empty_expression_stack(); ++ // throw exception ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_StackOverflowError)); ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() {SCOPEMARK_NAME(TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler, _masm) ++ address entry = __ pc(); ++ // The expression stack must be empty before entering the VM if an ++ // exception happened ++ __ empty_expression_stack(); ++ ++ Register rarg = c_rarg1; ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime:: ++ throw_ArrayIndexOutOfBoundsException), ++ rarg, c_rarg2); ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_ClassCastException_handler() {//__ warn("TODO:check function right generate_ClassCastException_handler jzy "); ++ address entry = __ pc(); ++ ++ // object is at TOS ++ Register rarg = c_rarg1; ++ __ pop(rarg); ++ ++ // expression stack must be empty before entering the VM if an ++ // exception happened ++ __ empty_expression_stack(); ++ ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime:: ++ throw_ClassCastException), ++ rarg);BLOCK_COMMENT("generate_ClassCastException_handler leave"); ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_exception_handler_common( ++ const char* name, const char* message, bool pass_oop) {SCOPEMARK_NAME(TemplateInterpreterGenerator::generate_exception_handler_common, _masm) ++ assert(!pass_oop || message == NULL, "either oop or message but not both"); ++ address entry = __ pc(); ++ ++ Register rarg = c_rarg1; ++ Register rarg2 = c_rarg2; ++ Register rax = V0; ++ ++ if (pass_oop) { ++ // object is at TOS ++ __ pop(rarg2); ++ } ++ // expression stack must be empty before entering the VM if an ++ // exception happened ++ __ empty_expression_stack(); ++ // setup parameters ++ __ lea(rarg, ExternalAddress((address)name)); ++ if (pass_oop) { ++ __ call_VM(rax, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime:: ++ create_klass_exception), ++ rarg, rarg2); ++ } else { ++ __ lea(rarg2, ExternalAddress((address)message)); ++ __ call_VM(rax, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), ++ rarg, rarg2); ++ } ++ // throw exception ++ __ jump(ExternalAddress(Interpreter::throw_exception_entry())); ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {SCOPEMARK_NAME(TemplateInterpreterGenerator::generate_return_entry_for, _masm); ++ address entry = __ pc(); ++ Register rax = FSR; ++ ++ // Restore stack bottom in case i2c adjusted stack ++ __ ldptr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ // and NULL it as marker that esp is now tos until next java call ++ __ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ ++ __ restore_bcp(); ++ __ restore_locals(); ++ ++ if (state == atos) { ++ Register mdp = rscratch1; ++ Register tmp = rscratch2; ++ __ profile_return_type(mdp, rax, tmp); ++ } ++ ++ const Register cache = rscratch1; ++ const Register index = rscratch2; ++ __ get_cache_and_index_at_bcp(cache, index, 1, index_size); ++ ++ const Register flags = cache; ++ __ ldw(flags, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); ++ __ andw(flags, ConstantPoolCacheEntry::parameter_size_mask, flags); ++ __ lea(esp, Address(esp, flags, Interpreter::stackElementScale())); ++ ++ const Register java_thread = rthread; ++ if (JvmtiExport::can_pop_frame()) { ++ __ check_and_handle_popframe(java_thread); ++ } ++ if (JvmtiExport::can_force_early_return()) { ++ __ check_and_handle_earlyret(java_thread); ++ } ++ ++ __ dispatch_next(state, step); ++ ++ return entry; ++} ++ ++ ++address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step, address continuation) {BLOCK_COMMENT("generate_deopt_entry_for enter");//__ warn("TODO:check function right generate_deopt_entry_for jzy "); ++ address entry = __ pc(); ++ // NULL last_sp until next java call ++ __ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ __ restore_bcp(); ++ __ restore_locals(); ++ Register rbx = rmethod; ++#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 || UseAOT) && state == vtos && step == 0) { ++ Label L; ++ __ ldbu(rcc, Address(rthread, JavaThread::pending_monitorenter_offset())); ++ __ jcc(Assembler::zero, L); ++ // Clear flag. ++ __ stb(R0, Address(rthread, JavaThread::pending_monitorenter_offset())); ++ // Satisfy calling convention for lock_method(). ++ __ get_method(rbx); ++ // Take lock. ++ lock_method(); ++ __ bind(L); ++ } else { ++#ifdef ASSERT ++ if (EnableJVMCI) { ++ Label L; ++ __ ldbu(rscratch3, Address(rthread, JavaThread::pending_monitorenter_offset())); ++ __ cmpw(rscratch3, R0); ++ __ jcc(Assembler::zero, L); ++ __ stop("unexpected pending monitor in deopt entry"); ++ __ bind(L); ++ } ++#endif ++ } ++#endif ++ // handle exceptions ++ { ++ Label L; ++ __ cmpptr(Address(rthread, Thread::pending_exception_offset()), R0); ++ __ jcc(Assembler::zero, L); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_pending_exception)); ++ __ should_not_reach_here("260"); ++ __ bind(L); ++ } ++ if (continuation == NULL) { ++ __ dispatch_next(state, step); ++ } else { ++ __ jump_to_entry(continuation); ++ }BLOCK_COMMENT("generate_deopt_entry_for leave"); ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_result_handler_for( ++ BasicType type) {BLOCK_COMMENT("generate_result_handler_for enter");//__ warn("TODO:check function right generate_result_handler_for jzy "); ++ address entry = __ pc(); ++ switch (type) { ++ case T_BOOLEAN: __ c2bool(V0); break; ++ case T_CHAR : __ zapnot(V0, 0x3, V0); break; ++ case T_BYTE : __ sign_extend_byte (V0); break; ++ case T_SHORT : __ sign_extend_short(V0); break; ++ case T_INT : /* nothing to do */ break; ++ case T_LONG : /* nothing to do */ break; ++ case T_VOID : /* nothing to do */ break; ++ case T_FLOAT : /* nothing to do */ break; ++ case T_DOUBLE : /* nothing to do */ break; ++ case T_OBJECT : ++ // retrieve result from frame ++ __ ldptr(V0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize)); ++ // and verify it ++ __ verify_oop(V0); ++ break; ++ default : ShouldNotReachHere(); ++ } ++ __ ret_sw(); // return from result handler ++ BLOCK_COMMENT("generate_result_handler_for leave"); ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_safept_entry_for( ++ TosState state, ++ address runtime_entry) {BLOCK_COMMENT("generate_safept_entry_for enter");//__ warn("TODO:check function right generate_safept_entry_for jzy "); ++ address entry = __ pc(); ++ __ push(state); ++ __ call_VM(noreg, runtime_entry); ++ __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));BLOCK_COMMENT("generate_safept_entry_for leave"); ++ 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 ++// ++// rmethod: method ++// ++void TemplateInterpreterGenerator::generate_counter_incr( ++ Label* overflow, ++ Label* profile_method, ++ Label* profile_method_continue) {SCOPEMARK_NAME(generate_counter_incr, _masm);//__ warn("TODO:check function right generate_counter_incr jzy "); ++ Label done; ++ Register rax = FSR; ++ Register rcx = rscratch1; ++ if (TieredCompilation) { ++ int increment = InvocationCounter::count_increment; ++ Label no_mdo; ++ if (ProfileInterpreter) { ++ // Are we profiling? ++ __ ldptr(rax, Address(rmethod, Method::method_data_offset())); ++ __ jcc(Assembler::zero, no_mdo, rax); ++ // Increment counter in the MDO ++ const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + ++ in_bytes(InvocationCounter::counter_offset())); ++ const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); ++ __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); ++ __ jmp(done); ++ } ++ __ bind(no_mdo); ++ // Increment counter in MethodCounters ++ const Address invocation_counter(rax, ++ MethodCounters::invocation_counter_offset() + ++ InvocationCounter::counter_offset()); ++ __ get_method_counters(rmethod, rax, done); ++ const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); ++ __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, ++ false, Assembler::zero, overflow); ++ __ bind(done); ++ } else { // not TieredCompilation ++ const Address backedge_counter(rax, ++ MethodCounters::backedge_counter_offset() + ++ InvocationCounter::counter_offset()); ++ const Address invocation_counter(rax, ++ MethodCounters::invocation_counter_offset() + ++ InvocationCounter::counter_offset()); ++ ++ __ get_method_counters(rmethod, rax, done); ++ ++ if (ProfileInterpreter) { // %%% Merge this into methodDataOop ++ __ ldws(rscratch2, Address(rax, ++ MethodCounters::interpreter_invocation_counter_offset())); ++ __ incrementw(rscratch2, 1); ++ __ stw(rscratch2, Address(rax, ++ MethodCounters::interpreter_invocation_counter_offset())); ++ } ++ // Update standard invocation counters ++ __ ldws(rcx, invocation_counter); ++ __ incrementw(rcx, InvocationCounter::count_increment); ++ __ stw(rcx, invocation_counter); // save invocation count ++ ++ __ ldws(rax, backedge_counter); // load backedge counter ++ __ andw(rax, InvocationCounter::count_mask_value, rax); ++ ++ __ addw(rcx, rax, rcx); // add both counters ++ ++ if (ProfileInterpreter && profile_method != NULL) { ++ // Test to see if we should create a method data oop ++ __ ldptr(rax, Address(rmethod, Method::method_counters_offset())); ++ __ ldw(rax, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); ++ __ cmpw(rcx, rax); ++ __ jcc(Assembler::less, *profile_method_continue); ++ ++ // if no method data exists, go to profile_method ++ __ test_method_data_pointer(rax, *profile_method); //this rax is ldw value ++ } ++ ++ __ ldptr(rax, Address(rmethod, Method::method_counters_offset())); ++ // Test to see if we should create a method data oop ++ __ cmpw(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); ++ __ jcc(Assembler::aboveEqual, *overflow); ++ __ bind(done); ++ } ++} ++ ++void TemplateInterpreterGenerator::generate_counter_overflow(Label& do_continue) {BLOCK_COMMENT("generate_counter_overflow enter"); //__ warn("TODO:check function right generate_counter_overflow jzy"); ++ ++ // Asm interpreter on entry ++ // rlocals - locals ++ // rbcp - bcp ++ // rmethod - method ++ // rfp - interpreter frame ++ ++ // On return (i.e. jump to entry_point) ++ // rmethod - method ++ // RA - return address of interpreter caller ++ // tos - the last parameter to Java method ++ // SP - sender_sp ++ ++ // InterpreterRuntime::frequency_counter_overflow takes two ++ // arguments, the first (thread) is passed by call_VM, the second ++ // indicates if the counter overflow occurs at a backwards branch ++ // (NULL bcp). We pass zero for it. 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). ++ Register rarg = c_rarg1; ++ __ movw(rarg, (u_int32_t)0); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::frequency_counter_overflow), ++ rarg); ++ ++ __ ldptr(rmethod, Address(rfp, method_offset)); // restore Method* ++ // Preserve invariant that r13/r14 contain bcp/locals of sender frame ++ // and jump to the interpreted entry. ++ __ jmp(do_continue);BLOCK_COMMENT("generate_counter_overflow leave"); ++} ++ ++// 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. ++// The expression stack grows down incrementally, so the normal guard ++// page mechanism will work for that. ++// ++// NOTE: Since the additional locals are also always pushed (wasn't ++// obvious in generate_method_entry) so the guard should work for them ++// too. ++// ++// Args: ++// c_rarg5: number of additional locals this frame needs (what we must check) ++// rmethod: Method* ++// ++void TemplateInterpreterGenerator::generate_stack_overflow_check(void) {BLOCK_COMMENT("generate_stack_overflow_check enter");//__ warn("TODO:check function right generate_stack_overflow_check jzy"); ++ // see if we've got enough room on the stack for locals plus overhead. ++ // the expression stack grows down incrementally, so the normal guard ++ // page mechanism will work for that. ++ // ++ // Registers live on entry: ++ // ++ // rmethod: Method* ++ // rdx: number of additional locals this frame needs (what we must check) ++ // register is special, should be same register in generate_normal_entry ++ ++ // killed: V0, rscratch2 ++ // NOTE: since the additional locals are also always pushed (wasn't obvious in ++ // generate_method_entry) so the guard should work for them too. ++ // ++ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; ++ ++ // total overhead size: entry_size + (saved fp thru expr stack bottom). ++ // be sure to change this if you add/subtract anything to/from the overhead area ++ const int overhead_size = ++ -(frame::interpreter_frame_initial_sp_offset * wordSize) + entry_size; ++ ++ const int page_size = os::vm_page_size(); ++ ++ Label after_frame_check; ++ //Register rdx = c_rarg5;//TODO:why set this? jzy ++ //Register rax = V0; ++ ++ // see if the frame is greater than one page in size. If so, ++ // then we need to verify there is enough stack space remaining ++ // for the additional locals. ++ __ cmpw(rdx, (page_size - overhead_size) / Interpreter::stackElementSize); ++ __ jcc(Assembler::belowEqual, after_frame_check); ++ ++ // compute sp as if this were going to be the last frame on ++ // the stack before the red zone ++ ++ ++ Label after_frame_check_pop; ++ ++ const Address stack_limit(rthread, JavaThread::stack_overflow_limit_offset()); ++ ++ // locals + overhead, in bytes ++ __ movl(rax, rdx); ++ __ slll(rax, Interpreter::logStackElementSize, rax); // Convert parameter count to bytes. ++ __ addptr(rax, overhead_size, rax); ++ ++#ifdef ASSERT ++ Label limit_okay; ++ // Verify that thread stack overflow limit is non-zero. ++ __ cmpptr(stack_limit, R0); ++ __ jcc(Assembler::notEqual, limit_okay); ++ __ stop("stack overflow limit is zero"); ++ __ bind(limit_okay); ++#endif ++ ++ // Add locals/frame size to stack limit. ++ __ ldptr(rscratch2, stack_limit); ++ __ addptr(rax, rscratch2, rax); ++ ++ // check against the current stack bottom ++ __ cmpptr(esp, rax); ++ __ jcc(Assembler::above, after_frame_check); ++ ++ // Restore sender's sp as SP. 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. ++ ++ __ movl(esp, rsender); ++ ++ // Note: 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"); ++ __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry())); ++ ++ // all done with frame size check ++ __ bind(after_frame_check);BLOCK_COMMENT("generate_stack_overflow_check leave"); ++} ++ ++// Allocate monitor and lock method (asm interpreter) ++// ++// Args: ++// rmethod: Method* ++// rlocals: locals ++// ++// Kills: ++// rax ++// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) ++// rscratch1, rscratch2 (scratch regs) ++void TemplateInterpreterGenerator::lock_method() {BLOCK_COMMENT("lock_method enter"); ++ const Register rbx = rmethod; ++ const Register rax = FSR; ++ ++ // synchronize method ++ const Address access_flags(rbx, Method::access_flags_offset()); ++ const Address monitor_block_top( ++ rfp, ++ frame::interpreter_frame_monitor_block_top_offset * wordSize); ++ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; ++ ++#ifdef ASSERT ++ { ++ Label L; ++ __ ldw(rax, access_flags); ++ __ testw(rax, JVM_ACC_SYNCHRONIZED); ++ __ jcc(Assembler::notZero, L); ++ __ stop("method doesn't need synchronization"); ++ __ bind(L); ++ } ++#endif // ASSERT ++ ++ // get synchronization object ++ { ++ Label done; ++ __ ldw(rax, access_flags); ++ __ testw(rax, JVM_ACC_STATIC); ++ // get receiver (assume this is frequent case) ++ __ ldptr(rax, Address(rlocals, Interpreter::local_offset_in_bytes(0))); ++ __ jcc(Assembler::zero, done); ++ __ load_mirror(rax, rbx); ++ ++#ifdef ASSERT ++ { ++ Label L; ++ __ jcc(Assembler::notZero, L, rax); ++ __ stop("synchronization object is NULL"); ++ __ bind(L); ++ } ++#endif // ASSERT ++ ++ __ bind(done); ++ } ++ ++ // add space for monitor & lock ++ __ subptr(esp, entry_size, esp); // add space for a monitor entry ++ __ stptr(esp, monitor_block_top); // set new monitor block top ++ // store object ++ __ stptr(rax, Address(esp, BasicObjectLock::obj_offset_in_bytes())); ++ const Register lockreg = c_rarg1; ++ __ movl(lockreg, esp); // object address ++ __ lock_object(lockreg);BLOCK_COMMENT("lock_method leave"); ++} ++ ++// Generate a fixed interpreter frame. This is identical setup for ++// interpreted methods and for native methods hence the shared code. ++// ++// Args: ++// RA: return address ++// rbx: Method* ++// r14: pointer to locals ++// r13: sender sp ++// rdx: cp cache ++void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {SCOPEMARK_NAME(generate_fixed_frame, _masm); ++ const Register rbx = rmethod; ++ const Register rdx = rscratch1; ++ ++ // initialize fixed part of activation frame ++ __ enter(); // save old & set new rbp ++ __ push(rsender); // set sender sp ++ __ push((int)NULL_WORD); // leave last_sp as null ++ __ ldptr(rbcp, Address(rbx, Method::const_offset())); // get ConstMethod* ++ __ lea(rbcp, Address(rbcp, ConstMethod::codes_offset())); // get codebase ++ __ push(rbx); // save Method* ++ // Get mirror and store it in the frame as GC root for this Method* ++ __ load_mirror(rdx, rbx, rscratch2); // ++ __ push(rdx); ++ if (ProfileInterpreter) { // ++ Label method_data_continue; ++ __ ldptr(rdx, Address(rbx, in_bytes(Method::method_data_offset()))); ++ __ testptr(rdx, rdx); ++ __ jcc(Assembler::zero, method_data_continue); ++ __ addptr(rdx, in_bytes(MethodData::data_offset()), rdx); ++ __ bind(method_data_continue); ++ __ push(rdx); // set the mdp (method data pointer) ++ } else { ++ __ push(0); ++ } ++ ++ __ ldptr(rdx, Address(rbx, Method::const_offset())); ++ __ ldptr(rdx, Address(rdx, ConstMethod::constants_offset())); ++ __ ldptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes())); ++ __ push(rdx); // set constant pool cache ++ __ push(rlocals); // set locals pointer ++ if (native_call) { ++ __ push(0); // no bcp ++ } else { ++ __ push(rbcp); // set bcp ++ } ++ __ push(0); // reserve word for pointer to expression stack bottom ++ __ stptr(esp, Address(esp, 0)); // set expression stack bottom ++} ++ ++// End of helpers ++ ++// Method entry for java.lang.ref.Reference.get. ++address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {BLOCK_COMMENT("generate_Reference_get_entry enter"); ++ // 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_entry. ++ // ++ // rmethod: Method* ++ // rsender: senderSP must preserve for slow path, set SP to it on fast path (rsender) ++ ++ address entry = __ pc(); ++ ++ const int referent_offset = java_lang_ref_Reference::referent_offset; ++ guarantee(referent_offset > 0, "referent offset not initialized"); ++ ++ Label slow_path; ++ Register rax = V0; ++ ++ // Check if local 0 != NULL ++ // If the receiver is null then it is OK to jump to the slow path. ++ __ ldptr(rax, Address(esp, 0)); ++ ++// __ testptr(rax, rax); ++ __ jcc(Assembler::zero, slow_path, rax); ++ ++ // Load the value of the referent field. ++ const Address field_address(rax, referent_offset); ++ ++ //__ push(RA); ++ __ load_heap_oop(rax, field_address, /*tmp1*/ rscratch1, /*tmp_thread*/ rscratch2, ON_WEAK_OOP_REF); ++ //__ pop(RA); ++ ++ __ movl(esp, rsender); // set sp to sender sp ++ __ ret_sw(); ++ ++ // generate a vanilla interpreter entry as the slow path ++ __ bind(slow_path); ++ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); ++ BLOCK_COMMENT("generate_Reference_get_entry leave"); ++ return entry; ++} ++ ++void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) {SCOPEMARK_NAME(bang_stack_shadow_pages, _masm) ++ // 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 receiever, 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); ++ } ++ } ++} ++ ++ ++/** ++ * Method entry for static native methods: ++ * int java.util.zip.CRC32.update(int crc, int b) ++ */ ++address TemplateInterpreterGenerator::generate_CRC32_update_entry() {BLOCK_COMMENT("generate_CRC32_update_entry enter"); ++ if (UseCRC32Intrinsics) { ++ address entry = __ pc(); ++ ++ Label slow_path; ++ // If we need a safepoint check, generate full interpreter entry. ++// __ mov(GP, SafepointSynchronize::address_of_state()); ++// __ lw(AT, GP, 0); ++// __ mov(GP, (SafepointSynchronize::_not_synchronized)); ++// __ bne_c(AT, GP, slow_path); ++ __ safepoint_poll(slow_path, rthread, rscratch1); ++ ++ // We don't generate local frame and don't align stack because ++ // we call stub code and there is no safepoint on this path. ++ // Load parameters ++ const Register crc = V0; // crc ++ const Register val = A0; // source java byte value ++ const Register tbl = A1; // scratch ++ ++ // Arguments are reversed on java expression stack ++ __ ldw(val, 0, esp); // byte value ++ __ ldw(crc, wordSize, esp); // Initial CRC ++ ++ __ lea(tbl, ExternalAddress(StubRoutines::crc_table_addr())); ++ __ notw(crc, crc); // ~crc ++ __ update_byte_crc32(crc, val, tbl); ++ __ notw(crc ,crc); // ~crc ++ ++ // result in V0 ++ // _areturn ++ __ addl(rsender, R0, esp); // set sp to sender sp ++ __ ret_sw(); ++ ++ // generate a vanilla native entry as the slow path ++ __ bind(slow_path); ++ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); ++ return entry; ++ }BLOCK_COMMENT("generate_CRC32_update_entry leave"); ++ 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) {BLOCK_COMMENT("generate_CRC32_updateBytes_entry enter"); ++ if (UseCRC32Intrinsics) { ++ address entry = __ pc(); ++ ++ // // rbx,: Method* ++ // // r13: senderSP must preserved for slow path, set SP to it on fast path ++ // // If we need a safepoint check, generate full interpreter entry. ++ // We don't generate local frame and don't align stack because ++ // // we call stub code and there is no safepoint on this path. ++ Label slow_path; ++// __ mov(GP, SafepointSynchronize::address_of_state()); ++// __ lw(AT, GP, 0); ++// __ mov(GP, (SafepointSynchronize::_not_synchronized)); ++// __ bne_c(AT, GP, slow_path); ++ __ safepoint_poll(slow_path, rthread, rscratch1); ++ ++ // Load parameters ++ const Register crc = A0; // crc ++ const Register buf = A1; // source java byte array address ++ const Register len = A2; // length ++ const Register off = len; // offset (never overlaps with 'len') ++// const Register table = A3; // crc_table address ++ ++ // // Arguments are reversed on java expression stack ++ // // Calculate address of start element ++ if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { ++ __ ldl(buf, 2 * wordSize, esp); // long buf ++ __ ldw(off, 1 * wordSize, esp); // offset ++ __ zapnot(off, 0xF, off); ++ __ addl(buf, off, buf); // + offset ++ __ ldw(crc, 4 * wordSize, esp); // Initial CRC ++ } else { ++ __ ldw(off, 1 * wordSize, esp); ++ __ zapnot(off, 0xF, off); ++ __ ldl(buf, 2 * wordSize, esp); // byte[] array ++ __ addl(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // + header size ++ __ addl(buf, off, buf); // offset ++ __ ldw(crc, 3 * wordSize, esp); // Initial CRC ++ } ++ // Can now load 'len' since we're finished with 'off' ++ __ ldw(len, 0 * wordSize, esp); ++ __ zapnot(len, 0xF, len); ++ __ enter(); ++ //__ stop("use SharedRuntime::updateBytesCRC32? jzy"); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::updateBytesCRC32), 3); ++ // _areturn ++ __ leave(); ++ __ daddu(esp, rsender, R0); // set sp to sender sp ++ __ ret_sw(); ++ // generate a vanilla native entry as the slow path ++ __ BIND(slow_path); ++ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); ++ return entry; ++ }BLOCK_COMMENT("generate_CRC32_updateBytes_entry leave"); ++ 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) { ++ __ should_not_reach_here("generate_CRC32C_updateBytes_entry not implement"); ++ return NULL; ++} ++ ++// 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) {SCOPEMARK_NAME(generate_native_entry, _masm); ++ // determine code generation flags ++ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; ++ // rsender: sender's sp ++ // rmethod: Method* ++ const Register rbx = rmethod; ++ const Register rcx = rscratch1; ++ const Register rax = V0; ++ address entry_point = __ pc(); ++ ++ const Address constMethod (rbx, Method::const_offset()); ++ const Address access_flags (rbx, Method::access_flags_offset()); ++ const Address size_of_parameters(rcx, ConstMethod:: ++ size_of_parameters_offset()); ++ ++ ++ // get parameter size (always needed) ++ __ ldptr(rcx, constMethod); ++ __ load_unsigned_short(rcx, size_of_parameters); ++ ++ // 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 ++ ++ // rmethod: Method* ++ // rcx: size of parameters ++ // rbcp: sender sp //? jzy ++ //__ pop(rax); // different from x86, sw donot need return address ++ ++ // for natives the size of locals is zero ++ ++ // compute beginning of parameters (rlocals) ++ __ lea(rlocals, Address(esp, rcx, Interpreter::stackElementScale(), -wordSize)); ++ ++ // add 2 zero-initialized slots for native calls ++ // initialize result_handler slot ++ __ push((int) NULL_WORD); ++ // slot for oop temp ++ // (static native method holder mirror/jni oop result) ++ __ push((int) NULL_WORD); ++ ++ // initialize fixed part of activation frame ++ generate_fixed_frame(true); ++ ++ // make sure method is native & not abstract ++#ifdef ASSERT ++ __ ldw(rax, access_flags); ++ { ++ Label L; ++ __ testw(rax, JVM_ACC_NATIVE); ++ __ jcc(Assembler::notZero, L); ++ __ stop("tried to execute non-native method as native"); ++ __ bind(L); ++ } ++ { ++ Label L; ++ __ testw(rax, JVM_ACC_ABSTRACT); ++ __ jcc(Assembler::zero, L); ++ __ stop("tried to execute abstract method in interpreter"); ++ __ bind(L); ++ } ++#endif ++ ++ // 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. The remove_activation will ++ // check this flag. ++ Register thread1 = rthread; ++ const Address do_not_unlock_if_synchronized(thread1, ++ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); ++ __ stbool(true, do_not_unlock_if_synchronized); ++ ++ // increment invocation count & check for overflow ++ Label invocation_counter_overflow; ++ if (inc_counter) { ++ generate_counter_incr(&invocation_counter_overflow, NULL, NULL); ++ } ++ ++ Label continue_after_compile; ++ __ bind(continue_after_compile); ++ ++ bang_stack_shadow_pages(true); ++ ++ // reset the _do_not_unlock_if_synchronized flag ++ __ stbool(false, 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 { ++ // no synchronization necessary ++#ifdef ASSERT ++ { ++ Label L; ++ __ ldw(rax, access_flags); ++ __ testw(rax, JVM_ACC_SYNCHRONIZED); ++ __ jcc(Assembler::zero, L); ++ __ stop("method needs synchronization"); ++ __ bind(L); ++ } ++#endif ++ } ++ ++ // start execution ++#ifdef ASSERT ++ { ++ Label L; ++ const Address monitor_block_top(rfp, ++ frame::interpreter_frame_monitor_block_top_offset * wordSize); ++ __ ldptr(rax, monitor_block_top); ++ __ cmpptr(rax, esp); ++ __ jcc(Assembler::equal, L); ++ __ stop("broken stack frame setup in interpreter"); ++ __ bind(L); ++ } ++#endif ++ ++ // jvmti support ++ __ notify_method_entry(); ++ ++ // work registers ++ const Register method = rmethod; ++ const Register thread = rthread; ++ const Register t = T12; //will use in call instruction in sw ++ ++ // allocate space for parameters ++ __ get_method(method); ++ __ ldptr(t, Address(method, Method::const_offset())); ++ __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset())); ++ ++ __ slll(t, Interpreter::logStackElementSize, t); ++ ++ __ subptr(esp, t, esp); ++ //__ subptr(esp, frame::arg_reg_save_area_bytes, esp); // windows ++ __ andptr(esp, -16, esp); // must be 16 byte boundary (see amd64 ABI) sw need this ? jzy ++ // get signature handler ++ __ block_comment(" get signature handler"); ++ { ++ Label L; ++ __ ldptr(t, Address(method, Method::signature_handler_offset())); ++ //__ testptr(t, t); ++ __ jcc(Assembler::notZero, L, t); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::prepare_native_call), ++ method); ++ __ get_method(method); ++ __ ldptr(t, Address(method, Method::signature_handler_offset())); ++ __ bind(L); ++ } ++ ++ // call signature handler ++ assert(InterpreterRuntime::SignatureHandlerGenerator::from() == rlocals, ++ "adjust this code"); ++ assert(InterpreterRuntime::SignatureHandlerGenerator::to() == esp, ++ "adjust this code"); ++ assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == rscratch1, ++ "adjust this code"); ++ ++ // The generated handlers do not touch RBX (the method oop). ++ // However, large signatures cannot be cached and are generated ++ // each time here. The slow-path generator can do a GC on return, ++ // so we must reload it after the call. ++ __ call(t); ++ __ get_method(method); // slow path can do a GC, reload RBX ++ ++ ++ // result handler is in V0 ++ // set result handler ++ __ stptr(rax, ++ Address(rfp, ++ (frame::interpreter_frame_result_handler_offset) * wordSize)); ++ ++ // pass mirror handle if static call ++ { ++ Label L; ++ __ ldw(t, Address(method, Method::access_flags_offset())); ++ __ testw(t, JVM_ACC_STATIC); ++ __ jcc(Assembler::zero, L); ++ // get mirror ++ __ load_mirror(t, method, rax); ++ // copy mirror into activation frame ++ __ stptr(t, ++ Address(rfp, frame::interpreter_frame_oop_temp_offset * wordSize)); ++ // pass handle to mirror ++ __ lea(c_rarg1, ++ Address(rfp, frame::interpreter_frame_oop_temp_offset * wordSize)); ++ __ bind(L); ++ } ++ ++ // get native function entry point ++ { ++ Label L; ++ __ ldptr(rax, Address(method, Method::native_function_offset())); ++ ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry()); ++ __ cmpptr(rax, unsatisfied.addr()); ++ __ jcc(Assembler::notEqual, L); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::prepare_native_call), ++ method); ++ __ get_method(method); ++ __ ldptr(rax, Address(method, Method::native_function_offset())); ++ __ bind(L); ++ } ++ ++ // pass JNIEnv ++ __ lea(c_rarg0, Address(rthread, JavaThread::jni_environment_offset())); ++ ++ // Set the last Java PC in the frame anchor to be the return address from ++ // the call to the native method: this will allow the debugger to ++ // generate an accurate stack trace. ++ Label native_return; ++ __ set_last_Java_frame(esp, rfp, native_return, rscratch1); //TODO:check jzy ++ ++ // change thread state ++#ifdef ASSERT ++ { ++ Label L; ++ __ ldwu(t, Address(thread, JavaThread::thread_state_offset())); ++ __ cmpw(t, _thread_in_Java); ++ __ jcc(Assembler::equal, L); ++ __ stop("Wrong thread state in native stub"); ++ __ bind(L); ++ } ++#endif ++ ++ // Change state to native ++ __ mov_immediate32(rscratch1, _thread_in_native); ++ __ stw(rscratch1, Address(thread, JavaThread::thread_state_offset())); ++ ++ // call native method ++ __ movl(t, rax); //SW ABI ++ __ call(t, &native_return);//t == T12 ++// __ bind(native_return); ++ // result potentially in V0 or f0 ++ ++ // via _last_native_pc and not via _last_jave_sp ++ // NOTE: the order of theses push(es) is known to frame::interpreter_frame_result. ++ // If the order changes or anything else is added to the stack the code in ++ // interpreter_frame_result will have to be changed. ++ //FIXME, should modify here ++ // save return value to keep the value from being destroyed by other calls ++ __ push_d(FSF); //? jzy ++ __ push(V0); ++ ++ // change thread state ++ __ mov_immediate32(rscratch1, _thread_in_native_trans); ++ __ stw(rscratch1, Address(thread, JavaThread::thread_state_offset())); ++ ++ if (os::is_MP()) { ++ if (UseMembar) { ++ // Force this write out before the read below ++ __ memb(); ++ } else { ++ // Write serialization page so VM thread can do a pseudo remote membar. ++ // We use the current thread pointer to calculate a thread specific ++ // offset to write to within the page. This minimizes bus traffic ++ // due to cache line collision. ++ __ serialize_memory(thread, rscratch1); ++ } ++ } ++ ++ // check for safepoint operation in progress and/or pending suspend requests ++ { ++ Label Continue; ++ Label slow_path; ++ ++ __ safepoint_poll(slow_path, rthread, rscratch2); ++ ++ __ cmpw(Address(thread, JavaThread::suspend_flags_offset()), R0); ++ __ jcc(Assembler::equal, Continue); ++ __ bind(slow_path); ++ ++ // Don't use call_VM as it will see a possible pending exception ++ // and forward it and never return here preventing us from ++ // clearing _last_native_pc down below. Also can't use ++ // call_VM_leaf either as it will check to see if r13 & r14 are ++ // preserved and correspond to the bcp/locals pointers. So we do a ++ // runtime call by hand. ++ // ++ __ movl(c_rarg0, rthread); ++ __ movl(r12_heapbase, esp); // remember sp (can only use r12 if not using call_VM) ++// __ subptr(esp, frame::arg_reg_save_area_bytes); // windows ++ __ subptr(esp, 16, esp); // align stack as required by ABI ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); ++ __ movl(esp, r12_heapbase); // restore sp ++ __ reinit_heapbase(); ++ __ bind(Continue); ++ } ++ ++ // change thread state ++ __ mov_immediate32(rscratch1, _thread_in_Java); ++ __ stw(rscratch1, Address(thread, JavaThread::thread_state_offset())); ++ ++ // reset_last_Java_frame ++ __ reset_last_Java_frame(thread, true); ++ ++ if (CheckJNICalls) { ++ // clear_pending_jni_exception_check ++ __ stptr(R0, Address(thread, JavaThread::pending_jni_exception_check_fn_offset())); ++ } ++ ++ // reset handle block ++ __ ldptr(t, Address(thread, JavaThread::active_handles_offset())); ++ __ stw(R0, Address(t, JNIHandleBlock::top_offset_in_bytes())); ++ ++ // If result is an oop unbox and store it in frame where gc will see it ++ // and result handler will pick it up ++ ++ { ++ Label no_oop, not_weak, store_result; ++ __ lea(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT))); ++ __ cmpptr(t, Address(rfp, frame::interpreter_frame_result_handler_offset*wordSize)); ++ __ jcc(Assembler::notEqual, no_oop); ++ // retrieve result ++ __ pop(rax); ++ // Unbox oop result, e.g. JNIHandles::resolve value. ++ __ resolve_jobject(rax /* value */, ++ thread /* thread */, ++ t /* tmp */); ++ __ stptr(rax, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize)); ++ // keep stack depth as expected by pushing oop which will eventually be discarded ++ __ push(rax); ++ __ BIND(no_oop); ++ } ++ { ++ Label no_reguard; ++ __ cmpptr(Address(thread, JavaThread::stack_guard_state_offset()), ++ JavaThread::stack_guard_yellow_reserved_disabled); ++ __ jcc(Assembler::notEqual, no_reguard); ++ ++ __ pushad(); ++ __ movl(r12_heapbase, esp);// ++ __ andptr(esp, 16, esp); // align stack as required by ABI ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages))); ++ __ movl(esp, r12_heapbase); ++ __ popad(); ++ //add for compressedoops ++ __ reinit_heapbase(); ++ __ BIND(no_reguard); ++ } ++ ++ ++ // The method register is junk from after the thread_in_native transition ++ // until here. Also can't call_VM until the bcp has been ++ // restored. Need bcp for throwing exception below so get it now. ++ __ get_method(method); ++ ++ __ ldptr(rbcp, Address(method, Method::const_offset())); // get ConstMethod* ++ __ lea(rbcp, Address(rbcp, in_bytes(ConstMethod::codes_offset()))); ++ // handle exceptions (exception handling will handle unlocking!) ++ { ++ Label L; ++ __ cmpptr(Address(thread, Thread::pending_exception_offset()),R0); ++ __ jcc(Assembler::zero, L); ++ // Note: At some point we may want to unify this with the code ++ // used in call_VM_base(); i.e., we should use the ++ // StubRoutines::forward_exception code. For now this doesn't work ++ // here because the rsp is not correctly set at this point. ++ __ MacroAssembler::call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_pending_exception)); ++ __ should_not_reach_here("1186"); ++ __ BIND(L); ++ } ++ ++ // do unlocking if necessary ++ { ++ Label L; ++ __ ldw(t, Address(method, Method::access_flags_offset())); ++ __ testw(t, JVM_ACC_SYNCHRONIZED); ++ __ jcc(Assembler::zero, L); ++ // the code below should be shared with interpreter macro ++ // assembler implementation ++ { ++ Label unlock; ++ // 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. ++ const Address monitor(rfp, ++ (int)(frame::interpreter_frame_initial_sp_offset * ++ wordSize - (int)sizeof(BasicObjectLock))); ++ ++ const Register regmon = c_rarg1; ++ ++ // monitor expect in c_rarg1 for slow unlock path ++ __ lea(regmon, monitor); // address of first monitor ++ ++ __ ldptr(t, Address(regmon, BasicObjectLock::obj_offset_in_bytes())); ++ __ testptr(t, t); ++ __ jcc(Assembler::notZero, unlock); ++ ++ // Entry already unlocked, need to throw exception ++ __ MacroAssembler::call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_illegal_monitor_state_exception)); ++ __ should_not_reach_here("1220"); ++ ++ __ BIND(unlock); ++ __ unlock_object(regmon); ++ } ++ __ BIND(L); ++ } ++ ++ // jvmti support ++ // Note: This must happen _after_ handling/throwing any exceptions since ++ // the exception handler code notifies the runtime of method exits ++ // too. If this happens before, method entry/exit notifications are ++ // not properly paired (was bug - gri 11/22/99). ++ __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);// ++ ++ // restore potential result in edx:eax, call result handler to ++ // restore potential result in ST0 & handle result ++ ++ __ pop(rax); ++ __ pop_d(); ++ __ ldptr(t, Address(rfp, ++ (frame::interpreter_frame_result_handler_offset) * wordSize)); ++ __ call(t); ++ ++ // remove activation ++ __ ldptr(t, Address(rfp, ++ frame::interpreter_frame_sender_sp_offset * ++ wordSize)); // get sender sp ++ __ leave(); // remove frame anchor ++ //__ pop(rdi); // get return address TODO:where set? jzy ++ __ movl(esp, t); // set sp to sender sp ++ __ jmp(RA); // return address, set RA in leave() ++ ++ if (inc_counter) { ++ // Handle overflow of counter and compile method ++ __ bind(invocation_counter_overflow); ++ generate_counter_overflow(continue_after_compile); ++ } ++ ++ return entry_point; ++} ++ ++// Abstract method entry ++// Attempt to execute abstract method. Throw exception ++address TemplateInterpreterGenerator::generate_abstract_entry(void) {BLOCK_COMMENT("generate_abstract_entry enter"); ++ // rmethod: methodOop ++ // V0: receiver (unused) ++ // rsender : sender 's sp ++ address entry_point = __ pc(); ++ ++ // abstract method entry ++ __ empty_expression_stack(); ++ __ restore_bcp(); ++ __ restore_locals(); ++ // throw exception ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorWithMethod), rmethod); ++ // the call_VM checks for exception, so we should never return here. ++ __ should_not_reach_here("1277"); ++BLOCK_COMMENT("generate_abstract_entry leave"); ++ return entry_point; ++} ++ ++// ++// Generic interpreted method entry to (asm) interpreter ++// ++address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {SCOPEMARK_NAME(generate_normal_entry, _masm) ++ // determine code generation flags ++ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; ++ ++ // rmethod: Method* ++ // rsender: sender 's sp ++ //const Register rbx = rmethod; ++ //const Register rdx = c_rarg5;//special,should be same register in generate_stack_overflow_check ++ //const Register rcx = c_rarg4; ++ //const Register rax = V0; ++ address entry_point = __ pc(); ++ ++ const Address constMethod(rbx, Method::const_offset()); ++ const Address access_flags(rbx, Method::access_flags_offset()); ++ const Address size_of_parameters(rdx, ++ ConstMethod::size_of_parameters_offset()); ++ const Address size_of_locals(rdx, ConstMethod::size_of_locals_offset()); ++ ++ ++ // get parameter size (always needed) ++ __ ldptr(rdx, constMethod); ++ __ ldhu(rcx, size_of_parameters); ++ ++ // rmethod: Method* ++ // rcx: size of parameters ++ // rsender: sender 's sp ,could be different frome sp if we call via c2i ++ ++ ++ __ ldhu(rdx, size_of_locals);// get size of locals in words ++ __ subl(rdx, rcx, rdx);// rdx = no. of additional locals ++ ++ // see if we've got enough room on the stack for locals plus overhead. ++ generate_stack_overflow_check(); // ++ ++// // get return address ++// __ pop(rax);// x86 pushes RA on stack, so pops here, we haven't push ++ ++ // compute beginning of parameters (rlocals) ++ __ lea(rlocals, Address(esp, rcx, Interpreter::stackElementScale(), -wordSize)); ++ ++ // rdx - # of additional locals ++ // allocate space for locals ++ // explicitly initialize locals ++ { ++ Label exit, loop; ++ __ jcc(Assembler::lessEqual, exit, rdx); // do nothing if rdx <= 0 ++ __ bind(loop); ++ __ push((int)NULL_WORD); // initialize local variables ++ __ decrementl(rdx); // until everything initialized ++ __ jcc(Assembler::greater, loop, rdx); ++ __ bind(exit); ++ } ++ ++ // initialize fixed part of activation frame ++ generate_fixed_frame(false); ++ ++ // make sure method is not native & not abstract ++#ifdef ASSERT ++ __ ldw(rax, access_flags); ++ { ++ Label L; ++ __ testw(rax, JVM_ACC_NATIVE); ++ __ jcc(Assembler::zero, L); ++ __ stop("tried to execute native method as non-native"); ++ __ bind(L); ++ } ++ { ++ Label L; ++ __ testw(rax, JVM_ACC_ABSTRACT); ++ __ jcc(Assembler::zero, L); ++ __ stop("tried to execute abstract method in interpreter"); ++ __ bind(L); ++ } ++#endif ++ ++ // 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. The remove_activation ++ // will check this flag. ++ ++ const Register thread = rthread; ++ const Address do_not_unlock_if_synchronized(thread, ++ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); ++ __ ldi(rscratch1, 1, R0); ++ __ stb(rscratch1, do_not_unlock_if_synchronized); ++ ++ __ profile_parameters_type(rax, rcx, rdx); // ++ // increment invocation count & check for overflow ++ Label invocation_counter_overflow; ++ Label profile_method; ++ Label profile_method_continue; ++ if (inc_counter) { ++ generate_counter_incr(&invocation_counter_overflow, ++ &profile_method, ++ &profile_method_continue); ++ if (ProfileInterpreter) { ++ __ bind(profile_method_continue); ++ } ++ } ++ ++ Label continue_after_compile; ++ __ bind(continue_after_compile); ++ ++ // check for synchronized interpreted methods ++ bang_stack_shadow_pages(false); ++ ++ // reset the _do_not_unlock_if_synchronized flag ++ __ ldi(rscratch1, 0, R0); ++ __ stb(rscratch1, 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) { ++ // Allocate monitor and lock method ++ lock_method(); ++ } else { ++ // no synchronization necessary ++#ifdef ASSERT ++ { ++ Label L; ++ __ ldw(rax, access_flags); ++ __ testw(rax, JVM_ACC_SYNCHRONIZED); ++ __ jcc(Assembler::zero, L); ++ __ stop("method needs synchronization"); ++ __ bind(L); ++ } ++#endif ++ } ++ ++ // start execution ++#ifdef ASSERT ++ { ++ Label L; ++ const Address monitor_block_top (rfp, ++ frame::interpreter_frame_monitor_block_top_offset * wordSize); ++ __ ldptr(rax, monitor_block_top); ++ __ cmpptr(rax, esp); ++ __ jcc(Assembler::equal, L); ++ __ stop("broken stack frame setup in interpreter"); ++ __ bind(L); ++ } ++#endif ++ ++ // jvmti support ++ __ notify_method_entry(); ++ __ block_comment("start to execute bytecode"); ++ __ dispatch_next(vtos); ++ ++ // invocation counter overflow ++ 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(); ++ __ get_method(rbx); ++ __ jmp(profile_method_continue); ++ } ++ // Handle overflow of counter and compile method ++ __ bind(invocation_counter_overflow); ++ generate_counter_overflow(continue_after_compile); ++ } ++ ++ return entry_point; ++} ++ ++//----------------------------------------------------------------------------- ++// Exceptions ++ ++void TemplateInterpreterGenerator::generate_throw_exception() {BLOCK_COMMENT("generate_throw_exception enter");//__ warn("TODO:check function right generate_throw_exception jzy "); ++ // Entry point in previous activation (i.e., if the caller was ++ // interpreted) ++ Interpreter::_rethrow_exception_entry = __ pc(); ++ Register rax = V0; ++ ++ // Restore sp to interpreter_frame_last_sp even though we are going ++ // to empty the expression stack for the exception processing. ++ __ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ // rax: exception ++ // rdx: return address/pc that threw exception ++ __ restore_bcp(); // r13/rsi points to call/send ++ __ restore_locals(); ++ //add for compressedoops ++ __ reinit_heapbase(); // restore r12_heapbase as heapbase. ++ // Entry point for exceptions thrown within interpreter code ++ Interpreter::_throw_exception_entry = __ pc(); ++ // expression stack is undefined here ++ // V0: exception ++ // rbcp: exception bcp ++ __ verify_oop(rax); ++ Register rarg = c_rarg1; ++ __ movl(rarg, rax); ++ ++ // 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_VM(rdx, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::exception_handler_for_exception), ++ rarg); ++ // V0: exception handler entry point ++ // rdx: preserved exception oop ++ // rbcp: bcp for exception handler ++ ++ __ push_ptr(rdx);// push exception which is now the only value on the stack ++ __ jmp(rax); // jump to exception handler (may be _remove_activation_entry!) ++ ++ // 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 ++ // V0: exception ++ // rbcp: exception bcp ++ ++ // ++ // JVMTI PopFrame support ++ // ++ ++ Interpreter::_remove_activation_preserving_args_entry = __ pc(); ++ __ empty_expression_stack(); ++ // Set the popframe_processing bit in pending_popframe_condition ++ // indicating that we are currently handling popframe, so that ++ // call_VMs that may happen later do not trigger new popframe ++ // handling cycles. ++ const Register thread = rthread; ++ __ ldw(rdx, Address(thread, JavaThread::popframe_condition_offset())); ++ __ orw(rdx, JavaThread::popframe_processing_bit, rdx); ++ __ stw(rdx, Address(thread, JavaThread::popframe_condition_offset())); ++ ++ { ++ // 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; ++ Register rarg = c_rarg1; // ++ __ ldptr(rarg, Address(rfp, frame::return_addr_offset * wordSize)); ++ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::interpreter_contains), rarg); ++ //__ testl(rax, rax); ++ __ jcc(Assembler::notZero, caller_not_deoptimized, rax); ++ ++ // Compute size of arguments for saving when returning to ++ // deoptimized caller ++ __ get_method(rax); ++ __ ldptr(rax, Address(rax, Method::const_offset())); ++ __ load_unsigned_short(rax, Address(rax, in_bytes(ConstMethod:: ++ size_of_parameters_offset()))); ++ __ slll(rax, Interpreter::logStackElementSize, rax); ++ __ restore_locals(); ++ __ subptr(rlocals, rax, rlocals); ++ __ addptr(rlocals, wordSize, rlocals); ++ // Save these arguments ++ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ++ Deoptimization:: ++ popframe_preserve_args), ++ thread, rax, rlocals); ++ ++ __ remove_activation(vtos, rdx, ++ /* throw_monitor_exception */ false, ++ /* install_monitor_exception */ false, ++ /* notify_jvmdi */ false); ++ ++ // Inform deoptimization that it is responsible for restoring these arguments ++ __ movw(rscratch3, JavaThread::popframe_force_deopt_reexecution_bit); ++ __ stw(rscratch3, Address(thread, JavaThread::popframe_condition_offset())); ++ // Continue in deoptimization handler ++ __ jmp(rdx); ++ ++ __ bind(caller_not_deoptimized); ++ } ++ ++ __ remove_activation(vtos, rdx, ++ /* throw_monitor_exception */ false, ++ /* install_monitor_exception */ false, ++ /* notify_jvmdi */ false); ++ ++ // Finish with popframe handling ++ // A previous I2C followed by a deoptimization might have moved the ++ // outgoing arguments further up the stack. PopFrame expects the ++ // mutations to those outgoing arguments to be preserved and other ++ // constraints basically require this frame to look exactly as ++ // though it had previously invoked an interpreted activation with ++ // no space between the top of the expression stack (current ++ // last_sp) and the top of stack. Rather than force deopt to ++ // maintain this kind of invariant all the time we call a small ++ // fixup routine to move the mutated arguments onto the top of our ++ // expression stack if necessary. ++ ++ __ movl(c_rarg1, esp); ++ __ ldptr(c_rarg2, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ // PC must point into interpreter here ++ __ set_last_Java_frame(noreg, rfp, __ pc(), rscratch1); ++ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), rthread, c_rarg1, c_rarg2); ++ __ reset_last_Java_frame(thread, true); ++ // Restore the last_sp and null it out ++ __ ldptr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ __ stptr(R0, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); ++ ++ __ restore_bcp(); ++ __ restore_locals(); ++ // 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(); ++ } ++ // Clear the popframe condition flag ++ __ movw(rscratch1, JavaThread::popframe_inactive); ++ __ stw(rscratch1, Address(thread, JavaThread::popframe_condition_offset())); ++#if INCLUDE_JVMTI ++ { ++ Label L_done; ++ const Register local0 = rlocals; ++ ++ __ cmpb(Address(rbcp, 0), Bytecodes::_invokestatic); ++ __ jcc(Assembler::notEqual, 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. ++ ++ __ get_method(rdx); ++ __ ldptr(rax, Address(local0, 0)); ++ __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), rax, rdx, rbcp); ++ ++ //__ testptr(rax, rax); ++ __ jcc(Assembler::zero, L_done, rax); ++ ++ __ stptr(rax, Address(esp, 0)); //store 64bits ++ __ bind(L_done); ++ } ++#endif // INCLUDE_JVMTI ++ __ dispatch_next(vtos); ++ // end of PopFrame support ++ ++ Interpreter::_remove_activation_entry = __ pc(); ++ ++ // preserve exception over this code sequence ++ __ pop_ptr(rax); ++ __ stptr(rax, Address(thread, JavaThread::vm_result_offset())); ++ // remove the activation (without doing throws on illegalMonitorExceptions) ++ __ remove_activation(vtos, rdx, false, true, false); ++ // restore exception ++ __ get_vm_result(rax, thread); ++ //__ verify_oop(rax); ++ ++ // Inbetween activations - previous activation type unknown yet ++ // compute continuation point - the continuation point expects ++ // the following registers set up: ++ // ++ // rax: exception ++ // rscratch1: return address/pc that threw exception ++ // rsp: expression stack of caller ++ // rbp: ebp of caller ++ __ push(rax); // save exception ++ __ push(rdx); // save return address ++ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ++ SharedRuntime::exception_handler_for_return_address), ++ thread, rdx); ++ __ movl(rbx, rax); // save exception handler ++ __ pop(rdx); // restore return address TODO:here need check jzy ++ __ pop(rax); ++ // Note that an "issuing PC" is actually the next PC after the call ++ __ jmp(rbx); // jump to exception handler of caller ++ BLOCK_COMMENT("generate_throw_exception leave"); ++} ++ ++ ++// ++// JVMTI ForceEarlyReturn support ++// ++address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {BLOCK_COMMENT("generate_earlyret_entry_for enter"); ++ address entry = __ pc(); ++ ++ __ restore_bcp(); ++ __ restore_locals(); ++ __ empty_expression_stack(); ++ __ empty_FPU_stack(); ++ __ load_earlyret_value(state); ++ ++ __ ldptr(rscratch1, Address(rthread, JavaThread::jvmti_thread_state_offset())); ++ ++ const Address cond_addr(rscratch1, in_bytes(JvmtiThreadState::earlyret_state_offset())); ++ // Clear the earlyret state ++ __ movw(rscratch2, JvmtiThreadState::earlyret_inactive); ++ __ stw(rscratch2, cond_addr); ++ __ memb(); ++ ++ __ remove_activation(state, rscratch1, ++ false, /* throw_monitor_exception */ ++ false, /* install_monitor_exception */ ++ true); /* notify_jvmdi */ ++ __ memb(); ++ __ jmp(rscratch1);BLOCK_COMMENT("generate_earlyret_entry_for leave"); ++ return entry; ++} // end of 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) {BLOCK_COMMENT("TemplateInterpreterGenerator::set_vtos_entry_points enter"); ++ assert(t->is_valid() && t->tos_in() == vtos, "illegal template"); ++ Label L; ++ fep = __ pc(); __ push(ftos); __ beq_l(R0, L); ++ dep = __ pc(); __ push(dtos); __ beq_l(R0, L); ++ lep = __ pc(); __ push(ltos); __ beq_l(R0, L); ++ aep =__ pc(); __ push(atos); __ beq_l(R0, L); ++ bep = cep = sep = iep = __ pc(); __ push(itos); ++ vep = __ pc(); ++ __ BIND(L); // fall through ++ generate_and_dispatch(t);BLOCK_COMMENT("TemplateInterpreterGenerator::set_vtos_entry_points leave"); ++} ++ ++//----------------------------------------------------------------------------- ++ ++// Non-product code ++#ifndef PRODUCT ++address TemplateInterpreterGenerator::generate_trace_code(TosState state) {//__ warn("TODO:check function right generate_trace_code jzy "); ++ address entry = __ pc(); ++ ++ // prepare expression stack ++ __ push(state); // save tosca ++ // tos & tos2 ++ // trace_bytecode need actually 4 args, the last two is tos&tos2 ++ // this work fine for x86. but mips o32 call convention will store A2-A3 ++ // to the stack position it think is the tos&tos2 ++ // when the expression stack have no more than 2 data, error occur. ++ __ ldptr(A2, Address(esp, 0));// ++ __ ldptr(A3, Address(esp, 1 * wordSize)); ++ // pass arguments & call tracer ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), RA, A2, A3); ++ __ movl(RA, V0); // make sure return address is not destroyed by pop(state) ++ ++ // restore expression stack ++ __ pop(state); // restore tosca ++ ++ // return ++ __ ret_sw(); ++ ++ return entry; ++} ++ ++void TemplateInterpreterGenerator::count_bytecode() {//__ warn("TODO:check function right count_bytecode jzy "); ++ __ incrementw(ExternalAddress((address) &BytecodeCounter::_counter_value)); ++} ++ ++void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {//__ warn("TODO:check function right histogram_bytecode jzy "); ++ __ incrementw(ExternalAddress((address) &BytecodeHistogram::_counters[t->bytecode()])); ++} ++ ++void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { ++ const Register rbx = T11; ++ ++ __ movw(rbx, ExternalAddress((address) &BytecodePairHistogram::_index)); ++ __ srll(rbx, BytecodePairHistogram::log2_number_of_codes, rbx); ++ __ orw(rbx, ++ ((int) t->bytecode()) << ++ BytecodePairHistogram::log2_number_of_codes, rbx); ++ __ movw(ExternalAddress((address) &BytecodePairHistogram::_index), rbx); ++ __ lea(rscratch1, ExternalAddress((address) BytecodePairHistogram::_counters)); ++ __ incrementw(Address(rscratch1, rbx, Address::times_4)); ++} ++ ++ ++void TemplateInterpreterGenerator::trace_bytecode(Template* t) {SCOPEMARK_NAME(trace_bytecode,_masm) ++ // 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. ++ ++ assert(Interpreter::trace_code(t->tos_in()) != NULL, ++ "entry must have been generated"); ++ ++ __ movl(r12_heapbase, esp); // remember sp (can only use r12 if not using call_VM) ++ __ andptr(esp, -16, esp); // align stack as required by ABI ++ __ call(RuntimeAddress(Interpreter::trace_code(t->tos_in()))); ++ __ movl(esp, r12_heapbase); // restore sp ++ __ reinit_heapbase(); ++} ++ ++ ++void TemplateInterpreterGenerator::stop_interpreter_at() {SCOPEMARK_NAME(stop_interpreter_at,_masm) ++ Label L; ++ __ mov_immediate32(rscratch1, (int)StopInterpreterAt);//TODO:current cmpw just compare 16bit jzy ++ __ cmpw(ExternalAddress((address) &BytecodeCounter::_counter_value), rscratch1); ++ __ jcc(Assembler::notEqual, L); ++// __ mov(GP, 1);// ++// __ bne(GP, -1); ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint))); ++ __ bind(L); ++} ++ ++#endif // !PRODUCT ++ ++address TemplateInterpreterGenerator::generate_slow_signature_handler() {SCOPEMARK_NAME(generate_slow_signature_handler,_masm) ++ address entry = __ pc(); ++ ++ const Register rbx = rmethod; ++ const Register r14 = rlocals; ++ ++ // rbx: method ++ // r14: pointer to locals ++ // c_rarg3: first stack arg - wordSize ++ __ movl(c_rarg3, esp); ++ __ push(RA); //position is subtle, you can move it's postion if you know its influence ++ __ subptr(esp, 6 * wordSize, esp); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::slow_signature_handler), ++ rbx, r14, c_rarg3); ++ ++ // rax: result handler ++ ++ // Stack layout: ++ // -------- 0 <- sp ++ // -------- 1 ++ // -------- 2 ++ // -------- 3 ++ // -------- 4 ++ // -------- 1 float/double identifiers ++ // -------- RA ++ // -------- c_rarg3 ++ ++ // rsp: 5 integer or float args (if static first is unused) ++ // 1 float/double identifiers ++ // return address ++ // stack args ++ // garbage ++ // expression stack bottom ++ // bcp (NULL) ++ // ... ++ ++ // Do FP first so we can use c_rarg3 as temp ++ Register identifier = T12; ++ __ ldw(identifier, Address(esp, 5 * wordSize)); // float/double identifiers ++ int floatreg_start_index = FloatRegisterImpl::float_arg_base + 1; //because a0(16) must be env in JNI ++ for ( int i= 0; i < Argument::n_int_register_parameters_c-1; i++ ) { ++ FloatRegister floatreg = as_FloatRegister(i + floatreg_start_index); ++ Label isfloatordouble, isdouble, next; ++ ++ __ testw(identifier, 1 << (i*2)); // Float or Double? ++ __ jcc(Assembler::notZero, isfloatordouble); ++ ++ // Do Int register here ++ switch ( i ) { ++ case 0: ++ __ ldptr(rscratch1, Address(esp, 0)); ++ __ ldw(rscratch2, Address(rbx, Method::access_flags_offset())); ++ __ testw(rscratch2, JVM_ACC_STATIC, rcc); ++ assert_different_registers(rscratch1, rcc); ++ __ cmove(Assembler::zero, c_rarg1, rscratch1, c_rarg1); ++ break; ++ case 1: ++ __ ldptr(c_rarg2, Address(esp, wordSize)); ++ break; ++ case 2: ++ __ ldptr(c_rarg3, Address(esp, 2 * wordSize)); ++ break; ++ case 3: ++ __ ldptr(c_rarg4, Address(esp, 3 * wordSize)); ++ break; ++ case 4: ++ __ ldptr(c_rarg5, Address(esp, 4 * wordSize)); ++ break; ++ default: ++ break; ++ } ++ ++ __ jmp (next); ++ ++ __ bind(isfloatordouble); ++ __ testw(identifier, 1 << ((i*2)+1)); // Double? ++ __ jcc(Assembler::notZero, isdouble); ++ ++ // Do Float Here ++ __ load_float(floatreg, Address(esp, i * wordSize)); ++ __ jmp(next); ++ ++ // Do Double here ++ __ bind(isdouble); ++ __ load_double(floatreg, Address(esp, i * wordSize)); ++ ++ __ bind(next); ++ } ++ ++ ++ // restore rsp ++ __ addptr(esp, 6 * wordSize, esp); ++ ++ // Restore RA ++ __ pop(RA); ++ ++ __ ret_sw(); ++ ++ return entry; ++} ++ ++address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {BLOCK_COMMENT("generate_math_entry enter"); ++ // rmethod: methodOop ++ // V0: scratrch ++ // rsender: send 's sp ++ ++ if (!InlineIntrinsics) return NULL; // Generate a vanilla entry ++ ++ address entry_point = __ pc(); ++ ++ // These don't need a safepoint check because they aren't virtually ++ // callable. We won't enter these intrinsics from compiled code. ++ // If in the future we added an intrinsic which was virtually callable ++ // we'd have to worry about how to safepoint so that this code is used. ++ ++ // mathematical functions inlined by compiler ++ // (interpreter must provide identical implementation ++ // in order to avoid monotonicity bugs when switching ++ // from interpreter to compiler in the middle of some ++ // computation) ++ // ++ // stack: [ lo(arg) ] <-- sp ++ // [ hi(arg) ] ++ // ++ ++ __ subl(esp, 2 * wordSize, esp); ++ __ stptr(RA, Address(esp, wordSize)); ++ __ stptr(rfp, Address(esp, 0)); ++ __ ldi(rfp, 2 * wordSize, esp); ++ ++ // [ fp ] <-- sp ++ // [ ra ] ++ // [ lo ] <-- fp ++ // [ hi ] ++ //FIXME, need consider this ++ ++ if (kind == Interpreter::java_lang_math_sqrt) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ sqrt_d(f0, F16); ++ } else if (kind == Interpreter::java_lang_math_exp) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dexp() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dexp()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dexp)); ++ } ++ __ addl(esp, wordSize * 2, esp); ++ } else if (kind == Interpreter::java_lang_math_log) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dlog() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dlog()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dlog)); ++ } ++ __ addl(esp, wordSize * 2, esp); ++ } else if (kind == Interpreter::java_lang_math_log10) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dlog10() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dlog10()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dlog10)); ++ } ++ __ addl(esp, wordSize * 2, esp); ++ } else if (kind == Interpreter::java_lang_math_sin) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dsin() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dsin()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); ++ } ++ __ addl(esp, wordSize * 2, esp); ++ } else if (kind == Interpreter::java_lang_math_cos) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dcos() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dcos()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); ++ } ++ __ addl(esp, wordSize * 2, esp); ++ } else if (kind == Interpreter::java_lang_math_pow) { ++ __ fldd(F17, 2 * wordSize, esp); ++ __ fldd(F16, 4 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dpow() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dpow()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dpow)); ++ } ++ __ addiu(esp, wordSize * 2, esp); ++ } else if (kind == Interpreter::java_lang_math_tan) { ++ __ fldd(F16, 2 * wordSize, esp); ++ __ subl(esp, wordSize * 2, esp); ++ if (StubRoutines::dtan() != NULL) { ++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dtan()))); ++ } else { ++ __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); ++ } ++ __ addiu(esp, wordSize * 2, esp); ++ } else { ++ __ fldd(F16, 2 * wordSize, esp); ++ switch (kind) { ++ case Interpreter::java_lang_math_abs: ++ __ abs_d(f0, F16); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ } ++ ++ // must maintain return value in f0:f1 ++ __ ldptr(RA, Address(rfp, (-1) * wordSize)); ++ //FIXME ++ __ movl(esp, rsender); ++ __ ldptr(rfp, Address(rfp, (-2) * wordSize)); ++ __ ret_sw();BLOCK_COMMENT("generate_math_entry leave"); ++ return entry_point; ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/templateTable_sw64.cpp afu11u/src/hotspot/cpu/sw64/templateTable_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/templateTable_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/templateTable_sw64.cpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,4190 @@ ++/* ++ * 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.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" ++#include "assembler_sw64.hpp" ++ ++#define __ _masm-> ++#ifdef PRODUCT ++#define BLOCK_COMMENT(str) /* nothing */ ++#else ++#define BLOCK_COMMENT(str) { char line[1024];sprintf(line,"%s:%s:%d",str,__FILE__, __LINE__); __ block_comment(line);} ++#endif ++#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") ++// Platform-dependent initialization ++void TemplateTable::pd_initialize() { ++ // No sw64 specific initialization ++} ++ ++// Address Computation: local variables ++static inline Address iaddress(int n) { ++ return Address(rlocals, Interpreter::local_offset_in_bytes(n)); ++} ++ ++static inline Address laddress(int n) { ++ return iaddress(n + 1); ++} ++ ++static inline Address faddress(int n) { ++ return iaddress(n); ++} ++ ++static inline Address daddress(int n) { ++ return laddress(n); ++} ++ ++static inline Address aaddress(int n) { ++ return iaddress(n); ++} ++ ++static inline Address iaddress(Register r) { ++ return Address(rlocals, r, Address::times_ptr); ++} ++ ++static inline Address laddress(Register r) { ++ return Address(rlocals, r, Address::times_ptr, Interpreter::local_offset_in_bytes(1)); ++} ++ ++static inline Address faddress(Register r) { ++ return iaddress(r); ++} ++ ++static inline Address daddress(Register r) { ++ return laddress(r); ++} ++ ++static inline Address aaddress(Register r) { ++ return iaddress(r); ++} ++ ++ ++// expression stack ++// (Note: Must not use symmetric equivalents at_rsp_m1/2 since they store ++// data beyond the rsp which is potentially unsafe in an MT environment; ++// an interrupt may overwrite that data.) ++static inline Address at_rsp() { ++ return Address(esp, 0); ++} ++ ++// At top of Java expression stack which may be different than esp(). It ++// isn't for category 1 objects. ++static inline Address at_tos () { ++ return Address(esp, Interpreter::expr_offset_in_bytes(0)); ++} ++ ++static inline Address at_tos_p1() { ++ return Address(esp, Interpreter::expr_offset_in_bytes(1)); ++} ++ ++static inline Address at_tos_p2() { ++ return Address(esp, Interpreter::expr_offset_in_bytes(2)); ++} ++ ++// Condition conversion ++static Assembler::Condition j_not(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 ++// Store an oop (or NULL) at the address described by obj. ++// If val == noreg this means store a NULL ++ ++ ++static void do_oop_store(InterpreterMacroAssembler* _masm, ++ Address dst, ++ Register val, ++ DecoratorSet decorators = 0) {SCOPEMARK_NAME(do_oop_store, _masm) ++ assert(val == noreg || val == V0, "parameter is just for looks"); ++ __ store_heap_oop(dst, val, T9, T11, decorators);//It's OK to use register like this? Can use rscratch* to replace? TODO:check jzy ++} ++ ++static void do_oop_load(InterpreterMacroAssembler* _masm, ++ Address src, ++ Register dst, ++ DecoratorSet decorators = 0) { ++ __ load_heap_oop(dst, src, T9, T11, decorators); ++} ++ ++Address TemplateTable::at_bcp(int offset) { ++ assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); ++ return Address(rbcp, offset); ++} ++ ++ ++void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, ++ Register temp_reg, bool load_bc_into_bc_reg/*=true*/, ++ int byte_no) {SCOPEMARK_NAME(patch_bytecode, _masm) ++ 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(temp_reg, bc_reg, temp_reg, byte_no, 1); ++ __ movw(bc_reg, bc); ++ __ cmpw(temp_reg, (int) 0); ++ __ jcc(Assembler::zero, L_patch_done); // don't patch ++ } ++ break; ++ default: ++ assert(byte_no == -1, "sanity"); ++ // the pair bytecodes have already done the load. ++ if (load_bc_into_bc_reg) { ++ __ movw(bc_reg, bc); ++ } ++ } ++ ++ if (JvmtiExport::can_post_breakpoint()) { ++ Label L_fast_patch; ++ // if a breakpoint is present we can't rewrite the stream directly ++ __ ldbu(temp_reg, at_bcp(0)); ++ __ cmpw(temp_reg, Bytecodes::_breakpoint); ++ __ jcc(Assembler::notEqual, L_fast_patch); ++ __ get_method(temp_reg); ++ // Let breakpoint table handling rewrite to quicker bytecode ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), temp_reg, rbcp, bc_reg); ++ __ jmp(L_patch_done); ++ __ bind(L_fast_patch); ++ } ++ ++#ifdef ASSERT ++ Label L_okay; ++ __ load_unsigned_byte(temp_reg, at_bcp(0)); ++ __ cmpw(temp_reg, (int) Bytecodes::java_code(bc)); ++ __ jcc(Assembler::equal, L_okay); ++ __ cmpw(temp_reg, bc_reg); ++ __ jcc(Assembler::equal, L_okay); ++ __ 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); ++ __ bis(R0, R0, FSR); ++} ++ ++void TemplateTable::iconst(int value) { ++ transition(vtos, itos); ++ if (value == 0) { ++ __ bis(R0, R0, FSR); ++ } else { ++ __ ldi(FSR, value, R0); ++ } ++} ++ ++void TemplateTable::lconst(int value) { ++ transition(vtos, ltos); ++ if (value == 0) { ++ __ bis(R0, R0, FSR); ++ } else { ++ __ ldi(FSR, value, R0); ++ } ++} ++ ++ ++ ++void TemplateTable::fconst(int value) { ++ transition(vtos, ftos); ++ static float _f1 = 1.0, _f2 = 2.0; ++ float* p; ++ switch( value ) { ++ default: ShouldNotReachHere(); ++ case 0: __ fcpys(f31, f31, FSF); return; ++ case 1: p = &_f1; break; ++ case 2: p = &_f2; break; ++ } ++ __ load_float(FSF, ExternalAddress((address)p)); ++} ++ ++void TemplateTable::dconst(int value) { ++ transition(vtos, dtos); ++ static double _d1 = 1.0; ++ double* p; ++ switch( value ) { ++ default: ShouldNotReachHere(); ++ case 0: __ fcpys(f31, f31, FSF); return; ++ case 1: p = &_d1; break; ++ } ++ __ load_double(FSF, ExternalAddress((address)p)); ++} ++ ++void TemplateTable::bipush() { ++ transition(vtos, itos); ++ __ load_signed_byte64(FSR, at_bcp(1)); ++} ++ ++void TemplateTable::sipush() {SCOPEMARK ++ transition(vtos, itos); ++// the following code is an optimization on sw64 since ++// we dont have unaligned load insn ++ __ load_signed_byte64(FSR, at_bcp(1)); ++ __ ldbu(AT, at_bcp(2)); ++ __ slll(FSR, 8, FSR); ++ __ bis(FSR, AT, FSR); ++ __ sexth(FSR, FSR); ++} ++ ++void TemplateTable::ldc(bool wide) {SCOPEMARK ++ transition(vtos, vtos); ++ Register rarg = c_rarg1; ++ Label call_ldc, notFloat, notClass, notInt, Done; ++ ++ if (wide) { ++ __ get_unsigned_2_byte_index_at_bcp(T2, 1); ++ } else { ++ __ load_unsigned_byte(T2, at_bcp(1)); ++ } ++ ++ __ get_cpool_and_tags(T3, T1); ++ const int base_offset = ConstantPool::header_size() * wordSize; ++ const int tags_offset = Array::base_offset_in_bytes(); ++ ++ // get type ++ __ ldbu(T4, Address(T1, T2, Address::times_1, tags_offset)); ++ ++ // unresolved class - get the resolved class ++ __ cmpw(T4, JVM_CONSTANT_UnresolvedClass); ++ __ jcc(Assembler::equal, call_ldc); ++ ++ // unresolved class in error state - call into runtime to throw the error ++ // from the first resolution attempt ++ __ cmpw(T4, JVM_CONSTANT_UnresolvedClassInError); ++ __ jcc(Assembler::equal, call_ldc); ++ ++ // resolved class - need to call vm to get java mirror of the class ++ __ cmpw(T4, JVM_CONSTANT_Class); ++ __ jcc(Assembler::notEqual, notClass); ++ ++ __ bind(call_ldc); ++ ++ __ movw(rarg, wide); ++ call_VM(FSR, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), rarg); ++ ++ __ push(atos); ++ __ jmp(Done); ++ ++ __ bind(notClass); ++ __ cmpw(T4, JVM_CONSTANT_Float); ++ __ jcc(Assembler::notEqual, notFloat); ++ ++ // ftos ++ __ load_float(FSF, Address(T3, T2, Address::times_ptr, base_offset)); ++ __ push(ftos); ++ __ jmp(Done); ++ ++ __ bind(notFloat); ++ __ cmpw(T4, JVM_CONSTANT_Integer); ++ __ jcc(Assembler::notEqual, notInt); ++ ++ // itos ++ __ ldws(FSR, Address(T3, T2, Address::times_ptr, base_offset)); ++ __ push(itos); ++ __ jmp(Done); ++ ++ // assume the tag is for condy; if not, the VM runtime will tell us ++ __ bind(notInt); ++ condy_helper(Done); ++ ++ __ bind(Done); ++} ++ ++// Fast path for caching oop constants. ++void TemplateTable::fast_aldc(bool wide) {SCOPEMARK ++ transition(vtos, atos); ++ ++ Register result = FSR; ++ Register tmp = SSR; ++ Register rarg = c_rarg1; ++ int index_size = wide ? sizeof(u2) : sizeof(u1); ++ ++ Label resolved; ++ ++ // We are resolved if the resolved reference cache entry contains a ++ // non-null object (String, MethodType, etc.) ++ assert_different_registers(result, tmp); ++ __ get_cache_index_at_bcp(tmp, 1, index_size); ++ __ load_resolved_reference_at_index(result, tmp); ++ __ testptr(result, result); ++ __ jcc(Assembler::notZero, resolved); ++ ++ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); ++ ++ // first time invocation - must resolve first ++ __ movw(rarg, (int)bytecode()); ++ __ call_VM(result, entry, rarg); ++ __ 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; ++ ExternalAddress null_sentinel((address)Universe::the_null_sentinel_addr()); ++ __ ldptr(tmp, null_sentinel); ++ __ cmpptr(tmp, result); ++ __ jcc(Assembler::notEqual, notNull); ++ __ bis(R0, R0, result); // NULL object reference ++ __ bind(notNull); ++ } ++ ++ if (VerifyOops) { ++ __ verify_oop(result); ++ } ++} ++ ++void TemplateTable::ldc2_w() {SCOPEMARK ++ transition(vtos, vtos); ++ Label notDouble, notLong, Done; ++ __ get_unsigned_2_byte_index_at_bcp(T2, 1); // get index in cpool ++ ++ __ get_cpool_and_tags(T3, T1); ++ const int base_offset = ConstantPool::header_size() * wordSize; ++ const int tags_offset = Array::base_offset_in_bytes(); ++ ++ // get type ++ __ ldbu(AT, Address(T1, T2, Address::times_1, tags_offset)); ++ __ cmpw(AT, JVM_CONSTANT_Double); ++ __ jcc(Assembler::notEqual, notDouble); ++ ++ // dtos ++ __ load_double(FSF, Address(T3, T2, Address::times_ptr, base_offset)); ++ __ push(dtos); ++ ++ __ jmp(Done); ++ __ bind(notDouble); ++ __ cmpw(AT, JVM_CONSTANT_Long); ++ __ jcc(Assembler::notEqual, notLong); ++ ++ // ltos ++ __ ldptr(FSR, Address(T3, T2, Address::times_ptr, base_offset + 0 * wordSize)); ++ __ push(ltos); ++ __ jmp(Done); ++ ++ __ bind(notLong); ++ condy_helper(Done); ++ ++ __ bind(Done); ++} ++ ++void TemplateTable::condy_helper(Label& Done) {SCOPEMARK ++ const Register obj = T0; ++ const Register off = T1; ++ const Register flags = T2; ++ const Register rarg = A1; ++ __ movw(rarg, (int)bytecode()); ++ call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg); ++ __ get_vm_result_2(flags, rthread); ++ // VMr = obj = base address to find primitive value to push ++ // VMr2 = flags = (tos, off) using format of CPCE::_flags ++ __ andw(flags, ConstantPoolCacheEntry::field_index_mask, off); ++ const Address field(obj, off, Address::times_1, 0*wordSize); ++ ++ // What sort of thing are we loading? ++ __ srll(flags, ConstantPoolCacheEntry::tos_state_shift, flags); ++ __ andw(flags, ConstantPoolCacheEntry::tos_state_mask, flags); ++ ++ switch (bytecode()) { ++ case Bytecodes::_ldc: ++ case Bytecodes::_ldc_w: ++ { ++ // tos in (itos, ftos, stos, btos, ctos, ztos) ++ Label notInt, notFloat, notShort, notByte, notChar, notBool; ++ __ cmpw(flags, itos); ++ __ jcc(Assembler::notEqual, notInt); ++ // itos ++ __ ldws(FSR, field); ++ __ push(itos); ++ __ jmp(Done); ++ ++ __ bind(notInt); ++ __ cmpw(flags, ftos); ++ __ jcc(Assembler::notEqual, notFloat); ++ // ftos ++ __ load_float(FSF, field); ++ __ push(ftos); ++ __ jmp(Done); ++ ++ __ bind(notFloat); ++ __ cmpw(flags, stos); ++ __ jcc(Assembler::notEqual, notShort); ++ // stos ++ __ load_signed_short(FSR, field); ++ __ push(stos); ++ __ jmp(Done); ++ ++ __ bind(notShort); ++ __ cmpw(flags, btos); ++ __ jcc(Assembler::notEqual, notByte); ++ // btos ++ __ load_signed_byte64(FSR, field); ++ __ push(btos); ++ __ jmp(Done); ++ ++ __ bind(notByte); ++ __ cmpw(flags, ctos); ++ __ jcc(Assembler::notEqual, notChar); ++ // ctos ++ __ load_unsigned_short(FSR, field); ++ __ push(ctos); ++ __ jmp(Done); ++ ++ __ bind(notChar); ++ __ cmpw(flags, ztos); ++ __ jcc(Assembler::notEqual, notBool); ++ // ztos ++ __ load_signed_byte64(FSR, field); ++ __ push(ztos); ++ __ jmp(Done); ++ ++ __ bind(notBool); ++ break; ++ } ++ ++ case Bytecodes::_ldc2_w: ++ { ++ Label notLong, notDouble; ++ __ cmpw(flags, ltos); ++ __ jcc(Assembler::notEqual, notLong); ++ // ltos ++ // Loading high word first because movptr clobbers rax ++ __ ldptr(FSR, field); ++ __ push(ltos); ++ __ jmp(Done); ++ ++ __ bind(notLong); ++ __ cmpw(flags, dtos); ++ __ jcc(Assembler::notEqual, notDouble); ++ // dtos ++ __ load_double(FSF, field); ++ __ push(dtos); ++ __ jmp(Done); ++ ++ __ bind(notDouble); ++ break; ++ } ++ ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ __ stop("bad ldc/condy"); ++} ++ ++void TemplateTable::locals_index(Register reg, int offset) {SCOPEMARK ++ __ load_unsigned_byte(reg, at_bcp(offset)); ++ __ subl(R0, reg, reg); ++} ++ ++void TemplateTable::iload() {SCOPEMARK ++ iload_internal(); ++} ++ ++void TemplateTable::nofast_iload() { ++ iload_internal(may_not_rewrite); ++} ++ ++void TemplateTable::iload_internal(RewriteControl rc) {SCOPEMARK_NAME(iload_internal, _masm) ++ transition(vtos, itos); ++ if (RewriteFrequentPairs && rc == may_rewrite) { ++ Label rewrite, done; ++ const Register bc = c_rarg3; ++ ++ // get next byte ++ __ load_unsigned_byte(T2, ++ at_bcp(Bytecodes::length_for(Bytecodes::_iload))); ++ // 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. ++ __ cmpw(T2, Bytecodes::_iload); ++ __ jcc(Assembler::equal, done); ++ ++ __ cmpw(T2, Bytecodes::_fast_iload); ++ __ movw(bc, Bytecodes::_fast_iload2); ++ ++ __ jcc(Assembler::equal, rewrite); ++ ++ // if _caload, rewrite to fast_icaload ++ __ cmpw(T2, Bytecodes::_caload); ++ __ movw(bc, Bytecodes::_fast_icaload); ++ __ jcc(Assembler::equal, rewrite); ++ ++ // rewrite so iload doesn't check again. ++ __ movw(bc, Bytecodes::_fast_iload); ++ ++ // rewrite ++ // bc: fast bytecode ++ __ bind(rewrite); ++ patch_bytecode(Bytecodes::_iload, bc, T2, false); ++ __ bind(done); ++ } ++ ++ // Get the local value into tos ++ locals_index(T2); ++ __ ldws(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::fast_iload2() {SCOPEMARK ++ transition(vtos, itos); ++ locals_index(T2); ++ __ ldws(FSR, iaddress(T2)); ++ __ push(itos); ++ locals_index(T2, 3); ++ __ ldws(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::fast_iload() {SCOPEMARK ++ transition(vtos, itos); ++ locals_index(T2); ++ __ ldws(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::lload() {SCOPEMARK ++ transition(vtos, ltos); ++ locals_index(T2); ++ __ ldptr(FSR, laddress(T2)); ++} ++ ++void TemplateTable::fload() {SCOPEMARK ++ transition(vtos, ftos); ++ locals_index(T2); ++ __ load_float(FSF, faddress(T2)); ++} ++ ++void TemplateTable::dload() {SCOPEMARK ++ transition(vtos, dtos); ++ locals_index(T2); ++ __ load_double(FSF, daddress(T2)); ++} ++ ++void TemplateTable::aload() {SCOPEMARK ++ transition(vtos, atos); ++ locals_index(T2); ++ __ ldptr(FSR, aaddress(T2)); ++} ++ ++void TemplateTable::locals_index_wide(Register reg) {SCOPEMARK ++ __ ldhu_unaligned_be(reg, at_bcp(2)); ++ __ subl(R0, reg, reg); ++} ++ ++void TemplateTable::wide_iload() { ++ transition(vtos, itos); ++ locals_index_wide(T2); ++ __ ldws(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::wide_lload() { ++ transition(vtos, ltos); ++ locals_index_wide(T2); ++ __ ldptr(FSR, laddress(T2)); ++} ++ ++void TemplateTable::wide_fload() { ++ transition(vtos, ftos); ++ locals_index_wide(T2); ++ __ load_float(FSF, faddress(T2)); ++} ++ ++void TemplateTable::wide_dload() { ++ transition(vtos, dtos); ++ locals_index_wide(T2); ++ __ load_double(FSF, daddress(T2)); ++} ++ ++void TemplateTable::wide_aload() { ++ transition(vtos, atos); ++ locals_index_wide(T2); ++ __ ldptr(FSR, aaddress(T2)); ++} ++ ++void TemplateTable::index_check(Register array, Register index) { ++ // Pop ptr into array ++ __ pop_ptr(array); ++ index_check_without_pop(array, index); ++} ++ ++void TemplateTable::index_check_without_pop(Register array, Register index) {SCOPEMARK_NAME(index_check_without_pop, _masm) ++ // destroys A2 ++ // check array ++ __ null_check(array, arrayOopDesc::length_offset_in_bytes()); ++ ++ // check index ++ __ cmpwu(index, Address(array, arrayOopDesc::length_offset_in_bytes())); ++ //throw_ArrayIndexOutOfBoundsException assume abberrant index in c_rarg2, should extend c_rarg2 as valid value because of negativen number ++ if (c_rarg2 != index) __ movl(c_rarg2, index); ++ ++ Label skip; ++ __ jcc(Assembler::below, skip); ++ // Pass array to create more detailed exceptions. ++ __ movl(c_rarg1, array); ++ __ jump(ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry)); ++ __ bind(skip); ++} ++ ++void TemplateTable::iaload() { ++ transition(itos, itos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_INT, IN_HEAP | IS_ARRAY, FSR, ++ Address(SSR, FSR, Address::times_4, ++ arrayOopDesc::base_offset_in_bytes(T_INT)), ++ noreg, noreg); ++} ++ ++void TemplateTable::laload() { ++ transition(itos, ltos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_LONG, IN_HEAP | IS_ARRAY, noreg /* ltos */, ++ Address(SSR, FSR, Address::times_8, ++ arrayOopDesc::base_offset_in_bytes(T_LONG)), ++ noreg, noreg); ++} ++ ++ ++ ++void TemplateTable::faload() { ++ transition(itos, ftos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_FLOAT, IN_HEAP | IS_ARRAY, noreg /* ftos */, ++ Address(SSR, FSR, ++ Address::times_4, ++ arrayOopDesc::base_offset_in_bytes(T_FLOAT)), ++ noreg, noreg); ++} ++ ++void TemplateTable::daload() { ++ transition(itos, dtos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_DOUBLE, IN_HEAP | IS_ARRAY, noreg /* dtos */, ++ Address(SSR, FSR, ++ Address::times_8, ++ arrayOopDesc::base_offset_in_bytes(T_DOUBLE)), ++ noreg, noreg); ++} ++ ++void TemplateTable::aaload() { ++ transition(itos, atos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ do_oop_load(_masm, ++ Address(SSR, FSR, ++ UseCompressedOops ? Address::times_4 : Address::times_ptr, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT)), ++ FSR, ++ IS_ARRAY); ++} ++ ++void TemplateTable::baload() { ++ transition(itos, itos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_BYTE, IN_HEAP | IS_ARRAY, FSR, ++ Address(SSR, FSR, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), ++ noreg, noreg); ++} ++ ++void TemplateTable::caload() { ++ transition(itos, itos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, FSR, ++ Address(SSR, FSR, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), ++ noreg, noreg); ++} ++ ++// iload followed by caload frequent pair ++void TemplateTable::fast_icaload() { ++ transition(vtos, itos); ++ // load index out of locals ++ locals_index(T2); ++ __ ldws(FSR, iaddress(T2)); ++ ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, FSR, ++ Address(SSR, FSR, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), ++ noreg, noreg); ++} ++ ++ ++void TemplateTable::saload() { ++ transition(itos, itos); ++ // FSR: index ++ // SSR: array ++ index_check(SSR, FSR); ++ __ access_load_at(T_SHORT, IN_HEAP | IS_ARRAY, FSR, ++ Address(SSR, FSR, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT)), ++ noreg, noreg); ++} ++ ++void TemplateTable::iload(int n) { ++ transition(vtos, itos); ++ __ ldws(FSR, iaddress(n)); ++} ++ ++void TemplateTable::lload(int n) { ++ transition(vtos, ltos); ++ __ ldptr(FSR, laddress(n)); ++} ++ ++void TemplateTable::fload(int n) { ++ transition(vtos, ftos); ++ __ load_float(FSF, faddress(n)); ++} ++ ++void TemplateTable::dload(int n) { ++ transition(vtos, dtos); ++ __ load_double(FSF, daddress(n)); ++} ++ ++void TemplateTable::aload(int n) { ++ transition(vtos, atos); ++ __ ldptr(FSR, aaddress(n)); ++} ++ ++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 ++ // _aload_0, _fast_agetfield ++ // _aload_0, _fast_fgetfield ++ // ++ // occur frequently. If RewriteFrequentPairs is set, the (slow) ++ // _aload_0 bytecode checks if the next bytecode is either ++ // _fast_igetfield, _fast_agetfield or _fast_fgetfield 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. ++ // ++ // Note: If the next bytecode is _getfield, the rewrite must be ++ // delayed, otherwise we may miss an opportunity for a pair. ++ // ++ // Also rewrite frequent pairs ++ // aload_0, aload_1 ++ // aload_0, iload_1 ++ // These bytecodes with a small amount of code are most profitable ++ // to rewrite ++ if (RewriteFrequentPairs && rc == may_rewrite) { ++ Label rewrite, done; ++ ++ const Register bc = c_rarg3; ++ ++ // get next byte ++ __ load_unsigned_byte(T2, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0))); ++ ++ // if _getfield then wait with rewrite ++ __ cmpw(T2, Bytecodes::_getfield); ++ __ jcc(Assembler::equal, done); ++ ++ // if _igetfield then rewrite to _fast_iaccess_0 ++ assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); ++ __ cmpw(T2, Bytecodes::_fast_igetfield); ++ __ movw(bc, Bytecodes::_fast_iaccess_0); ++ __ jcc(Assembler::equal, rewrite); ++ ++ // if _agetfield then rewrite to _fast_aaccess_0 ++ assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); ++ __ cmpw(T2, Bytecodes::_fast_agetfield); ++ __ movw(bc, Bytecodes::_fast_aaccess_0); ++ __ jcc(Assembler::equal, rewrite); ++ ++ // if _fgetfield then rewrite to _fast_faccess_0 ++ assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); ++ __ cmpw(T2, Bytecodes::_fast_fgetfield); ++ __ movw(bc, Bytecodes::_fast_faccess_0); ++ __ jcc(Assembler::equal, rewrite); ++ ++ // else rewrite to _fast_aload0 ++ assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "fix bytecode definition"); ++ __ movw(bc, Bytecodes::_fast_aload_0); ++ ++ // rewrite ++ // bc: fast bytecode ++ __ bind(rewrite); ++ patch_bytecode(Bytecodes::_aload_0, bc, T2, 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(T2); ++ __ stw(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::lstore() { ++ transition(ltos, vtos); ++ locals_index(T2); ++ __ stptr(FSR, laddress(T2)); ++} ++ ++void TemplateTable::fstore() { ++ transition(ftos, vtos); ++ locals_index(T2); ++ __ store_float(FSF, faddress(T2)); ++} ++ ++void TemplateTable::dstore() { ++ transition(dtos, vtos); ++ locals_index(T2); ++ __ store_double(FSF, daddress(T2)); ++} ++ ++void TemplateTable::astore() { ++ transition(vtos, vtos); ++ __ pop_ptr(FSR); ++ locals_index(T2); ++ __ stptr(FSR, aaddress(T2)); ++} ++ ++void TemplateTable::wide_istore() { ++ transition(vtos, vtos); ++ __ pop_i(); ++ locals_index_wide(T2); ++ __ stw(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::wide_lstore() { ++ transition(vtos, vtos); ++ __ pop_l(); ++ locals_index_wide(T2); ++ __ stptr(FSR, laddress(T2)); ++} ++ ++void TemplateTable::wide_fstore() { ++ transition(vtos, vtos); ++ __ pop_f(FSF); ++ locals_index_wide(T2); ++ __ fsts(FSF, faddress(T2)); ++} ++ ++void TemplateTable::wide_dstore() { ++ transition(vtos, vtos); ++ __ pop_d(FSF); ++ locals_index_wide(T2); ++ __ fstd(FSF, daddress(T2)); ++} ++ ++void TemplateTable::wide_astore() { ++ transition(vtos, vtos); ++ __ pop_ptr(FSR); ++ locals_index_wide(T2); ++ __ stptr(FSR, aaddress(T2)); ++} ++ ++void TemplateTable::iastore() { ++ transition(itos, vtos); ++ __ pop_i(SSR); ++ // FSR: value ++ // SSR: index ++ // T2 : array ++ index_check(T2, SSR); // prefer index in SSR ++ __ access_store_at(T_INT, IN_HEAP | IS_ARRAY, ++ Address(T2, SSR, Address::times_4, ++ arrayOopDesc::base_offset_in_bytes(T_INT)), ++ FSR, noreg, noreg); ++} ++ ++void TemplateTable::lastore() { ++ transition(ltos, vtos); ++ __ pop_i(SSR); ++ // FSR: value ++ // SSR: index ++ // T2 : array ++ index_check(T2, SSR); ++ __ access_store_at(T_LONG, IN_HEAP | IS_ARRAY, ++ Address(T2, SSR, Address::times_8, ++ arrayOopDesc::base_offset_in_bytes(T_LONG)), ++ noreg /* ltos */, noreg, noreg); ++} ++ ++ ++void TemplateTable::fastore() { ++ transition(ftos, vtos); ++ __ pop_i(SSR); ++ // FSR: value ++ // SSR: index ++ // T2 : array ++ index_check(T2, SSR); ++ __ access_store_at(T_FLOAT, IN_HEAP | IS_ARRAY, ++ Address(T2, SSR, Address::times_4, ++ arrayOopDesc::base_offset_in_bytes(T_FLOAT)), ++ noreg /* ftos */, noreg, noreg); ++} ++ ++void TemplateTable::dastore() { ++ transition(dtos, vtos); ++ __ pop_i(SSR); ++ // FSR: value ++ // SSR: index ++ // T2 : array ++ index_check(T2, SSR); ++ __ access_store_at(T_DOUBLE, IN_HEAP | IS_ARRAY, ++ Address(T2, SSR, Address::times_8, ++ arrayOopDesc::base_offset_in_bytes(T_DOUBLE)), ++ noreg /* dtos */, noreg, noreg); ++} ++ ++void TemplateTable::aastore() { ++ Label is_null, ok_is_subtype, done; ++ transition(vtos, vtos); ++ // stack: ..., array, index, value ++ __ ldptr(FSR, at_tos()); // value ++ __ ldws(SSR, at_tos_p1()); // index ++ __ ldptr(T2, at_tos_p2()); // array ++ ++ Address element_address(T2, SSR, ++ UseCompressedOops? Address::times_4 : Address::times_ptr, ++ arrayOopDesc::base_offset_in_bytes(T_OBJECT)); ++ ++ index_check_without_pop(T2, SSR); ++ __ testptr(FSR, FSR); ++ __ jcc(Assembler::zero, is_null); ++ ++ // Move subklass into T3 ++ __ load_klass(T3, FSR); ++ // Move superklass into FSR ++ __ load_klass(FSR, T2); ++ __ ldptr(FSR, Address(FSR, ++ ObjArrayKlass::element_klass_offset())); ++ ++ // Generate subtype check. Blows T0, T1 ++ // Superklass in FSR. Subklass in T3. ++ __ gen_subtype_check(T3, ok_is_subtype); ++ ++ // Come here on failure ++ // object is at TOS ++ __ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry)); ++ ++ // Come here on success ++ __ bind(ok_is_subtype); ++ ++ // Get the value we will store ++ __ ldptr(FSR, at_tos()); ++ __ ldws(SSR, at_tos_p1()); // index ++ // Now store using the appropriate barrier ++ do_oop_store(_masm, element_address, FSR, IS_ARRAY); ++ __ jmp(done); ++ ++ // Have a NULL in FSR, T2=array, SSR=index. Store NULL at ary[idx] ++ __ bind(is_null); ++ __ profile_null_seen(T3); ++ ++ // Store a NULL ++ do_oop_store(_masm, element_address, noreg, IS_ARRAY); ++ ++ // Pop stack arguments ++ __ bind(done); ++ __ addptr(esp, 3 * Interpreter::stackElementSize, esp); ++} ++ ++void TemplateTable::bastore() { ++ transition(itos, vtos); ++ Register rbx = SSR; ++ Register rdx = T2; ++ Register rcx = T12; ++ Register rax = FSR; ++ __ pop_i(rbx); ++ // rax: value ++ // rbx: index ++ // rdx: array ++ index_check(rdx, rbx); // prefer index in rbx ++ // Need to check whether array is boolean or byte ++ // since both types share the bastore bytecode. ++ __ load_klass(rcx, rdx); ++ __ ldw(rcx, Address(rcx, Klass::layout_helper_offset())); ++ int diffbit = Klass::layout_helper_boolean_diffbit(); ++ __ testw(rcx, diffbit); ++ Label L_skip; ++ __ jcc(Assembler::zero, L_skip); ++ __ andw(rax, 0x1, rax); // if it is a T_BOOLEAN array, mask the stored value to 0/1 ++ __ bind(L_skip); ++ __ access_store_at(T_BYTE, IN_HEAP | IS_ARRAY, ++ Address(rdx, rbx, Address::times_1, ++ arrayOopDesc::base_offset_in_bytes(T_BYTE)), ++ rax, noreg, noreg); ++} ++ ++void TemplateTable::castore() { ++ transition(itos, vtos); ++ __ pop_i(SSR); ++ // FSR: value ++ // SSR: index ++ // T2: array ++ index_check(T2, SSR); ++ __ access_store_at(T_CHAR, IN_HEAP | IS_ARRAY, ++ Address(T2, SSR, Address::times_2, ++ arrayOopDesc::base_offset_in_bytes(T_CHAR)), ++ FSR, noreg, noreg); ++} ++ ++ ++void TemplateTable::sastore() { ++ castore(); ++} ++ ++void TemplateTable::istore(int n) { ++ transition(itos, vtos); ++ __ stw(FSR, iaddress(n)); ++} ++ ++void TemplateTable::lstore(int n) { ++ transition(ltos, vtos); ++ __ stptr(FSR, laddress(n)); ++} ++ ++void TemplateTable::fstore(int n) { ++ transition(ftos, vtos); ++ __ store_float(FSF, faddress(n)); ++} ++ ++void TemplateTable::dstore(int n) { ++ transition(dtos, vtos); ++ __ store_double(FSF, laddress(n)); ++} ++ ++void TemplateTable::astore(int n) { ++ transition(vtos, vtos); ++ __ pop_ptr(FSR); ++ __ stptr(FSR, aaddress(n)); ++} ++ ++void TemplateTable::pop() { ++ transition(vtos, vtos); ++ __ addptr(esp, Interpreter::stackElementSize, esp); ++} ++ ++void TemplateTable::pop2() { ++ transition(vtos, vtos); ++ __ addptr(esp, 2 * Interpreter::stackElementSize, esp); ++} ++ ++void TemplateTable::dup() { ++ transition(vtos, vtos); ++ __ load_ptr(0, FSR); ++ __ push_ptr(FSR); ++ // stack: ..., a, a ++} ++ ++void TemplateTable::dup_x1() { ++ transition(vtos, vtos); ++ // stack: ..., a, b ++ __ load_ptr( 0, FSR); // load b ++ __ load_ptr( 1, A5 ); // load a ++ __ store_ptr(1, FSR); // store b ++ __ store_ptr(0, A5 ); // store a ++ __ push_ptr(FSR); // push b ++ // stack: ..., b, a, b ++} ++ ++void TemplateTable::dup_x2() { ++ transition(vtos, vtos); ++ // stack: ..., a, b, c ++ __ load_ptr( 0, FSR); // load c ++ __ load_ptr( 2, A5 ); // load a ++ __ store_ptr(2, FSR); // store c in a ++ __ push_ptr(FSR); // push c ++ // stack: ..., c, b, c, c ++ __ load_ptr( 2, FSR); // load b ++ __ store_ptr(2, A5 ); // store a in b ++ // stack: ..., c, a, c, c ++ __ store_ptr(1, FSR); // store b in c ++ // stack: ..., c, a, b, c ++} ++ ++void TemplateTable::dup2() { ++ transition(vtos, vtos); ++ // stack: ..., a, b ++ __ load_ptr(1, FSR); // load a ++ __ push_ptr(FSR); // push a ++ __ load_ptr(1, FSR); // load b ++ __ push_ptr(FSR); // push b ++ // stack: ..., a, b, a, b ++} ++ ++void TemplateTable::dup2_x1() { ++ transition(vtos, vtos); ++ // stack: ..., a, b, c ++ __ load_ptr( 0, T2); // load c ++ __ load_ptr( 1, FSR); // load b ++ __ push_ptr(FSR); // push b ++ __ push_ptr(T2); // push c ++ // stack: ..., a, b, c, b, c ++ __ store_ptr(3, T2); // store c in b ++ // stack: ..., a, c, c, b, c ++ __ load_ptr( 4, T2); // load a ++ __ store_ptr(2, T2); // store a in 2nd c ++ // stack: ..., a, c, a, b, c ++ __ store_ptr(4, FSR); // store b in a ++ // stack: ..., b, c, a, b, c ++} ++ ++void TemplateTable::dup2_x2() { ++ transition(vtos, vtos); ++ // stack: ..., a, b, c, d ++ __ load_ptr(0, T2); // load d ++ __ load_ptr(1, FSR); // load c ++ __ push_ptr(FSR); // push c ++ __ push_ptr(T2); // push d ++ // stack: ..., a, b, c, d, c, d ++ __ load_ptr(4, FSR); // load b ++ __ store_ptr(2, FSR); // store b in d ++ __ store_ptr(4, T2); // store d in b ++ // stack: ..., a, d, c, b, c, d ++ __ load_ptr(5, T2); // load a ++ __ load_ptr(3, FSR); // load c ++ __ store_ptr(3, T2); // store a in c ++ __ store_ptr(5, FSR); // store c in a ++ // stack: ..., c, d, a, b, c, d ++} ++ ++void TemplateTable::swap() { ++ transition(vtos, vtos); ++ // stack: ..., a, b ++ __ load_ptr(1, A5); // load a ++ __ load_ptr(0, FSR); // load b ++ __ store_ptr(0, A5); // store a in b ++ __ store_ptr(1, FSR); // store b in a ++ // stack: ..., b, a ++} ++ ++void TemplateTable::iop2(Operation op) { ++ transition(itos, itos); ++ ++ __ pop_i(SSR); ++ if (UseSW8A) { ++ switch (op) { ++ case add : __ addwu(SSR, FSR, FSR); break; ++ case sub : __ subwu(SSR, FSR, FSR); break; ++ case mul : __ mulwu(SSR, FSR, FSR); break; ++ case _and : __ andw(SSR, FSR, FSR); break; ++ case _or : __ orw(SSR, FSR, FSR); break; ++ case _xor : __ xorw(SSR, FSR, FSR); break; ++ case shl : __ sllw(SSR, FSR, FSR); break; ++ case shr : __ sraw(SSR, FSR, FSR); break; ++ case ushr : __ srlw(SSR, FSR, FSR); break; ++ default : ShouldNotReachHere(); ++ } ++ __ movws(FSR, FSR); ++ } else { ++ switch (op) { ++ case add : __ addwu(SSR, FSR, FSR); break; ++ case sub : __ subwu(SSR, FSR, FSR); break; ++ case mul : __ mulwu(SSR, FSR, FSR); break; ++ case _and : __ andw(SSR, FSR, FSR); break; ++ case _or : __ orw(SSR, FSR, FSR); break; ++ case _xor : __ xorw(SSR, FSR, FSR); break; ++ case shl : __ and_ins(FSR, 0x1f, FSR); __ slll(SSR, FSR, FSR); break; ++ case shr : __ and_ins(FSR, 0x1f, FSR); __ addw(SSR, 0, SSR); __ sral(SSR, FSR, FSR); break; ++ case ushr : __ and_ins(FSR, 0x1f, FSR); __ movwu(SSR, SSR); __ srll(SSR, FSR, FSR); break; ++ default : ShouldNotReachHere(); ++ } ++ __ movws(FSR, FSR); ++ } ++} ++ ++void TemplateTable::lop2(Operation op) { ++ transition(ltos, ltos); ++ __ pop_l(T2); ++ ++ switch (op) { ++ case add : __ addptr(T2, FSR, FSR); break; ++ case sub : __ subptr(T2, FSR, FSR); break; ++ case _and: __ andptr(T2, FSR, FSR); break; ++ case _or : __ orptr(T2, FSR, FSR); break; ++ case _xor: __ xorptr(T2, FSR, FSR); break; ++ default : ShouldNotReachHere(); ++ } ++} ++ ++void TemplateTable::idiv() { ++ transition(itos, itos); ++ Label not_zero; ++ ++ __ bne_l(FSR, not_zero); ++ __ jump(ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); ++ __ bind(not_zero); ++ ++ __ pop_i(SSR); ++ if (UseSW8A) { ++ __ corrected_idivw(SSR, FSR, FSR); ++ } else if (FastIntDiv) { ++ __ stop("check idiv_sw"); ++ __ idiv_sw(SSR, FSR, FSR);//TODO:need check jzy ++ } else { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::sdiv), FSR, SSR); ++ //__ movws(FSR, FSR);//clear high 32bits ++ } ++} ++ ++void TemplateTable::irem() { ++ transition(itos, itos); ++ Label not_zero; ++ __ pop_i(SSR); ++ ++ __ bne_l(FSR, not_zero); ++ __ jump(ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); ++ ++ __ bind(not_zero); ++ if (UseSW8A) { ++ __ remw(SSR, FSR, FSR); ++ } else if (FastIntRem) { ++ __ stop("check irem_sw"); ++ __ irem_sw(SSR, FSR, FSR);//TODO:need check jzy ++ } else { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::srem), FSR, SSR); ++ //__ movws(FSR, FSR);//clear high 32bits ++ } ++} ++ ++void TemplateTable::lmul() { ++ transition(ltos, ltos); ++ __ pop_l(T2); ++ __ mull(FSR, T2, FSR); ++} ++ ++void TemplateTable::ldiv() { ++ transition(ltos, ltos); ++ Label normal; ++ ++ __ bne_l(FSR, normal); ++ ++ __ jump(ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); ++ ++ __ bind(normal); ++ __ pop_l(A2); ++ if (UseSW8A) { ++ __ corrected_idivl(A2, FSR, FSR); ++ } else if (FastLongDiv) { ++ Label ldiv, exit; ++ __ slll(A2, 0xb, T7); ++ __ sral(T7, 0xb, T7); ++ __ cmpeq(A2, T7, T7); ++ __ bne_l(T7, ldiv); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv), FSR, A2); ++ __ jmp(exit); ++ ++ __ bind(ldiv); ++ __ ldiv_sw(A2, FSR, FSR); ++ ++ __ bind(exit); ++ } else { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv), FSR, A2); ++ } ++} ++ ++void TemplateTable::lrem() { ++ transition(ltos, ltos); ++ Label normal; ++ ++ __ bne_l(FSR, normal); ++ ++ __ jump(ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); ++ ++ __ bind(normal); ++ __ pop_l (A2); ++ if (UseSW8A) { ++ __ reml(A2, FSR, FSR); ++ } else if (FastLongRem) { ++ Label lrem, exit; ++ __ slll(A2, 0xb, T7); ++ __ sral(T7, 0xb, T7); ++ __ cmpeq(A2, T7, T7); ++ __ bne_l(T7, lrem); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem), FSR, A2); ++ __ jmp(exit); ++ ++ __ bind(lrem); ++ __ lrem_sw(A2, FSR, FSR); ++ ++ __ bind(exit); ++ } else { ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem), FSR, A2); ++ } ++} ++ ++void TemplateTable::lshl() { ++ transition(itos, ltos); ++ __ pop_l(T0); ++ __ slll(T0, FSR, FSR); ++} ++ ++void TemplateTable::lshr() { ++ transition(itos, ltos); ++ __ pop_l(T0); ++ __ sral(T0, FSR, FSR); ++} ++ ++void TemplateTable::lushr() { ++ transition(itos, ltos); ++ __ pop_l(T0); ++ __ srll(T0, FSR, FSR); ++} ++ ++void TemplateTable::fop2(Operation op) { ++ transition(ftos, ftos); ++ switch (op) { ++ case add: ++ __ flds(FTF, 0, esp); ++ __ add_s(FSF, FTF, FSF); ++ break; ++ case sub: ++ __ flds(FTF, 0, esp); ++ __ sub_s(FSF, FTF, FSF); ++ break; ++ case mul: ++ __ flds(FTF, 0, esp); ++ __ mul_s(FSF, FTF, FSF); ++ break; ++ case div: ++ __ flds(FTF, 0, esp); ++ __ div_s(FSF, FTF, FSF); ++ break; ++ case rem: ++ { ++ __ flds(f16, 0, esp); //x ++ __ fcpys(FSF, FSF, f17); ++ Label nan, cont, end; ++ ++ // y = 0.0f ++ __ ffbeq(f17, nan); ++ // x = NaN infinity ++ __ boundary_test(f16, GP); ++ __ beq_l(GP, nan); ++ // y = NaN ++ __ boundary_test(f17, GP); ++ __ bne_l(GP, cont); ++ __ fimovd(f17, AT); ++ __ slll(AT, 12, GP); ++ __ bne_l(GP, nan); ++ ++ __ bind(cont); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), 2); ++ __ jmp(end); ++ ++ __ bind(nan); ++ __ fdivd(f31, f31, FSF); ++ __ bind(end); ++ } ++ break; ++ default : ShouldNotReachHere(); ++ } ++ ++ __ addptr(esp, 1 * wordSize, esp); ++} ++ ++void TemplateTable::dop2(Operation op) { ++ transition(dtos, dtos); ++ switch (op) { ++ case add: ++ __ fldd(FTF, 0, esp); ++ __ add_d(FSF, FTF, FSF); ++ break; ++ case sub: ++ __ fldd(FTF, 0, esp); ++ __ sub_d(FSF, FTF, FSF); ++ break; ++ case mul: ++ __ fldd(FTF, 0, esp); ++ __ mul_d(FSF, FTF, FSF); ++ break; ++ case div: ++ __ fldd(FTF, 0, esp); ++ __ div_d(FSF, FTF, FSF); ++ break; ++ case rem: ++ { ++ __ fldd(f16, 0, esp); //x ++ __ fcpys(FSF, FSF, f17); ++ Label nan, cont, end; ++ // y = 0.0f ++ __ ffbeq(f17, nan); ++ // x = NaN infinity ++ __ boundary_test(f16, GP); ++ __ beq_l(GP, nan); ++ // y = NaN ++ __ boundary_test(f17, GP); ++ __ bne_l(GP, cont); ++ __ fimovd(f17, AT); ++ __ slll(AT, 12, GP); ++ __ bne_l(GP, nan); ++ ++ __ bind(cont); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), 2); ++ __ jmp(end); ++ ++ __ bind(nan); ++ __ fdivd(f31, f31, FSF); ++ __ bind(end); ++ } ++ break; ++ default : ShouldNotReachHere(); ++ } ++ ++ __ addptr(esp, 2 * wordSize, esp); ++} ++ ++void TemplateTable::ineg() { ++ transition(itos, itos); ++ __ subw(R0, FSR, FSR); ++} ++ ++void TemplateTable::lneg() { ++ transition(ltos, ltos); ++ __ subl(R0, FSR, FSR); ++} ++ ++void TemplateTable::fneg() { ++ transition(ftos, ftos); ++ __ fcpysn(FSF, FSF, FSF); ++} ++ ++void TemplateTable::dneg() { ++ transition(dtos, dtos); ++ __ fcpysn(FSF, FSF, FSF); ++} ++ ++void TemplateTable::iinc() { ++ transition(vtos, vtos); ++ __ load_signed_byte64(AT, at_bcp(2)); // get constant ++ locals_index(T2); ++ __ ldws(FSR, iaddress(T2)); ++ __ addl(FSR, AT, FSR); ++ __ stw(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::wide_iinc() { ++ transition(vtos, vtos); ++ locals_index_wide(T2); ++ __ get_unsigned_2_byte_index_at_bcp(FSR, 4); ++ __ sexth(FSR, FSR); ++ __ ldws(AT, iaddress(T2)); ++ __ addl(AT, FSR, FSR); ++ __ stw(FSR, iaddress(T2)); ++} ++ ++void TemplateTable::convert() { ++ // Checking ++#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 // ASSERT ++ ++ // Conversion ++ switch (bytecode()) { ++ case Bytecodes::_i2l: ++ __ movws(FSR, FSR); ++ break; ++ case Bytecodes::_i2f: ++ //__ movws(FSR, FSR); ++ if (UseSW8A) { ++ __ cmovws(FSF, FSR); ++ }else { ++ __ ifmovd(FSR, f30); ++ __ fcvtls(f30, FSF); ++ } ++ break; ++ case Bytecodes::_i2d: ++ //__ movws(FSR, FSR); ++ if (UseSW8A) { ++ __ cmovwd(FSF, FSR); ++ }else { ++ __ ifmovd(FSR, f30); ++ __ fcvtld(f30, FSF); ++ } ++ break; ++ case Bytecodes::_i2b: ++ __ sextb(FSR, FSR); ++ //__ movw(FSR, FSR); ++ break; ++ case Bytecodes::_i2c: ++ __ zapnot(FSR, 0x3, FSR); ++ break; ++ case Bytecodes::_i2s: ++ __ sexth(FSR, FSR); ++ //__ movws(FSR, FSR); ++ break; ++ case Bytecodes::_l2i: ++ __ movws(FSR, FSR); ++ break; ++ case Bytecodes::_l2f: ++ if (UseSW8A) { ++ __ cmovls(FSF, FSR); ++ }else { ++ __ ifmovd(FSR, FSF); ++ __ cvt_s_l(FSF, FSF); ++ } ++ break; ++ case Bytecodes::_l2d: ++ if (UseSW8A) { ++ __ cmovld(FSF, FSR); ++ }else { ++ __ ifmovd(FSR, FSF); ++ __ cvt_d_l(FSF, FSF); ++ } ++ break; ++ case Bytecodes::_f2i: ++ { ++ if (UseSW8A) { ++ __ cmovdw_z(FSR, FSF); ++ }else { ++ Label L; ++ __ fcpys(FSF, FSF, f16); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2i), 1); ++ //__ movws(FSR, FSR); ++ __ bind(L); ++ } ++ } ++ break; ++ case Bytecodes::_f2l: ++ { ++ if (UseSW8A) { ++ __ cmovdl_z(FSR, FSF); ++ }else { ++ Label L; ++ __ fcpys(FSF, FSF, f16); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2l), 1); ++ __ bind(L); ++ } ++ } ++ break; ++ case Bytecodes::_f2d: ++ __ cvt_d_s(FSF, FSF); ++ break; ++ case Bytecodes::_d2i: ++ { ++ if (UseSW8A) { ++ __ cmovdw_z(FSR, FSF); ++ }else { ++ Label L; ++ __ fcpys(FSF, FSF, f16); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2i), 1); ++ //__ movws(FSR, FSR); ++ __ bind(L); ++ } ++ } ++ break; ++ case Bytecodes::_d2l: ++ { ++ if (UseSW8A) { ++ __ cmovdl_z(FSR, FSF); ++ }else { ++ Label L; ++ __ fcpys(FSF, FSF, f16); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2l), 1); ++ __ bind(L); ++ } ++ } ++ break; ++ case Bytecodes::_d2f: ++ __ cvt_s_d(FSF, FSF); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++} ++ ++void TemplateTable::lcmp() { ++ transition(ltos, itos); ++ ++ Label done; ++ __ pop_l(SSR); ++ __ cmpl(SSR, FSR); ++ __ ldi(FSR, -1, R0); ++ __ jcc(Assembler::less, done); ++ __ ldi(FSR, 0, R0); ++ __ jcc(Assembler::equal, done); ++ __ ldi(FSR, 1, R0); ++ __ bind(done); ++} ++ ++void TemplateTable::float_cmp(bool is_float, int unordered_result) { ++ Label less, done; ++ ++ __ bis(R0, R0, FSR); ++ if (is_float) { ++ __ flds(FTF, 0, esp); ++ __ fcmpeq(FTF, FSF, FcmpRES); ++ __ addiu(esp, 1 * wordSize, esp); ++ __ ffbne(FcmpRES, done); ++ ++ if (unordered_result < 0) ++ __ c_ult_s(FTF, FSF); ++ else ++ __ c_olt_s(FTF, FSF); ++ } else { ++ __ fldd(FTF, 0, esp); ++ __ fcmpeq(FTF, FSF, FcmpRES); ++ __ addiu(esp, 2 * wordSize, esp); ++ __ ffbne(FcmpRES, done); ++ ++ if (unordered_result<0) ++ __ c_ult_d(FTF, FSF); ++ else ++ __ c_olt_d(FTF, FSF); ++ } ++ __ ffbne(FcmpRES, less); ++ __ ldi(FSR, 1, R0); ++ __ jmp(done); ++ __ bind(less); ++ __ ldi(FSR, -1, R0); ++ __ bind(done); ++} ++ ++void TemplateTable::branch(bool is_jsr, bool is_wide) {SCOPEMARK_NAME(TemplateTable_branch, _masm) ++ Register rcx = rmethod; ++ Register rax = T5; ++ Register rbx = T2; ++ Register rdx = T7; ++ __ get_method(rcx); ++ __ profile_taken_branch(rax, rbx); // T5 holds updated MDP, T2 ++ // holds bumped taken count ++ ++ const ByteSize be_offset = MethodCounters::backedge_counter_offset() + ++ InvocationCounter::counter_offset(); ++ const ByteSize inv_offset = MethodCounters::invocation_counter_offset() + ++ InvocationCounter::counter_offset(); ++ ++ // Load up T7 with the branch displacement TODO:check jzy ++ if (is_wide) { ++ __ ldbu(T7, at_bcp(1)); ++ __ ldbu(AT, at_bcp(2)); ++ __ slll(T7, 8, T7); ++ __ bis(T7, AT, T7); ++ __ ldbu(AT, at_bcp(3)); ++ __ slll(T7, 8, T7); ++ __ bis(T7, AT, T7); ++ __ ldbu(AT, at_bcp(4)); ++ __ slll(T7, 8, T7); ++ __ bis(T7, AT, T7); ++ __ movws(T7, T7); ++ } else { ++ __ load_signed_byte64(T7, at_bcp(1)); ++ __ ldbu(AT, at_bcp(2)); ++ __ slll(T7, 8, T7); ++ __ bis(T7, AT, T7); ++ } ++ ++ // 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) { ++ // Pre-load the next target bytecode into rnext ++ __ load_unsigned_byte(rnext, Address(rbcp, T7, Address::times_1, 0)); ++ ++ // compute return address as bci in FSR ++ __ lea(FSR, at_bcp((is_wide ? 5 : 3) - ++ in_bytes(ConstMethod::codes_offset()))); ++ __ ldptr(AT, Address(rmethod, Method::const_offset())); ++ __ subptr(FSR, AT, FSR); ++ // Adjust the bcp in rbcp by the displacement in T7 ++ __ addptr(rbcp, T7, rbcp); ++ // jsr returns atos that is not an oop ++ __ push_i(FSR); ++ __ dispatch_only(vtos, true); ++ return; ++ } ++ ++ // Normal (non-jsr) branch handling ++ ++ // Adjust the bcp in S0 by the displacement in T7 ++ __ addptr(rbcp, T7, rbcp); ++ ++ assert(UseLoopCounter || !UseOnStackReplacement, ++ "on-stack-replacement requires loop counters"); ++ Label backedge_counter_overflow; ++ Label profile_method; ++ Label dispatch; ++ if (UseLoopCounter) { ++ // increment backedge counter for backward branches ++ // T5: MDO ++ // T2: MDO bumped taken-count ++ // rmethod: method ++ // T7: target offset ++ // rbcp: target bcp ++ // rlocals: locals pointer ++ // check if forward or backward branch ++ __ jcc(Assembler::positive, dispatch, T7); // count only if backward branch ++ ++ // check if MethodCounters exists ++ Label has_counters; ++ __ ldptr(rcc, Address(rmethod, Method::method_counters_offset())); ++ __ jcc(Assembler::notZero, has_counters); ++ __ push(T7); ++ __ push(T2); ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), ++ rmethod); ++ __ pop(T2); ++ __ pop(T7); ++ __ ldptr(T5, Address(rmethod, Method::method_counters_offset())); ++ __ jcc(Assembler::zero, dispatch, T5); ++ __ bind(has_counters); ++ ++ if (TieredCompilation) { ++ Label no_mdo; ++ int increment = InvocationCounter::count_increment; ++ if (ProfileInterpreter) { ++ // Are we profiling? ++ __ ldptr(T2, Address(rmethod, Method::method_data_offset())); //T2 for p1876 used ++ __ jcc(Assembler::zero, no_mdo, T2); ++ // Increment the MDO backedge counter ++ const Address mdo_backedge_counter(T2, in_bytes(MethodData::backedge_counter_offset()) + ++ in_bytes(InvocationCounter::counter_offset())); ++ const Address mask(T2, in_bytes(MethodData::backedge_mask_offset())); ++ __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, T5, false, Assembler::zero, ++ UseOnStackReplacement ? &backedge_counter_overflow : NULL); ++ __ jmp(dispatch); ++ } ++ __ bind(no_mdo); ++ // Increment backedge counter in MethodCounters* ++ __ ldptr(T0, Address(rmethod, Method::method_counters_offset())); ++ const Address mask(T0, in_bytes(MethodCounters::backedge_mask_offset())); ++ __ increment_mask_and_jump(Address(T0, be_offset), increment, mask, ++ T5, false, Assembler::zero, ++ UseOnStackReplacement ? &backedge_counter_overflow : NULL); ++ } else { // not TieredCompilation ++ // increment counter ++ Register rmcs = T4; ++ Register rbe = T3; ++ Register rinv = T1; //backedge counter & invocation counter ++ __ ldptr(rmcs, Address(rmethod, Method::method_counters_offset())); ++ __ ldws(rbe, Address(rmcs, be_offset)); // load backedge counter ++ __ addl(rbe, InvocationCounter::count_increment, rbe); // increment counter ++ __ stw(rbe, Address(rmcs, be_offset)); // store counter ++ ++ __ ldws(rinv, Address(rmcs, inv_offset)); // load invocation counter ++ ++ __ andw(rinv, InvocationCounter::count_mask_value, rinv); // and the status bits ++ __ addwu(rinv, rbe, rinv); // add both counters TODO:check jzy ++ ++ if (ProfileInterpreter) { ++ // Test to see if we should create a method data oop ++ __ cmpw(rinv, Address(rmcs, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); ++ __ jcc(Assembler::less, dispatch); ++ ++ // if no method data exists, go to profile method ++ __ test_method_data_pointer(rinv, profile_method); ++ ++ if (UseOnStackReplacement) { ++ // check for overflow against T2 which is the MDO taken count ++ __ cmpw(T2, Address(rmcs, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); ++ __ jcc(Assembler::below, dispatch); ++ ++ // 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. ++ const int overflow_frequency = 1024; ++ __ andw(T2, overflow_frequency - 1, rcc);// TODO check lsp zero extend is ok?? ++// __ ldi(rscratch3, overflow_frequency-1, R0); ++// __ and_ins(rscratch3, T2, rcc); ++ __ jcc(Assembler::zero, backedge_counter_overflow); ++ ++ } ++ } else { ++ if (UseOnStackReplacement) { ++ // check for overflow against rax, which is the sum of the ++ // counters ++ __ cmpw(rinv, Address(rmcs, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); ++ __ jcc(Assembler::aboveEqual, backedge_counter_overflow); ++ ++ } ++ } ++ } ++ __ bind(dispatch); ++ } ++ ++ // Pre-load the next target bytecode into rnext ++ __ load_unsigned_byte(rnext, Address(rbcp, 0)); ++ ++ // continue with the bytecode @ target ++ // FSR: return bci for jsr's, unused otherwise ++ // rnext: target bytecode ++ // rbcp: target bcp ++ __ dispatch_only(vtos, true); ++ ++ if (UseLoopCounter) { ++ if (ProfileInterpreter && !TieredCompilation) { ++ // Out-of-line code to allocate method data oop. ++ __ bind(profile_method); ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); ++ __ load_unsigned_byte(rnext, Address(rbcp, 0)); //swjdk8 and aarch64 use it lsp?? ++ __ set_method_data_pointer_for_bcp(); ++ __ jmp(dispatch); ++ } ++ ++ if (UseOnStackReplacement) { ++ // invocation counter overflow ++ __ bind(backedge_counter_overflow); ++ __ subptr(R0, T7, T7); // yj todo: ?? why neg T7 ++ __ addptr(T7, rbcp, T7); // branch bcp ++ // IcoResult frequency_counter_overflow([JavaThread*], address branch_bcp) ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::frequency_counter_overflow), ++ T7); ++ __ load_unsigned_byte(rnext, Address(rbcp, 0)); //swjdk8 and aarch64 use it lsp?? ++ // V0: osr nmethod (osr ok) or NULL (osr not possible) return by the call_vm ++ __ testptr(V0, V0); // test result ++ __ jcc(Assembler::zero, dispatch); // no osr if null ++ // nmethod may have been invalidated (VM may block upon call_VM return) ++ __ cmpb(Address(V0, nmethod::state_offset()), nmethod::in_use); ++ __ jcc(Assembler::notEqual, dispatch); ++ ++ // We have the address of an on stack replacement routine in V0. ++ // In preparation of invoking it, first we must migrate the locals ++ // and monitors from off the interpreter frame on the stack. ++ // Ensure to save the osr nmethod over the migration call, ++ // it will be preserved in rbcp. ++ __ movl(rbcp, V0); ++ ++ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); ++ ++ // V0 is OSR buffer, move it to expected parameter location ++ __ movl(j_rarg0, V0); ++ // We use j_rarg definitions here so that registers don't conflict as parameter ++ // registers change across platforms as we are in the midst of a calling ++ // sequence to the OSR nmethod and we don't want collision. These are NOT parameters. ++ ++ const Register retaddr = j_rarg2; ++ const Register sender_sp = j_rarg1; ++ ++ // pop the interpreter frame ++ __ ldptr(sender_sp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender ++ __ leave(); // remove frame anchor ++ __ move(retaddr, RA); // get return address ++ // set sp to sender sp ++ // Ensure compiled code always sees stack at proper alignment ++ //__ andptr(sender_sp, -(StackAlignmentInBytes), esp); //TODO: jzy check why need alignment? ++ __ movl(esp, sender_sp); ++ ++ // unlike x86 we need no specialized return from compiled code ++ // to the interpreter or the call stub. ++ ++ // push the return address ++// __ push(retaddr); ++ ++ // and begin the OSR nmethod ++ __ jmp(Address(rbcp, nmethod::osr_entry_point_offset())); ++ } ++ } ++} ++ ++void TemplateTable::if_0cmp(Condition cc) {SCOPEMARK_NAME(if_0cmp, _masm) ++ transition(itos, vtos); ++ // assume branch is more often taken than not (loops use backward branches) ++ Label not_taken; ++ __ cmpw(FSR, R0); ++ __ jcc(j_not(cc), not_taken); ++ branch(false, false); ++ __ bind(not_taken); ++ __ profile_not_taken_branch(FSR); ++} ++ ++void TemplateTable::if_icmp(Condition cc) { ++ transition(itos, vtos); ++ // assume branch is more often taken than not (loops use backward branches) ++ Label not_taken; ++ __ pop_i(SSR); ++ __ cmpw(SSR, FSR); ++ __ jcc(j_not(cc), not_taken); ++ branch(false, false); ++ __ bind(not_taken); ++ __ profile_not_taken_branch(FSR); ++} ++ ++void TemplateTable::if_nullcmp(Condition cc) { ++ transition(atos, vtos); ++ // assume branch is more often taken than not (loops use backward branches) ++ Label not_taken; ++ __ testptr(FSR, FSR); ++ __ jcc(j_not(cc), not_taken); ++ branch(false, false); ++ __ bind(not_taken); ++ __ profile_not_taken_branch(FSR); ++} ++ ++void TemplateTable::if_acmp(Condition cc) { ++ transition(atos, vtos); ++ // assume branch is more often taken than not (loops use backward branches) ++ Label not_taken; ++ __ pop_ptr(SSR); ++ __ cmpoop(SSR, FSR); ++ __ jcc(j_not(cc), not_taken); ++ branch(false, false); ++ __ bind(not_taken); ++ __ profile_not_taken_branch(FSR); ++} ++ ++void TemplateTable::ret() {SCOPEMARK_NAME(TemplateTable::ret, _masm) ++ transition(vtos, vtos); ++ locals_index(T2); ++ __ ldptr(T2, iaddress(T2)); // get return bci, compute return bcp ++ __ profile_ret(T2, T3); ++ __ get_method(T1); ++ __ ldptr(rbcp, Address(T1, Method::const_offset())); ++ __ lea(rbcp, Address(rbcp, T2, Address::times_1, ++ ConstMethod::codes_offset())); ++ __ dispatch_next(vtos, 0, true); ++} ++ ++void TemplateTable::wide_ret() { ++ transition(vtos, vtos); ++ locals_index_wide(T2); ++ __ ldptr(T2, aaddress(T2)); // get return bci, compute return bcp ++ __ profile_ret(T2, T3); ++ __ get_method(T1); ++ __ ldptr(rbcp, Address(T1, Method::const_offset())); ++ __ lea(rbcp, Address(rbcp, T2, Address::times_1, ConstMethod::codes_offset())); ++ __ dispatch_next(vtos, 0, true); ++} ++ ++void TemplateTable::tableswitch() { ++ Label default_case, continue_execution; ++ transition(itos, vtos); ++ Register rbx = T2; ++ Register rcx = T3; ++ Register rdx = T7; ++ Register rax = FSR; ++ ++ // align rbcp ++ __ lea(rbx, at_bcp(BytesPerInt)); ++ __ andptr(rbx, -BytesPerInt, rbx); ++ // load lo & hi ++ __ ldwu(rcx, Address(rbx, BytesPerInt)); ++ __ ldwu(rdx, Address(rbx, 2 * BytesPerInt)); ++ __ bswapw(rcx); ++ __ bswapw(rdx); ++ // check against lo & hi ++ __ cmpw(rax, rcx); ++ __ jcc(Assembler::less, default_case); ++ __ cmpw(rax, rdx); ++ __ jcc(Assembler::greater, default_case); ++ // lookup dispatch offset ++ __ subwu(rax, rcx, rax); ++ __ ldwu(rdx, Address(rbx, rax, Address::times_4, 3 * BytesPerInt)); ++ __ profile_switch_case(rax, rbx, rcx); ++ // continue execution ++ __ bind(continue_execution); ++ __ bswapw(rdx); ++ __ addw(rdx, R0, rdx);// sign extend T7 ++ __ load_unsigned_byte(rnext, Address(rbcp, rdx, Address::times_1)); ++ __ addptr(rbcp, rdx, rbcp); ++ __ dispatch_only(vtos, true); ++ // handle default ++ __ bind(default_case); ++ __ profile_switch_default(rax); ++ __ ldw(rdx, Address(rbx, 0)); ++ __ jmp(continue_execution); ++} ++ ++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; ++ const Register rbx = T2; ++ const Register rcx = T3; ++ const Register rdx = T7; ++ // swap FSR so we can avoid swapping the table entries ++ __ bswapw(FSR); ++ // align rbcp ++ __ lea(rbx, at_bcp(BytesPerInt)); // btw: should be able to get rid of ++ // this instruction (change offsets ++ // below) ++ __ andptr(rbx, -BytesPerInt, rbx); ++ // set counter ++ __ ldwu(rcx, Address(rbx, BytesPerInt)); ++ __ bswapw(rcx); ++ __ jmp(loop_entry); ++ // table search ++ __ bind(loop); ++ __ cmpw(FSR, Address(rbx, rcx, Address::times_8, 2 * BytesPerInt)); ++ __ jcc(Assembler::equal, found); ++ __ bind(loop_entry); ++ __ decrementl(rcx); ++ __ jcc(Assembler::greaterEqual, loop, rcx); ++ // default case ++ __ profile_switch_default(FSR); ++ __ ldw(rdx, Address(rbx, 0)); ++ __ jmp(continue_execution); ++ // entry found -> get offset ++ __ bind(found); ++ __ ldwu(rdx, Address(rbx, rcx, Address::times_8, 3 * BytesPerInt)); ++ __ profile_switch_case(rcx, FSR, rbx); ++ // continue execution ++ __ bind(continue_execution); ++ __ bswapw(rdx); ++ __ addw(rdx, R0, rdx);// sign extend rdx ++ __ load_unsigned_byte(rnext, Address(rbcp, rdx, Address::times_1)); ++ __ addptr(rbcp, rdx, rbcp); ++ __ dispatch_only(vtos, true); ++} ++ ++void TemplateTable::fast_binaryswitch() { ++ transition(itos, vtos); ++ // Implementation using the following core algorithm: ++ // ++ // 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 ++ const Register key = FSR; // already set (tosca) ++ const Register array = T2; ++ const Register i = T3; ++ const Register j = T7; ++ const Register h = T1; ++ const Register temp = T0; ++ ++ //__ subw(FSR, R0, key);//sign extend ++ // Find array start ++ __ lea(array, at_bcp(3 * BytesPerInt)); // btw: should be able to ++ // get rid of this ++ // instruction (change ++ // offsets below) ++ __ andptr(array, -BytesPerInt, array); ++ ++ // initialize i & j ++ __ movw(i, R0); // i = 0; ++ __ ldwu(j, Address(array, -BytesPerInt)); // j = length(array); ++ ++ // Convert j into native byteordering ++ __ bswapw(j); ++ ++ // And start ++ Label entry; ++ __ jmp(entry); ++ BLOCK_COMMENT("binary search loop"); ++ // binary search loop ++ { ++ Label loop; ++ __ bind(loop); ++ // int h = (i + j) >> 1; ++ __ addw(i, j, h); // h = i + j; ++ __ srll(h, 1, h); // h = (i + j) >> 1; ++ // if (key < array[h].fast_match()) { ++ // j = h; ++ // } else { ++ // i = h; ++ // } ++ // Convert array[h].match to native byte-ordering before compare ++ __ ldwu(temp, Address(array, h, Address::times_8)); ++ __ bswapw(temp); ++ __ subw(temp, R0, temp); ++ __ cmpl(key, temp); ++ // j = h if (key < array[h].fast_match()) ++ __ cmove(Assembler::less, j, h, j); ++ // i = h if (key >= array[h].fast_match()) ++ __ cmove(Assembler::greaterEqual, i, h, i); ++ // while (i+1 < j) ++ __ bind(entry); ++ __ addwu(i, 1, h); // i+1 ++ __ cmpw(h, j); // i+1 < j ++ __ jcc(Assembler::less, loop); ++ } ++ ++ // end of binary search, result index is i (must check again!) ++ Label default_case; ++ // Convert array[i].match to native byte-ordering before compare ++ __ ldwu(temp, Address(array, i, Address::times_8)); ++ __ bswapw(temp); ++ __ subw(temp, R0, temp); ++ __ cmpl(key, temp); ++ __ jcc(Assembler::notEqual, default_case); ++ ++ // entry found -> j = offset ++ __ ldwu(j , Address(array, i, Address::times_8, BytesPerInt)); ++ __ profile_switch_case(i, key, array); ++ __ bswapw(j); ++ __ addw(j, R0, j);// sign extend j ++ ++ __ load_unsigned_byte(rnext, Address(rbcp, j, Address::times_1)); ++ __ addptr(rbcp, j, rbcp); ++ __ dispatch_only(vtos, true); ++ ++ // default case -> j = default offset ++ __ bind(default_case); ++ __ profile_switch_default(i); ++ __ ldwu(j, Address(array, -2 * BytesPerInt)); ++ __ bswapw(j); ++ __ addw(j, R0, j); ++ ++ __ movws(key, key);//clear hi-32bit ++ ++ __ load_unsigned_byte(rnext, Address(rbcp, j, Address::times_1)); ++ __ addptr(rbcp, j, rbcp); ++ __ dispatch_only(vtos, true); ++} ++ ++void TemplateTable::_return(TosState state) {SCOPEMARK_NAME(TemplateTable::_return, _masm) ++ transition(state, state); ++ ++ assert(_desc->calls_vm(), ++ "inconsistent calls_vm information"); // call in remove_activation ++ ++ if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { ++ assert(state == vtos, "only valid state"); ++ Register robj = c_rarg1; ++ __ ldptr(robj, aaddress(0)); ++ __ load_klass(T1, robj); ++ __ ldw(T1, Address(T1, Klass::access_flags_offset())); ++ __ testw(T1, JVM_ACC_HAS_FINALIZER); ++ Label skip_register_finalizer; ++ __ jcc(Assembler::zero, skip_register_finalizer); ++ ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), robj); ++ ++ __ bind(skip_register_finalizer); ++ } ++ ++ if (SafepointMechanism::uses_thread_local_poll() && _desc->bytecode() != Bytecodes::_return_register_finalizer) { ++ Label no_safepoint; ++ NOT_PRODUCT(__ block_comment("Thread-local Safepoint poll")); ++ __ ldbu(AT, Address(rthread, Thread::polling_page_offset())); ++ __ and_ins(AT, SafepointMechanism::poll_bit(), rcc); ++ __ jcc(Assembler::zero, no_safepoint); ++ __ 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(FSR); ++ } ++ ++ __ remove_activation(state, T12); ++ if(UseWmemb) ++ __ wmemb(); ++ else ++ __ memb(); ++ ++ __ jmp(T12); ++} ++ ++// ---------------------------------------------------------------------------- ++// 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() { ++ if(os::is_MP()) __ memb(); ++} ++ ++void TemplateTable::resolve_cache_and_index(int byte_no, ++ Register Rcache, ++ Register index, ++ size_t index_size) {SCOPEMARK_NAME(resolve_cache_and_index, _masm) ++ const Register temp = A1; ++ assert_different_registers(Rcache, index, temp); ++ ++ Label resolved, Ldone; ++ ++ Bytecodes::Code code = bytecode(); ++ switch (code) { ++ case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; ++ case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; ++ default: 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, temp, byte_no, 1, index_size); ++ __ cmpw(temp, code); // have we resolved this bytecode? ++ __ jcc(Assembler::equal, resolved); ++ ++ // resolve first time through ++ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); ++ __ movw(temp, code); ++ __ call_VM(noreg, entry, temp); ++ // Update registers with resolved info ++ __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); ++ __ jmp(Ldone); ++ ++ __ bind(resolved); ++ __ memb(); // Order load wrt. succeeding loads. ++ __ bind(Ldone); ++} ++ ++// The Rcache and index registers must be set before call ++// n.b unlike x86 cache already includes the index offset// yj todo: ?? ++void TemplateTable::load_field_cp_cache_entry(Register obj, ++ Register cache, ++ Register index, ++ Register off, ++ Register flags, ++ bool is_static = false) {SCOPEMARK_NAME(load_field_cp_cache_entry, _masm) ++ assert_different_registers(cache, index, flags, off); ++ ++ ByteSize cp_base_offset = ConstantPoolCache::base_offset(); ++ // Field offset ++ __ ldptr(off, Address(cache, index, Address::times_ptr, ++ in_bytes(cp_base_offset + ++ ConstantPoolCacheEntry::f2_offset()))); ++ // Flags ++ __ ldwu(flags, Address(cache, index, Address::times_ptr, ++ in_bytes(cp_base_offset + ++ ConstantPoolCacheEntry::flags_offset()))); ++ ++ // klass overwrite register ++ if (is_static) { ++ __ ldptr(obj, Address(cache, index, Address::times_ptr, ++ in_bytes(cp_base_offset + ++ ConstantPoolCacheEntry::f1_offset()))); ++ const int mirror_offset = in_bytes(Klass::java_mirror_offset()); ++ __ ldptr(obj, Address(obj, mirror_offset)); ++ __ resolve_oop_handle(obj); ++ } ++} ++ ++void TemplateTable::load_invoke_cp_cache_entry(int byte_no, ++ Register method, ++ Register itable_index, ++ Register flags, ++ bool is_invokevirtual, ++ bool is_invokevfinal, /*unused*/ ++ bool is_invokedynamic) {SCOPEMARK_NAME(load_invoke_cp_cache_entry, _masm) ++ // setup registers ++ const Register cache = T3; ++ const Register index = T1; ++ assert_different_registers(method, flags); ++ assert_different_registers(method, cache, index); ++ assert_different_registers(itable_index, flags); ++ assert_different_registers(itable_index, cache, 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()); ++ ++ size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2)); ++ resolve_cache_and_index(byte_no, cache, index, index_size); ++ __ ldptr(method, Address(cache, index, Address::times_ptr, method_offset)); ++ ++ if (itable_index != noreg) { ++ // pick up itable or appendix index from f2 also: ++ __ ldptr(itable_index, Address(cache, index, Address::times_ptr, index_offset)); ++ } ++ __ ldwu(flags, Address(cache, index, Address::times_ptr, flags_offset)); ++} ++ ++// The registers cache and index expected to be set before call. ++// Correct values of the cache and index registers are preserved. ++void TemplateTable::jvmti_post_field_access(Register cache, ++ Register index, ++ bool is_static, ++ bool has_tos) { ++ 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 L1; ++ assert_different_registers(cache, index, rax); ++ __ ldws(rax, ExternalAddress((address) JvmtiExport::get_field_access_count_addr())); ++ __ jcc(Assembler::zero, L1, rax); ++ ++ // cache entry pointer ++ __ addptr(cache, in_bytes(ConstantPoolCache::base_offset()), cache); ++ __ slll(index, LogBytesPerWord, index); ++ __ addptr(cache, index, cache); ++ if (is_static) { ++ __ movl(rax, R0); // NULL object reference ++ } else { ++ __ pop(atos); ++ __ verify_oop(rax); ++ __ push(atos); ++ } ++ // FSR: object pointer or NULL ++ // cache: cache entry pointer ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), ++ rax, cache); ++ __ get_cache_and_index_at_bcp(cache, index, 1); ++ __ bind(L1); ++ } ++} ++ ++void TemplateTable::pop_and_check_object(Register r) {SCOPEMARK_NAME(pop_and_check_object, _masm) ++ __ pop_ptr(r); ++ __ null_check(r); // for field access must check obj. ++ __ verify_oop(r); ++} ++ ++void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) {SCOPEMARK_NAME(getfield_or_static, _masm) ++ transition(vtos, vtos); ++ ++ const Register cache = T3; ++ const Register index = T0; ++ const Register obj = c_rarg3; ++ const Register off = T2; ++ const Register flags = T1; ++ const Register bc = c_rarg3; // uses same reg as obj, so don't mix them ++ ++ resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); ++ jvmti_post_field_access(cache, index, is_static, false); ++ load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); ++ ++ const Register bVolatile = T11;// don't clobber it ++ {// yj todo: x86 seems don't care for the volatile, but aarch64 cares. ++ __ andw(flags, 1 << ConstantPoolCacheEntry::is_volatile_shift, bVolatile); ++ ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, bVolatile); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++ ++ if (!is_static) pop_and_check_object(obj); ++ ++ const Address field(obj, off, Address::times_1, 0*wordSize); ++ ++ Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; ++ ++ __ srll(flags, ConstantPoolCacheEntry::tos_state_shift, flags); ++ // Make sure we don't need to mask edx after the above shift ++ assert(btos == 0, "change code, btos != 0"); ++ ++ __ andw(flags, ConstantPoolCacheEntry::tos_state_mask, flags); ++ ++ __ jcc(Assembler::notZero, notByte, flags); ++ // btos ++ __ access_load_at(T_BYTE, IN_HEAP, FSR, field, noreg, noreg); ++ __ push(btos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_bgetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notByte); ++ __ cmpw(flags, ztos); ++ __ jcc(Assembler::notEqual, notBool); ++ ++ // ztos (same code as btos) ++ __ access_load_at(T_BOOLEAN, IN_HEAP, FSR, field, noreg, noreg); ++ __ push(ztos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ // use btos rewriting, no truncating to t/f bit is needed for getfield. ++ patch_bytecode(Bytecodes::_fast_bgetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notBool); ++ __ cmpw(flags, atos); ++ __ jcc(Assembler::notEqual, notObj); ++ // atos ++ do_oop_load(_masm, field, FSR); ++ __ push(atos); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_agetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notObj); ++ __ cmpw(flags, itos); ++ __ jcc(Assembler::notEqual, notInt); ++ // itos ++ __ access_load_at(T_INT, IN_HEAP, FSR, field, noreg, noreg); ++ __ push(itos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_igetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notInt); ++ __ cmpw(flags, ctos); ++ __ jcc(Assembler::notEqual, notChar); ++ // ctos ++ __ access_load_at(T_CHAR, IN_HEAP, FSR, field, noreg, noreg); ++ __ push(ctos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_cgetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notChar); ++ __ cmpw(flags, stos); ++ __ jcc(Assembler::notEqual, notShort); ++ // stos ++ __ access_load_at(T_SHORT, IN_HEAP, FSR, field, noreg, noreg); ++ __ push(stos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_sgetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notShort); ++ __ cmpw(flags, ltos); ++ __ jcc(Assembler::notEqual, notLong); ++ // ltos ++ // yj todo: ??Generate code as if volatile (x86_32). There just aren't enough registers to ++ // save that information and this code is faster than the test. ++ __ access_load_at(T_LONG, IN_HEAP | MO_RELAXED, noreg /* ltos */, field, noreg, noreg); ++ __ push(ltos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) patch_bytecode(Bytecodes::_fast_lgetfield, bc, T2); ++ __ jmp(Done); ++ ++ __ bind(notLong); ++ __ cmpw(flags, ftos); ++ __ jcc(Assembler::notEqual, notFloat); ++ // ftos ++ ++ __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); ++ __ push(ftos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_fgetfield, bc, T2); ++ } ++ __ jmp(Done); ++ ++ __ bind(notFloat); ++#ifdef ASSERT ++ __ cmpw(flags, dtos); ++ __ jcc(Assembler::notEqual, notDouble); ++#endif ++ // dtos ++ __ access_load_at(T_DOUBLE, IN_HEAP, noreg /* dtos */, field, noreg, noreg); ++ __ push(dtos); ++ // Rewrite bytecode to be faster ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_dgetfield, bc, T2); ++ } ++#ifdef ASSERT ++ __ jmp(Done); ++ ++ ++ __ bind(notDouble); ++ __ stop("Bad state"); ++#endif ++ ++ __ bind(Done); ++ ++ { ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, bVolatile); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++} ++ ++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); ++} ++ ++ ++// The registers cache and index expected to be set before call. ++// The function may destroy various registers, just not the cache and index registers. ++void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { ++ ++ const Register robj = c_rarg2; ++ const Register RBX = c_rarg1; ++ const Register RCX = c_rarg3; ++ const Register RDX = rscratch1; ++ ++ 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 L1; ++ assert_different_registers(cache, index, rcc); ++ __ ldws(rcc, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr())); ++ __ jcc(Assembler::zero, L1); ++ ++ __ get_cache_and_index_at_bcp(robj, RDX, 1); ++ ++ ++ if (is_static) { ++ // Life is simple. Null out the object pointer. ++ __ movw(RBX, R0); ++ ++ } else { ++ // 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. ++ __ ldwu(RCX, Address(robj, RDX, ++ Address::times_ptr, ++ in_bytes(cp_base_offset + ++ ConstantPoolCacheEntry::flags_offset()))); ++ __ srll(RCX, ConstantPoolCacheEntry::tos_state_shift, RCX); ++ ++ // Make sure we don't need to mask rcx after the above shift ++ ConstantPoolCacheEntry::verify_tos_state_shift(); ++ __ ldptr(c_rarg1, at_tos_p1()); // initially assume a one word jvalue ++ __ cmpw(c_rarg3, ltos); ++ __ ldptr(AT, at_tos_p2()); ++ __ cmove(Assembler::equal, ++ c_rarg1, AT, c_rarg1); // ltos (two word jvalue) ++ __ cmpw(c_rarg3, dtos); ++ __ cmove(Assembler::equal, ++ c_rarg1, AT, c_rarg1); // dtos (two word jvalue) ++ } ++ // cache entry pointer ++ __ addptr(robj, in_bytes(cp_base_offset), robj); ++ __ slll(RDX, LogBytesPerWord, RDX); ++ __ addptr(robj, RDX, robj); ++ // object (tos) ++ __ movl(RCX, esp); ++ // c_rarg1: object pointer set up above (NULL if static) ++ // c_rarg2: cache entry pointer ++ // c_rarg3: jvalue object on the stack ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::post_field_modification), ++ RBX, robj, RCX); ++ __ get_cache_and_index_at_bcp(cache, index, 1); ++ __ bind(L1); ++ } ++} ++ ++void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) {SCOPEMARK_NAME(putfield_or_static, _masm) ++ transition(vtos, vtos); ++ ++ const Register cache = T3; ++ const Register index = T0; ++ const Register obj = T3; ++ const Register off = T2; ++ const Register flags = T1; ++ const Register bc = c_rarg3; ++ ++ resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); ++ jvmti_post_field_mod(cache, index, is_static); ++ load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); ++ ++ //x64 dont need mb since its mem seq model is strong, but we are weak, we ref aarch64 here. ++ const Register bVolatile = T11;// yj todo: will T11 be clobber?? ++ Label notVolatile, Done; ++ __ andw(flags, 1 << ConstantPoolCacheEntry::is_volatile_shift, bVolatile); ++ __ jcc(Assembler::zero, notVolatile, bVolatile); ++ volatile_barrier(); ++ __ BIND(notVolatile); ++ ++ // field addresses ++ const Address field(obj, off, Address::times_1, 0*wordSize); ++ ++ Label notByte, notBool, notInt, notShort, notChar, ++ notLong, notFloat, notObj, notDouble; ++ ++ __ srll(flags, ConstantPoolCacheEntry::tos_state_shift, flags); ++ ++ assert(btos == 0, "change code, btos != 0"); ++ __ andw(flags, ConstantPoolCacheEntry::tos_state_mask, flags); ++ __ jcc(Assembler::notZero, notByte, flags); ++ ++ // btos ++ { ++ __ pop(btos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_BYTE, IN_HEAP, field, FSR, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_bputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notByte); ++ __ cmpw(flags, ztos); ++ __ jcc(Assembler::notEqual, notBool); ++ ++ // ztos ++ { ++ __ pop(ztos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_BOOLEAN, IN_HEAP, field, FSR, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_zputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notBool); ++ __ cmpw(flags, atos); ++ __ jcc(Assembler::notEqual, notObj); ++ ++ // atos ++ { ++ __ pop(atos); ++ if (!is_static) pop_and_check_object(obj); ++ // Store into the field ++ do_oop_store(_masm, field, FSR); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_aputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notObj); ++ __ cmpw(flags, itos); ++ __ jcc(Assembler::notEqual, notInt); ++ ++ // itos ++ { ++ __ pop(itos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_INT, IN_HEAP, field, FSR, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_iputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notInt); ++ __ cmpw(flags, ctos); ++ __ jcc(Assembler::notEqual, notChar); ++ ++ // ctos ++ { ++ __ pop(ctos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_CHAR, IN_HEAP, field, FSR, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_cputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notChar); ++ __ cmpw(flags, stos); ++ __ jcc(Assembler::notEqual, notShort); ++ ++ // stos ++ { ++ __ pop(stos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_SHORT, IN_HEAP, field, FSR, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_sputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notShort); ++ __ cmpw(flags, ltos); ++ __ jcc(Assembler::notEqual, notLong); ++ ++ // ltos ++ { ++ __ pop(ltos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_LONG, IN_HEAP, field, noreg /* ltos*/, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_lputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notLong); ++ __ cmpw(flags, ftos); ++ __ jcc(Assembler::notEqual, notFloat); ++ ++ // ftos ++ { ++ __ pop(ftos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_fputfield, bc, T2, true, byte_no); ++ } ++ __ jmp(Done); ++ } ++ ++ __ BIND(notFloat); ++#ifdef ASSERT ++ __ cmpw(flags, dtos); ++ __ jcc(Assembler::notEqual, notDouble); ++#endif ++ ++ // dtos ++ { ++ __ pop(dtos); ++ if (!is_static) pop_and_check_object(obj); ++ __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos */, noreg, noreg); ++ if (!is_static && rc == may_rewrite) { ++ patch_bytecode(Bytecodes::_fast_dputfield, bc, T2, true, byte_no); ++ } ++ } ++ ++#ifdef ASSERT ++ __ jmp(Done); ++ ++ __ BIND(notDouble); ++ __ stop("Bad state"); ++#endif ++ ++ __ BIND(Done); ++ ++ // Check for volatile store ++ { ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, bVolatile); ++ volatile_barrier(); ++ __ BIND(notVolatile); ++ } ++} ++ ++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::jvmti_post_fast_field_mod() { ++ ++ const Register scratch = c_rarg3; ++ const Register rbx = T2; ++ ++ 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 L2; ++ __ ldws(scratch, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr())); ++ __ jcc(Assembler::zero, L2, scratch); ++ __ pop_ptr(rbx); // copy the object pointer from tos ++ __ verify_oop(rbx); ++ __ push_ptr(rbx); // put the object pointer back on tos ++ // 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()) { // load values into the jvalue object ++ case Bytecodes::_fast_aputfield: __ push_ptr(FSR); 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(FSR); break; ++ case Bytecodes::_fast_dputfield: __ push(dtos); break; ++ case Bytecodes::_fast_fputfield: __ push(ftos); break; ++ case Bytecodes::_fast_lputfield: __ push_l(FSR); break; ++ ++ default: ++ ShouldNotReachHere(); ++ } ++ __ movl(scratch, esp); ++ // access constant pool cache entry ++ __ get_cache_entry_pointer_at_bcp(c_rarg2, FSR, 1); ++ __ verify_oop(rbx); ++ // rbx: object pointer copied above ++ // c_rarg2: cache entry pointer ++ // c_rarg3: jvalue object on the stack ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, c_rarg2, c_rarg3); ++ ++ switch (bytecode()) { // restore tos values ++ case Bytecodes::_fast_aputfield: __ pop_ptr(FSR); 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(FSR); break; ++ case Bytecodes::_fast_dputfield: __ pop(dtos); break; ++ case Bytecodes::_fast_fputfield: __ pop(ftos); break; ++ case Bytecodes::_fast_lputfield: __ pop_l(FSR); break; ++ default: break; ++ } ++ __ bind(L2); ++ } ++} ++ ++void TemplateTable::fast_storefield(TosState state) { ++ transition(state, vtos); ++ ++ const Register scratch = T11; ++ const Register rbx = T2; ++ const Register rcx = T3; ++ const Register rdx = T1; ++ ++ ByteSize base = ConstantPoolCache::base_offset(); ++ ++ jvmti_post_fast_field_mod(); ++ ++ // access constant pool cache ++ __ get_cache_and_index_at_bcp(rcx, rbx, 1); ++ ++ // test for volatile with rdx but rdx is tos register for lputfield. ++ __ ldwu(rdx, Address(rcx, rbx, Address::times_ptr, ++ in_bytes(base + ++ ConstantPoolCacheEntry::flags_offset()))); ++ ++ // replace index with field offset from cache entry ++ __ ldptr(rbx, Address(rcx, rbx, Address::times_ptr, ++ in_bytes(base + ConstantPoolCacheEntry::f2_offset()))); ++ ++ //x64 dont need mb since its mem seq model is strong, but we are weak, we ref aarch64 here. ++ { ++ __ andw(rdx, 1 << ConstantPoolCacheEntry::is_volatile_shift, scratch); ++ ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, scratch); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++ ++ // Get object from stack ++ pop_and_check_object(rcx); ++ ++ // field address ++ const Address field(rcx, rbx, Address::times_1); ++ ++ // access field ++ switch (bytecode()) { ++ case Bytecodes::_fast_aputfield: ++ do_oop_store(_masm, field, FSR); ++ break; ++ case Bytecodes::_fast_lputfield: ++ __ access_store_at(T_LONG, IN_HEAP, field, noreg /* ltos */, noreg, noreg); ++ break; ++ case Bytecodes::_fast_iputfield: ++ __ access_store_at(T_INT, IN_HEAP, field, FSR, noreg, noreg); ++ break; ++ case Bytecodes::_fast_zputfield: ++ __ access_store_at(T_BOOLEAN, IN_HEAP, field, FSR, noreg, noreg); ++ break; ++ case Bytecodes::_fast_bputfield: ++ __ access_store_at(T_BYTE, IN_HEAP, field, FSR, noreg, noreg); ++ break; ++ case Bytecodes::_fast_sputfield: ++ __ access_store_at(T_SHORT, IN_HEAP, field, FSR, noreg, noreg); ++ break; ++ case Bytecodes::_fast_cputfield: ++ __ access_store_at(T_CHAR, IN_HEAP, field, FSR, noreg, noreg); ++ break; ++ case Bytecodes::_fast_fputfield: ++ __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos*/, noreg, noreg); ++ break; ++ case Bytecodes::_fast_dputfield: ++ __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos*/, noreg, noreg); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ { ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, scratch); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++} ++ ++void TemplateTable::fast_accessfield(TosState state) { ++ transition(atos, state); ++ ++ const Register scratch = T11; ++ const Register rcx = T3; ++ const Register rbx = T2; ++ ++ // Do the JVMTI work here to avoid disturbing the register state below ++ 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 L1; ++ __ ldws(rcx, ExternalAddress((address) JvmtiExport::get_field_access_count_addr())); ++ __ jcc(Assembler::zero, L1, rcx); ++ // access constant pool cache entry ++ __ get_cache_entry_pointer_at_bcp(c_rarg2, rcx, 1); ++ __ verify_oop(FSR); ++ __ push(FSR); // save object pointer before call_VM() clobbers it ++ __ movl(c_rarg1, FSR); ++ // c_rarg1: object pointer copied above ++ // c_rarg2: cache entry pointer ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), ++ c_rarg1, c_rarg2); ++ __ pop_ptr(FSR); ++ __ bind(L1); ++ } ++ ++ // access constant pool cache ++ __ get_cache_and_index_at_bcp(rcx, rbx, 1); ++ // replace index with field offset from cache entry ++ { ++ __ ldw(AT, Address(rcx, rbx, Address::times_8, ++ in_bytes(ConstantPoolCache::base_offset() + ++ ConstantPoolCacheEntry::flags_offset()))); ++ __ andw(AT, 1 << ConstantPoolCacheEntry::is_volatile_shift, scratch); ++ ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, scratch); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++ __ ldptr(rbx, Address(rcx, rbx, Address::times_ptr, ++ in_bytes(ConstantPoolCache::base_offset() + ++ ConstantPoolCacheEntry::f2_offset()))); ++ ++ // FSR: object ++ __ verify_oop(FSR); ++ __ null_check(FSR); ++ // field addresses ++ Address field(FSR, rbx, Address::times_1); ++ ++ // access field ++ switch (bytecode()) { ++ case Bytecodes::_fast_agetfield: ++ do_oop_load(_masm, field, FSR); ++ __ verify_oop(FSR); ++ break; ++ case Bytecodes::_fast_lgetfield: ++ __ access_load_at(T_LONG, IN_HEAP, noreg /* ltos */, field, noreg, noreg); ++ break; ++ case Bytecodes::_fast_igetfield: ++ __ access_load_at(T_INT, IN_HEAP, FSR, field, noreg, noreg); ++ break; ++ case Bytecodes::_fast_bgetfield: ++ __ access_load_at(T_BYTE, IN_HEAP, FSR, field, noreg, noreg); ++ break; ++ case Bytecodes::_fast_sgetfield: ++ __ access_load_at(T_SHORT, IN_HEAP, FSR, field, noreg, noreg); ++ break; ++ case Bytecodes::_fast_cgetfield: ++ __ access_load_at(T_CHAR, IN_HEAP, FSR, field, noreg, noreg); ++ break; ++ case Bytecodes::_fast_fgetfield: ++ __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); ++ break; ++ case Bytecodes::_fast_dgetfield: ++ __ access_load_at(T_DOUBLE, IN_HEAP, noreg /* dtos */, field, noreg, noreg); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ { ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, scratch); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++} ++ ++void TemplateTable::fast_xaccess(TosState state) { ++ transition(vtos, state); ++ ++ const Register scratch = T11; ++ const Register rcx = T3; ++ const Register rdx = T2; ++ const Register rbx = T1; ++ ++ // get receiver ++ __ ldptr(FSR, aaddress(0)); ++ // access constant pool cache ++ __ get_cache_and_index_at_bcp(rcx, rdx, 2); ++ __ ldptr(rbx, ++ Address(rcx, rdx, Address::times_ptr, ++ in_bytes(ConstantPoolCache::base_offset() + ++ ConstantPoolCacheEntry::f2_offset()))); ++ ++ { ++ __ ldw(AT, Address(rcx, rdx, Address::times_8, ++ in_bytes(ConstantPoolCache::base_offset() + ++ ConstantPoolCacheEntry::flags_offset()))); ++ __ andw(AT, 1 << ConstantPoolCacheEntry::is_volatile_shift, scratch); ++ ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, scratch); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++ ++ // make sure exception is reported in correct bcp range (getfield is ++ // next instruction) ++ __ incrementl(rbcp); ++ __ null_check(FSR); ++ const Address field = Address(FSR, rbx, Address::times_1, 0*wordSize); ++ switch (state) { ++ case itos: ++ __ access_load_at(T_INT, IN_HEAP, FSR, field, noreg, noreg); ++ break; ++ case atos: ++ do_oop_load(_masm, field, FSR); ++ __ verify_oop(FSR); ++ break; ++ case ftos: ++ __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ { ++ Label notVolatile; ++ __ jcc(Assembler::zero, notVolatile, scratch); ++ volatile_barrier(); ++ __ bind(notVolatile); ++ } ++ ++ __ decrementl(rbcp); ++} ++ ++//----------------------------------------------------------------------------- ++// 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 index, // itable index, MethodType, etc. ++ Register recv, // if caller wants to see it ++ Register flags // if caller wants to test it ++ ) {SCOPEMARK_NAME(prepare_invoke, _masm) ++ const Register rdx = T1; ++ const Register rcx = T3; ++ ++ // 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); ++ const bool save_flags = (flags != noreg); ++ assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), ""); ++ assert(save_flags == (is_invokeinterface || is_invokevirtual), "need flags for vfinal"); ++ assert(flags == noreg || flags == rdx, ""); ++ assert(recv == noreg || recv == rcx, ""); ++ //assert(method == rmethod, "rmethod is a S reg"); ++ ++ // setup registers & access constant pool cache ++ if (recv == noreg) recv = rcx; ++ if (flags == noreg) flags = rdx; ++ assert_different_registers(method, index, recv, flags); ++ ++ // save 'interpreter return address' ++ __ save_bcp(); ++ ++ load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic); ++ ++ // maybe push appendix to arguments (just before return address) ++ if (is_invokedynamic || is_invokehandle) {// ++ Label L_no_push; ++ Register rbx = rmethod; ++ __ testw(flags, (1 << ConstantPoolCacheEntry::has_appendix_shift)); ++ __ jcc(Assembler::zero, L_no_push); ++ // Push the appendix as a trailing parameter. ++ // This must be done before we get the receiver, ++ // since the parameter_size includes it. ++ __ push(rbx); ++ __ movl(rbx, index); ++ assert(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset == 0, "appendix expected at index+0"); ++ __ load_resolved_reference_at_index(index, rbx); ++ __ pop(rbx); ++ __ push(index); // push appendix (MethodType, CallSite, etc.) ++ __ bind(L_no_push); ++ } ++ ++ // load receiver if needed (after appendix is pushed so parameter size is correct) ++ // Note: no return address pushed yet ++ if (load_receiver) { ++ __ andw(flags, ConstantPoolCacheEntry::parameter_size_mask, recv); ++ const int no_return_pc_pushed_yet = 0; // argument slot correction before we push return address ++ // Since we won't push RA on stack, no_return_pc_pushed_yet should be 0. ++ const int receiver_is_at_end = -1; // back off one slot to get receiver ++ Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end); ++ __ ldptr(recv, recv_addr); ++ __ verify_oop(recv); ++ } ++ ++ if (save_flags) { ++ __ movw(rbcp, flags); ++ } ++ ++ // compute return type ++ __ srll(flags, ConstantPoolCacheEntry::tos_state_shift, flags); ++ // 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); ++ ExternalAddress table(table_addr); ++ __ lea(rscratch1, table); ++ __ ldptr(RA, Address(rscratch1, flags, Address::times_ptr)); ++ } ++ ++ // push return address ++ // __ push(RA);// yj: we dont't push ret addr ++ ++ if (save_flags) { ++ __ movw(flags, rbcp); ++ __ restore_bcp(); ++ } ++} ++ ++void TemplateTable::invokevirtual_helper(Register index, ++ Register recv, ++ Register flags) {SCOPEMARK_NAME(invokevirtual_helper, _masm) ++ const Register rdx = T2; ++ const Register rax = FSR; ++ ++ // Uses temporary registers FSR, rdx ++ assert_different_registers(index, recv, rax, rdx); ++ assert(index == rmethod, ""); ++ assert(recv == T3, ""); ++ ++ // Test for an invoke of a final method ++ Label notFinal; ++ __ testw(flags, (1 << ConstantPoolCacheEntry::is_vfinal_shift)); ++ __ jcc(Assembler::zero, notFinal); ++ ++ const Register method = index; // method must be rmethod ++ assert(method == rmethod, ++ "method* must be rmethod for interpreter calling convention"); ++ ++ // do the call - the index is actually the method to call ++ // that is, f2 is a vtable index if !is_vfinal, else f2 is a Method* ++ ++ // It's final, need a null check here! ++ __ null_check(recv); ++ ++ // profile this call ++ __ profile_final_call(rax); ++ __ profile_arguments_type(rax, method, rbcp, true); ++ ++ __ jump_from_interpreted(method, rax); ++ ++ __ bind(notFinal); ++ ++ // get receiver klass ++ __ null_check(recv, oopDesc::klass_offset_in_bytes()); ++ __ load_klass(rax, recv); ++ ++ // profile this call ++ __ profile_virtual_call(rax, rlocals, rdx); ++ // get target Method* & entry point ++ __ lookup_virtual_method(rax, index, method); ++ __ profile_called_method(method, rdx, rbcp); ++ ++ __ profile_arguments_type(rdx, method, rbcp, true); ++ __ jump_from_interpreted(method, rdx); ++} ++ ++void TemplateTable::invokevirtual(int byte_no) {SCOPEMARK_NAME(invokevirtual, _masm) ++ transition(vtos, vtos); ++ assert(byte_no == f2_byte, "use this argument"); ++ prepare_invoke(byte_no, ++ rmethod,// method or vtable index ++ noreg, // unused itable index ++ T3, T1); // recv, flags ++ ++ // rmethod: index ++ // T3 : receiver ++ // T1 : flags ++ ++ invokevirtual_helper(rmethod, T3, T1); ++} ++ ++void TemplateTable::invokespecial(int byte_no) {SCOPEMARK_NAME(invokespecial, _masm) ++ transition(vtos, vtos); ++ assert(byte_no == f1_byte, "use this argument"); ++ Register rcx = T3; // ++ Register rax = V0; ++ Register rbx = rmethod; ++ prepare_invoke(byte_no, rbx, noreg, // get f1 Method* ++ rcx); // get receiver also for null check ++ __ verify_oop(rcx); ++ __ null_check(rcx); ++ // do the call ++ __ profile_call(rax); ++ __ profile_arguments_type(rax, rbx, c_rarg4, false); ++ __ jump_from_interpreted(rbx, rax); ++} ++ ++void TemplateTable::invokestatic(int byte_no) {SCOPEMARK_NAME(invokestatic, _masm) ++ transition(vtos, vtos); ++ assert(byte_no == f1_byte, "use this argument"); ++ Register rax = V0; ++ prepare_invoke(byte_no, rmethod, noreg); ++ // do the call ++ __ profile_call(rax); ++ __ profile_arguments_type(rax, rmethod, c_rarg3, false); ++ __ jump_from_interpreted(rmethod, rax); ++} ++ ++ ++void TemplateTable::fast_invokevfinal(int byte_no) { ++ transition(vtos, vtos); ++ assert(byte_no == f2_byte, "use this argument"); ++ __ stop("fast_invokevfinal not used on sw64"); ++} ++ ++ ++void TemplateTable::invokeinterface(int byte_no) {SCOPEMARK_NAME(invokeinterface, _masm) ++ transition(vtos, vtos); ++ assert(byte_no == f1_byte, "use this argument"); ++ Register rax = V0; ++ Register rcx = T3; ++ Register rdx = T1; ++ ++ prepare_invoke(byte_no, rax, rmethod, // get f1 Klass*, f2 Method* ++ rcx, rdx); // recv, flags ++ ++ // rax: reference klass (from f1) if interface method ++ // rbx: method (from f2) ++ // rcx: receiver ++ // rdx: flags ++ ++ // First check for Object case, then private interface method, ++ // then regular interface method. ++ ++ // Special case of invokeinterface called for virtual method of ++ // java.lang.Object. See cpCache.cpp for details. ++ Label notObjectMethod; ++ __ testw(rdx, (1 << ConstantPoolCacheEntry::is_forced_virtual_shift)); ++ __ jcc(Assembler::zero, notObjectMethod); ++ invokevirtual_helper(rmethod, rcx, rdx); ++ // no return from above ++ __ bind(notObjectMethod); ++ ++ Label no_such_interface; // for receiver subtype check ++ Register recvKlass; // used for exception processing ++ ++ // Check for private method invocation - indicated by vfinal ++ Label notVFinal; ++ __ testw(rdx, (1 << ConstantPoolCacheEntry::is_vfinal_shift)); ++ __ jcc(Assembler::zero, notVFinal); ++ ++ // Get receiver klass into rlocals - also a null check ++ __ null_check(rcx, oopDesc::klass_offset_in_bytes()); ++ __ load_klass(rlocals, rcx); ++ ++ Label subtype; ++ __ check_klass_subtype(rlocals, rax, c_rarg4, subtype); ++ // If we get here the typecheck failed ++ recvKlass = rdx; ++ __ movl(recvKlass, rlocals); // shuffle receiver class for exception use ++ __ jmp(no_such_interface); ++ ++ __ bind(subtype); ++ ++ // do the call - rbx is actually the method to call ++ ++ __ profile_final_call(rdx); ++ __ profile_arguments_type(rdx, rmethod, c_rarg4, true); ++ ++ __ jump_from_interpreted(rmethod, rdx); ++ // no return from above ++ __ bind(notVFinal); ++ ++ // Get receiver klass into rdx - also a null check ++ __ restore_locals(); // restore r14 ++ __ null_check(rcx, oopDesc::klass_offset_in_bytes()); ++ __ load_klass(rdx, rcx); ++ ++ Label no_such_method; ++ ++ // Preserve method for throw_AbstractMethodErrorVerbose. ++ __ movl(rcx, rmethod); ++ // Receiver subtype check against REFC. ++ // Superklass in rax. Subklass in rdx. Blows rcx, rdi. ++ __ lookup_interface_method(// inputs: rec. class, interface, itable index ++ rdx, rax, noreg, ++ // outputs: scan temp. reg, scan temp. reg ++ c_rarg4, rlocals, ++ no_such_interface, ++ /*return_method=*/false); ++ ++ // profile this call ++ __ restore_bcp(); // rbcp was destroyed by receiver type check ++ __ profile_virtual_call(rdx, c_rarg4, rlocals); ++ ++ // Get declaring interface class from method, and itable index ++ __ ldptr(rax, Address(rmethod, Method::const_offset())); ++ __ ldptr(rax, Address(rax, ConstMethod::constants_offset())); ++ __ ldptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes())); ++ __ ldws(rmethod, Address(rmethod, Method::itable_index_offset())); ++ __ movw(rscratch1, Method::itable_index_max); ++ __ subw(rmethod, rscratch1, rmethod); ++ __ subw(R0, rmethod, rmethod); ++ ++ // Preserve recvKlass for throw_AbstractMethodErrorVerbose. ++ __ movl(rlocals, rdx); ++ __ lookup_interface_method(// inputs: rec. class, interface, itable index ++ rlocals, rax, rmethod, ++ // outputs: method, scan temp. reg ++ rmethod, c_rarg4, ++ no_such_interface); ++ ++ // rmethod: Method* to call ++ // rcx: receiver ++ // Check for abstract method error ++ // Note: This should be done more efficiently via a throw_abstract_method_error ++ // interpreter entry point and a conditional jump to it in case of a null ++ // method. ++ __ testptr(rmethod, rmethod); ++ __ jcc(Assembler::zero, no_such_method); ++ ++ __ profile_called_method(rmethod, c_rarg4, rdx); ++ __ profile_arguments_type(rdx, rmethod, c_rarg4, true); ++ ++ // do the call ++ // rcx: receiver ++ // rmethod,: Method* ++ __ jump_from_interpreted(rmethod, rdx); ++ __ should_not_reach_here("3501"); ++ ++ // exception handling code follows... ++ // note: must restore interpreter registers to canonical ++ // state for exception handling to work correctly! ++ ++ __ bind(no_such_method); ++ // throw exception ++ //__ pop(rbx); // pop return address (pushed by prepare_invoke) ++ __ restore_bcp(); // rbcp must be correct for exception handler (was destroyed) ++ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) ++ // Pass arguments for generating a verbose error message. ++ ++ recvKlass = c_rarg1; ++ Register method = c_rarg2; ++ if (recvKlass != rdx) { __ movl(recvKlass, rdx); } ++ if (method != rcx) { __ movl(method, rcx); } ++ ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorVerbose), ++ recvKlass, method); ++ // The call_VM checks for exception, so we should never return here. ++ __ should_not_reach_here("3522"); ++ ++ __ bind(no_such_interface); ++ // throw exception ++ //__ pop(rbx); // pop return address (pushed by prepare_invoke) ++ __ restore_bcp(); // rbcp must be correct for exception handler (was destroyed) ++ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) ++ // Pass arguments for generating a verbose error message. ++ if (recvKlass != rdx) { __ movl(recvKlass, rdx); } ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose), ++ recvKlass, rax); ++ // the call_VM checks for exception, so we should never return here. ++ __ should_not_reach_here("3534"); ++} ++ ++void TemplateTable::invokehandle(int byte_no) {SCOPEMARK_NAME(invokehandle, _masm) ++ transition(vtos, vtos); ++ assert(byte_no == f1_byte, "use this argument"); ++ const Register rbx_method = rmethod; ++ const Register rax_mtype = V0; ++ const Register rcx_recv = T3; ++ const Register rdx_flags = c_rarg3; ++ const Register rdx = c_rarg3; ++ const Register rax = V0; ++ ++ prepare_invoke(byte_no, rbx_method, rax_mtype, rcx_recv); ++ __ verify_method_ptr(rbx_method); ++ __ verify_oop(rcx_recv); ++ __ null_check(rcx_recv); ++ ++ // rax: MethodType object (from cpool->resolved_references[f1], if necessary) ++ // rbx: MH.invokeExact_MT method (from f2) ++ ++ // Note: rax_mtype is already pushed (if necessary) by prepare_invoke ++ ++ // FIXME: profile the LambdaForm also ++ __ profile_final_call(rax); ++ __ profile_arguments_type(rdx, rbx_method, c_rarg5, true); ++ ++ __ jump_from_interpreted(rbx_method, rdx); ++} ++ ++void TemplateTable::invokedynamic(int byte_no) { ++ transition(vtos, vtos); ++ assert(byte_no == f1_byte, "use this argument"); ++ ++ const Register rbx_method = rmethod; ++ const Register rax_callsite = V0; ++ Register rdx = c_rarg2; ++ ++ //__ stop("TODO: should check function right:invokedynamic jzy"); ++ prepare_invoke(byte_no, rbx_method, rax_callsite); ++ ++ // rax: CallSite object (from cpool->resolved_references[f1]) ++ // rbx: MH.linkToCallSite method (from f2) ++ ++ // Note: rax_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(c_rarg3); ++ __ profile_arguments_type(rdx, rbx_method, c_rarg3, false); ++ ++ __ verify_oop(rax_callsite); ++ ++ __ jump_from_interpreted(rbx_method, rdx); ++} ++ ++//----------------------------------------------------------------------------- ++// Allocation ++ ++void TemplateTable::_new() {SCOPEMARK_NAME(TemplateTable::_new, _masm) ++ transition(vtos, atos); ++ Register rax = V0; ++ Register rbx = c_rarg3; ++ Register rcx = c_rarg4; ++ Register rdx = c_rarg5; ++ __ get_unsigned_2_byte_index_at_bcp(rdx, 1); ++ Label slow_case; ++ Label slow_case_no_pop; ++ Label done; ++ Label initialize_header; ++ Label initialize_object; // including clearing the fields ++ ++ __ get_cpool_and_tags(rcx, rax); ++ ++ // 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) ++ const int tags_offset = Array::base_offset_in_bytes(); ++ __ cmpb(Address(rax, rdx, Address::times_1, tags_offset), JVM_CONSTANT_Class); ++ __ jcc(Assembler::notEqual, slow_case_no_pop); ++ ++ // get InstanceKlass ++ __ load_resolved_klass_at_index(rcx, rdx, rcx); ++ __ push(rcx); // save the contexts of klass for initializing the header ++ ++ // make sure klass is initialized & doesn't have finalizer ++ // make sure klass is fully initialized ++ __ cmpb(Address(rcx, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); ++ __ jcc(Assembler::notEqual, slow_case); ++ ++ // get instance_size in InstanceKlass (scaled to a count of bytes) ++ __ ldw(rdx, Address(rcx, Klass::layout_helper_offset())); ++ // test to see if it has a finalizer or is malformed in some way ++ __ testw(rdx, Klass::_lh_instance_slow_path_bit); ++ __ jcc(Assembler::notZero, slow_case); ++ ++ // 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(); ++ ++ const Register thread = rthread; ++ if (UseTLAB) { ++ __ tlab_allocate(thread, rax, rdx, 0, rcx, rbx, slow_case); ++ if (ZeroTLAB) { ++ // the fields have been already cleared ++ __ jmp(initialize_header); ++ } else { ++ // initialize both the header and fields ++ __ jmp(initialize_object); ++ } ++ } else { ++ // Allocation in the shared Eden, if allowed. ++ // ++ // rdx: instance size in bytes ++ __ eden_allocate(thread, rax, rdx, 0, rbx, slow_case); ++ } ++ ++ // 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) { ++ // The object is initialized before the header. If the object size is ++ // zero, go directly to the header initialization. ++ __ BIND(initialize_object); ++ __ decrementl(rdx, sizeof(oopDesc)); ++ __ jcc(Assembler::zero, initialize_header, rdx); ++ ++ // Initialize topmost object field, divide rdx by 8, check if odd and ++ // test if zero. ++ __ movw(rcx, R0); // use zero reg to clear memory (shorter code) ++#ifdef ASSERT ++ __ movl(rscratch1, rdx); ++#endif ++ __ srll(rdx, LogBytesPerLong, rdx); // divide by 2*oopSize and set result flag if odd ++ ++ // rdx must have been multiple of 8 ++#ifdef ASSERT ++ // make sure rdx was multiple of 8 ++ Label L; ++ // Ignore partial flag stall after shrl() since it is debug VM ++ __ srll(rscratch1, LogBytesPerLong-1, rscratch1); ++ __ testptr(rscratch1, 0x1);// the least significant bit is zero? ++ __ jcc(Assembler::zero, L); ++ __ stop("object size is not multiple of 2 - adjust this code"); ++ __ BIND(L); ++ // rdx must be > 0, no extra check needed here ++#endif ++ ++ // initialize remaining object fields: rdx was a multiple of 8 ++ { Label loop; ++ __ BIND(loop); ++ __ stptr(rcx, Address(rax, rdx, Address::times_8, sizeof(oopDesc) - 1*oopSize)); ++ __ decrementl(rdx); ++ __ jcc(Assembler::notZero, loop, rdx); ++ } ++ ++ // initialize object header only. ++ __ BIND(initialize_header); ++ if (UseBiasedLocking) { ++ __ pop(rcx); // get saved klass back in the register. ++ __ ldptr(rbx, Address(rcx, Klass::prototype_header_offset())); ++ __ stptr(rbx, Address(rax, oopDesc::mark_offset_in_bytes ())); ++ } else { ++ __ mov_immediate64(rscratch1, (intptr_t)markOopDesc::prototype()); ++ __ stptr(rscratch1, Address(rax, oopDesc::mark_offset_in_bytes ())); // header ++ __ pop(rcx); // get saved klass back in the register. ++ } ++ __ store_klass_gap(rax, R0); ++ __ store_klass(rax, rcx); // klass ++ ++ { ++ SkipIfEqual skip_if(_masm, &DTraceAllocProbes, 0); ++ // Trigger dtrace event for fastpath ++ __ push(atos); ++ __ call_VM_leaf( ++ CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax); ++ __ pop(atos); ++ } ++ ++ __ jmp(done); ++ } ++ ++ // slow case ++ __ BIND(slow_case); ++ __ pop(rcx); // restore stack pointer to what it was when we came in. ++ __ BIND(slow_case_no_pop); ++ ++ Register rarg1 = c_rarg1; ++ Register rarg2 = c_rarg2; ++ ++ __ get_constant_pool(rarg1); ++ __ get_unsigned_2_byte_index_at_bcp(rarg2, 1); ++ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), rarg1, rarg2); ++ __ verify_oop(rax); ++ ++ // continue ++ __ BIND(done); ++ if(UseWmemb) ++ __ wmemb(); ++ else ++ __ memb();// add for sw64 ++} ++ ++void TemplateTable::newarray() { ++ transition(itos, atos); ++ Register rarg1 = c_rarg1; ++ Register rax = V0; ++ __ load_unsigned_byte(rarg1, at_bcp(1)); ++ //__ movws(rax, rax); ++ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), ++ rarg1, rax); ++ if(UseWmemb) ++ __ wmemb(); ++ else ++ __ memb();// add for sw64 ++} ++ ++void TemplateTable::anewarray() { ++ transition(itos, atos); ++ ++ Register rarg1 = c_rarg1; ++ Register rarg2 = c_rarg2; ++ Register rax = V0; ++ ++ __ get_unsigned_2_byte_index_at_bcp(rarg2, 1); ++ __ get_constant_pool(rarg1); ++ //__ movws(rax, rax); ++ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), ++ rarg1, rarg2, rax); ++ if(UseWmemb) ++ __ wmemb(); ++ else ++ __ memb(); ++} ++ ++void TemplateTable::arraylength() { ++ transition(atos, itos); ++ Register rax = V0; ++ __ null_check(rax, arrayOopDesc::length_offset_in_bytes()); ++ __ ldws(rax, Address(rax, arrayOopDesc::length_offset_in_bytes())); ++} ++ ++void TemplateTable::checkcast() { ++ transition(atos, atos); ++ Label done, is_null, ok_is_subtype, quicked, resolved; ++ Register rax = V0; ++ Register rcx = c_rarg4; ++ Register rdx = c_rarg3; ++ Register rbx = rmethod; ++ __ testptr(rax, rax); // object is in rax ++ __ jcc(Assembler::zero, is_null); ++ ++ // Get cpool & tags index ++ __ get_cpool_and_tags(rcx, rdx); // rcx=cpool, rdx=tags array ++ __ get_unsigned_2_byte_index_at_bcp(rbx, 1); // rbx=index ++ // See if bytecode has already been quicked ++ __ cmpb(Address(rdx, rbx, ++ Address::times_1, ++ Array::base_offset_in_bytes()), ++ JVM_CONSTANT_Class); ++ __ jcc(Assembler::equal, quicked); ++ __ push(atos); // save receiver for result, and for GC ++ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); ++ ++ // vm_result_2 has metadata result ++ __ get_vm_result_2(rax, rthread); ++ ++ __ pop_ptr(rdx); // restore receiver ++ __ jmp(resolved); ++ ++ // Get superklass in rax and subklass in rbx ++ __ bind(quicked); ++ __ movl(rdx, rax); // Save object in rdx; rax needed for subtype check ++ __ load_resolved_klass_at_index(rcx, rbx, rax); ++ ++ __ bind(resolved); ++ __ load_klass(rbx, rdx); ++ ++ // Generate subtype check. Blows rcx, rdi. Object in rdx. ++ // Superklass in rax. Subklass in rbx. ++ __ gen_subtype_check(rbx, ok_is_subtype); ++ ++ // Come here on failure ++ __ push_ptr(rdx); ++ // object is at TOS ++ __ jump(ExternalAddress(Interpreter::_throw_ClassCastException_entry)); ++ ++ // Come here on success ++ __ bind(ok_is_subtype); ++ __ movl(rax, rdx); // Restore object in rdx ++ ++ // Collect counts on whether this check-cast sees NULLs a lot or not. ++ if (ProfileInterpreter) { ++ __ jmp(done); ++ __ bind(is_null); ++ __ profile_null_seen(rcx); ++ } else { ++ __ bind(is_null); // same as 'done' ++ } ++ __ bind(done); ++} ++ ++void TemplateTable::instanceof() { ++ transition(atos, itos); ++ Label done, is_null, ok_is_subtype, quicked, resolved; ++ Register rax = V0; ++ Register rcx = c_rarg4; ++ Register rdx = c_rarg3; ++ Register rbx = rmethod; ++ __ testptr(rax, rax); ++ __ jcc(Assembler::zero, is_null); ++ ++ // Get cpool & tags index ++ __ get_cpool_and_tags(rcx, rdx); // rcx=cpool, rdx=tags array ++ __ get_unsigned_2_byte_index_at_bcp(rbx, 1); // rbx=index ++ // See if bytecode has already been quicked ++ __ cmpb(Address(rdx, rbx, ++ Address::times_1, ++ Array::base_offset_in_bytes()), ++ JVM_CONSTANT_Class); ++ __ jcc(Assembler::equal, quicked); ++ ++ __ push(atos); // save receiver for result, and for GC ++ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); ++ // vm_result_2 has metadata result ++ ++ __ get_vm_result_2(rax, rthread); ++ ++ __ pop_ptr(rdx); // restore receiver ++ __ verify_oop(rdx); ++ __ load_klass(rdx, rdx); ++ __ jmp(resolved); ++ ++ // Get superklass in rax and subklass in rdx ++ __ bind(quicked); ++ __ load_klass(rdx, rax); ++ __ load_resolved_klass_at_index(rcx, rbx, rax); ++ ++ __ bind(resolved); ++ ++ // Generate subtype check. Blows rcx, rdi ++ // Superklass in rax. Subklass in rdx. ++ __ gen_subtype_check(rdx, ok_is_subtype); ++ ++ // Come here on failure ++ __ movl(rax, R0); ++ __ jmp(done); ++ // Come here on success ++ __ bind(ok_is_subtype); ++ __ movw(rax, 1); ++ ++ // Collect counts on whether this test sees NULLs a lot or not. ++ if (ProfileInterpreter) { ++ __ jmp(done); ++ __ bind(is_null); ++ __ profile_null_seen(rcx); ++ } else { ++ __ bind(is_null); // same as 'done' ++ } ++ __ bind(done); ++ // rax = 0: obj == NULL or obj is not an instanceof the specified klass ++ // rax = 1: obj != NULL and obj is an instanceof the specified klass ++} ++ ++ ++//---------------------------------------------------------------------------------------------------- ++// Breakpoints ++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); ++ ++ Register rarg = c_rarg1; ++ Register rax = V0; ++ ++ // get the unpatched byte code ++ __ get_method(rarg); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::get_original_bytecode_at), ++ rarg, rbcp); ++ __ movl(rmethod, rax); // why? ++ ++ // post the breakpoint event ++ __ get_method(rarg); ++ __ call_VM(noreg, ++ CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), ++ rarg, rbcp); ++ __ movl(rnext, rmethod); ++ // complete the execution of original bytecode ++ __ dispatch_only_normal(vtos); ++} ++ ++//----------------------------------------------------------------------------- ++// Exceptions ++ ++void TemplateTable::athrow() { ++ transition(atos, vtos); ++ const Register rax = FSR; ++ __ null_check(rax); ++ __ jump(ExternalAddress(Interpreter::throw_exception_entry())); ++} ++ ++//----------------------------------------------------------------------------- ++// Synchronization ++// ++// Note: monitorenter & exit are symmetric routines; which is reflected ++// in the assembly code structure as well ++// ++// Stack layout: ++// ++// [expressions ] <--- esp = expression stack top ++// .. ++// [expressions ] ++// [monitor entry] <--- monitor block top = expression stack bot ++// .. ++// [monitor entry] ++// [frame data ] <--- monitor block bot ++// ... ++// [saved rbp ] <--- rbp ++void TemplateTable::monitorenter() { ++ transition(atos, vtos); ++ Register rax = FSR; ++ ++ // check for NULL object ++ __ null_check(rax); ++ ++ const Address monitor_block_top( ++ rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); ++ const Address monitor_block_bot( ++ rfp, frame::interpreter_frame_initial_sp_offset * wordSize); ++ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; ++ ++ Label allocated; ++ ++ Register rtop = c_rarg3; ++ Register rbot = c_rarg2; ++ Register rmon = c_rarg1; ++ ++ // initialize entry pointer ++ __ movl(rmon, R0); // points to free slot or NULL ++ ++ // find a free slot in the monitor block (result in rmon) ++ { ++ Label entry, loop, exit; ++ __ ldptr(rtop, monitor_block_top); // points to current entry, ++ // starting with top-most entry ++ __ lea(rbot, monitor_block_bot); // points to word before bottom ++ // of monitor block ++ __ jmp(entry); ++ ++ __ bind(loop); ++ // check if current entry is used ++ __ cmpptr(Address(rtop, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL_WORD); ++ // if not used then remember entry in rmon ++ __ cmove(Assembler::equal, rmon, rtop, rmon); // cmov => cmovptr ++ // check if current entry is for same object ++ __ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes())); ++ // if same object then stop searching ++ __ jcc(Assembler::equal, exit); ++ // otherwise advance to next entry ++ __ addptr(rtop, entry_size, rtop); ++ __ bind(entry); ++ // check if bottom reached ++ __ cmpptr(rtop, rbot); ++ // if not at bottom then check this entry ++ __ jcc(Assembler::notEqual, loop); ++ __ bind(exit); ++ } ++ ++ __ testptr(rmon, rmon); // check if a slot has been found ++ __ jcc(Assembler::notZero, allocated); // if found, continue with that one ++ ++ // allocate one if there's no free slot ++ { ++ Label entry, loop; ++ // 1. compute new pointers // rsp: old expression stack top ++ __ ldptr(rmon, monitor_block_bot); // rmon: old expression stack bottom ++ __ subptr(esp, entry_size, esp); // move expression stack top ++ __ subptr(rmon, entry_size, rmon); // move expression stack bottom ++ __ movl(rtop, esp); // set start value for copy loop ++ __ stptr(rmon, monitor_block_bot); // set new monitor block bottom ++ __ jmp(entry); ++ ++ // 2. move expression stack contents ++ __ bind(loop); ++ __ ldptr(rbot, Address(rtop, entry_size)); // load expression stack ++ // word from old location ++ __ stptr(rbot, Address(rtop, 0)); // and store it at new location ++ __ addptr(rtop, wordSize, rtop); // advance to next word ++ __ bind(entry); ++ __ cmpptr(rtop, rmon); // check if bottom reached ++ __ jcc(Assembler::notEqual, loop); // if not at bottom then ++ // copy next word ++ } ++ ++ // call run-time routine ++ // rmon: points to monitor entry ++ __ 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. ++ __ incrementl(rbcp); ++ ++ // store object ++ __ stptr(rax, Address(rmon, BasicObjectLock::obj_offset_in_bytes())); ++ __ lock_object(rmon); ++ ++ // check to make sure this monitor doesn't cause stack overflow after locking ++ __ save_bcp(); // in case of exception ++ __ 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); ++ Register rax = FSR; ++ ++ // check for NULL object ++ __ null_check(rax); ++ ++ const Address monitor_block_top( ++ rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); ++ const Address monitor_block_bot( ++ rfp, frame::interpreter_frame_initial_sp_offset * wordSize); ++ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; ++ ++ Register rtop = c_rarg1; ++ Register rbot = c_rarg2; ++ ++ Label found; ++ ++ // find matching slot ++ { ++ Label entry, loop; ++ __ ldptr(rtop, monitor_block_top); // points to current entry, ++ // starting with top-most entry ++ __ lea(rbot, monitor_block_bot); // points to word before bottom ++ // of monitor block ++ __ jmp(entry); ++ ++ __ bind(loop); ++ // check if current entry is for same object ++ __ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes())); ++ // if same object then stop searching ++ __ jcc(Assembler::equal, found); ++ // otherwise advance to next entry ++ __ addptr(rtop, entry_size, rtop); ++ __ bind(entry); ++ // check if bottom reached ++ __ cmpptr(rtop, rbot); ++ // if not at bottom then check this entry ++ __ jcc(Assembler::notEqual, loop); ++ } ++ ++ // error handling. Unlocking was not block-structured ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, ++ InterpreterRuntime::throw_illegal_monitor_state_exception)); ++ __ should_not_reach_here("4101"); ++ ++ // call run-time routine ++ __ bind(found); ++ __ push_ptr(rax); // make sure object is on stack (contract with oopMaps) ++ __ unlock_object(rtop); ++ __ pop_ptr(rax); // discard object ++} ++ ++// Wide instructions ++void TemplateTable::wide() { //__ stop("TODO:check function right:wide jzy"); ++ transition(vtos, vtos); ++ __ load_unsigned_byte(rscratch1, at_bcp(1)); ++ ExternalAddress wtable((address)Interpreter::_wentry_point); ++ __ jump(ArrayAddress(wtable, Address(noreg, rscratch1, Address::times_ptr)), rscratch2, rcc); ++ // Note: the rbcp increment step is part of the individual wide bytecode implementations ++} ++ ++// Multi arrays ++void TemplateTable::multianewarray() { ++ transition(vtos, atos); ++ ++ Register rax = FSR; ++ const Register rbx = rscratch1; ++ Register rarg = c_rarg1; ++ ++ __ load_unsigned_byte(rax, at_bcp(3)); // get number of dimensions ++ // last dim is on top of stack; we want address of first one: ++ // first_addr = last_addr + (ndims - 1) * stackElementSize - 1*wordsize ++ // the latter wordSize to point to the beginning of the array. ++ __ lea(rarg, Address(esp, rax, Interpreter::stackElementScale(), -wordSize)); ++ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), rarg); ++ __ load_unsigned_byte(rbx, at_bcp(3)); ++ __ lea(esp, Address(esp, rbx, Interpreter::stackElementScale())); // get rid of counts ++ __ memb();// add for sw64 ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/templateTable_sw64.hpp afu11u/src/hotspot/cpu/sw64/templateTable_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/templateTable_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/templateTable_sw64.hpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_TEMPLATETABLE_SW64_64_HPP ++#define CPU_SW64_VM_TEMPLATETABLE_SW64_64_HPP ++ ++static void prepare_invoke(int byte_no, ++ Register method, // linked method (or i-klass) ++ 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 ++ ); ++ static void invokevirtual_helper(Register index, Register recv, ++ Register flags); ++ static void volatile_barrier(); ++ ++ // Helpers ++ static void index_check(Register array, Register index); ++ static void index_check_without_pop(Register array, Register index); ++ ++#endif // CPU_SW64_VM_TEMPLATETABLE_SW64_64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/vmreg_sw64.cpp afu11u/src/hotspot/cpu/sw64/vmreg_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/vmreg_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vmreg_sw64.cpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/assembler.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(); ++ regName[i++] = freg->name(); ++ freg = freg->successor(); ++ } ++ ++ for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) { ++ regName[i] = "NON-GPR-FPR"; ++ } ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/vmreg_sw64.hpp afu11u/src/hotspot/cpu/sw64/vmreg_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/vmreg_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vmreg_sw64.hpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++ #ifndef CPU_SW64_VM_VMREG_SW64_HPP ++ #define CPU_SW64_VM_VMREG_SW64_HPP ++ ++ inline bool is_Register() { ++ return (unsigned int) value() < (unsigned int) ConcreteRegisterImpl::max_gpr; ++ } ++ ++ inline bool is_FloatRegister() { ++ return value() >= ConcreteRegisterImpl::max_gpr && value() < ConcreteRegisterImpl::max_fpr; ++ } ++ ++ inline Register as_Register() { ++ ++ assert( is_Register(), "must be"); ++ // Yuk ++ return ::as_Register(value() >> 1); ++ } ++ ++ inline FloatRegister as_FloatRegister() { ++ assert( is_FloatRegister() && is_even(value()), "must be" ); ++ // Yuk ++ return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> 1); ++ } ++ ++ inline bool is_concrete() { ++ assert(is_reg(), "must be"); ++ if(is_Register()) return true; ++ if(is_FloatRegister()) return true; ++ assert(false, "what register?"); ++ return false; ++ } ++ ++ #endif // CPU_SW64_VM_VMREG_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/vmreg_sw64.inline.hpp afu11u/src/hotspot/cpu/sw64/vmreg_sw64.inline.hpp +--- openjdk/src/hotspot/cpu/sw64/vmreg_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vmreg_sw64.inline.hpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef CPU_SW64_VM_VMREG_SW64_INLINE_HPP ++#define CPU_SW64_VM_VMREG_SW64_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((encoding() << 1) + ConcreteRegisterImpl::max_gpr); ++} ++ ++#endif // CPU_SW64_VM_VMREG_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/vmStructs_sw64.hpp afu11u/src/hotspot/cpu/sw64/vmStructs_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/vmStructs_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vmStructs_sw64.hpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. All rights reserved. ++ * 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_SW64_VM_VMSTRUCTS_SW64_HPP ++#define CPU_SW64_VM_VMSTRUCTS_SW64_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, _last_Java_fp, intptr_t*) ++ ++#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) ++ ++#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) ++ ++#endif // CPU_SW64_VM_VMSTRUCTS_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/vm_version_ext_sw64.cpp afu11u/src/hotspot/cpu/sw64/vm_version_ext_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/vm_version_ext_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vm_version_ext_sw64.cpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2016, 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 "memory/allocation.hpp" ++#include "memory/allocation.inline.hpp" ++#include "runtime/os.inline.hpp" ++#include "vm_version_ext_sw64.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; ++bool VM_Version_Ext::_initialized = false; ++char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; ++char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; ++ ++void VM_Version_Ext::initialize_cpu_information(void) { ++ // do nothing if cpu info has been initialized ++ if (_initialized) { ++ return; ++ } ++ ++ int core_id = -1; ++ int chip_id = -1; ++ int len = 0; ++ char* src_string = NULL; ++ ++ _no_of_cores = os::processor_count(); ++ _no_of_threads = _no_of_cores; ++ _no_of_sockets = _no_of_cores; ++ snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Sw64"); ++ snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "Sw64 %s", _features_string); ++ _initialized = true; ++} ++ ++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) { ++ initialize_cpu_information(); ++ 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) { ++ initialize_cpu_information(); ++ 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 -uNr openjdk/src/hotspot/cpu/sw64/vm_version_ext_sw64.hpp afu11u/src/hotspot/cpu/sw64/vm_version_ext_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/vm_version_ext_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vm_version_ext_sw64.hpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2016, 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_SW64_VM_VM_VERSION_EXT_SW64_HPP ++#define CPU_SW64_VM_VM_VERSION_EXT_SW64_HPP ++ ++#include "runtime/vm_version.hpp" ++#include "utilities/macros.hpp" ++ ++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; ++ static bool _initialized; ++ static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; ++ static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; ++ ++ 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); ++ static void initialize_cpu_information(void); ++ ++}; ++ ++#endif // CPU_SW64_VM_VM_VERSION_EXT_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/vm_version_sw64.cpp afu11u/src/hotspot/cpu/sw64/vm_version_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/vm_version_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vm_version_sw64.cpp 2025-05-09 10:06:54.196292504 +0800 +@@ -0,0 +1,568 @@ ++/* ++ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "asm/macroAssembler.hpp" ++#include "asm/macroAssembler.inline.hpp" ++#include "memory/resourceArea.hpp" ++#include "runtime/java.hpp" ++#include "runtime/stubCodeGenerator.hpp" ++#include "runtime/vm_version.hpp" ++#include "utilities/macros.hpp" ++ ++#include OS_HEADER_INLINE(os) ++ ++//ZHJ #include ++//ZHJ #include ++ ++#ifndef HWCAP_AES ++#define HWCAP_AES (1<<3) ++#endif ++ ++#ifndef HWCAP_PMULL ++#define HWCAP_PMULL (1<<4) ++#endif ++ ++#ifndef HWCAP_SHA1 ++#define HWCAP_SHA1 (1<<5) ++#endif ++ ++#ifndef HWCAP_SHA2 ++#define HWCAP_SHA2 (1<<6) ++#endif ++ ++#ifndef HWCAP_CRC32 ++#define HWCAP_CRC32 (1<<7) ++#endif ++ ++#ifndef HWCAP_ATOMICS ++#define HWCAP_ATOMICS (1<<8) ++#endif ++ ++#ifndef HWCAP_ASIMD ++#define HWCAP_ASIMD (1<<9) ++#endif ++ ++////int VM_Version::_cpu; ++////int VM_Version::_model; ++////int VM_Version::_model2; ++////int VM_Version::_variant; ++////int VM_Version::_revision; ++////int VM_Version::_stepping; ++////VM_Version::PsrInfo VM_Version::_psr_info = { 0, }; ++int VM_Version::_features = VM_Version::unknown_m; ++const char* VM_Version::_features_str = ""; ++ ++////static BufferBlob* stub_blob; ++////static const int stub_size = 550; ++ ++////extern "C" { ++//// typedef void (*getPsrInfo_stub_t)(void*); ++////} ++////static getPsrInfo_stub_t getPsrInfo_stub = NULL; ++ ++ ++////class VM_Version_StubGenerator: public StubCodeGenerator { ++//// public: ++//// ++//// VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} ++//// ++//// address generate_getPsrInfo() { ++//// StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub"); ++////# define __ _masm-> ++//// address start = __ pc(); ++//// ++//// // void getPsrInfo(VM_Version::PsrInfo* psr_info); ++//// ++//// address entry = __ pc(); ++//// ++//// __ enter(); ++//// ++//// __ get_dczid_el0(rscratch1); ++//// __ strw(rscratch1, Address(c_rarg0, in_bytes(VM_Version::dczid_el0_offset()))); ++//// ++//// __ get_ctr_el0(rscratch1); ++//// __ strw(rscratch1, Address(c_rarg0, in_bytes(VM_Version::ctr_el0_offset()))); ++//// ++//// __ leave(); ++//// __ ret(lr); ++//// ++////# undef __ ++//// ++//// return start; ++//// } ++////}; ++ ++ ++////void VM_Version::get_processor_features() { ++//// _supports_cx8 = true; ++//// _supports_atomic_getset4 = true; ++//// _supports_atomic_getadd4 = true; ++//// _supports_atomic_getset8 = true; ++//// _supports_atomic_getadd8 = true; ++//// ++//// getPsrInfo_stub(&_psr_info); ++//// ++//// int dcache_line = VM_Version::dcache_line_size(); ++//// ++//// // Limit AllocatePrefetchDistance so that it does not exceed the ++//// // constraint in AllocatePrefetchDistanceConstraintFunc. ++//// if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) ++//// FLAG_SET_DEFAULT(AllocatePrefetchDistance, MIN2(512, 3*dcache_line)); ++//// ++//// if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) ++//// FLAG_SET_DEFAULT(AllocatePrefetchStepSize, dcache_line); ++//// if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) ++//// FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 3*dcache_line); ++//// if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes)) ++//// FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 3*dcache_line); ++//// if (FLAG_IS_DEFAULT(SoftwarePrefetchHintDistance)) ++//// FLAG_SET_DEFAULT(SoftwarePrefetchHintDistance, 3*dcache_line); ++//// ++//// if (PrefetchCopyIntervalInBytes != -1 && ++//// ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768))) { ++//// warning("PrefetchCopyIntervalInBytes must be -1, or a multiple of 8 and < 32768"); ++//// PrefetchCopyIntervalInBytes &= ~7; ++//// if (PrefetchCopyIntervalInBytes >= 32768) ++//// PrefetchCopyIntervalInBytes = 32760; ++//// } ++//// ++//// if (AllocatePrefetchDistance !=-1 && (AllocatePrefetchDistance & 7)) { ++//// warning("AllocatePrefetchDistance must be multiple of 8"); ++//// AllocatePrefetchDistance &= ~7; ++//// } ++//// ++//// if (AllocatePrefetchStepSize & 7) { ++//// warning("AllocatePrefetchStepSize must be multiple of 8"); ++//// AllocatePrefetchStepSize &= ~7; ++//// } ++//// ++//// if (SoftwarePrefetchHintDistance != -1 && ++//// (SoftwarePrefetchHintDistance & 7)) { ++//// warning("SoftwarePrefetchHintDistance must be -1, or a multiple of 8"); ++//// SoftwarePrefetchHintDistance &= ~7; ++//// } ++//// ++//// unsigned long auxv = 0; //ZHJ getauxval(AT_HWCAP); ++//// ++//// char buf[512]; ++//// ++//// _features = auxv; ++//// ++//// int cpu_lines = 0; ++//// if (FILE *f = fopen("/proc/cpuinfo", "r")) { ++//// char buf[128], *p; ++//// while (fgets(buf, sizeof (buf), f) != NULL) { ++//// if ((p = strchr(buf, ':')) != NULL) { ++//// long v = strtol(p+1, NULL, 0); ++//// if (strncmp(buf, "CPU implementer", sizeof "CPU implementer" - 1) == 0) { ++//// _cpu = v; ++//// cpu_lines++; ++//// } else if (strncmp(buf, "CPU variant", sizeof "CPU variant" - 1) == 0) { ++//// _variant = v; ++//// } else if (strncmp(buf, "CPU part", sizeof "CPU part" - 1) == 0) { ++//// if (_model != v) _model2 = _model; ++//// _model = v; ++//// } else if (strncmp(buf, "CPU revision", sizeof "CPU revision" - 1) == 0) { ++//// _revision = v; ++//// } ++//// } ++//// } ++//// fclose(f); ++//// } ++//// ++//// // Enable vendor specific features ++//// ++//// // ThunderX ++//// if (_cpu == CPU_CAVIUM && (_model == 0xA1)) { ++//// if (_variant == 0) _features |= CPU_DMB_ATOMICS; ++//// if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) { ++//// FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true); ++//// } ++//// if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { ++//// FLAG_SET_DEFAULT(UseSIMDForMemoryOps, (_variant > 0)); ++//// } ++//// if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) { ++//// FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false); ++//// } ++//// } ++//// ++//// // ThunderX2 ++//// if ((_cpu == CPU_CAVIUM && (_model == 0xAF)) || ++//// (_cpu == CPU_BROADCOM && (_model == 0x516))) { ++//// if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) { ++//// FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true); ++//// } ++//// if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { ++//// FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); ++//// } ++//// if (FLAG_IS_DEFAULT(UseFPUForSpilling)) { ++//// FLAG_SET_DEFAULT(UseFPUForSpilling, true); ++//// } ++//// } ++//// ++//// // Cortex A53 ++//// if (_cpu == CPU_ARM && (_model == 0xd03 || _model2 == 0xd03)) { ++//// _features |= CPU_A53MAC; ++//// if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) { ++//// FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false); ++//// } ++//// } ++//// ++//// // Cortex A73 ++//// if (_cpu == CPU_ARM && (_model == 0xd09 || _model2 == 0xd09)) { ++//// if (FLAG_IS_DEFAULT(SoftwarePrefetchHintDistance)) { ++//// FLAG_SET_DEFAULT(SoftwarePrefetchHintDistance, -1); ++//// } ++//// // A73 is faster with short-and-easy-for-speculative-execution-loop ++//// if (FLAG_IS_DEFAULT(UseSimpleArrayEquals)) { ++//// FLAG_SET_DEFAULT(UseSimpleArrayEquals, true); ++//// } ++//// } ++//// ++//// if (_cpu == CPU_ARM && (_model == 0xd07 || _model2 == 0xd07)) _features |= CPU_STXR_PREFETCH; ++//// // If an olde style /proc/cpuinfo (cpu_lines == 1) then if _model is an A57 (0xd07) ++//// // we assume the worst and assume we could be on a big little system and have ++//// // undisclosed A53 cores which we could be swapped to at any stage ++//// if (_cpu == CPU_ARM && cpu_lines == 1 && _model == 0xd07) _features |= CPU_A53MAC; ++//// ++//// sprintf(buf, "0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); ++//// if (_model2) sprintf(buf+strlen(buf), "(0x%03x)", _model2); ++//// if (auxv & HWCAP_ASIMD) strcat(buf, ", simd"); ++//// if (auxv & HWCAP_CRC32) strcat(buf, ", crc"); ++//// if (auxv & HWCAP_AES) strcat(buf, ", aes"); ++//// if (auxv & HWCAP_SHA1) strcat(buf, ", sha1"); ++//// if (auxv & HWCAP_SHA2) strcat(buf, ", sha256"); ++//// if (auxv & HWCAP_ATOMICS) strcat(buf, ", lse"); ++//// ++//// _features_string = os::strdup(buf); ++//// ++//// if (FLAG_IS_DEFAULT(UseCRC32)) { ++//// UseCRC32 = (auxv & HWCAP_CRC32) != 0; ++//// } ++//// ++//// if (UseCRC32 && (auxv & HWCAP_CRC32) == 0) { ++//// warning("UseCRC32 specified, but not supported on this CPU"); ++//// FLAG_SET_DEFAULT(UseCRC32, false); ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { ++//// FLAG_SET_DEFAULT(UseAdler32Intrinsics, true); ++//// } ++//// ++//// if (UseVectorizedMismatchIntrinsic) { ++//// warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); ++//// FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); ++//// } ++//// ++//// if (auxv & HWCAP_ATOMICS) { ++//// if (FLAG_IS_DEFAULT(UseLSE)) ++//// FLAG_SET_DEFAULT(UseLSE, true); ++//// } else { ++//// if (UseLSE) { ++//// warning("UseLSE specified, but not supported on this CPU"); ++//// FLAG_SET_DEFAULT(UseLSE, false); ++//// } ++//// } ++//// ++//// if (auxv & HWCAP_AES) { ++//// UseAES = UseAES || FLAG_IS_DEFAULT(UseAES); ++//// UseAESIntrinsics = ++//// UseAESIntrinsics || (UseAES && FLAG_IS_DEFAULT(UseAESIntrinsics)); ++//// if (UseAESIntrinsics && !UseAES) { ++//// warning("UseAESIntrinsics enabled, but UseAES not, enabling"); ++//// UseAES = true; ++//// } ++//// } else { ++//// if (UseAES) { ++//// warning("UseAES specified, but not supported on this CPU"); ++//// FLAG_SET_DEFAULT(UseAES, false); ++//// } ++//// if (UseAESIntrinsics) { ++//// warning("UseAESIntrinsics specified, but not supported 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); ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { ++//// UseCRC32Intrinsics = true; ++//// } ++//// ++//// if (auxv & HWCAP_CRC32) { ++//// if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { ++//// FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true); ++//// } ++//// } else if (UseCRC32CIntrinsics) { ++//// warning("CRC32C is not available on the CPU"); ++//// FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseFMA)) { ++//// FLAG_SET_DEFAULT(UseFMA, true); ++//// } ++//// ++//// if (auxv & (HWCAP_SHA1 | HWCAP_SHA2)) { ++//// if (FLAG_IS_DEFAULT(UseSHA)) { ++//// FLAG_SET_DEFAULT(UseSHA, true); ++//// } ++//// } else if (UseSHA) { ++//// warning("SHA instructions are not available on this CPU"); ++//// FLAG_SET_DEFAULT(UseSHA, false); ++//// } ++//// ++//// if (UseSHA && (auxv & HWCAP_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 && (auxv & HWCAP_SHA2)) { ++//// 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 (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 (auxv & HWCAP_PMULL) { ++//// if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { ++//// FLAG_SET_DEFAULT(UseGHASHIntrinsics, true); ++//// } ++//// } else if (UseGHASHIntrinsics) { ++//// warning("GHASH intrinsics are not available on this CPU"); ++//// FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); ++//// } ++//// ++//// if (is_zva_enabled()) { ++//// if (FLAG_IS_DEFAULT(UseBlockZeroing)) { ++//// FLAG_SET_DEFAULT(UseBlockZeroing, true); ++//// } ++//// if (FLAG_IS_DEFAULT(BlockZeroingLowLimit)) { ++//// FLAG_SET_DEFAULT(BlockZeroingLowLimit, 4 * VM_Version::zva_length()); ++//// } ++//// } else if (UseBlockZeroing) { ++//// warning("DC ZVA is not available on this CPU"); ++//// FLAG_SET_DEFAULT(UseBlockZeroing, false); ++//// } ++//// ++//// // This machine allows unaligned memory accesses ++//// if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { ++//// FLAG_SET_DEFAULT(UseUnalignedAccesses, true); ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { ++//// UseMultiplyToLenIntrinsic = true; ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { ++//// UseSquareToLenIntrinsic = true; ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { ++//// UseMulAddIntrinsic = true; ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseBarriersForVolatile)) { ++//// UseBarriersForVolatile = (_features & CPU_DMB_ATOMICS) != 0; ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { ++//// UsePopCountInstruction = true; ++//// } ++//// ++//// if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { ++//// UseMontgomeryMultiplyIntrinsic = true; ++//// } ++//// if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { ++//// UseMontgomerySquareIntrinsic = true; ++//// } ++//// ++////#ifdef COMPILER2 ++//// if (FLAG_IS_DEFAULT(OptoScheduling)) { ++//// OptoScheduling = true; ++//// } ++////#endif ++////} ++ ++int VM_Version::determine_features() { ++ //////////////////////add some other feature here////////////////// ++ int features = platform_features(unknown_m); ++ //spt_16k_page_m; ++ return features; ++} ++ ++void VM_Version::initialize() { ++ ++ _features = determine_features(); ++ //no need, Abstract_VM_Version already define it as false ++ _supports_cx8 = true; ++ ++ //////////////////////add some other feature here////////////////// ++ ++ if (UseG1GC && FLAG_IS_DEFAULT(MaxGCPauseMillis)) { ++ FLAG_SET_DEFAULT(MaxGCPauseMillis, 650*8); ++ } ++ ++ if (UseG1GC && FLAG_IS_DEFAULT(GCPauseIntervalMillis)) { ++ FLAG_SET_DEFAULT(GCPauseIntervalMillis, MaxGCPauseMillis + 1); ++ } ++ ++#ifdef COMPILER2 ++ if (MaxVectorSize > 0) { ++ if (!is_power_of_2(MaxVectorSize)) { ++ warning("MaxVectorSize must be a power of 2"); ++ MaxVectorSize = 8; ++ } ++ } ++ // Vector optimization was closed by default. ++ if (FLAG_IS_DEFAULT(MaxVectorSize)) { ++ MaxVectorSize = 0; ++ } ++ ++ // Use ctlz/cttz/ctpop instructions if available. ++ if (is_shenwei()) { ++ if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { ++ FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, 1); ++ } ++ if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { ++ FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, 1); ++ } ++ if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { ++ FLAG_SET_DEFAULT(UsePopCountInstruction, 1); ++ } ++ if (is_sw6b() && FLAG_IS_DEFAULT(UseSW6B)) { ++ //FLAG_SET_DEFAULT(UseSW6B, 1); ++ } ++ if (is_sw8a() && FLAG_IS_DEFAULT(UseSW8A)) { ++ FLAG_SET_DEFAULT(UseSW8A, 1); ++ FLAG_SET_DEFAULT(FRegisterConflict, 0); ++ FLAG_SET_DEFAULT(UseWmemb, 1); ++ FLAG_SET_DEFAULT(UseAddpi, 0); ++ } ++ } else if (UseCountLeadingZerosInstruction || UseCountTrailingZerosInstruction ++ || UsePopCountInstruction) { ++ if (!FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) ++ warning("Only SW CPUs support UseCountTrailingZerosInstruction"); ++ FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, 0); ++ FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, 0); ++ FLAG_SET_DEFAULT(UsePopCountInstruction, 0); ++ } ++ if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { ++ UseMontgomeryMultiplyIntrinsic = true; ++ } ++ if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { ++ UseMontgomerySquareIntrinsic = true; ++ } ++#endif ++ ++ UseSSE = 0; // Only on x86 and x64 ++ ++ if (TieredCompilation) { ++ if (!FLAG_IS_DEFAULT(TieredCompilation)) ++ warning("TieredCompilation not supported"); ++ FLAG_SET_DEFAULT(TieredCompilation, false); ++ } ++// if (UseCRC32Intrinsics) { ++// if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) ++// warning("CRC32 intrinsics are not available on this CPU"); ++// FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); ++// } ++ char buf[512]; ++ jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", ++ (has_l2_cache() ? ", has_l2_cache" : ""), ++ (has_16k_page() ? ", has_16k_page" : ""), ++ (is_shenwei() ? ", on_shenwei_platform" : ""), ++ (is_sw2f() ? ", SW410(2F)" : ""), ++ (is_sw4a() ? ", SW411(4A)" : "" ), ++ (is_sw6a() ? ", SW421(6A)" : ""), ++ (is_sw6b() ? ", SW422(6B)" : ""), ++ (is_sw1621() ? ", SW1621" : ""), ++ (is_sw8a() ? ", SW8A" : ""), ++ (UseCountTrailingZerosInstruction ? ", UseCountTrailingZerosInstruction" : "")); ++ ++ // buf is started with ", " or is empty ++ _features_str = strdup(strlen(buf) > 2 ? buf + 2 : buf); ++ ++ if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { ++ FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); ++ } ++ ++ if (FLAG_IS_DEFAULT(AllocatePrefetchLines)) { ++ FLAG_SET_DEFAULT(AllocatePrefetchLines, 1); ++ } ++ ++ if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) { ++ FLAG_SET_DEFAULT(AllocatePrefetchStepSize, 64); ++ } ++ ++ if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { ++ FLAG_SET_DEFAULT(AllocatePrefetchDistance, 64); ++ } ++ ++ if (FLAG_IS_DEFAULT(AllocateInstancePrefetchLines)) { ++ FLAG_SET_DEFAULT(AllocateInstancePrefetchLines, 1); ++ } ++ ++ if (UseSHA) { ++ warning("SHA instructions are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseSHA, false); ++ } ++ ++ if (UseFMA) { ++ warning("FMA instructions are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseFMA, false); ++ } ++ ++ if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) { ++ warning("SHA intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); ++ FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); ++ FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); ++ } ++ ++ NOT_PRODUCT( if (PrintMiscellaneous && Verbose) print_features(); ); ++} ++ ++void VM_Version::print_features() { ++ tty->print_cr("Version:%s", cpu_features()); ++} +diff -uNr openjdk/src/hotspot/cpu/sw64/vm_version_sw64.hpp afu11u/src/hotspot/cpu/sw64/vm_version_sw64.hpp +--- openjdk/src/hotspot/cpu/sw64/vm_version_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vm_version_sw64.hpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * 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_SW64_VM_VM_VERSION_SW64_HPP ++#define CPU_SW64_VM_VM_VERSION_SW64_HPP ++ ++#include "runtime/abstract_vm_version.hpp" ++#include "runtime/globals_extension.hpp" ++#include "utilities/sizes.hpp" ++ ++class VM_Version : public Abstract_VM_Version { ++//// friend class JVMCIVMStructs; ++ ++protected: ++//// static int _cpu; ++//// static int _model; ++//// static int _model2; ++//// static int _variant; ++//// static int _revision; ++//// static int _stepping; ++//// ++//// struct PsrInfo { ++//// uint32_t dczid_el0; ++//// uint32_t ctr_el0; ++//// }; ++//// static PsrInfo _psr_info; ++ static int _features; ++ static const char* _features_str; ++//// static void get_processor_features(); ++ static void print_features(); ++ static int determine_features(); ++ static int platform_features(int features); ++ ++public: ++ // Initialization ++ static void initialize(); ++ ++//// // Asserts ++//// static void assert_is_initialized() { ++//// } ++ ++ static bool has_l2_cache() { return _features & with_l2_cache_m; } ++ static bool has_16k_page() { return _features & spt_16k_page_m; } ++ static bool is_sw2f() { return _features & sw2f_m; } ++ static bool is_sw4a() { return _features & sw4a_m; } ++ static bool is_sw6a() { return _features & sw6a_m; } ++ static bool is_sw6b() { return _features & sw6b_m; } ++ static bool is_sw8a() { return _features & wx_h8000_m; }//TODO UseSW8A ++ static bool is_sw1621() { return _features & sw1621_m; } ++ static bool is_sw3231() { return _features & sw3231_m; } ++ static bool is_shenwei() { return _features & with_sw_support_m; } ++// static bool sw2only() { return is_sw2f() || is_sw4a() || is_sw6a(); } ++ static bool sw2only() { return true; } ++ static bool sw3only() { return is_sw6b(); } ++ static bool sw4only() { return is_sw8a(); } ++ static const char* cpu_features() { return _features_str; } ++ ++//// static bool expensive_load(int ld_size, int scale) { ++//// if (cpu_family() == CPU_ARM) { ++//// // Half-word load with index shift by 1 (aka scale is 2) has ++//// // extra cycle latency, e.g. ldrsh w0, [x1,w2,sxtw #1]. ++//// if (ld_size == 2 && scale == 2) { ++//// return true; ++//// } ++//// } ++//// return false; ++//// } ++ ++ enum Family { ++ CPU_ARM = 'A', ++ CPU_BROADCOM = 'B', ++ CPU_CAVIUM = 'C', ++ CPU_DEC = 'D', ++ CPU_INFINEON = 'I', ++ CPU_MOTOROLA = 'M', ++ CPU_NVIDIA = 'N', ++ CPU_AMCC = 'P', ++ CPU_QUALCOM = 'Q', ++ CPU_MARVELL = 'V', ++ CPU_INTEL = 'i', ++ }; ++ ++ enum Feature_Flag { ++ with_l2_cache = 0, ++ spt_16k_page = 1, ++ sw2f = 2, ++ sw4a = 3, ++ sw6a = 4, ++ sw6b = 5, ++ sw1621 = 6, ++ sw3231 = 7, ++ wx_h8000 = 8, ++ with_sw_support = 9, ++// CPU_FP = (1<<0), ++// CPU_ASIMD = (1<<1), ++// CPU_EVTSTRM = (1<<2), ++// CPU_AES = (1<<3), ++// CPU_PMULL = (1<<4), ++// CPU_SHA1 = (1<<5), ++// CPU_SHA2 = (1<<6), ++// CPU_CRC32 = (1<<7), ++// CPU_LSE = (1<<8), ++// CPU_STXR_PREFETCH= (1 << 29), ++// CPU_A53MAC = (1 << 30), ++// CPU_DMB_ATOMICS = (1 << 31), ++ }; ++ ++ enum Feature_Flag_Set { ++ unknown_m = 0, ++ all_features_m = -1, ++ with_l2_cache_m = 1 << with_l2_cache, ++ spt_16k_page_m = 1 << spt_16k_page, ++ sw2f_m = 1 << sw2f, ++ sw4a_m = 1 << sw4a, ++ sw6a_m = 1 << sw6a, ++ sw6b_m = 1 << sw6b, ++ sw1621_m = 1 << sw1621, ++ sw3231_m = 1 << sw3231, ++ wx_h8000_m = 1 << wx_h8000, ++ with_sw_support_m = 1 << with_sw_support, ++ ++ //////////////////////add some other feature here////////////////// ++ }; ++ ++//// static int cpu_family() { return _cpu; } ++//// static int cpu_model() { return _model; } ++//// static int cpu_model2() { return _model2; } ++//// static int cpu_variant() { return _variant; } ++//// static int cpu_revision() { return _revision; } ++//// static ByteSize dczid_el0_offset() { return byte_offset_of(PsrInfo, dczid_el0); } ++//// static ByteSize ctr_el0_offset() { return byte_offset_of(PsrInfo, ctr_el0); } ++//// static bool is_zva_enabled() { ++//// // Check the DZP bit (bit 4) of dczid_el0 is zero ++//// // and block size (bit 0~3) is not zero. ++//// return ((_psr_info.dczid_el0 & 0x10) == 0 && ++//// (_psr_info.dczid_el0 & 0xf) != 0); ++//// } ++//// static int icache_line_size() { ++//// return (1 << (_psr_info.ctr_el0 & 0x0f)) * 4; ++//// } ++//// static int dcache_line_size() { ++//// return (1 << ((_psr_info.ctr_el0 >> 16) & 0x0f)) * 4; ++//// } ++}; ++ ++#endif // CPU_SW64_VM_VM_VERSION_SW64_HPP +diff -uNr openjdk/src/hotspot/cpu/sw64/vtableStubs_sw64.cpp afu11u/src/hotspot/cpu/sw64/vtableStubs_sw64.cpp +--- openjdk/src/hotspot/cpu/sw64/vtableStubs_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/cpu/sw64/vtableStubs_sw64.cpp 2025-05-09 10:05:55.888290535 +0800 +@@ -0,0 +1,269 @@ ++/* ++ * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. ++ * 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 "assembler_sw64.inline.hpp" ++#include "code/vtableStubs.hpp" ++#include "interp_masm_sw64.hpp" ++#include "memory/resourceArea.hpp" ++#include "oops/compiledICHolder.hpp" ++#include "oops/instanceKlass.hpp" ++#include "oops/klassVtable.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "vmreg_sw64.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, oop receiver, int index); ++#endif ++ ++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; ++ // No variance was detected in vtable stub sizes. Setting index_dependent_slop == 0 will unveil any deviation from this observation. ++ const int index_dependent_slop = 0; ++ ++ ResourceMark rm; ++ CodeBuffer cb(s->entry_point(), stub_code_length); ++ MacroAssembler* masm = new MacroAssembler(&cb); ++ ++#if (!defined(PRODUCT) && defined(COMPILER2)) ++ if (CountCompiledCalls) { ++ __ incrementw(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); ++ } ++#endif ++ ++ // get receiver (need to skip return address on top of stack) ++ assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); ++ ++ // get receiver klass ++ Register rax = V0; ++// Register rbx = rscratch1; ++ address npe_addr = __ pc(); ++ __ load_klass(rax, j_rarg0); ++ ++#ifndef PRODUCT ++ if (DebugVtables) { ++ Label L; ++ start_pc = __ pc(); ++ // check offset vs vtable length ++ __ cmpw(Address(rax, Klass::vtable_length_offset()), vtable_index*vtableEntry::size()); ++ slop_delta = 12 - (__ pc() - start_pc); // cmpl varies in length, depending on data ++ slop_bytes += slop_delta; ++ assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta); ++ ++ __ jcc(Assembler::greater, L); ++ __ movw(c_rarg2, vtable_index); ++ // VTABLE TODO: find upper bound for call_VM length. ++ start_pc = __ pc(); ++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, c_rarg2); ++ slop_delta = 550 - (__ pc() - start_pc); ++ slop_bytes += slop_delta; ++ assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta); ++ __ bind(L); ++ } ++#endif // PRODUCT ++ ++ const Register method = rmethod; ++ ++ // load Method* and target address ++ start_pc = __ pc(); ++ __ lookup_virtual_method(rax, vtable_index, method); ++ slop_delta = 8 - (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; ++ __ cmpptr(method, R0); ++ __ jcc(Assembler::equal, L); ++ __ cmpptr(Address(method, Method::from_compiled_offset()), R0); ++ __ jcc(Assembler::notZero, L); ++ __ stop("Vtable entry is NULL"); ++ __ bind(L); ++ } ++#endif // PRODUCT ++ ++ // rax: receiver klass ++ // method (rbx): Method* ++ // rcx: receiver ++ address ame_addr = __ pc(); ++ __ jmp( Address(method, Method::from_compiled_offset())); ++ ++ 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 == 0) ? 4 : // code size change with transition from 8-bit to 32-bit constant (@index == 16). ++ (itable_index < 16) ? 3 : 0; // index == 0 generates even shorter code. ++ ++ ResourceMark rm; ++ CodeBuffer cb(s->entry_point(), stub_code_length); ++ MacroAssembler *masm = new MacroAssembler(&cb); ++ ++#if (!defined(PRODUCT) && defined(COMPILER2)) ++ if (CountCompiledCalls) { ++ __ incrementw(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); ++ } ++#endif // PRODUCT ++ ++ // Entry arguments: ++ // rax: CompiledICHolder ++ // j_rarg0: Receiver ++ ++ // Most registers are in use; we'll use rax, rbx, r10, r11 ++ // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) ++ const Register recv_klass_reg = r10; ++ const Register holder_klass_reg = rax; // declaring interface klass (DECC) ++ const Register resolved_klass_reg = rbx; // resolved interface klass (REFC) ++ const Register temp_reg = r11; ++ ++ const Register icholder_reg = rax; ++ __ ldptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); ++ __ ldptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); ++ ++ Label L_no_such_interface; ++ ++ // get receiver klass (also an implicit null-check) ++ assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); ++ address npe_addr = __ pc(); ++ __ load_klass(recv_klass_reg, j_rarg0); ++ ++ start_pc = __ pc(); ++ ++ // Receiver subtype check against REFC. ++ // Destroys recv_klass_reg value. ++ __ lookup_interface_method(// inputs: rec. class, interface ++ recv_klass_reg, resolved_klass_reg, noreg, ++ // outputs: scan temp. reg1, scan temp. reg2 ++ recv_klass_reg, temp_reg, ++ L_no_such_interface, ++ /*return_method=*/false); ++ ++ const ptrdiff_t typecheckSize = __ pc() - start_pc; ++ start_pc = __ pc(); ++ ++ // Get selected method from declaring class and itable index ++ const Register method = rbx; ++ __ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg ++ __ lookup_interface_method(// inputs: rec. class, interface, itable index ++ recv_klass_reg, holder_klass_reg, itable_index, ++ // outputs: method, scan temp. reg ++ method, temp_reg, ++ L_no_such_interface); ++ ++ const ptrdiff_t lookupSize = __ pc() - start_pc; ++ ++ // We expect we need index_dependent_slop extra bytes. Reason: ++ // The emitted code in lookup_interface_method changes when itable_index exceeds 15. ++ // For linux, a very narrow estimate would be 112, but Solaris requires some more space (130). ++ const ptrdiff_t estimate = 144; ++ 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); ++ ++ // If we take a trap while this arg is on the stack we will not ++ // be able to walk the stack properly. This is not an issue except ++ // when there are mistakes in this assembly code that could generate ++ // a spurious fault. Ask me how I know... ++ ++ // method (rbx): Method* ++ // j_rarg0: receiver ++ ++#ifdef ASSERT ++ if (DebugVtables) { ++ Label L2; ++ __ cmpptr(method, R0); ++ __ jcc(Assembler::equal, L2); ++ __ cmpptr(Address(method, Method::from_compiled_offset()), R0); ++ __ jcc(Assembler::notZero, L2); ++ __ stop("compiler entrypoint is null"); ++ __ bind(L2); ++ } ++#endif // ASSERT ++ ++ address ame_addr = __ pc(); ++ __ jmp(Address(method, Method::from_compiled_offset())); ++ ++ __ 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. ++ __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); ++ ++ 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() { ++ // cache line size is 64 bytes, but we want to limit alignment loss. ++ const unsigned int icache_line_size = wordSize; ++ return icache_line_size; ++} +diff -uNr openjdk/src/hotspot/os/linux/os_linux.cpp afu11u/src/hotspot/os/linux/os_linux.cpp +--- openjdk/src/hotspot/os/linux/os_linux.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/os/linux/os_linux.cpp 2025-05-09 10:06:54.212292504 +0800 +@@ -427,7 +427,7 @@ + // 1: ... + // ... + // 7: The default directories, normally /lib and /usr/lib. +-#if defined(AMD64) || (defined(_LP64) && defined(SPARC)) || defined(PPC64) || defined(S390) ++#if defined(AMD64) || (defined(_LP64) && defined(SPARC)) || defined(PPC64) || defined(S390) || defined(SW64) + #define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib" + #else + #if defined(AARCH64) +@@ -1396,6 +1396,9 @@ + #if defined(X86) || defined(PPC64) || defined(S390) + #define SYS_clock_getres AMD64_ONLY(229) IA32_ONLY(266) PPC64_ONLY(247) S390_ONLY(261) + #define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y) ++ #elif defined(SW64) ++ #define SYS_clock_getres SW64_ONLY(421) ++ #define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y) + #else + #warning "SYS_clock_getres not defined for this platform, disabling fast_thread_cpu_time" + #define sys_clock_getres(x,y) -1 +@@ -1894,7 +1897,11 @@ + #endif + {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, + {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"}, ++#if defined(__sw_64) ++ {EM_SW_64, EM_SW_64, ELFCLASS64, ELFDATA2LSB, (char*)"Sw64"}, ++#else + {EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"}, ++#endif + {EM_MIPS_RS3_LE, EM_MIPS_RS3_LE, ELFCLASS32, ELFDATA2LSB, (char*)"MIPSel"}, + {EM_MIPS, EM_MIPS, ELFCLASS32, ELFDATA2MSB, (char*)"MIPS"}, + {EM_PARISC, EM_PARISC, ELFCLASS32, ELFDATA2MSB, (char*)"PARISC"}, +@@ -1926,6 +1933,10 @@ + static Elf32_Half running_arch_code=EM_S390; + #elif (defined ALPHA) + static Elf32_Half running_arch_code=EM_ALPHA; ++#elif (defined __sw_64) && (defined SW64) ++ static Elf32_Half running_arch_code=EM_SW_64; ++#elif (defined __alpha) && (defined SW64) ++ static Elf32_Half running_arch_code=EM_ALPHA; + #elif (defined MIPSEL) + static Elf32_Half running_arch_code=EM_MIPS_RS3_LE; + #elif (defined PARISC) +@@ -1941,8 +1952,8 @@ + #elif (defined LOONGARCH) + static Elf32_Half running_arch_code=EM_LOONGARCH; + #else +- #error Method os::dll_load requires that one of following is defined:\ +- AARCH64, ALPHA, ARM, AMD64, IA32, IA64, LOONGARCH, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc ++// #error Method os::dll_load requires that one of following is defined:\ ++// AARCH64, ALPHA, ARM, AMD64, IA32, IA64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, S390, SH, __sparc + #endif + + // Identify compatability class for VM's architecture and library's architecture +@@ -3139,9 +3150,13 @@ + } + + // Define MAP_HUGETLB here so we can build HotSpot on old systems. ++#ifdef SW64 //ZHJ20170828 ++#define MAP_HUGETLB 0x100000 ++#else + #ifndef MAP_HUGETLB + #define MAP_HUGETLB 0x40000 + #endif ++#endif + + // Define MADV_HUGEPAGE here so we can build HotSpot on old systems. + #ifndef MADV_HUGEPAGE +@@ -3150,6 +3165,22 @@ + + int os::Linux::commit_memory_impl(char* addr, size_t size, + size_t alignment_hint, bool exec) { ++#ifdef SW64 ++ if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { ++ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; ++ uintptr_t res = ++ (uintptr_t) ::mmap(addr, size, prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB, ++ -1, 0); ++ if (res != (uintptr_t) MAP_FAILED) { ++ if (UseNUMAInterleaving) { ++ numa_make_global(addr, size); ++ } ++ return 0; ++ } ++ // Fall through and try to use small pages ++ } ++#endif + int err = os::Linux::commit_memory_impl(addr, size, exec); + if (err == 0) { + realign_memory(addr, size, alignment_hint); +@@ -3965,6 +3996,7 @@ + ARM32_ONLY(2 * M) + IA32_ONLY(4 * M) + IA64_ONLY(256 * M) ++ SW64_ONLY(8 * M) + PPC_ONLY(4 * M) + S390_ONLY(1 * M) + SPARC_ONLY(4 * M); +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/assembler_linux_sw64.cpp afu11u/src/hotspot/os_cpu/linux_sw64/assembler_linux_sw64.cpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/assembler_linux_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/assembler_linux_sw64.cpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++// nothing required here ++ ++ +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/atomic_linux_sw64.hpp afu11u/src/hotspot/os_cpu/linux_sw64/atomic_linux_sw64.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/atomic_linux_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/atomic_linux_sw64.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,260 @@ ++/* ++ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_ATOMIC_LINUX_SW64_HPP ++#define OS_CPU_LINUX_SW64_VM_ATOMIC_LINUX_SW64_HPP ++ ++#include "vm_version_sw64.hpp" ++ ++// Implementation of class atomic ++ ++#define FULL_MEM_BARRIER __sync_synchronize() ++#define READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE); ++#define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE); ++ ++template ++struct Atomic::PlatformAdd ++ : Atomic::FetchAndAdd > ++{ ++ template ++ D fetch_and_add(I add_value, D volatile* dest, atomic_memory_order order) const; ++}; ++ ++template<> ++template ++inline D Atomic::PlatformAdd<4>::fetch_and_add(I add_value, D volatile* dest, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(4 == sizeof(I)); ++ STATIC_ASSERT(4 == sizeof(D)); ++ D __ret; ++ I __tmp; ++ D* __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldw %[__ret],0(%[__addr])\n\t" ++ " ldi %[__tmp],1\n\t" ++ " wr_f %[__tmp]\n\t" ++ " addw %[__ret],%[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstw %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__tmp],1b\n\t" ++ " zapnot %[__ret],0xf,%[__ret]\n\t" ++ " \n\t" ++ : [__ret]"=&r" (__ret), [__addr]"=&r"(__addr), [__tmp]"=&r"(__tmp) ++ : [__dest] "m" (*(volatile jint*)dest), [__val] "Ir" (add_value) ++ : "memory" ); ++ ++ return __ret; ++} ++ ++template<> ++template ++inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, ++ T volatile* dest, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(4 == sizeof(T)); ++ ++ //warning("Atomic::PlatformXchg<4>"); ++ T __ret, __tmp; ++ T* __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldw %[__ret],0(%[__addr])\n\t" ++ " ldi %[__tmp],1\n\t" ++ " wr_f %[__tmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstw %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__tmp],1b\n\t" ++ " zapnot %[__ret],0xf,%[__ret]\n\t" ++ " \n\t" ++ : [__ret]"=&r" (__ret), [__addr]"=&r"(__addr), [__tmp]"=&r"(__tmp) ++ : [__dest] "m" (*(T volatile *)dest), [__val] "Ir"(exchange_value) /* _val can not be constant in stl */ ++ : "memory" ); ++ return __ret; ++} ++ ++ ++// No direct support for cmpxchg of bytes; emulate using int. ++template<> ++struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; ++ ++/*template<> ++template ++inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, ++ T volatile* dest, ++ T compare_value, ++ atomic_memory_order ) const { ++ STATIC_ASSERT(1 == sizeof(T)); ++ T __prev, __cmp; ++ T __tmp; ++ T* __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldw %[__prev],0(%[__addr])\n\t" ++ " zap %[__prev], 0x1, %[__tmp]\n\t" ++ " bis %[__val], %[__tmp], %[__val]\n\t" ++ " mov %[__old],%[__tmp]\n\t" ++ " zapnot %[__prev], 0x1, %[__prev]\n\t" ++ " cmpeq %[__prev],%[__tmp],%[__cmp]\n\t" ++ " wr_f %[__cmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstw %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__cmp],2f\n\t" ++ " beq %[__tmp],1b\n\t" ++ "2: \n\t" ++ " zapnot %[__prev],0xf,%[__prev]\n\t" ++ : [__prev]"=&r" (__prev), [__addr]"=&r" (__addr), [__cmp] "=&r" (__cmp), [__tmp] "=&r" (__tmp) ++ : [__dest] "m" (*(T volatile *)dest), [__old]"Ir" (compare_value), [__val]"Ir" (exchange_value) ++ : "memory" ); ++ ++ return __prev; ++}*/ ++ ++template<> ++template ++inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, ++ T volatile* dest, ++ T compare_value, ++ atomic_memory_order /* order */) const { ++ STATIC_ASSERT(4 == sizeof(T)); ++ ++ //warning("Atomic::PlatformCmpxchg<4_1> exchange_value=%d dest=%d compare_value=%d\n", exchange_value, *dest, compare_value); ++ T __prev, __cmp; ++ T __tmp; ++ T* __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldw %[__prev],0(%[__addr])\n\t" ++ " mov %[__old],%[__tmp]\n\t" ++ " addw %[__tmp], 0x0, %[__tmp]\n\t" ++ " cmpeq %[__prev],%[__tmp],%[__cmp]\n\t" ++ " wr_f %[__cmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstw %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__cmp],2f\n\t" ++ " beq %[__tmp],1b\n\t" ++ "2: \n\t" ++ " zapnot %[__prev],0xf,%[__prev]\n\t" ++ : [__prev]"=&r" (__prev), [__addr]"=&r" (__addr), [__cmp] "=&r" (__cmp), [__tmp] "=&r" (__tmp) ++ : [__dest] "m" (*(T volatile *)dest), [__old]"Ir" (compare_value), [__val]"Ir" (exchange_value) /* _val can not be constant in stl */ ++ : "memory" ); ++ //warning("Atomic::PlatformCmpxchg<4_2> exchange_value=%d dest=%d compare_value=%d\n", exchange_value, *dest, compare_value); ++ return __prev; ++} ++ ++ ++template<> ++template ++inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(8 == sizeof(I)); ++ STATIC_ASSERT(8 == sizeof(D)); ++ //warning("Atomic::PlatformAdd<8>::fetch_and_add"); ++ D __ret; ++ I __tmp; ++ D* __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldl %[__ret],0(%[__addr])\n\t" ++ " ldi %[__tmp],1\n\t" ++ " wr_f %[__tmp]\n\t" ++ " addl %[__ret],%[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstl %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__tmp],1b\n\t" ++ " \n\t" ++ : [__ret]"=&r" (__ret), [__addr]"=&r"(__addr), [__tmp]"=&r"(__tmp) ++ : [__dest] "m" (*(D volatile *)dest), [__val] "Ir"(add_value) ++ : "memory" ); ++ ++ return __ret; ++} ++ ++template<> ++template ++inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, T volatile* dest, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(8 == sizeof(T)); ++ ++ //warning("Atomic::PlatformXchg<8>"); ++ T __ret, __tmp; ++ T __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldl %[__ret],0(%[__addr])\n\t" ++ " ldi %[__tmp],1\n\t" ++ " wr_f %[__tmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstl %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__tmp],1b\n\t" ++ " \n\t" ++ : [__ret]"=&r" (__ret), [__addr]"=&r"(__addr), [__tmp]"=&r"(__tmp) ++ : [__dest] "m" (*(T volatile *)dest), [__val] "Ir"(exchange_value) /* _val can not be constant in stl */ ++ : "memory" ); ++ ++ return __ret; ++} ++ ++template<> ++template ++inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, ++ T volatile* dest, ++ T compare_value, ++ atomic_memory_order /* order */) const { ++ STATIC_ASSERT(8 == sizeof(T)); ++ //warning("Atomic::PlatformCmpxchg<8>"); ++ T __prev, __cmp; ++ T __tmp, __addr; ++ ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldl %[__prev],0(%[__addr])\n\t" ++ " cmpeq %[__prev],%[__old],%[__cmp]\n\t" ++ " wr_f %[__cmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstl %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__cmp],2f\n\t" ++ " beq %[__tmp],1b\n\t" ++ "2: \n\t" ++ : [__prev]"=&r" (__prev), [__addr]"=&r" (__addr), [__cmp] "=&r" (__cmp), [__tmp] "=&r" (__tmp) ++ : [__dest] "m" (*(T volatile *)dest), [__old]"Ir" (compare_value), [__val]"Ir" (exchange_value) /* _val can not be constant in stl */ ++ : "memory" ); ++ ++ return __prev; ++} ++ ++#endif // OS_CPU_LINUX_SW64_VM_ATOMIC_LINUX_SW64_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/bytes_linux_sw64.inline.hpp afu11u/src/hotspot/os_cpu/linux_sw64/bytes_linux_sw64.inline.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/bytes_linux_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/bytes_linux_sw64.inline.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_BYTES_LINUX_SW64_INLINE_HPP ++#define OS_CPU_LINUX_SW64_VM_BYTES_LINUX_SW64_INLINE_HPP ++ ++#include ++ ++// Efficient swapping of data bytes from Java byte ++// ordering to native byte ordering and vice versa. ++inline u2 Bytes::swap_u2(u2 x) { return bswap_16(x); } ++inline u4 Bytes::swap_u4(u4 x) { return bswap_32(x); } ++inline u8 Bytes::swap_u8(u8 x) { return bswap_64(x); } ++ ++#endif // OS_CPU_LINUX_SW64_VM_BYTES_LINUX_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/copy_linux_sw64.inline.hpp afu11u/src/hotspot/os_cpu/linux_sw64/copy_linux_sw64.inline.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/copy_linux_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/copy_linux_sw64.inline.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_COPY_LINUX_SW64_INLINE_HPP ++#define OS_CPU_LINUX_SW64_VM_COPY_LINUX_SW64_INLINE_HPP ++ ++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) { ++ pd_conjoint_words(from, to, count); ++} ++ ++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) { ++ pd_conjoint_bytes(from, to, count); ++} ++ ++template ++static void copy_conjoint_atomic(const T* from, T* 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_jshorts_atomic(const jshort* from, jshort* to, size_t count) { ++ copy_conjoint_atomic(from, to, count); ++} ++ ++static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { ++ copy_conjoint_atomic(from, to, count); ++} ++ ++static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { ++ copy_conjoint_atomic(from, to, count); ++} ++ ++static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { ++ //assert(!UseCompressedOops, "foo!"); ++ assert(HeapWordSize == BytesPerOop, "heapwords and oops must be the same size"); ++ copy_conjoint_atomic(from, to, count); ++} ++ ++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((jshort*)from, (jshort*)to, count); ++} ++ ++static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { ++ pd_conjoint_jints_atomic((jint*)from, (jint*)to, count); ++} ++ ++static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { ++ pd_conjoint_jlongs_atomic((jlong*)from, (jlong*)to, count); ++} ++ ++static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { ++ //assert(!UseCompressedOops, "foo!"); ++ assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); ++ pd_conjoint_oops_atomic((oop*)from, (oop*)to, count); ++} ++ ++#endif // OS_CPU_LINUX_SW64_VM_COPY_LINUX_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/globals_linux_sw64.hpp afu11u/src/hotspot/os_cpu/linux_sw64/globals_linux_sw64.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/globals_linux_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/globals_linux_sw64.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_GLOBALS_LINUX_SW64_HPP ++#define OS_CPU_LINUX_SW64_VM_GLOBALS_LINUX_SW64_HPP ++ ++// Sets the default values for platform dependent flags used by the runtime system. ++// (see globals.hpp) ++ ++define_pd_global(bool, DontYieldALot, false); ++define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default ++define_pd_global(intx, VMThreadStackSize, 1024); ++ ++define_pd_global(intx, CompilerThreadStackSize, 0); ++ ++define_pd_global(uintx,JVMInvokeMethodSlack, 8192); ++ ++// Used on 64 bit platforms for UseCompressedOops base address ++define_pd_global(uintx,HeapBaseMinAddress, 2*G); ++ ++#endif // OS_CPU_LINUX_SW64_VM_GLOBALS_LINUX_SW64_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/linux_sw64.ad afu11u/src/hotspot/os_cpu/linux_sw64/linux_sw64.ad +--- openjdk/src/hotspot/os_cpu/linux_sw64/linux_sw64.ad 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/linux_sw64.ad 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,69 @@ ++// ++// Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. ++// Copyright (c) 2014, Red Hat Inc. All rights reserved. ++// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++// ++// This code is free software; you can redistribute it and/or modify it ++// under the terms of the GNU General Public License version 2 only, as ++// published by the Free Software Foundation. ++// ++// This code is distributed in the hope that it will be useful, but WITHOUT ++// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++// version 2 for more details (a copy is included in the LICENSE file that ++// accompanied this code). ++// ++// You should have received a copy of the GNU General Public License version ++// 2 along with this work; if not, write to the Free Software Foundation, ++// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++// ++// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++// or visit www.oracle.com if you need additional information or have any ++// questions. ++// ++// ++ ++// AArch64 Linux Architecture Description File ++ ++//----------OS-DEPENDENT ENCODING BLOCK---------------------------------------- ++// This block specifies the encoding classes used by the compiler to ++// output byte streams. Encoding classes generate functions which are ++// called 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. ++// They use the ins_encode keyword to specify their encoding class ++// (which must be one of the class names 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 %{ ++ // Build emit functions for each basic byte or larger field in the intel ++ // encoding scheme (opcode, rm, sib, immediate), and call them from C++ ++ // code in the enc_class source block. Emit functions will live in the ++ // main source block for now. In future, we can generalize this by ++ // adding a syntax that specifies the sizes of fields in an order, ++ // so that the adlc can build the emit functions automagically ++ ++ enc_class Java_To_Runtime(method meth) %{ ++ %} ++ ++%} ++ ++ ++// Platform dependent source ++ ++source %{ ++ ++%} +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/linux_sw64.s afu11u/src/hotspot/os_cpu/linux_sw64/linux_sw64.s +--- openjdk/src/hotspot/os_cpu/linux_sw64/linux_sw64.s 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/linux_sw64.s 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,380 @@ ++# ++# Copyright (c) 2004, 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. ++# ++ ++ ++# # NOTE WELL! The _Copy functions are called directly ++ # from server-compiler-generated code via CallLeafNoFP, ++ # which means that they *must* either not use floating ++ # point or use it in the same manner as does the server ++ # compiler. ++ ++# .globl _Copy_arrayof_conjoint_bytes ++ .globl _Copy_arrayof_conjoint_jshorts ++# .globl _Copy_conjoint_jshorts_atomic ++# .globl _Copy_arrayof_conjoint_jints ++# .globl _Copy_conjoint_jints_atomic ++# .globl _Copy_arrayof_conjoint_jlongs ++# .globl _Copy_conjoint_jlongs_atomic ++ ++ .text ++ ++# .globl SpinPause ++# .align 16 ++# .type SpinPause,@function ++SpinPause: ++# rep ++# nop ++# movq $1, %rax ++# ret ++ ++# # Support for void Copy::arrayof_conjoint_bytes(void* from, ++# # void* to, ++# # size_t count) ++# # rdi - from ++# # rsi - to ++# # rdx - count, treated as ssize_t ++# # ++# .p2align 4,,15 ++ .type _Copy_arrayof_conjoint_bytes,@function ++_Copy_arrayof_conjoint_bytes: ++# movq %rdx,%r8 # byte count ++# shrq $3,%rdx # qword count ++# cmpq %rdi,%rsi ++# leaq -1(%rdi,%r8,1),%rax # from + bcount*1 - 1 ++# jbe acb_CopyRight ++# cmpq %rax,%rsi ++# jbe acb_CopyLeft ++acb_CopyRight: ++# leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 ++# leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 ++# negq %rdx ++# jmp 7f ++# .p2align 4,,15 ++#1: movq 8(%rax,%rdx,8),%rsi ++# movq %rsi,8(%rcx,%rdx,8) ++# addq $1,%rdx ++# jnz 1b ++#2: testq $4,%r8 # check for trailing dword ++# jz 3f ++# movl 8(%rax),%esi # copy trailing dword ++# movl %esi,8(%rcx) ++# addq $4,%rax ++# addq $4,%rcx # original %rsi is trashed, so we ++# # can't use it as a base register ++#3: testq $2,%r8 # check for trailing word ++# jz 4f ++# movw 8(%rax),%si # copy trailing word ++# movw %si,8(%rcx) ++# addq $2,%rcx ++#4: testq $1,%r8 # check for trailing byte ++# jz 5f ++# movb -1(%rdi,%r8,1),%al # copy trailing byte ++# movb %al,8(%rcx) ++#5: ret ++# .p2align 4,,15 ++#6: movq -24(%rax,%rdx,8),%rsi ++# movq %rsi,-24(%rcx,%rdx,8) ++# movq -16(%rax,%rdx,8),%rsi ++# movq %rsi,-16(%rcx,%rdx,8) ++# movq -8(%rax,%rdx,8),%rsi ++# movq %rsi,-8(%rcx,%rdx,8) ++# movq (%rax,%rdx,8),%rsi ++# movq %rsi,(%rcx,%rdx,8) ++#7: addq $4,%rdx ++# jle 6b ++# subq $4,%rdx ++# jl 1b ++# jmp 2b ++acb_CopyLeft: ++# testq $1,%r8 # check for trailing byte ++# jz 1f ++# movb -1(%rdi,%r8,1),%cl # copy trailing byte ++# movb %cl,-1(%rsi,%r8,1) ++# subq $1,%r8 # adjust for possible trailing word ++#1: testq $2,%r8 # check for trailing word ++# jz 2f ++# movw -2(%rdi,%r8,1),%cx # copy trailing word ++# movw %cx,-2(%rsi,%r8,1) ++#2: testq $4,%r8 # check for trailing dword ++# jz 5f ++# movl (%rdi,%rdx,8),%ecx # copy trailing dword ++# movl %ecx,(%rsi,%rdx,8) ++# jmp 5f ++# .p2align 4,,15 ++#3: movq -8(%rdi,%rdx,8),%rcx ++# movq %rcx,-8(%rsi,%rdx,8) ++# subq $1,%rdx ++# jnz 3b ++# ret ++# .p2align 4,,15 ++#4: movq 24(%rdi,%rdx,8),%rcx ++# movq %rcx,24(%rsi,%rdx,8) ++# movq 16(%rdi,%rdx,8),%rcx ++# movq %rcx,16(%rsi,%rdx,8) ++# movq 8(%rdi,%rdx,8),%rcx ++# movq %rcx,8(%rsi,%rdx,8) ++# movq (%rdi,%rdx,8),%rcx ++# movq %rcx,(%rsi,%rdx,8) ++#5: subq $4,%rdx ++# jge 4b ++# addq $4,%rdx ++# jg 3b ++# ret ++ ++# # Support for void Copy::arrayof_conjoint_jshorts(void* from, ++# # void* to, ++# # size_t count) ++# # Equivalent to ++# # conjoint_jshorts_atomic ++# # ++# # If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we ++# # let the hardware handle it. The tow or four words within dwords ++# # or qwords that span cache line boundaries will still be loaded ++# # and stored atomically. ++# # ++# # rdi - from ++# # rsi - to ++# # rdx - count, treated as ssize_t ++# # ++# .p2align 4,,15 ++ .type _Copy_arrayof_conjoint_jshorts,@function ++ .type _Copy_conjoint_jshorts_atomic,@function ++_Copy_arrayof_conjoint_jshorts: ++_Copy_conjoint_jshorts_atomic: ++# movq %rdx,%r8 # word count ++# shrq $2,%rdx # qword count ++# cmpq %rdi,%rsi ++# leaq -2(%rdi,%r8,2),%rax # from + wcount*2 - 2 ++# jbe acs_CopyRight ++# cmpq %rax,%rsi ++# jbe acs_CopyLeft ++acs_CopyRight: ++# leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 ++# leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 ++# negq %rdx ++# jmp 6f ++#1: movq 8(%rax,%rdx,8),%rsi ++# movq %rsi,8(%rcx,%rdx,8) ++# addq $1,%rdx ++# jnz 1b ++#2: testq $2,%r8 # check for trailing dword ++# jz 3f ++# movl 8(%rax),%esi # copy trailing dword ++# movl %esi,8(%rcx) ++# addq $4,%rcx # original %rsi is trashed, so we ++# # can't use it as a base register ++#3: testq $1,%r8 # check for trailing word ++# jz 4f ++# movw -2(%rdi,%r8,2),%si # copy trailing word ++# movw %si,8(%rcx) ++#4: ret ++# .p2align 4,,15 ++#5: movq -24(%rax,%rdx,8),%rsi ++# movq %rsi,-24(%rcx,%rdx,8) ++# movq -16(%rax,%rdx,8),%rsi ++# movq %rsi,-16(%rcx,%rdx,8) ++# movq -8(%rax,%rdx,8),%rsi ++# movq %rsi,-8(%rcx,%rdx,8) ++# movq (%rax,%rdx,8),%rsi ++# movq %rsi,(%rcx,%rdx,8) ++#6: addq $4,%rdx ++# jle 5b ++# subq $4,%rdx ++# jl 1b ++# jmp 2b ++acs_CopyLeft: ++# testq $1,%r8 # check for trailing word ++# jz 1f ++# movw -2(%rdi,%r8,2),%cx # copy trailing word ++# movw %cx,-2(%rsi,%r8,2) ++#1: testq $2,%r8 # check for trailing dword ++# jz 4f ++# movl (%rdi,%rdx,8),%ecx # copy trailing dword ++# movl %ecx,(%rsi,%rdx,8) ++# jmp 4f ++#2: movq -8(%rdi,%rdx,8),%rcx ++# movq %rcx,-8(%rsi,%rdx,8) ++# subq $1,%rdx ++# jnz 2b ++# ret ++# .p2align 4,,15 ++#3: movq 24(%rdi,%rdx,8),%rcx ++# movq %rcx,24(%rsi,%rdx,8) ++# movq 16(%rdi,%rdx,8),%rcx ++# movq %rcx,16(%rsi,%rdx,8) ++# movq 8(%rdi,%rdx,8),%rcx ++# movq %rcx,8(%rsi,%rdx,8) ++# movq (%rdi,%rdx,8),%rcx ++# movq %rcx,(%rsi,%rdx,8) ++#4: subq $4,%rdx ++# jge 3b ++# addq $4,%rdx ++# jg 2b ++# ret ++ ++# # Support for void Copy::arrayof_conjoint_jints(jint* from, ++# # jint* to, ++# # size_t count) ++# # Equivalent to ++# # conjoint_jints_atomic ++# # ++# # If 'from' and/or 'to' are aligned on 4-byte boundaries, we let ++# # the hardware handle it. The two dwords within qwords that span ++# # cache line boundaries will still be loaded and stored atomically. ++# # ++# # rdi - from ++# # rsi - to ++# # rdx - count, treated as ssize_t ++# # ++# .p2align 4,,15 ++ .type _Copy_arrayof_conjoint_jints,@function ++ .type _Copy_conjoint_jints_atomic,@function ++_Copy_arrayof_conjoint_jints: ++_Copy_conjoint_jints_atomic: ++# movq %rdx,%r8 # dword count ++# shrq %rdx # qword count ++# cmpq %rdi,%rsi ++# leaq -4(%rdi,%r8,4),%rax # from + dcount*4 - 4 ++# jbe aci_CopyRight ++# cmpq %rax,%rsi ++# jbe aci_CopyLeft ++aci_CopyRight: ++# leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 ++# leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 ++# negq %rdx ++# jmp 5f ++# .p2align 4,,15 ++#1: movq 8(%rax,%rdx,8),%rsi ++# movq %rsi,8(%rcx,%rdx,8) ++# addq $1,%rdx ++# jnz 1b ++#2: testq $1,%r8 # check for trailing dword ++# jz 3f ++# movl 8(%rax),%esi # copy trailing dword ++# movl %esi,8(%rcx) ++#3: ret ++# .p2align 4,,15 ++#4: movq -24(%rax,%rdx,8),%rsi ++# movq %rsi,-24(%rcx,%rdx,8) ++# movq -16(%rax,%rdx,8),%rsi ++# movq %rsi,-16(%rcx,%rdx,8) ++# movq -8(%rax,%rdx,8),%rsi ++# movq %rsi,-8(%rcx,%rdx,8) ++# movq (%rax,%rdx,8),%rsi ++# movq %rsi,(%rcx,%rdx,8) ++#5: addq $4,%rdx ++# jle 4b ++# subq $4,%rdx ++# jl 1b ++# jmp 2b ++aci_CopyLeft: ++# testq $1,%r8 # check for trailing dword ++# jz 3f ++# movl -4(%rdi,%r8,4),%ecx # copy trailing dword ++# movl %ecx,-4(%rsi,%r8,4) ++# jmp 3f ++#1: movq -8(%rdi,%rdx,8),%rcx ++# movq %rcx,-8(%rsi,%rdx,8) ++# subq $1,%rdx ++# jnz 1b ++# ret ++# .p2align 4,,15 ++#2: movq 24(%rdi,%rdx,8),%rcx ++# movq %rcx,24(%rsi,%rdx,8) ++# movq 16(%rdi,%rdx,8),%rcx ++# movq %rcx,16(%rsi,%rdx,8) ++# movq 8(%rdi,%rdx,8),%rcx ++# movq %rcx,8(%rsi,%rdx,8) ++# movq (%rdi,%rdx,8),%rcx ++# movq %rcx,(%rsi,%rdx,8) ++#3: subq $4,%rdx ++# jge 2b ++# addq $4,%rdx ++# jg 1b ++# ret ++ ++# # Support for void Copy::arrayof_conjoint_jlongs(jlong* from, ++# # jlong* to, ++# # size_t count) ++# # Equivalent to ++# # conjoint_jlongs_atomic ++# # arrayof_conjoint_oops ++# # conjoint_oops_atomic ++# # ++# # rdi - from ++# # rsi - to ++# # rdx - count, treated as ssize_t ++# # ++# .p2align 4,,15 ++ .type _Copy_arrayof_conjoint_jlongs,@function ++ .type _Copy_conjoint_jlongs_atomic,@function ++_Copy_arrayof_conjoint_jlongs: ++_Copy_conjoint_jlongs_atomic: ++# cmpq %rdi,%rsi ++# leaq -8(%rdi,%rdx,8),%rax # from + count*8 - 8 ++# jbe acl_CopyRight ++# cmpq %rax,%rsi ++# jbe acl_CopyLeft ++acl_CopyRight: ++# leaq -8(%rsi,%rdx,8),%rcx # to + count*8 - 8 ++# negq %rdx ++# jmp 3f ++#1: movq 8(%rax,%rdx,8),%rsi ++# movq %rsi,8(%rcx,%rdx,8) ++# addq $1,%rdx ++# jnz 1b ++# ret ++# .p2align 4,,15 ++#2: movq -24(%rax,%rdx,8),%rsi ++# movq %rsi,-24(%rcx,%rdx,8) ++# movq -16(%rax,%rdx,8),%rsi ++# movq %rsi,-16(%rcx,%rdx,8) ++# movq -8(%rax,%rdx,8),%rsi ++# movq %rsi,-8(%rcx,%rdx,8) ++# movq (%rax,%rdx,8),%rsi ++# movq %rsi,(%rcx,%rdx,8) ++#3: addq $4,%rdx ++# jle 2b ++# subq $4,%rdx ++# jl 1b ++# ret ++#4: movq -8(%rdi,%rdx,8),%rcx ++# movq %rcx,-8(%rsi,%rdx,8) ++# subq $1,%rdx ++# jnz 4b ++# ret ++# .p2align 4,,15 ++#5: movq 24(%rdi,%rdx,8),%rcx ++# movq %rcx,24(%rsi,%rdx,8) ++# movq 16(%rdi,%rdx,8),%rcx ++# movq %rcx,16(%rsi,%rdx,8) ++# movq 8(%rdi,%rdx,8),%rcx ++# movq %rcx,8(%rsi,%rdx,8) ++# movq (%rdi,%rdx,8),%rcx ++# movq %rcx,(%rsi,%rdx,8) ++acl_CopyLeft: ++# subq $4,%rdx ++# jge 5b ++# addq $4,%rdx ++# jg 4b ++# ret +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/orderAccess_linux_sw64.hpp afu11u/src/hotspot/os_cpu/linux_sw64/orderAccess_linux_sw64.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/orderAccess_linux_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/orderAccess_linux_sw64.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,147 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_ORDERACCESS_LINUX_SW64_HPP ++#define OS_CPU_LINUX_SW64_VM_ORDERACCESS_LINUX_SW64_HPP ++ ++// Included in orderAccess.hpp header file. ++ ++#include "vm_version_sw64.hpp" ++ ++// Implementation of class OrderAccess. ++#define inlasm_sync() __asm__ __volatile__ ("memb" : : : "memory"); ++ ++inline void OrderAccess::loadload() { acquire(); } ++inline void OrderAccess::storestore() { release(); } ++inline void OrderAccess::loadstore() { acquire(); } ++inline void OrderAccess::storeload() { fence(); } ++ ++inline void OrderAccess::acquire() { ++ inlasm_sync(); ++} ++ ++inline void OrderAccess::release() { ++ inlasm_sync(); ++} ++ ++inline void OrderAccess::fence() { ++ inlasm_sync(); ++} ++ ++/* ++template<> ++struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> ++{ ++ template ++ void operator()(T v, volatile T* p) const { ++ __asm__ volatile ( "xchgb (%2),%0" ++ : "=q" (v) ++ : "0" (v), "r" (p) ++ : "memory"); ++ } ++}; ++ ++template<> ++struct OrderAccess::PlatformOrderedStore<2, RELEASE_X_FENCE> ++{ ++ template ++ void operator()(T v, volatile T* p) const { ++ __asm__ volatile ( "xchgw (%2),%0" ++ : "=r" (v) ++ : "0" (v), "r" (p) ++ : "memory"); ++ } ++};*/ ++/* ++template<> ++struct OrderAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> ++{ ++ template ++ void operator()(T v, volatile T* p) const { ++ T __ret, __tmp; ++ T* __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldw %[__ret],0(%[__addr])\n\t" ++ " ldi %[__tmp],1\n\t" ++ " wr_f %[__tmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstw %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__tmp],1b\n\t" ++ " zapnot %[__ret],0xf,%[__ret]\n\t" ++ " \n\t" ++ : [__ret]"=&r" (__ret), [__addr]"=&r"(__addr), [__tmp]"=&r"(__tmp) ++ : [__dest] "m" (*(T volatile *)p), [__val] "Ir"(v) ++ : "memory" ); ++ } ++}; ++ ++template<> ++struct OrderAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> ++{ ++ template ++ void operator()(T v, volatile T* p) const { ++ T __ret, __tmp; ++ T __addr; ++ __asm__ __volatile__ ( ++ "1: ldi %[__addr],%[__dest]\n\t" ++ " lldl %[__ret],0(%[__addr])\n\t" ++ " ldi %[__tmp],1\n\t" ++ " wr_f %[__tmp]\n\t" ++ " mov %[__val],%[__tmp]\n\t" ++ " .align 3\n\t" ++ " lstl %[__tmp],0(%[__addr])\n\t" ++ " rd_f %[__tmp]\n\t" ++ " beq %[__tmp],1b\n\t" ++ " \n\t" ++ : [__ret]"=&r" (__ret), [__addr]"=&r"(__addr), [__tmp]"=&r"(__tmp) ++ : [__dest] "m" (*(T volatile *)p), [__val] "Ir"(v) ++ : "memory" ); ++ } ++}; ++*/ ++template ++struct OrderAccess::PlatformOrderedLoad ++{ ++ template ++ T operator()(const volatile T* p) const { T data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } ++}; ++ ++template ++struct OrderAccess::PlatformOrderedStore ++{ ++ template ++ void operator()(T v, volatile T* p) const { __atomic_store(p, &v, __ATOMIC_RELEASE); } ++}; ++ ++template ++struct OrderAccess::PlatformOrderedStore ++{ ++ template ++ void operator()(T v, volatile T* p) const { release_store(p, v); fence(); } ++}; ++#endif // OS_CPU_LINUX_SW64_VM_ORDERACCESS_LINUX_SW64_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.cpp afu11u/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.cpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.cpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,803 @@ ++/* ++ * 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. ++ * ++ */ ++ ++// 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 "code/nativeInst.hpp" ++#include "interpreter/interpreter.hpp" ++#include "logging/log.hpp" ++#include "memory/allocation.inline.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/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" ++ ++// put OS-includes here ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++//not sure ++#define REG_SP 30 //// #define REG_SP 29 ++#define REG_FP 15 //// #define REG_FP 30 ++#define REG_RA 26 //// #define REG_FP 30 ++//#define PRINT_SIGNAL_HANDLE ++ ++address __attribute__((always_inline)) os::current_stack_pointer() { ++//ZHJ return (address)__builtin_frame_address(0); ++ register void *ssp; ++ __asm__ (" mov $sp,%0\n":"=r"(ssp)); ++ ++ return (address) (char *)ssp; ++} ++ ++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). ++ ++ return (char*) -1; ++} ++ ++address os::Linux::ucontext_get_pc(const ucontext_t * uc) { ++ //return (address)uc->uc_mcontext.gregs[REG_PC]; ++ return (address)uc->uc_mcontext.sc_pc; ++} ++ ++void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { ++//ZHJ uc->uc_mcontext.pc = (intptr_t)pc; ++ uc->uc_mcontext.sc_pc = (intptr_t)pc; ++} ++ ++intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) { ++//ZHJ return (intptr_t*)uc->uc_mcontext.sp; ++ return (intptr_t*)uc->uc_mcontext.sc_regs[REG_SP]; ++} ++ ++intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) { ++//ZHJ return (intptr_t*)uc->uc_mcontext.regs[REG_FP]; ++ return (intptr_t*)uc->uc_mcontext.sc_regs[REG_FP]; ++} ++ ++address os::ucontext_get_ra(const ucontext_t * uc) { ++ return (address)uc->uc_mcontext.sc_regs[REG_RA]; ++} ++ ++// 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(). ++// This method is also used for stack overflow signal handling. ++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) { ++ ++ ExtendedPC epc; ++ const ucontext_t* uc = (const ucontext_t*)ucVoid; ++ ++ 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 = os::Linux::ucontext_get_fp(uc); ++ } 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; ++ intptr_t* fp; ++ ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); ++ frame ret_frame(sp, fp, epc.pc()); ++ ret_frame.fixRa(ucVoid); ++ return ret_frame; ++} ++ ++frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { ++ intptr_t* sp; ++ intptr_t* fp; ++ ExtendedPC epc = os::Linux::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp); ++ frame ret_frame(sp, fp, epc.pc()); ++ ret_frame.fixRa(ucVoid); ++ return ret_frame; ++} ++ ++bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { ++ address pc = (address) os::Linux::ucontext_get_pc(uc); ++ if (Interpreter::contains(pc)) { ++ // interpreter performs stack banging after the fixed frame header has ++ // been generated while the compilers perform it before. To maintain ++ // semantic consistency between interpreted and compiled frames, the ++ // method returns the Java sender of the current frame. ++ *fr = os::fetch_frame_from_ucontext(thread, uc); ++ if (!fr->is_first_java_frame()) { ++ // get_frame_at_stack_banging_point() is only called when we ++ // have well defined stacks so java_sender() calls do not need ++ // to assert safe_for_sender() first. ++ *fr = fr->java_sender(); ++ } ++ } else { ++ // more complex code with compiled code ++ assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); ++ CodeBlob* cb = CodeCache::find_blob(pc); ++ if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { ++ // Not sure where the pc points to, fallback to default ++ // stack overflow handling ++ return false; ++ } else { ++ // in compiled code, the stack banging is performed just after the return pc ++ // has been pushed on the stack ++ intptr_t* fp = os::Linux::ucontext_get_fp(uc); ++ intptr_t* sp = os::Linux::ucontext_get_sp(uc); ++ address pc = (address)uc->uc_mcontext.sc_regs[REG_RA]; ++ *fr = frame(sp, fp, pc); ++ if (!fr->is_java_frame()) { ++ assert(!fr->is_first_frame(), "Safety check"); ++ // See java_sender() comment above. ++ *fr = fr->java_sender(); ++ } ++ } ++ } ++ assert(fr->is_java_frame(), "Safety check"); ++ return true; ++} ++ ++// By default, gcc always saves frame pointer rfp on this stack. This ++// may get turned off by -fomit-frame-pointer. ++frame os::get_sender_for_C_frame(frame* fr) { ++ return frame(NULL, fr->link(), fr->sender_pc()); ++} ++ ++intptr_t* __attribute__((always_inline)) os::get_previous_fp() { ++ register void *sfp; ++ __asm__ (" mov $fp,%0\n":"=r"(sfp)); ++ ++ return (intptr_t *)sfp; ++} ++ ++frame os::current_frame() { ++ intptr_t* fp = (intptr_t*)get_previous_fp(); ++ frame myframe((intptr_t*)os::current_stack_pointer(), ++ (intptr_t*)fp, ++ CAST_FROM_FN_PTR(address, os::current_frame)); ++ myframe.init_sender_for_c_frame(CAST_FROM_FN_PTR(address, os::current_frame)); ++ if (os::is_first_C_frame(&myframe)) { ++ // stack is not walkable ++ return frame(); ++ } else { ++ myframe = os::get_sender_for_C_frame(&myframe); ++ return os::get_sender_for_C_frame(&myframe); ++ } ++} ++ ++// Utility functions ++extern "C" int ++JVM_handle_linux_signal(int sig, ++ siginfo_t* info, ++ void* ucVoid, ++ int abort_if_unrecognized) { ++ if (TraceSignalHandling) { ++ tty->print_cr("Signal: signo=%d, sicode=%d, sierrno=%d, siaddr=%lx", ++ info->si_signo, ++ info->si_code, ++ info->si_errno, ++ (unsigned long)info->si_addr); ++ if (info->si_signo == 4) // the pc for SIGILL is (info->si_addr)-1) for SW, but mips and aarch64 are just info->si_addr ++ tty->print_cr("SIGILL 0x%08x", *((int*)(info->si_addr)-1)); ++ } ++ ++ ucontext_t* uc = (ucontext_t*) 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()) { ++ if (TraceSignalHandling) tty->print_cr("this thread is a java thread"); ++ thread = (JavaThread*)t; ++ } ++ else if(t->is_VM_thread()){ ++ if (TraceSignalHandling) tty->print_cr("this thread is a VM thread\n"); ++ vmthread = (VMThread *)t; ++ } ++ } ++ } ++ ++ // Handle SafeFetch faults: ++ if (uc != NULL) { ++ address const pc = (address) os::Linux::ucontext_get_pc(uc); ++ if (pc && StubRoutines::is_safefetch_fault(pc)) { ++ os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); ++ return 1; ++ } ++ } ++ ++/* ++ NOTE: does not seem to work on linux. ++ if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { ++ // can't decode this kind of signal ++ info = NULL; ++ } else { ++ assert(sig == info->si_signo, "bad siginfo"); ++ } ++*/ ++ // decide if this trap can be handled by a stub ++ address stub = NULL; ++ ++ address pc = NULL; ++ ++// pc = (address) os::Linux::ucontext_get_pc(uc); ++//if (TraceSignalHandling) { ++// tty->print_cr("pc=%lx", pc); ++// os::print_context(tty, uc); ++//} ++ //%note os_trap_1 ++ if (info != NULL && uc != NULL && thread != NULL) { ++ pc = (address) os::Linux::ucontext_get_pc(uc); ++ ++ // Halt if SI_KERNEL before more crashes get misdiagnosed as Java bugs ++ // This can happen in any running code (currently more frequently in ++ // interpreter code but has been seen in compiled code) ++ if (sig == SIGSEGV && info->si_addr == 0 && info->si_code == SI_KERNEL) { ++ fatal("An irrecoverable SI_KERNEL SIGSEGV has occurred due " ++ "to unstable signal handling in this distribution."); ++ } ++ ++ // Handle ALL stack overflow variations here ++ if (sig == SIGSEGV) { ++ address addr = (address) info->si_addr; ++ if (TraceSignalHandling) tty->print("handle all stack overflow variations: "); ++ /*tty->print("addr = %lx, stack base = %lx, stack top = %lx\n", ++ addr, ++ thread->stack_base(), ++ thread->stack_base() - thread->stack_size()); ++ */ ++ ++ // check if fault address is within thread stack ++ if (thread->on_local_stack(addr)) { ++ // stack overflow ++ if (TraceSignalHandling) tty->print("stack exception check \n"); ++ if (thread->in_stack_yellow_reserved_zone(addr)) { ++ if (TraceSignalHandling) tty->print("exception addr is in yellow zone\n"); ++ if (thread->thread_state() == _thread_in_Java) { ++ if (thread->in_stack_reserved_zone(addr)) { ++ frame fr; ++ if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { ++ assert(fr.is_java_frame(), "Must be a Java frame"); ++ frame activation = ++ SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); ++ if (activation.sp() != NULL) { ++ thread->disable_stack_reserved_zone(); ++ if (activation.is_interpreted_frame()) { ++ thread->set_reserved_stack_activation((address)( ++ activation.fp() + frame::interpreter_frame_initial_sp_offset)); ++ } else { ++ thread->set_reserved_stack_activation((address)activation.unextended_sp()); ++ } ++ return 1; ++ } ++ } ++ } ++ // Throw a stack overflow exception. Guard pages will be reenabled ++ // while unwinding the stack. ++ if (TraceSignalHandling) tty->print("this thread is in java\n"); ++ thread->disable_stack_yellow_reserved_zone(); ++ 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. ++ if (TraceSignalHandling) tty->print("this thread is in vm or native codes and return\n"); ++ thread->disable_stack_yellow_reserved_zone(); ++ return 1; ++ } ++ } 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. ++ if (TraceSignalHandling) tty->print("exception addr is in red zone\n"); ++ 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 (TraceSignalHandling) tty->print("exception addr is neither in yellow zone nor in the red one\n"); ++ 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 1; ++ } ++ thread->osthread()->clear_expanding_stack(); ++ } else { ++ fatal("recursive segv. expanding stack."); ++ } ++ } ++ } //addr < ++ } //sig == SIGSEGV ++ ++ if (thread->thread_state() == _thread_in_Java) { ++ // Java thread running in Java code => find exception handler if any ++ // a fault inside compiled code, the interpreter, or a stub ++ if (TraceSignalHandling) tty->print("java thread running in java code\n"); ++ if (sig == SIGILL && (nativeInstruction_at(pc)->is_sigill_zombie_not_entrant() || nativeInstruction_at(pc - 4)->is_sigill_zombie_not_entrant())) { ++#ifdef PRINT_SIGNAL_HANDLE ++ tty->print_cr("verified entry = %lx, sig=%d", nativeInstruction_at(pc), sig); ++#endif ++ stub = SharedRuntime::get_handle_wrong_method_stub(); ++ // Handle signal from NativeJump::patch_verified_entry(). ++ }else if (sig == SIGSEGV && os::is_poll_address((address)info->si_addr)) { ++ stub = SharedRuntime::get_poll_stub(pc); ++ if (TraceSignalHandling) tty->print_cr("polling address = %lx, sig=%d, stub = %lx", (unsigned long)os::get_polling_page(), sig, (unsigned long)stub); ++ } else if (sig == SIGBUS /* && info->si_code == BUS_OBJERR */) { ++ // 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 != NULL) ? cb->as_compiled_method_or_null() : NULL; ++ if (TraceSignalHandling) tty->print("cb = %lx, nm = %lx\n", (unsigned long)cb, (unsigned long)nm); ++ if (nm != NULL && nm->has_unsafe_access()) { ++ address next_pc = pc + NativeCall::instruction_size; ++ stub = SharedRuntime::handle_unsafe_access(thread, next_pc); ++ } ++ } else if (sig == SIGFPE && ++ (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) { ++ stub = SharedRuntime::continuation_for_implicit_exception(thread, ++ pc, ++ SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); ++ } else if (sig == SIGSEGV && ++ !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) { ++ if (TraceSignalHandling) tty->print("continuation for implicit exception\n"); ++ // Determination of interpreter/vtable stub/compiled code null exception ++ stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); ++ if (TraceSignalHandling) tty->print_cr("continuation_for_implicit_exception stub: %lx", (unsigned long)stub); ++ } ++ } else if (thread->thread_state() == _thread_in_vm && ++ sig == SIGBUS && /* info->si_code == BUS_OBJERR && */ ++ thread->doing_unsafe_access()) { ++ if (TraceSignalHandling) tty->print_cr("SIGBUS in vm thread \n"); ++ address next_pc = pc + NativeCall::instruction_size; ++ stub = SharedRuntime::handle_unsafe_access(thread, next_pc); ++ } ++ ++ // 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)) { ++ if (TraceSignalHandling) tty->print("jni fast get trap: "); ++ address addr = JNI_FastGetField::find_slowcase_pc(pc); ++ if (addr != (address)-1) { ++ stub = addr; ++ } ++ if (TraceSignalHandling) tty->print_cr("addr = %lx, stub = %lx", (unsigned long)addr, (unsigned long)stub); ++ } ++ ++ // Check to see if we caught the safepoint code in the ++ // process of write protecting the memory serialization page. ++ // It write enables the page immediately after protecting it ++ // so we can just return to retry the write. ++ if ((sig == SIGSEGV) && ++ os::is_memory_serialize_page(thread, (address) info->si_addr)) { ++ if (TraceSignalHandling) tty->print("write protecting the memory serialiazation page\n"); ++ // Block current thread until the memory serialize page permission restored. ++ os::block_on_serialize_page_trap(); ++ return true; ++ } ++ } ++ ++ // Execution protection violation ++ // ++ // This should be kept as the last step in the triage. We don't ++ // have a dedicated trap number for a no-execute fault, so be ++ // conservative and allow other handlers the first shot. ++ // ++ // Note: We don't test that info->si_code == SEGV_ACCERR here. ++ // this si_code is so generic that it is almost meaningless; and ++ // the si_code for this condition may change in the future. ++ // Furthermore, a false-positive should be harmless. ++ if (UnguardOnExecutionViolation > 0 && ++ (sig == SIGSEGV || sig == SIGBUS) /*&& ++ uc->uc_mcontext.sc_regs[REG_TRAPNO] == trap_page_fault*/) { ++ ShouldNotReachHere(); ++ int page_size = os::vm_page_size(); ++ address addr = (address) info->si_addr; ++ address pc = os::Linux::ucontext_get_pc(uc); ++ // Make sure the pc and the faulting address are sane. ++ // ++ // If an instruction spans a page boundary, and the page containing ++ // the beginning of the instruction is executable but the following ++ // page is not, the pc and the faulting address might be slightly ++ // different - we still want to unguard the 2nd page in this case. ++ // ++ // 15 bytes seems to be a (very) safe value for max instruction size. ++ bool pc_is_near_addr = ++ (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); ++ bool instr_spans_page_boundary = ++ (align_down((intptr_t) pc ^ (intptr_t) addr, ++ (intptr_t) page_size) > 0); ++ ++ if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { ++ static volatile address last_addr = ++ (address) os::non_memory_address_word(); ++ ++ // In conservative mode, don't unguard unless the address is in the VM ++ if (addr != last_addr && ++ (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { ++ ++ // Set memory to RWX and retry ++ address page_start = align_down(addr, page_size); ++ bool res = os::protect_memory((char*) page_start, page_size, ++ os::MEM_PROT_RWX); ++ ++ log_debug(os)("Execution protection violation " ++ "at " INTPTR_FORMAT ++ ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), ++ p2i(page_start), (res ? "success" : "failed"), errno); ++ stub = pc; ++ ++ // Set last_addr so if we fault again at the same address, we don't end ++ // up in an endless loop. ++ // ++ // There are two potential complications here. Two threads trapping at ++ // the same address at the same time could cause one of the threads to ++ // think it already unguarded, and abort the VM. Likely very rare. ++ // ++ // The other race involves two threads alternately trapping at ++ // different addresses and failing to unguard the page, resulting in ++ // an endless loop. This condition is probably even more unlikely than ++ // the first. ++ // ++ // Although both cases could be avoided by using locks or thread local ++ // last_addr, these solutions are unnecessary complication: this ++ // handler is a best-effort safety net, not a complete solution. It is ++ // disabled by default and should only be used as a workaround in case ++ // we missed any no-execute-unsafe VM code. ++ ++ last_addr = addr; ++ } ++ } ++ } ++ ++ ++ if (stub != NULL) { ++ if (TraceSignalHandling) tty->print_cr("resolved stub=%lx\n",(unsigned long)stub); ++ // save all thread context in case we need to restore it ++ if (thread != NULL) thread->set_saved_exception_pc(pc); ++ ++ os::Linux::ucontext_set_pc(uc, stub); ++ return true; ++ } ++ ++ // signal-chaining ++ if (os::Linux::chained_handler(sig, info, ucVoid)) { ++ if (TraceSignalHandling) tty->print_cr("signal chaining\n"); ++ return true; ++ } ++ ++ if (!abort_if_unrecognized) { ++ if (TraceSignalHandling) tty->print_cr("abort becauce of unrecognized\n"); ++ // caller wants another chance, so give it to him ++ return false; ++ } ++ ++ if (pc == NULL && uc != NULL) { ++ pc = os::Linux::ucontext_get_pc(uc); ++ } ++ ++ // unmask current signal ++ sigset_t newset; ++ sigemptyset(&newset); ++ sigaddset(&newset, sig); ++ sigprocmask(SIG_UNBLOCK, &newset, NULL); ++ if (TraceSignalHandling) tty->print_cr("VMError in signal handler\n"); ++ ++ VMError::report_and_die(t, sig, pc, info, ucVoid); ++ ++ ShouldNotReachHere(); ++ return true; // Mute compiler ++} ++ ++// FCSR:...|24| 23 |22|21|... ++// ...|FS|FCC0|FO|FN|... ++void os::Linux::init_thread_fpu_state(void) { ++ // Nothing to do ++} ++ ++int os::Linux::get_fpu_control_word(void) { ++ ShouldNotReachHere(); ++ return 0; ++} ++ ++void os::Linux::set_fpu_control_word(int fpu_control) { ++ ShouldNotReachHere(); ++} ++ ++bool os::is_allocatable(size_t bytes) { ++ ++ if (bytes < 2 * G) { ++ return true; ++ } ++ ++ char* addr = reserve_memory(bytes, NULL); ++ ++ if (addr != NULL) { ++ release_memory(addr, bytes); ++ } ++ ++ return addr != NULL; ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++// thread stack ++ ++size_t os::Posix::_compiler_thread_min_stack_allowed = 48 * K; ++size_t os::Posix::_java_thread_min_stack_allowed = 40 * K; ++size_t os::Posix::_vm_internal_thread_min_stack_allowed = 96 * 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 ? 2 * M : 512 * K); ++ return s; ++} ++ ++///////////////////////////////////////////////////////////////////////////// ++// helper functions for fatal error handler ++ ++void os::print_context(outputStream *st, const void *context) { ++ if (context == NULL) return; ++ ++ const ucontext_t *uc = (const ucontext_t*)context; ++ st->print_cr("Registers:"); ++ st->print( "V0=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[0]); ++ st->print(", T0=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[1]); ++ st->print(", T1=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[2]); ++ st->print(", T2=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[3]); ++ st->cr(); ++ st->print( "T3=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[4]); ++ st->print(", T4=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[5]); ++ st->print(", T5=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[6]); ++ st->print(", T6=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[7]); ++ st->cr(); ++ st->print( "T7=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[8]); ++ st->print(", S0=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[9]); ++ st->print(", S1=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[10]); ++ st->print(", S2=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[11]); ++ st->cr(); ++ st->print( "S3=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[12]); ++ st->print(", S4=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[13]); ++ st->print(", S5=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[14]); ++ st->print(", FP=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[15]); ++ st->cr(); ++ st->print( "A0=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[16]); ++ st->print(", A1=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[17]); ++ st->print(", A2=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[18]); ++ st->print(", A3=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[19]); ++ st->cr(); ++ st->print( "A4=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[20]); ++ st->print(", A5=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[21]); ++ st->print(", T8=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[22]); ++ st->print(", T9=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[23]); ++ st->cr(); ++ st->print( "T10=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[24]); ++ st->print(", T11=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[25]); ++ st->print(", RA=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[26]); ++ st->print(", T12=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[27]); ++ st->cr(); ++ st->print( "AT=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[28]); ++ st->print(", GP=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[29]); ++ st->print(", SP=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[30]); ++ st->print(", R0=" INTPTR_FORMAT, uc->uc_mcontext.sc_regs[31]); ++ st->cr(); ++ st->cr(); ++ ++ intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); ++ st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", p2i(sp)); ++ //print_hex_dump(st, (address)sp, (address)(sp + 8), sizeof(intptr_t)); ++ print_hex_dump(st, (address)sp-32, (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; ++ ++ st->print_cr("Register to memory mapping:"); ++ st->cr(); ++ ++ // this is horrendously verbose but the layout of the registers in the ++ // // context does not match how we defined our abstract Register set, so ++ // // we can't just iterate through the gregs area ++ // ++ // // this is only for the "general purpose" registers ++ st->print("V0=" ); print_location(st, uc->uc_mcontext.sc_regs[0]); ++ st->print("T0=" ); print_location(st, uc->uc_mcontext.sc_regs[1]); ++ st->print("T1=" ); print_location(st, uc->uc_mcontext.sc_regs[2]); ++ st->print("T2=" ); print_location(st, uc->uc_mcontext.sc_regs[3]); ++ st->cr(); ++ st->print("T3=" ); print_location(st, uc->uc_mcontext.sc_regs[4]); ++ st->print("T4=" ); print_location(st, uc->uc_mcontext.sc_regs[5]); ++ st->print("T5=" ); print_location(st, uc->uc_mcontext.sc_regs[6]); ++ st->print("T6=" ); print_location(st, uc->uc_mcontext.sc_regs[7]); ++ st->cr(); ++ st->print("T7=" ); print_location(st, uc->uc_mcontext.sc_regs[8]); ++ st->print("S0=" ); print_location(st, uc->uc_mcontext.sc_regs[9]); ++ st->print("S1=" ); print_location(st, uc->uc_mcontext.sc_regs[10]); ++ st->print("S2=" ); print_location(st, uc->uc_mcontext.sc_regs[11]); ++ st->cr(); ++ st->print("S3=" ); print_location(st, uc->uc_mcontext.sc_regs[12]); ++ st->print("S4=" ); print_location(st, uc->uc_mcontext.sc_regs[13]); ++ st->print("S5=" ); print_location(st, uc->uc_mcontext.sc_regs[14]); ++ st->print("FP=" ); print_location(st, uc->uc_mcontext.sc_regs[15]); ++ st->cr(); ++ st->print("A0=" ); print_location(st, uc->uc_mcontext.sc_regs[16]); ++ st->print("A1=" ); print_location(st, uc->uc_mcontext.sc_regs[17]); ++ st->print("A2=" ); print_location(st, uc->uc_mcontext.sc_regs[18]); ++ st->print("A3=" ); print_location(st, uc->uc_mcontext.sc_regs[19]); ++ st->cr(); ++ st->print("A4=" ); print_location(st, uc->uc_mcontext.sc_regs[20]); ++ st->print("A5=" ); print_location(st, uc->uc_mcontext.sc_regs[21]); ++ st->print("T8=" ); print_location(st, uc->uc_mcontext.sc_regs[22]); ++ st->print("T9=" ); print_location(st, uc->uc_mcontext.sc_regs[23]); ++ st->cr(); ++ st->print("T10=" ); print_location(st, uc->uc_mcontext.sc_regs[24]); ++ st->print("T11=" ); print_location(st, uc->uc_mcontext.sc_regs[25]); ++ st->print("RA=" ); print_location(st, uc->uc_mcontext.sc_regs[26]); ++ st->print("T12=" ); print_location(st, uc->uc_mcontext.sc_regs[27]); ++ st->cr(); ++ st->print("AT=" ); print_location(st, uc->uc_mcontext.sc_regs[28]); ++ st->print("GP=" ); print_location(st, uc->uc_mcontext.sc_regs[29]); ++ st->print("SP=" ); print_location(st, uc->uc_mcontext.sc_regs[30]); ++ st->print("R0=" ); print_location(st, uc->uc_mcontext.sc_regs[31]); ++ st->cr(); ++} ++ ++void os::setup_fpu() { ++ /* ++ //no use for MIPS ++ int fcsr; ++ address fpu_cntrl = StubRoutines::addr_fpu_cntrl_wrd_std(); ++ __asm__ __volatile__ ( ++ ".set noat;" ++ "cfc1 %0, $31;" ++ "sw %0, 0(%1);" ++ : "=r" (fcsr) ++ : "r" (fpu_cntrl) ++ : "memory" ++ ); ++ printf("fpu_cntrl: %lx\n", fpu_cntrl); ++ */ ++} ++ ++#ifndef PRODUCT ++void os::verify_stack_alignment() { ++ //warning("TODO:os::verify_stack_alignment, check jzy"); ++ //assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); ++} ++#endif ++ ++int os::extra_bang_size_in_bytes() { ++ // sw64 does not require the additional stack bang. ++ //warning("TODO:os::extra_bang_size_in_bytes, check lsp"); ++ return 0; ++} ++ ++extern "C" int SpinPause() {return 0;} +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.hpp afu11u/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_OS_LINUX_SW64_HPP ++#define OS_CPU_LINUX_SW64_VM_OS_LINUX_SW64_HPP ++ ++ static void setup_fpu(); ++//// static bool supports_sse(); ++//// ++//// static jlong rdtsc(); ++ ++ static bool is_allocatable(size_t bytes); ++ static intptr_t *get_previous_fp(); ++ static address ucontext_get_ra(const ucontext_t* uc); ++ ++ // 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; } ++ ++//// // Atomically copy 64 bits of data ++//// static void atomic_copy64(const volatile void *src, volatile void *dst) { ++//// *(jlong *) dst = *(const jlong *) src; ++//// } ++ ++#endif // OS_CPU_LINUX_SW64_VM_OS_LINUX_SW64_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.inline.hpp afu11u/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.inline.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/os_linux_sw64.inline.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_OS_LINUX_SW64_INLINE_HPP ++#define OS_CPU_LINUX_SW64_VM_OS_LINUX_SW64_INLINE_HPP ++ ++#include "runtime/os.hpp" ++ ++////// See http://www.technovelty.org/code/c/reading-rdtsc.htl for details ++////inline jlong os::rdtsc() { ++////#if 0 ++//// uint64_t res; ++//// uint32_t ts1, ts2; ++//// __asm__ __volatile__ ("rdtsc" : "=a" (ts1), "=d" (ts2)); ++//// res = ((uint64_t)ts1 | (uint64_t)ts2 << 32); ++//// return (jlong)res; ++////#else ++//// return (jlong)0; ++////#endif ++////} ++ ++#endif // OS_CPU_LINUX_SW64_VM_OS_LINUX_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/prefetch_linux_sw64.inline.hpp afu11u/src/hotspot/os_cpu/linux_sw64/prefetch_linux_sw64.inline.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/prefetch_linux_sw64.inline.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/prefetch_linux_sw64.inline.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_PREFETCH_LINUX_SW64_INLINE_HPP ++#define OS_CPU_LINUX_SW64_VM_PREFETCH_LINUX_SW64_INLINE_HPP ++ ++#include "runtime/prefetch.hpp" ++ ++ ++inline void Prefetch::read (void *loc, intx interval) { ++ if (interval >= 0) ++ __asm__ __volatile__ ( ++ " fillcs 0(%0) \n" ++ : ++ : "r" ( ((address)loc) +((long)interval) ) ++ : "memory" ++ ); ++} ++ ++inline void Prefetch::write(void *loc, intx interval) { ++ if (interval >= 0) ++ __asm__ __volatile__ ( ++ " fillde 0(%0) \n" ++ : ++ : "r" ( ((address)loc) +((long)interval) ) ++ : "memory" ++ ); ++} ++ ++#endif // OS_CPU_LINUX_SW64_VM_PREFETCH_LINUX_SW64_INLINE_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.cpp afu11u/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.cpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.cpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "memory/metaspaceShared.hpp" ++#include "runtime/frame.inline.hpp" ++#include "runtime/thread.inline.hpp" ++ ++void JavaThread::pd_initialize() ++{ ++ _anchor.clear(); ++ ++ // A non-existing address as error detector ++// if (CompileBroker::get_compilation_id() > 0) ++// _handle_wrong_method_stub = (address)SharedRuntime::get_handle_wrong_method_stub(); ++// else ++// _handle_wrong_method_stub = (address)0x2B2B2B; ++} ++ ++frame JavaThread::pd_last_frame() { ++ assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); ++ vmassert(_anchor.last_Java_pc() != NULL, "not walkable"); ++ return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); ++} ++ ++// 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"); ++ return pd_get_top_frame(fr_addr, ucontext, isInJava); ++} ++ ++bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { ++ return pd_get_top_frame(fr_addr, ucontext, isInJava); ++} ++ ++bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) { ++ assert(this->is_Java_thread(), "must be JavaThread"); ++ JavaThread* jt = (JavaThread *)this; ++ ++ // If we have a last_Java_frame, then we should use it even if ++ // isInJava == true. It should be more reliable than ucontext info. ++ if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { ++ *fr_addr = jt->pd_last_frame(); ++ return true; ++ } ++ ++ // At this point, we don't have a last_Java_frame, so ++ // we try to glean some information out of the ucontext ++ // if we were running Java code when SIGPROF came in. ++ if (isInJava) { ++ ucontext_t* uc = (ucontext_t*) ucontext; ++ ++ intptr_t* ret_fp; ++ intptr_t* ret_sp; ++ ExtendedPC addr = os::Linux::fetch_frame_from_ucontext(this, uc, ++ &ret_sp, &ret_fp); ++ 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; ++ } ++ ++ frame ret_frame(ret_sp, ret_fp, addr.pc()); ++ if (!ret_frame.safe_for_sender(jt)) { ++#if COMPILER2_OR_JVMCI ++ // C2 and JVMCI use ebp as a general register see if NULL fp helps ++ frame ret_frame2(ret_sp, NULL, addr.pc()); ++ if (!ret_frame2.safe_for_sender(jt)) { ++ // nothing else to try if the frame isn't good ++ return false; ++ } ++ ret_frame = ret_frame2; ++#else ++ // nothing else to try if the frame isn't good ++ return false; ++#endif // COMPILER2_OR_JVMCI ++ } ++ *fr_addr = ret_frame; ++ return true; ++ } ++ ++ // nothing else to try ++ return false; ++} ++ ++void JavaThread::cache_global_variables() { } ++ +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.hpp afu11u/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/thread_linux_sw64.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_THREAD_LINUX_SW64_HPP ++#define OS_CPU_LINUX_SW64_VM_THREAD_LINUX_SW64_HPP ++ ++ private: ++ void pd_initialize(); ++ ++ frame pd_last_frame(); ++ ++ public: ++ // Mutators are highly dangerous.... ++ intptr_t* last_Java_fp() { return _anchor.last_Java_fp(); } ++ void set_last_Java_fp(intptr_t* fp) { _anchor.set_last_Java_fp(fp); } ++ ++ void set_base_of_stack_pointer(intptr_t* base_sp) { ++ } ++ ++ static ByteSize last_Java_fp_offset() { ++ return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset(); ++ } ++ ++ intptr_t* base_of_stack_pointer() { ++ return NULL; ++ } ++ void record_base_of_stack_pointer() { ++ } ++ ++ 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); ++private: ++ bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava); ++public: ++ ++ // 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() {} ++ ++ // For convenient implementation of NativeGeneralJump::replace_mt_safe() ++ volatile address _handle_wrong_method_stub; ++ static ByteSize handle_wrong_method_stub_offset() { return byte_offset_of(JavaThread, _handle_wrong_method_stub); } ++// void set_handle_wrong_method_stub(address stub) { _handle_wrong_method_stub = stub; } ++ ++#endif // OS_CPU_LINUX_SW64_VM_THREAD_LINUX_SW64_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/vmStructs_linux_sw64.hpp afu11u/src/hotspot/os_cpu/linux_sw64/vmStructs_linux_sw64.hpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/vmStructs_linux_sw64.hpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/vmStructs_linux_sw64.hpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_CPU_LINUX_SW64_VM_VMSTRUCTS_LINUX_SW64_HPP ++#define OS_CPU_LINUX_SW64_VM_VMSTRUCTS_LINUX_SW64_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(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) ++ ++#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_SW64_VM_VMSTRUCTS_LINUX_SW64_HPP +diff -uNr openjdk/src/hotspot/os_cpu/linux_sw64/vm_version_linux_sw64.cpp afu11u/src/hotspot/os_cpu/linux_sw64/vm_version_linux_sw64.cpp +--- openjdk/src/hotspot/os_cpu/linux_sw64/vm_version_linux_sw64.cpp 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/hotspot/os_cpu/linux_sw64/vm_version_linux_sw64.cpp 2025-05-09 10:05:55.956290537 +0800 +@@ -0,0 +1,118 @@ ++/* ++ * 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 "precompiled.hpp" ++#include "runtime/os.hpp" ++#include "runtime/vm_version.hpp" ++ ++#define CPU_FAMILY_AMOUNT 9 ++ ++const char cpuinfo[CPU_FAMILY_AMOUNT][30] = { ++ "not-sw", // 0 ++ "sw410", // 1 ++ "sw4a", // 2 ++ "sw6a", // 3 ++ "sw6b", // 4 ++ "sw1621", // 5 ++ "sw421", // 6 ++ "sw3231", // 7 ++ "h8000", // 8 WX-H8000 for 8A ++}; ++ ++void read_cpu_info(const char *path, char *result) { ++ FILE *ptr; ++ char buf[1024]; ++ int i = 0; ++ if((ptr=fopen(path, "r")) != NULL) { ++ while(fgets(buf, 1024, ptr)!=NULL) { ++ strcat(result,buf); ++ i++; ++ if (i == 10) break; ++ } ++ fclose(ptr); ++ } else { ++ tty->print_cr("fopen %s error\n", path); ++ } ++} ++ ++void strlwr(char *str){ ++ for (; *str!='\0'; str++) ++ *str = tolower(*str); ++} ++ ++int VM_Version::platform_features(int features) { ++ char res[10240]; ++ int i; ++ features = spt_16k_page_m; //default support ++ memset(res, '\0', 10240 * sizeof(char)); ++ read_cpu_info("/proc/cpuinfo", res); ++ // res is converted to lower case ++ strlwr(res); ++ for (i = 1; i < CPU_FAMILY_AMOUNT; i++) { ++ if (strstr(res, cpuinfo[i])) { ++ break; ++ } ++ } ++ //add some other support when detected on shenwei ++ if (i != CPU_FAMILY_AMOUNT) { ++ features |= with_sw_support_m; ++ } ++ switch (i % CPU_FAMILY_AMOUNT) { ++ case 1 : ++ features |= sw2f_m; ++ //tty->print_cr("sw2f platform"); ++ break; ++ case 2 : ++ features |= sw4a_m; ++ //tty->print_cr("sw4a platform"); ++ break; ++ case 3 : ++ features |= sw6a_m; ++ //tty->print_cr("sw6a platform"); ++ break; ++ case 4 : ++ features |= sw6b_m; ++ //tty->print_cr("sw6b platform"); ++ break; ++ case 5 : ++ features |= sw1621_m; ++ //tty->print_cr("sw6b platform"); ++ break; ++ case 6 : ++ features |= sw4a_m; ++ //tty->print_cr("sw6b platform"); ++ break; ++ case 7 : ++ features |= sw3231_m; ++ break; ++ case 8 : ++ features |= wx_h8000_m; ++ break; ++ default: ++ ; ++ //tty->print_cr("cpu not support, the cpuinfo is: %s", res); ++ //ShouldNotReachHere(); ++ } ++ return features; ++} +diff -uNr openjdk/src/hotspot/share/asm/assembler.hpp afu11u/src/hotspot/share/asm/assembler.hpp +--- openjdk/src/hotspot/share/asm/assembler.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/asm/assembler.hpp 2025-05-09 10:05:55.972290537 +0800 +@@ -300,6 +300,9 @@ + static bool is_simm9(int64_t x) { return is_simm(x, 9); } + static bool is_simm10(int64_t x) { return is_simm(x, 10); } + static bool is_simm16(int64_t x) { return is_simm(x, 16); } ++#ifdef SW64 ++ static bool is_simm21(int64_t x) { return is_simm(x, 21); } ++#endif + static bool is_simm32(int64_t x) { return is_simm(x, 32); } + + // Test if x is within unsigned immediate range for width. +diff -uNr openjdk/src/hotspot/share/asm/codeBuffer.cpp afu11u/src/hotspot/share/asm/codeBuffer.cpp +--- openjdk/src/hotspot/share/asm/codeBuffer.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/asm/codeBuffer.cpp 2025-05-09 10:06:54.212292504 +0800 +@@ -1176,7 +1176,11 @@ + + const char* CodeStrings::add_string(const char * string) { + check_valid(); ++#ifdef SW64 ++ CodeString* s = new CodeString(string, 0); ++#else + CodeString* s = new CodeString(string); ++#endif + s->set_next(_strings); + _strings = s; + assert(s->string() != NULL, "should have a string"); +diff -uNr openjdk/src/hotspot/share/asm/register.hpp afu11u/src/hotspot/share/asm/register.hpp +--- openjdk/src/hotspot/share/asm/register.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/asm/register.hpp 2025-05-09 10:05:55.972290537 +0800 +@@ -103,7 +103,7 @@ + AbstractRegister a, + AbstractRegister b + ) { +- assert( ++ guarantee( + a != b, + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT "", p2i(a), p2i(b) + ); +@@ -115,7 +115,7 @@ + AbstractRegister b, + AbstractRegister c + ) { +- assert( ++ guarantee( + a != b && a != c + && b != c, + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT +@@ -131,7 +131,7 @@ + AbstractRegister c, + AbstractRegister d + ) { +- assert( ++ guarantee( + a != b && a != c && a != d + && b != c && b != d + && c != d, +@@ -149,7 +149,7 @@ + AbstractRegister d, + AbstractRegister e + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e + && b != c && b != d && b != e + && c != d && c != e +@@ -169,7 +169,7 @@ + AbstractRegister e, + AbstractRegister f + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f + && b != c && b != d && b != e && b != f + && c != d && c != e && c != f +@@ -192,7 +192,7 @@ + AbstractRegister f, + AbstractRegister g + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f && a != g + && b != c && b != d && b != e && b != f && b != g + && c != d && c != e && c != f && c != g +@@ -217,7 +217,7 @@ + AbstractRegister g, + AbstractRegister h + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f && a != g && a != h + && b != c && b != d && b != e && b != f && b != g && b != h + && c != d && c != e && c != f && c != g && c != h +@@ -244,7 +244,7 @@ + AbstractRegister h, + AbstractRegister i + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i + && b != c && b != d && b != e && b != f && b != g && b != h && b != i + && c != d && c != e && c != f && c != g && c != h && c != i +@@ -273,7 +273,7 @@ + AbstractRegister i, + AbstractRegister j + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j + && c != d && c != e && c != f && c != g && c != h && c != i && c != j +@@ -304,7 +304,7 @@ + AbstractRegister j, + AbstractRegister k + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k + && c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k +@@ -337,7 +337,7 @@ + AbstractRegister k, + AbstractRegister l + ) { +- assert( ++ guarantee( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k && a !=l + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k && b !=l + && c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k && c !=l +diff -uNr openjdk/src/hotspot/share/c1/c1_CodeStubs.hpp afu11u/src/hotspot/share/c1/c1_CodeStubs.hpp +--- openjdk/src/hotspot/share/c1/c1_CodeStubs.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/c1/c1_CodeStubs.hpp 2025-05-09 10:05:55.972290537 +0800 +@@ -422,7 +422,7 @@ + NativeMovRegMem* n_move = nativeMovRegMem_at(pc_start()); + n_move->set_offset(field_offset); + // Copy will never get executed, so only copy the part which is required for patching. +- _bytes_to_copy = MAX2(n_move->num_bytes_to_end_of_patch(), (int)NativeGeneralJump::instruction_size); ++//// _bytes_to_copy = MAX2(n_move->num_bytes_to_end_of_patch(), (int)NativeGeneralJump::instruction_size); //DJX need fix + } else if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) { + assert(_obj != noreg, "must have register object for load_klass/load_mirror"); + #ifdef ASSERT +diff -uNr openjdk/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp afu11u/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +--- openjdk/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp 2025-05-09 10:05:56.028290539 +0800 +@@ -76,8 +76,17 @@ + check_index(right, "right index out of range"); + assert(left <= right, "indexes out of order"); + size_t num_cards = right - left + 1; ++#ifndef SW64 //TODO check liangsp + memset_with_concurrent_readers + (const_cast (&_offset_array[left]), offset, num_cards); ++#else ++ size_t i = left; ++ const size_t end = i + num_cards; ++ for (; i < end; i++) { ++ _offset_array[i] = offset; ++ } ++#endif ++ + } + + // Variant of index_for that does not check the index for validity. +diff -uNr openjdk/src/hotspot/share/gc/g1/g1CardTable.cpp afu11u/src/hotspot/share/gc/g1/g1CardTable.cpp +--- openjdk/src/hotspot/share/gc/g1/g1CardTable.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/gc/g1/g1CardTable.cpp 2025-05-09 10:05:56.028290539 +0800 +@@ -56,7 +56,10 @@ + jbyte *const first = byte_for(mr.start()); + jbyte *const last = byte_after(mr.last()); + +- memset_with_concurrent_readers(first, g1_young_gen, last - first); ++// memset_with_concurrent_readers(first, g1_young_gen, last - first); ++ for (jbyte* i = first; i < last; i++) { ++ *i = g1_young_gen; ++ } + } + + #ifndef PRODUCT +diff -uNr openjdk/src/hotspot/share/interpreter/abstractInterpreter.cpp afu11u/src/hotspot/share/interpreter/abstractInterpreter.cpp +--- openjdk/src/hotspot/share/interpreter/abstractInterpreter.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/abstractInterpreter.cpp 2025-05-09 10:05:56.100290542 +0800 +@@ -180,8 +180,8 @@ + case vmIntrinsics::_dlog10: return java_lang_math_log10; + case vmIntrinsics::_dpow : return java_lang_math_pow ; + case vmIntrinsics::_dexp : return java_lang_math_exp ; +- case vmIntrinsics::_fmaD : return java_lang_math_fmaD ; +- case vmIntrinsics::_fmaF : return java_lang_math_fmaF ; ++//// case vmIntrinsics::_fmaD : return java_lang_math_fmaD ; ++//// case vmIntrinsics::_fmaF : return java_lang_math_fmaF ; + + case vmIntrinsics::_Reference_get + : return java_lang_ref_reference_get; +@@ -276,8 +276,8 @@ + case java_lang_math_sqrt : tty->print("java_lang_math_sqrt" ); break; + case java_lang_math_log : tty->print("java_lang_math_log" ); break; + case java_lang_math_log10 : tty->print("java_lang_math_log10" ); break; +- case java_lang_math_fmaD : tty->print("java_lang_math_fmaD" ); break; +- case java_lang_math_fmaF : tty->print("java_lang_math_fmaF" ); break; ++//// case java_lang_math_fmaD : tty->print("java_lang_math_fmaD" ); break; ++//// case java_lang_math_fmaF : tty->print("java_lang_math_fmaF" ); break; + case java_util_zip_CRC32_update : tty->print("java_util_zip_CRC32_update"); break; + case java_util_zip_CRC32_updateBytes : tty->print("java_util_zip_CRC32_updateBytes"); break; + case java_util_zip_CRC32_updateByteBuffer : tty->print("java_util_zip_CRC32_updateByteBuffer"); break; +diff -uNr openjdk/src/hotspot/share/interpreter/abstractInterpreter.hpp afu11u/src/hotspot/share/interpreter/abstractInterpreter.hpp +--- openjdk/src/hotspot/share/interpreter/abstractInterpreter.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/abstractInterpreter.hpp 2025-05-09 10:05:56.100290542 +0800 +@@ -253,7 +253,7 @@ + return stackElementWords * i; + } + +-#if !defined(ZERO) && (defined(IA32) || defined(AMD64)) ++#if !defined(ZERO) && (defined(IA32) || defined(AMD64)) || defined(SW64) + static Address::ScaleFactor stackElementScale() { + return NOT_LP64(Address::times_4) LP64_ONLY(Address::times_8); + } +diff -uNr openjdk/src/hotspot/share/interpreter/bytecodeTracer.cpp afu11u/src/hotspot/share/interpreter/bytecodeTracer.cpp +--- openjdk/src/hotspot/share/interpreter/bytecodeTracer.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/bytecodeTracer.cpp 2025-05-09 10:05:56.104290542 +0800 +@@ -169,7 +169,7 @@ + + + void BytecodeTracer::trace(const methodHandle& method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) { +- if (TraceBytecodes && BytecodeCounter::counter_value() >= TraceBytecodesAt) { ++ if (TraceBytecodes && BytecodeCounter::counter_value() >= TraceBytecodesAt && !TraceBytecodesStubNoPrint) { + ttyLocker ttyl; // 5065316: keep the following output coherent + // The ttyLocker also prevents races between two threads + // trying to use the single instance of BytecodePrinter. +diff -uNr openjdk/src/hotspot/share/interpreter/interpreterRuntime.cpp afu11u/src/hotspot/share/interpreter/interpreterRuntime.cpp +--- openjdk/src/hotspot/share/interpreter/interpreterRuntime.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/interpreterRuntime.cpp 2025-05-09 10:05:56.104290542 +0800 +@@ -1506,7 +1506,7 @@ + // preparing the same method will be sure to see non-null entry & mirror. + IRT_END + +-#if defined(IA32) || defined(AMD64) || defined(ARM) ++#if defined(IA32) || defined(AMD64) || defined(ARM) || defined(SW64) + IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address)) + if (src_address == dest_address) { + return; +diff -uNr openjdk/src/hotspot/share/interpreter/interpreterRuntime.hpp afu11u/src/hotspot/share/interpreter/interpreterRuntime.hpp +--- openjdk/src/hotspot/share/interpreter/interpreterRuntime.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/interpreterRuntime.hpp 2025-05-09 10:05:56.104290542 +0800 +@@ -146,7 +146,7 @@ + Method* method, + intptr_t* from, intptr_t* to); + +-#if defined(IA32) || defined(AMD64) || defined(ARM) ++#if defined(IA32) || defined(AMD64) || defined(ARM) || defined(SW64) + // Popframe support (only needed on x86, AMD64 and ARM) + static void popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address); + #endif +diff -uNr openjdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp afu11u/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp +--- openjdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp 2025-05-09 10:05:56.104290542 +0800 +@@ -204,8 +204,8 @@ + method_entry(java_lang_math_log10) + method_entry(java_lang_math_exp ) + method_entry(java_lang_math_pow ) +- method_entry(java_lang_math_fmaF ) +- method_entry(java_lang_math_fmaD ) ++//// method_entry(java_lang_math_fmaF ) ++//// method_entry(java_lang_math_fmaD ) + method_entry(java_lang_ref_reference_get) + + AbstractInterpreter::initialize_method_handle_entries(); +diff -uNr openjdk/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp afu11u/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +--- openjdk/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp 2025-05-09 10:05:56.104290542 +0800 +@@ -118,6 +118,10 @@ + void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); + #endif // AARCH64 + ++#ifdef SW64 ++ void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); ++#endif // SW64 ++ + #ifdef PPC + void lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded=false); + void generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals); +diff -uNr openjdk/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp afu11u/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp +--- openjdk/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp 2025-05-09 10:05:56.120290542 +0800 +@@ -102,7 +102,7 @@ + inline bool JfrBigEndian::platform_supports_unaligned_reads(void) { + #if defined(IA32) || defined(AMD64) || defined(PPC) || defined(S390) + return true; +-#elif defined(SPARC) || defined(ARM) || defined(AARCH64) ++#elif defined(SPARC) || defined(ARM) || defined(AARCH64) || defined(SW64) + return false; + #else + #warning "Unconfigured platform" +diff -uNr openjdk/src/hotspot/share/oops/method.cpp afu11u/src/hotspot/share/oops/method.cpp +--- openjdk/src/hotspot/share/oops/method.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/oops/method.cpp 2025-05-09 10:06:54.232292505 +0800 +@@ -1504,9 +1504,11 @@ + // exception: the AES intrinsics come from lib/ext/sunjce_provider.jar + // which does not use the class default class loader so we check for its loader here + const InstanceKlass* ik = InstanceKlass::cast(holder); ++#ifndef SW64 + if ((ik->class_loader() != NULL) && !SystemDictionary::is_platform_class_loader(ik->class_loader())) { + return vmSymbols::NO_SID; // regardless of name, no intrinsics here + } ++#endif + + // see if the klass name is well-known: + Symbol* klass_name = ik->name(); +diff -uNr openjdk/src/hotspot/share/runtime/globals.hpp afu11u/src/hotspot/share/runtime/globals.hpp +--- openjdk/src/hotspot/share/runtime/globals.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/globals.hpp 2025-05-09 10:05:56.208290545 +0800 +@@ -1017,7 +1017,8 @@ + \ + develop(bool, TraceBytecodes, false, \ + "Trace bytecode execution") \ +- \ ++ develop(bool, TraceBytecodesStubNoPrint, false, \ ++ "Trace bytecode stub, just for debug") \ + develop(bool, TraceICs, false, \ + "Trace inline cache changes") \ + \ +diff -uNr openjdk/src/hotspot/share/runtime/safepointMechanism.cpp afu11u/src/hotspot/share/runtime/safepointMechanism.cpp +--- openjdk/src/hotspot/share/runtime/safepointMechanism.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/safepointMechanism.cpp 2025-05-09 10:05:56.224290546 +0800 +@@ -29,7 +29,7 @@ + #include "runtime/safepointMechanism.inline.hpp" + #include "services/memTracker.hpp" + #include "utilities/globalDefinitions.hpp" +- ++#include + SafepointMechanism::PollingType SafepointMechanism::_polling_type = SafepointMechanism::_global_page_poll; + void* SafepointMechanism::_poll_armed_value; + void* SafepointMechanism::_poll_disarmed_value; +@@ -73,11 +73,16 @@ + _poll_disarmed_value = reinterpret_cast(poll_disarmed_value); + } else { + const size_t page_size = os::vm_page_size(); ++#ifdef OPT_SAFEPOINT ++ void * p = (void *)(0x10000); ++ address polling_page = (address) ::mmap(p, page_size, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++#else + char* polling_page = os::reserve_memory(page_size, NULL, page_size); + os::commit_memory_or_exit(polling_page, page_size, false, "Unable to commit Safepoint polling page"); + os::protect_memory(polling_page, page_size, os::MEM_PROT_READ); ++#endif + MemTracker::record_virtual_memory_type((address)polling_page, mtSafepoint); +- ++ guarantee( polling_page != MAP_FAILED, "os::init_2: failed to allocate polling page" ); + log_info(os)("SafePoint Polling address: " INTPTR_FORMAT, p2i(polling_page)); + os::set_polling_page((address)(polling_page)); + } +diff -uNr openjdk/src/hotspot/share/runtime/sharedRuntime.cpp afu11u/src/hotspot/share/runtime/sharedRuntime.cpp +--- openjdk/src/hotspot/share/runtime/sharedRuntime.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/sharedRuntime.cpp 2025-05-09 10:05:56.224290546 +0800 +@@ -211,6 +211,26 @@ + JRT_END + + ++#ifdef SW64 //ZHJ ++JRT_LEAF(jint, SharedRuntime::sdiv(jint y, jint x)) ++ if (x == min_jint && y == CONST64(-1)) { ++ return x; ++ } else { ++ return x / y; ++ } ++JRT_END ++ ++ ++JRT_LEAF(jint, SharedRuntime::srem(jint y, jint x)) ++ if (x == min_jint && y == CONST64(-1)) { ++ return 0; ++ } else { ++ return x % y; ++ } ++JRT_END ++#endif ++ ++ + JRT_LEAF(jlong, SharedRuntime::ldiv(jlong y, jlong x)) + if (x == min_jlong && y == CONST64(-1)) { + return x; +@@ -2550,7 +2570,7 @@ + // Implementation of AdapterHandlerLibrary + AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL; + AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL; +-const int AdapterHandlerLibrary_size = 16*K; ++const int AdapterHandlerLibrary_size = NOT_SW64(16*K)SW64_ONLY(46*K); + BufferBlob* AdapterHandlerLibrary::_buffer = NULL; + + BufferBlob* AdapterHandlerLibrary::buffer_blob() { +diff -uNr openjdk/src/hotspot/share/runtime/sharedRuntime.hpp afu11u/src/hotspot/share/runtime/sharedRuntime.hpp +--- openjdk/src/hotspot/share/runtime/sharedRuntime.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/sharedRuntime.hpp 2025-05-09 10:05:56.224290546 +0800 +@@ -92,6 +92,12 @@ + // not have machine instructions to implement their functionality. + // Do not remove these. + ++#ifdef SW64 ++ static jint sdiv(jint y, jint x); ++ static jint srem(jint y, jint x); ++ static unsigned int updateBytesCRC32(unsigned long crc, const unsigned char *buf_bytes, unsigned int len_ints); ++#endif ++ + // long arithmetics + static jlong lmul(jlong y, jlong x); + static jlong ldiv(jlong y, jlong x); +diff -uNr openjdk/src/hotspot/share/runtime/sharedRuntimeTrig.cpp afu11u/src/hotspot/share/runtime/sharedRuntimeTrig.cpp +--- openjdk/src/hotspot/share/runtime/sharedRuntimeTrig.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/sharedRuntimeTrig.cpp 2025-05-09 10:05:56.224290546 +0800 +@@ -496,29 +496,29 @@ + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 +- * sin(x) ~ x + S1*x + ... + S6*x ++ * sin(x) ~ x + SS1*x + ... + SS6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 +- * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 ++ * |----- - (1+SS1*x +SS2*x +SS3*x +SS4*x +SS5*x +SS6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 +- * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) ++ * r = x *(SS2+x *(SS3+x *(SS4+x *(SS5+x *SS6)))) + * then 3 2 +- * sin(x) = x + (S1*x + (x *(r-y/2)+y)) ++ * sin(x) = x + (SS1*x + (x *(r-y/2)+y)) + */ + + static const double +-S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +-S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +-S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +-S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +-S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +-S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ ++SS1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ ++SS2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ ++SS3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ ++SS4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ ++SS5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ ++SS6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + + static double __kernel_sin(double x, double y, int iy) + { +@@ -529,9 +529,9 @@ + {if((int)x==0) return x;} /* generate inexact */ + z = x*x; + v = z*x; +- r = S2+z*(S3+z*(S4+z*(S5+z*S6))); +- if(iy==0) return x+v*(S1+z*r); +- else return x-((z*(half*y-v*r)-y)-v*S1); ++ r = SS2+z*(SS3+z*(SS4+z*(SS5+z*SS6))); ++ if(iy==0) return x+v*(SS1+z*r); ++ else return x-((z*(half*y-v*r)-y)-v*SS1); + } + + /* +diff -uNr openjdk/src/hotspot/share/runtime/stubRoutines.cpp afu11u/src/hotspot/share/runtime/stubRoutines.cpp +--- openjdk/src/hotspot/share/runtime/stubRoutines.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/stubRoutines.cpp 2025-05-09 10:05:56.224290546 +0800 +@@ -287,7 +287,7 @@ + assert(code_size2 == 0 || buffer.insts_remaining() > 200, "increase code_size2"); + } + +-#ifdef ASSERT ++#ifdef ASSERT_TODO_need_check_jzy + + MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXExec)); + +@@ -339,9 +339,9 @@ + } \ + } \ + +- TEST_FILL(jbyte); +- TEST_FILL(jshort); +- TEST_FILL(jint); ++// TEST_FILL(jbyte); ++// TEST_FILL(jshort); ++// TEST_FILL(jint); + + #undef TEST_FILL + +diff -uNr openjdk/src/hotspot/share/runtime/thread.cpp afu11u/src/hotspot/share/runtime/thread.cpp +--- openjdk/src/hotspot/share/runtime/thread.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/runtime/thread.cpp 2025-05-09 10:06:54.256292506 +0800 +@@ -3832,6 +3832,7 @@ + return status; + } + ++ + JFR_ONLY(Jfr::on_create_vm_1();) + + // Should be done after the heap is fully created +diff -uNr openjdk/src/hotspot/share/utilities/macros.hpp afu11u/src/hotspot/share/utilities/macros.hpp +--- openjdk/src/hotspot/share/utilities/macros.hpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/utilities/macros.hpp 2025-05-09 10:05:56.244290547 +0800 +@@ -595,8 +595,17 @@ + #define NOT_AARCH64(code) code + #endif + ++#ifdef SW64 ++#define SW64_ONLY(code) code ++#define NOT_SW64(code) ++#else ++#define SW64_ONLY(code) ++#define NOT_SW64(code) code ++#endif ++ + #define MACOS_AARCH64_ONLY(x) MACOS_ONLY(AARCH64_ONLY(x)) + ++ + #ifdef VM_LITTLE_ENDIAN + #define LITTLE_ENDIAN_ONLY(code) code + #define BIG_ENDIAN_ONLY(code) +diff -uNr openjdk/src/hotspot/share/utilities/nativeCallStack.cpp afu11u/src/hotspot/share/utilities/nativeCallStack.cpp +--- openjdk/src/hotspot/share/utilities/nativeCallStack.cpp 2022-10-12 23:00:01.000000000 +0800 ++++ afu11u/src/hotspot/share/utilities/nativeCallStack.cpp 2025-05-09 10:05:56.244290547 +0800 +@@ -38,7 +38,7 @@ + // to call os::get_native_stack. A tail call is used if _NMT_NOINLINE_ is not defined + // (which means this is not a slowdebug build), and we are on 64-bit (except Windows). + // This is not necessarily a rule, but what has been obvserved to date. +-#if (defined(_NMT_NOINLINE_) || defined(_WINDOWS) || !defined(_LP64) || (defined(BSD) && defined (__aarch64__))) ++#if (defined(_NMT_NOINLINE_) || defined(_WINDOWS) || !defined(_LP64) || (defined(BSD) && defined (__aarch64__)) || defined(SW64)) + // Not a tail call. + toSkip++; + #if (defined(_NMT_NOINLINE_) && defined(BSD) && defined(_LP64)) +diff -uNr openjdk/src/java.base/share/classes/sun/security/rsa/RSACore.java afu11u/src/java.base/share/classes/sun/security/rsa/RSACore.java +--- openjdk/src/java.base/share/classes/sun/security/rsa/RSACore.java 2022-10-12 23:00:02.000000000 +0800 ++++ afu11u/src/java.base/share/classes/sun/security/rsa/RSACore.java 2025-05-09 10:05:56.516290556 +0800 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -25,20 +25,25 @@ + + package sun.security.rsa; + +-import java.math.BigInteger; +-import java.util.*; +- +-import java.security.SecureRandom; +-import java.security.interfaces.*; ++import sun.security.jca.JCAUtil; + + import javax.crypto.BadPaddingException; +- +-import sun.security.jca.JCAUtil; ++import java.math.BigInteger; ++import java.security.SecureRandom; ++import java.security.interfaces.RSAKey; ++import java.security.interfaces.RSAPrivateCrtKey; ++import java.security.interfaces.RSAPrivateKey; ++import java.security.interfaces.RSAPublicKey; ++import java.util.Arrays; ++import java.util.Map; ++import java.util.WeakHashMap; ++import java.util.concurrent.ConcurrentLinkedQueue; ++import java.util.concurrent.locks.ReentrantLock; + + /** + * Core of the RSA implementation. Has code to perform public and private key + * RSA operations (with and without CRT for private key ops). Private CRT ops +- * also support blinding to twart timing attacks. ++ * also support blinding to thwart timing attacks. + * + * The code in this class only does the core RSA operation. Padding and + * unpadding must be done externally. +@@ -53,11 +58,14 @@ + // globally enable/disable use of blinding + private static final boolean ENABLE_BLINDING = true; + +- // cache for blinding parameters. Map +- // use a weak hashmap so that cached values are automatically cleared +- // when the modulus is GC'ed +- private static final Map ++ // cache for blinding parameters. Map> use a weak hashmap so that, ++ // cached values are automatically cleared when the modulus is GC'ed. ++ // Multiple BlindingParameters can be queued during times of heavy load, ++ // like performance testing. ++ private static final Map> + blindingCache = new WeakHashMap<>(); ++ private static final ReentrantLock lock = new ReentrantLock(); + + private RSACore() { + // empty +@@ -402,56 +410,68 @@ + if ((this.e != null && this.e.equals(e)) || + (this.d != null && this.d.equals(d))) { + +- BlindingRandomPair brp = null; +- synchronized (this) { +- if (!u.equals(BigInteger.ZERO) && +- !v.equals(BigInteger.ZERO)) { +- +- brp = new BlindingRandomPair(u, v); +- if (u.compareTo(BigInteger.ONE) <= 0 || +- v.compareTo(BigInteger.ONE) <= 0) { +- +- // need to reset the random pair next time +- u = BigInteger.ZERO; +- v = BigInteger.ZERO; +- } else { +- u = u.modPow(BIG_TWO, n); +- v = v.modPow(BIG_TWO, n); +- } +- } // Otherwise, need to reset the random pair. ++ BlindingRandomPair brp = new BlindingRandomPair(u, v); ++ if (u.compareTo(BigInteger.ONE) <= 0 || ++ v.compareTo(BigInteger.ONE) <= 0) { ++ // Reset so the parameters will be not queued later ++ u = BigInteger.ZERO; ++ v = BigInteger.ZERO; ++ } else { ++ u = u.modPow(BIG_TWO, n); ++ v = v.modPow(BIG_TWO, n); + } ++ + return brp; + } + + return null; + } ++ ++ // Check if reusable, return true if both u & v are not zero. ++ boolean isReusable() { ++ return !u.equals(BigInteger.ZERO) && !v.equals(BigInteger.ZERO); ++ } + } + + private static BlindingRandomPair getBlindingRandomPair( + BigInteger e, BigInteger d, BigInteger n) { + +- BlindingParameters bps = null; +- synchronized (blindingCache) { +- bps = blindingCache.get(n); ++ ConcurrentLinkedQueue queue; ++ ++ // Get queue from map, if there is none then create one ++ lock.lock(); ++ try { ++ queue = blindingCache.computeIfAbsent(n, ++ ignored -> new ConcurrentLinkedQueue<>()); ++ } finally { ++ lock.unlock(); + } + ++ BlindingParameters bps = queue.poll(); + if (bps == null) { + bps = new BlindingParameters(e, d, n); +- synchronized (blindingCache) { +- blindingCache.putIfAbsent(n, bps); +- } + } + +- BlindingRandomPair brp = bps.getBlindingRandomPair(e, d, n); +- if (brp == null) { +- // need to reset the blinding parameters +- bps = new BlindingParameters(e, d, n); +- synchronized (blindingCache) { +- blindingCache.replace(n, bps); +- } ++ BlindingRandomPair brp = null; ++ ++ // Loops to get a valid pair, going through the queue or create a new ++ // parameters if needed. ++ while (brp == null) { + brp = bps.getBlindingRandomPair(e, d, n); ++ if (brp == null) { ++ // need to reset the blinding parameters, first check for ++ // another in the queue. ++ bps = queue.poll(); ++ if (bps == null) { ++ bps = new BlindingParameters(e, d, n); ++ } ++ } + } + ++ // If this parameters are still usable, put them back into the queue. ++ if (bps.isReusable()) { ++ queue.add(bps); ++ } + return brp; + } + +diff -uNr openjdk/src/java.base/share/classes/sun/security/ssl/NamedGroup.java afu11u/src/java.base/share/classes/sun/security/ssl/NamedGroup.java +--- openjdk/src/java.base/share/classes/sun/security/ssl/NamedGroup.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/java.base/share/classes/sun/security/ssl/NamedGroup.java 2025-05-09 10:05:56.524290556 +0800 +@@ -49,7 +49,114 @@ + // Elliptic Curves (RFC 4492) + // + // See sun.security.util.CurveDB for the OIDs ++ // NIST K-163 ++ ++ SECT163_K1(0x0001, "sect163k1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect163k1")), ++ SECT163_R1(0x0002, "sect163r1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect163r1")), ++ ++ // NIST B-163 ++ SECT163_R2(0x0003, "sect163r2", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect163r2")), ++ SECT193_R1(0x0004, "sect193r1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect193r1")), ++ SECT193_R2(0x0005, "sect193r2", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect193r2")), ++ ++ // NIST K-233 ++ SECT233_K1(0x0006, "sect233k1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect233k1")), ++ ++ // NIST B-233 ++ SECT233_R1(0x0007, "sect233r1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect233r1")), ++ SECT239_K1(0x0008, "sect239k1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect239k1")), ++ ++ // NIST K-283 ++ SECT283_K1(0x0009, "sect283k1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect283k1")), ++ ++ // NIST B-283 ++ SECT283_R1(0x000A, "sect283r1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect283r1")), ++ ++ // NIST K-409 ++ SECT409_K1(0x000B, "sect409k1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect409k1")), ++ ++ // NIST B-409 ++ SECT409_R1(0x000C, "sect409r1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect409r1")), ++ ++ // NIST K-571 ++ SECT571_K1(0x000D, "sect571k1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect571k1")), ++ ++ // NIST B-571 ++ SECT571_R1(0x000E, "sect571r1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("sect571r1")), ++ SECP160_K1(0x000F, "secp160k1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp160k1")), ++ SECP160_R1(0x0010, "secp160r1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp160r1")), ++ SECP160_R2(0x0011, "secp160r2", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp160r2")), ++ SECP192_K1(0x0012, "secp192k1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp192k1")), ++ ++ // NIST P-192 ++ SECP192_R1(0x0013, "secp192r1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp192r1")), ++ SECP224_K1(0x0014, "secp224k1", false, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp224k1")), ++ + // NIST P-224 ++ SECP224_R1(0x0015, "secp224r1", true, ++ NamedGroupSpec.NAMED_GROUP_ECDHE, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ CurveDB.lookup("secp224r1")), + SECP256_K1(0x0016, "secp256k1", false, + NamedGroupSpec.NAMED_GROUP_ECDHE, + ProtocolVersion.PROTOCOLS_TO_12, +@@ -104,7 +211,19 @@ + FFDHE_8192(0x0104, "ffdhe8192", true, + NamedGroupSpec.NAMED_GROUP_FFDHE, + ProtocolVersion.PROTOCOLS_TO_13, +- PredefinedDHParameterSpecs.ffdheParams.get(8192)); ++ PredefinedDHParameterSpecs.ffdheParams.get(8192)), ++ ++ // Elliptic Curves (RFC 4492) ++ // ++ // arbitrary prime and characteristic-2 curves ++ ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", false, ++ NamedGroupSpec.NAMED_GROUP_ARBITRARY, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ null), ++ ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", false, ++ NamedGroupSpec.NAMED_GROUP_ARBITRARY, ++ ProtocolVersion.PROTOCOLS_TO_12, ++ null); + + final int id; // hash + signature + final String name; // literal name +diff -uNr openjdk/src/java.base/share/classes/sun/security/util/CurveDB.java afu11u/src/java.base/share/classes/sun/security/util/CurveDB.java +--- openjdk/src/java.base/share/classes/sun/security/util/CurveDB.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/java.base/share/classes/sun/security/util/CurveDB.java 2025-05-09 10:05:56.540290557 +0800 +@@ -176,6 +176,105 @@ + Pattern nameSplitPattern = Holder.nameSplitPattern; + + /* SEC2 prime curves */ ++ add("secp112r1", "1.3.132.0.6", P, ++ "DB7C2ABF62E35E668076BEAD208B", ++ "DB7C2ABF62E35E668076BEAD2088", ++ "659EF8BA043916EEDE8911702B22", ++ "09487239995A5EE76B55F9C2F098", ++ "A89CE5AF8724C0A23E0E0FF77500", ++ "DB7C2ABF62E35E7628DFAC6561C5", ++ 1, nameSplitPattern); ++ ++ add("secp112r2", "1.3.132.0.7", P, ++ "DB7C2ABF62E35E668076BEAD208B", ++ "6127C24C05F38A0AAAF65C0EF02C", ++ "51DEF1815DB5ED74FCC34C85D709", ++ "4BA30AB5E892B4E1649DD0928643", ++ "adcd46f5882e3747def36e956e97", ++ "36DF0AAFD8B8D7597CA10520D04B", ++ 4, nameSplitPattern); ++ ++ add("secp128r1", "1.3.132.0.28", P, ++ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", ++ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", ++ "E87579C11079F43DD824993C2CEE5ED3", ++ "161FF7528B899B2D0C28607CA52C5B86", ++ "CF5AC8395BAFEB13C02DA292DDED7A83", ++ "FFFFFFFE0000000075A30D1B9038A115", ++ 1, nameSplitPattern); ++ ++ add("secp128r2", "1.3.132.0.29", P, ++ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", ++ "D6031998D1B3BBFEBF59CC9BBFF9AEE1", ++ "5EEEFCA380D02919DC2C6558BB6D8A5D", ++ "7B6AA5D85E572983E6FB32A7CDEBC140", ++ "27B6916A894D3AEE7106FE805FC34B44", ++ "3FFFFFFF7FFFFFFFBE0024720613B5A3", ++ 4, nameSplitPattern); ++ ++ add("secp160k1", "1.3.132.0.9", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", ++ "0000000000000000000000000000000000000000", ++ "0000000000000000000000000000000000000007", ++ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", ++ "938CF935318FDCED6BC28286531733C3F03C4FEE", ++ "0100000000000000000001B8FA16DFAB9ACA16B6B3", ++ 1, nameSplitPattern); ++ ++ add("secp160r1", "1.3.132.0.8", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", ++ "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", ++ "4A96B5688EF573284664698968C38BB913CBFC82", ++ "23A628553168947D59DCC912042351377AC5FB32", ++ "0100000000000000000001F4C8F927AED3CA752257", ++ 1, nameSplitPattern); ++ ++ add("secp160r2", "1.3.132.0.30", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", ++ "B4E134D3FB59EB8BAB57274904664D5AF50388BA", ++ "52DCB034293A117E1F4FF11B30F7199D3144CE6D", ++ "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", ++ "0100000000000000000000351EE786A818F3A1A16B", ++ 1, nameSplitPattern); ++ ++ add("secp192k1", "1.3.132.0.31", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", ++ "000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000003", ++ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", ++ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", ++ "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", ++ 1, nameSplitPattern); ++ ++ add("secp192r1 [NIST P-192, X9.62 prime192v1]", "1.2.840.10045.3.1.1", PD, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", ++ "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", ++ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", ++ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", ++ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", ++ 1, nameSplitPattern); ++ ++ add("secp224k1", "1.3.132.0.32", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", ++ "00000000000000000000000000000000000000000000000000000000", ++ "00000000000000000000000000000000000000000000000000000005", ++ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", ++ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", ++ "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", ++ 1, nameSplitPattern); ++ ++ add("secp224r1 [NIST P-224]", "1.3.132.0.33", PD, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", ++ "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", ++ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", ++ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", ++ 1, nameSplitPattern); ++ + add("secp256k1", "1.3.132.0.10", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0000000000000000000000000000000000000000000000000000000000000000", +@@ -212,6 +311,435 @@ + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + 1, nameSplitPattern); + ++ /* ANSI X9.62 prime curves */ ++ add("X9.62 prime192v2", "1.2.840.10045.3.1.2", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", ++ "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", ++ "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", ++ "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", ++ "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", ++ 1, nameSplitPattern); ++ ++ add("X9.62 prime192v3", "1.2.840.10045.3.1.3", P, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", ++ "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", ++ "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", ++ "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", ++ "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", ++ 1, nameSplitPattern); ++ ++ add("X9.62 prime239v1", "1.2.840.10045.3.1.4", P, ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", ++ "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", ++ "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", ++ "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", ++ 1, nameSplitPattern); ++ ++ add("X9.62 prime239v2", "1.2.840.10045.3.1.5", P, ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", ++ "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", ++ "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", ++ "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", ++ "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", ++ 1, nameSplitPattern); ++ ++ add("X9.62 prime239v3", "1.2.840.10045.3.1.6", P, ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", ++ "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", ++ "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", ++ "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", ++ 1, nameSplitPattern); ++ ++ /* SEC2 binary curves */ ++ add("sect113r1", "1.3.132.0.4", B, ++ "020000000000000000000000000201", ++ "003088250CA6E7C7FE649CE85820F7", ++ "00E8BEE4D3E2260744188BE0E9C723", ++ "009D73616F35F4AB1407D73562C10F", ++ "00A52830277958EE84D1315ED31886", ++ "0100000000000000D9CCEC8A39E56F", ++ 2, nameSplitPattern); ++ ++ add("sect113r2", "1.3.132.0.5", B, ++ "020000000000000000000000000201", ++ "00689918DBEC7E5A0DD6DFC0AA55C7", ++ "0095E9A9EC9B297BD4BF36E059184F", ++ "01A57A6A7B26CA5EF52FCDB8164797", ++ "00B3ADC94ED1FE674C06E695BABA1D", ++ "010000000000000108789B2496AF93", ++ 2, nameSplitPattern); ++ ++ add("sect131r1", "1.3.132.0.22", B, ++ "080000000000000000000000000000010D", ++ "07A11B09A76B562144418FF3FF8C2570B8", ++ "0217C05610884B63B9C6C7291678F9D341", ++ "0081BAF91FDF9833C40F9C181343638399", ++ "078C6E7EA38C001F73C8134B1B4EF9E150", ++ "0400000000000000023123953A9464B54D", ++ 2, nameSplitPattern); ++ ++ add("sect131r2", "1.3.132.0.23", B, ++ "080000000000000000000000000000010D", ++ "03E5A88919D7CAFCBF415F07C2176573B2", ++ "04B8266A46C55657AC734CE38F018F2192", ++ "0356DCD8F2F95031AD652D23951BB366A8", ++ "0648F06D867940A5366D9E265DE9EB240F", ++ "0400000000000000016954A233049BA98F", ++ 2, nameSplitPattern); ++ ++ add("sect163k1 [NIST K-163]", "1.3.132.0.1", BD, ++ "0800000000000000000000000000000000000000C9", ++ "000000000000000000000000000000000000000001", ++ "000000000000000000000000000000000000000001", ++ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8", ++ "0289070FB05D38FF58321F2E800536D538CCDAA3D9", ++ "04000000000000000000020108A2E0CC0D99F8A5EF", ++ 2, nameSplitPattern); ++ ++ add("sect163r1", "1.3.132.0.2", B, ++ "0800000000000000000000000000000000000000C9", ++ "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2", ++ "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9", ++ "0369979697AB43897789566789567F787A7876A654", ++ "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883", ++ "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", ++ 2, nameSplitPattern); ++ ++ add("sect163r2 [NIST B-163]", "1.3.132.0.15", BD, ++ "0800000000000000000000000000000000000000C9", ++ "000000000000000000000000000000000000000001", ++ "020A601907B8C953CA1481EB10512F78744A3205FD", ++ "03F0EBA16286A2D57EA0991168D4994637E8343E36", ++ "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", ++ "040000000000000000000292FE77E70C12A4234C33", ++ 2, nameSplitPattern); ++ ++ add("sect193r1", "1.3.132.0.24", B, ++ "02000000000000000000000000000000000000000000008001", ++ "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01", ++ "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814", ++ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1", ++ "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05", ++ "01000000000000000000000000C7F34A778F443ACC920EBA49", ++ 2, nameSplitPattern); ++ ++ add("sect193r2", "1.3.132.0.25", B, ++ "02000000000000000000000000000000000000000000008001", ++ "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B", ++ "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE", ++ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F", ++ "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C", ++ "010000000000000000000000015AAB561B005413CCD4EE99D5", ++ 2, nameSplitPattern); ++ ++ add("sect233k1 [NIST K-233]", "1.3.132.0.26", BD, ++ "020000000000000000000000000000000000000004000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126", ++ "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", ++ "008000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", ++ 4, nameSplitPattern); ++ ++ add("sect233r1 [NIST B-233]", "1.3.132.0.27", B, ++ "020000000000000000000000000000000000000004000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", ++ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B", ++ "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", ++ "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", ++ 2, nameSplitPattern); ++ ++ add("sect239k1", "1.3.132.0.3", B, ++ "800000000000000000004000000000000000000000000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC", ++ "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA", ++ "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", ++ 4, nameSplitPattern); ++ ++ add("sect283k1 [NIST K-283]", "1.3.132.0.16", BD, ++ "0800000000000000000000000000000000000000000000000000000000000000000010A1", ++ "000000000000000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836", ++ "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", ++ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", ++ 4, nameSplitPattern); ++ ++ add("sect283r1 [NIST B-283]", "1.3.132.0.17", B, ++ "0800000000000000000000000000000000000000000000000000000000000000000010A1", ++ "000000000000000000000000000000000000000000000000000000000000000000000001", ++ "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", ++ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", ++ "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", ++ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", ++ 2, nameSplitPattern); ++ ++ add("sect409k1 [NIST K-409]", "1.3.132.0.36", BD, ++ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746", ++ "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", ++ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", ++ 4, nameSplitPattern); ++ ++ add("sect409r1 [NIST B-409]", "1.3.132.0.37", B, ++ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", ++ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7", ++ "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", ++ "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", ++ 2, nameSplitPattern); ++ ++ add("sect571k1 [NIST K-571]", "1.3.132.0.38", BD, ++ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972", ++ "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", ++ "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", ++ 4, nameSplitPattern); ++ ++ add("sect571r1 [NIST B-571]", "1.3.132.0.39", B, ++ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", ++ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19", ++ "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", ++ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", ++ 2, nameSplitPattern); ++ ++ /* ANSI X9.62 binary curves */ ++ add("X9.62 c2tnb191v1", "1.2.840.10045.3.0.5", B, ++ "800000000000000000000000000000000000000000000201", ++ "2866537B676752636A68F56554E12640276B649EF7526267", ++ "2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", ++ "36B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D", ++ "765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB", ++ "40000000000000000000000004A20E90C39067C893BBB9A5", ++ 2, nameSplitPattern); ++ ++ add("X9.62 c2tnb191v2", "1.2.840.10045.3.0.6", B, ++ "800000000000000000000000000000000000000000000201", ++ "401028774D7777C7B7666D1366EA432071274F89FF01E718", ++ "0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", ++ "3809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10", ++ "17434386626D14F3DBF01760D9213A3E1CF37AEC437D668A", ++ "20000000000000000000000050508CB89F652824E06B8173", ++ 4, nameSplitPattern); ++ ++ add("X9.62 c2tnb191v3", "1.2.840.10045.3.0.7", B, ++ "800000000000000000000000000000000000000000000201", ++ "6C01074756099122221056911C77D77E77A777E7E7E77FCB", ++ "71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", ++ "375D4CE24FDE434489DE8746E71786015009E66E38A926DD", ++ "545A39176196575D985999366E6AD34CE0A77CD7127B06BE", ++ "155555555555555555555555610C0B196812BFB6288A3EA3", ++ 6, nameSplitPattern); ++ ++ add("X9.62 c2tnb239v1", "1.2.840.10045.3.0.11", B, ++ "800000000000000000000000000000000000000000000000001000000001", ++ "32010857077C5431123A46B808906756F543423E8D27877578125778AC76", ++ "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", ++ "57927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D", ++ "61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305", ++ "2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", ++ 4, nameSplitPattern); ++ ++ add("X9.62 c2tnb239v2", "1.2.840.10045.3.0.12", B, ++ "800000000000000000000000000000000000000000000000001000000001", ++ "4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", ++ "5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", ++ "28F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205", ++ "5667334C45AFF3B5A03BAD9DD75E2C71A99362567D5453F7FA6E227EC833", ++ "1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", ++ 6, nameSplitPattern); ++ ++ add("X9.62 c2tnb239v3", "1.2.840.10045.3.0.13", B, ++ "800000000000000000000000000000000000000000000000001000000001", ++ "01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", ++ "6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", ++ "70F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92", ++ "2E5A0EAF6E5E1305B9004DCE5C0ED7FE59A35608F33837C816D80B79F461", ++ "0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", ++ 0xA, nameSplitPattern); ++ ++ add("X9.62 c2tnb359v1", "1.2.840.10045.3.0.18", B, ++ "800000000000000000000000000000000000000000000000000000000000000000000000100000000000000001", ++ "5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", ++ "2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", ++ "3C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097", ++ "53D7E08529547048121E9C95F3791DD804963948F34FAE7BF44EA82365DC7868FE57E4AE2DE211305A407104BD", ++ "01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", ++ 0x4C, nameSplitPattern); ++ ++ add("X9.62 c2tnb431r1", "1.2.840.10045.3.0.20", B, ++ "800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001", ++ "1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", ++ "10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", ++ "120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7", ++ "20D0AF8903A96F8D5FA2C255745D3C451B302C9346D9B7E485E7BCE41F6B591F3E8F6ADDCBB0BC4C2F947A7DE1A89B625D6A598B3760", ++ "0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", ++ 0x2760, nameSplitPattern); ++ ++ /* ANSI X9.62 binary curves from the 1998 standard but forbidden ++ * in the 2005 version of the standard. ++ * We don't register them but leave them here for the time being in ++ * case we need to support them after all. ++ */ ++/* ++ add("X9.62 c2pnb163v1", "1.2.840.10045.3.0.1", B, ++ "080000000000000000000000000000000000000107", ++ "072546B5435234A422E0789675F432C89435DE5242", ++ "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", ++ "07AF69989546103D79329FCC3D74880F33BBE803CB", ++ "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F", ++ "0400000000000000000001E60FC8821CC74DAEAFC1", ++ 2, nameSplitPattern); ++ ++ add("X9.62 c2pnb163v2", "1.2.840.10045.3.0.2", B, ++ "080000000000000000000000000000000000000107", ++ "0108B39E77C4B108BED981ED0E890E117C511CF072", ++ "0667ACEB38AF4E488C407433FFAE4F1C811638DF20", ++ "0024266E4EB5106D0A964D92C4860E2671DB9B6CC5", ++ "079F684DDF6684C5CD258B3890021B2386DFD19FC5", ++ "03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", ++ 2, nameSplitPattern); ++ ++ add("X9.62 c2pnb163v3", "1.2.840.10045.3.0.3", B, ++ "080000000000000000000000000000000000000107", ++ "07A526C63D3E25A256A007699F5447E32AE456B50E", ++ "03F7061798EB99E238FD6F1BF95B48FEEB4854252B", ++ "02F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB", ++ "05B935590C155E17EA48EB3FF3718B893DF59A05D0", ++ "03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", ++ 2, nameSplitPattern); ++ ++ add("X9.62 c2pnb176w1", "1.2.840.10045.3.0.4", B, ++ "0100000000000000000000000000000000080000000007", ++ "E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", ++ "5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", ++ "8D16C2866798B600F9F08BB4A8E860F3298CE04A5798", ++ "6FA4539C2DADDDD6BAB5167D61B436E1D92BB16A562C", ++ "00010092537397ECA4F6145799D62B0A19CE06FE26AD", ++ 0xFF6E, nameSplitPattern); ++ ++ add("X9.62 c2pnb208w1", "1.2.840.10045.3.0.10", B, ++ "010000000000000000000000000000000800000000000000000007", ++ "0000000000000000000000000000000000000000000000000000", ++ "C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", ++ "89FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A", ++ "0F55B51A06E78E9AC38A035FF520D8B01781BEB1A6BB08617DE3", ++ "000101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", ++ 0xFE48, nameSplitPattern); ++ ++ add("X9.62 c2pnb272w1", "1.2.840.10045.3.0.16", B, ++ "010000000000000000000000000000000000000000000000000000010000000000000B", ++ "91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", ++ "7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", ++ "6108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D", ++ "10C7695716851EEF6BA7F6872E6142FBD241B830FF5EFCACECCAB05E02005DDE9D23", ++ "000100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", ++ 0xFF06, nameSplitPattern); ++ ++ add("X9.62 c2pnb304w1", "1.2.840.10045.3.0.17", B, ++ "010000000000000000000000000000000000000000000000000000000000000000000000000807", ++ "FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", ++ "BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", ++ "197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614", ++ "E19FBEB76E0DA171517ECF401B50289BF014103288527A9B416A105E80260B549FDC1B92C03B", ++ "000101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", ++ 0xFE2E, nameSplitPattern); ++ ++ add("X9.62 c2pnb368w1", "1.2.840.10045.3.0.19", B, ++ "0100000000000000000000000000000000000000000000000000000000000000000000002000000000000000000007", ++ "E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", ++ "FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", ++ "1085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F", ++ "7B3EB1BDDCBA62D5D8B2059B525797FC73822C59059C623A45FF3843CEE8F87CD1855ADAA81E2A0750B80FDA2310", ++ "00010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", ++ 0xFF70, nameSplitPattern); ++*/ ++ ++ /* ++ * Brainpool curves (RFC 5639) ++ * (Twisted curves are not included) ++ */ ++ ++ add("brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1", P, ++ "E95E4A5F737059DC60DFC7AD95B3D8139515620F", ++ "340E7BE2A280EB74E2BE61BADA745D97E8F7C300", ++ "1E589A8595423412134FAA2DBDEC95C8D8675E58", ++ "BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", ++ "1667CB477A1A8EC338F94741669C976316DA6321", ++ "E95E4A5F737059DC60DF5991D45029409E60FC09", ++ 1, nameSplitPattern); ++ ++ add("brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", P, ++ "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", ++ "6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", ++ "469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", ++ "C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6", ++ "14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", ++ "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", ++ 1, nameSplitPattern); ++ ++ add("brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", P, ++ "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", ++ "68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", ++ "2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", ++ "0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D", ++ "58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", ++ "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", ++ 1, nameSplitPattern); ++ ++ add("brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", P, ++ "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", ++ "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", ++ "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", ++ "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", ++ "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", ++ "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", ++ 1, nameSplitPattern); ++ ++ add("brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", P, ++ "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", ++ "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", ++ "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", ++ "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", ++ "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", ++ "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", ++ 1, nameSplitPattern); ++ ++ add("brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", P, ++ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", ++ "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", ++ "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", ++ "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", ++ "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", ++ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", ++ 1, nameSplitPattern); ++ ++ add("brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", P, ++ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", ++ "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", ++ "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", ++ "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", ++ "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", ++ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", ++ 1, nameSplitPattern); ++ + specCollection = Collections.unmodifiableCollection(oidMap.values()); + } + } +diff -uNr openjdk/src/java.base/share/conf/security/java.security afu11u/src/java.base/share/conf/security/java.security +--- openjdk/src/java.base/share/conf/security/java.security 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/java.base/share/conf/security/java.security 2025-05-09 10:06:54.280292507 +0800 +@@ -505,7 +505,16 @@ + # in the jdk.[tls|certpath|jar].disabledAlgorithms properties. To include this + # list in any of the disabledAlgorithms properties, add the property name as + # an entry. +-jdk.disabled.namedCurves = secp256k1 ++jdk.disabled.namedCurves = secp112r1, secp112r2, secp128r1, secp128r2, \ ++ secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \ ++ secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \ ++ sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \ ++ sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \ ++ sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, \ ++ X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, \ ++ X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, \ ++ X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1, \ ++ brainpoolP320r1, brainpoolP384r1, brainpoolP512r1 + + # + # Algorithm restrictions for certification path (CertPath) processing +@@ -743,7 +752,7 @@ + # + # Example: + # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048, \ +-# rsa_pkcs1_sha1 ++# rsa_pkcs1_sha1, secp224r1 + jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \ + DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ + include jdk.disabled.namedCurves +diff -uNr openjdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/ECDSAUtils.java afu11u/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/ECDSAUtils.java +--- openjdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/ECDSAUtils.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/ECDSAUtils.java 2025-05-09 10:05:57.324290583 +0800 +@@ -171,6 +171,149 @@ + static { + ecCurveDefinitions.add( + new ECCurveDefinition( ++ "secp112r1", ++ "1.3.132.0.6", ++ "db7c2abf62e35e668076bead208b", ++ "db7c2abf62e35e668076bead2088", ++ "659ef8ba043916eede8911702b22", ++ "09487239995a5ee76b55f9c2f098", ++ "a89ce5af8724c0a23e0e0ff77500", ++ "db7c2abf62e35e7628dfac6561c5", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp112r2", ++ "1.3.132.0.7", ++ "db7c2abf62e35e668076bead208b", ++ "6127c24c05f38a0aaaf65c0ef02c", ++ "51def1815db5ed74fcc34c85d709", ++ "4ba30ab5e892b4e1649dd0928643", ++ "adcd46f5882e3747def36e956e97", ++ "36df0aafd8b8d7597ca10520d04b", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp128r1", ++ "1.3.132.0.28", ++ "fffffffdffffffffffffffffffffffff", ++ "fffffffdfffffffffffffffffffffffc", ++ "e87579c11079f43dd824993c2cee5ed3", ++ "161ff7528b899b2d0c28607ca52c5b86", ++ "cf5ac8395bafeb13c02da292dded7a83", ++ "fffffffe0000000075a30d1b9038a115", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp128r2", ++ "1.3.132.0.29", ++ "fffffffdffffffffffffffffffffffff", ++ "d6031998d1b3bbfebf59cc9bbff9aee1", ++ "5eeefca380d02919dc2c6558bb6d8a5d", ++ "7b6aa5d85e572983e6fb32a7cdebc140", ++ "27b6916a894d3aee7106fe805fc34b44", ++ "3fffffff7fffffffbe0024720613b5a3", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp160k1", ++ "1.3.132.0.9", ++ "fffffffffffffffffffffffffffffffeffffac73", ++ "0000000000000000000000000000000000000000", ++ "0000000000000000000000000000000000000007", ++ "3b4c382ce37aa192a4019e763036f4f5dd4d7ebb", ++ "938cf935318fdced6bc28286531733c3f03c4fee", ++ "0100000000000000000001b8fa16dfab9aca16b6b3", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp160r1", ++ "1.3.132.0.8", ++ "ffffffffffffffffffffffffffffffff7fffffff", ++ "ffffffffffffffffffffffffffffffff7ffffffc", ++ "1c97befc54bd7a8b65acf89f81d4d4adc565fa45", ++ "4a96b5688ef573284664698968c38bb913cbfc82", ++ "23a628553168947d59dcc912042351377ac5fb32", ++ "0100000000000000000001f4c8f927aed3ca752257", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp160r2", ++ "1.3.132.0.30", ++ "fffffffffffffffffffffffffffffffeffffac73", ++ "fffffffffffffffffffffffffffffffeffffac70", ++ "b4e134d3fb59eb8bab57274904664d5af50388ba", ++ "52dcb034293a117e1f4ff11b30f7199d3144ce6d", ++ "feaffef2e331f296e071fa0df9982cfea7d43f2e", ++ "0100000000000000000000351ee786a818f3a1a16b", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp192k1", ++ "1.3.132.0.31", ++ "fffffffffffffffffffffffffffffffffffffffeffffee37", ++ "000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000003", ++ "db4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d", ++ "9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d", ++ "fffffffffffffffffffffffe26f2fc170f69466a74defd8d", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp192r1 [NIST P-192, X9.62 prime192v1]", ++ "1.2.840.10045.3.1.1", ++ "fffffffffffffffffffffffffffffffeffffffffffffffff", ++ "fffffffffffffffffffffffffffffffefffffffffffffffc", ++ "64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", ++ "188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", ++ "07192b95ffc8da78631011ed6b24cdd573f977a11e794811", ++ "ffffffffffffffffffffffff99def836146bc9b1b4d22831", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp224k1", ++ "1.3.132.0.32", ++ "fffffffffffffffffffffffffffffffffffffffffffffffeffffe56d", ++ "00000000000000000000000000000000000000000000000000000000", ++ "00000000000000000000000000000000000000000000000000000005", ++ "a1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c", ++ "7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5", ++ "010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "secp224r1 [NIST P-224]", ++ "1.3.132.0.33", ++ "ffffffffffffffffffffffffffffffff000000000000000000000001", ++ "fffffffffffffffffffffffffffffffefffffffffffffffffffffffe", ++ "b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", ++ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", ++ "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", ++ "ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( + "secp256k1", + "1.3.132.0.10", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", +@@ -220,6 +363,409 @@ + "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + 1) + ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 prime192v2", ++ "1.2.840.10045.3.1.2", ++ "fffffffffffffffffffffffffffffffeffffffffffffffff", ++ "fffffffffffffffffffffffffffffffefffffffffffffffc", ++ "cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", ++ "eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a", ++ "6574d11d69b6ec7a672bb82a083df2f2b0847de970b2de15", ++ "fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 prime192v3", ++ "1.2.840.10045.3.1.3", ++ "fffffffffffffffffffffffffffffffeffffffffffffffff", ++ "fffffffffffffffffffffffffffffffefffffffffffffffc", ++ "22123dc2395a05caa7423daeccc94760a7d462256bd56916", ++ "7d29778100c65a1da1783716588dce2b8b4aee8e228f1896", ++ "38a90f22637337334b49dcb66a6dc8f9978aca7648a943b0", ++ "ffffffffffffffffffffffff7a62d031c83f4294f640ec13", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 prime239v1", ++ "1.2.840.10045.3.1.4", ++ "7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff", ++ "7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", ++ "6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", ++ "0ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf", ++ "7debe8e4e90a5dae6e4054ca530ba04654b36818ce226b39fccb7b02f1ae", ++ "7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 prime239v2", ++ "1.2.840.10045.3.1.5", ++ "7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff", ++ "7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", ++ "617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", ++ "38af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7", ++ "5b0125e4dbea0ec7206da0fc01d9b081329fb555de6ef460237dff8be4ba", ++ "7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 prime239v3", ++ "1.2.840.10045.3.1.6", ++ "7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff", ++ "7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", ++ "255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", ++ "6768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a", ++ "1607e6898f390c06bc1d552bad226f3b6fcfe48b6e818499af18e3ed6cf3", ++ "7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", ++ 1) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect113r1", ++ "1.3.132.0.4", ++ "020000000000000000000000000201", ++ "003088250ca6e7c7fe649ce85820f7", ++ "00e8bee4d3e2260744188be0e9c723", ++ "009d73616f35f4ab1407d73562c10f", ++ "00a52830277958ee84d1315ed31886", ++ "0100000000000000d9ccec8a39e56f", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect113r2", ++ "1.3.132.0.5", ++ "020000000000000000000000000201", ++ "00689918dbec7e5a0dd6dfc0aa55c7", ++ "0095e9a9ec9b297bd4bf36e059184f", ++ "01a57a6a7b26ca5ef52fcdb8164797", ++ "00b3adc94ed1fe674c06e695baba1d", ++ "010000000000000108789b2496af93", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect131r1", ++ "1.3.132.0.22", ++ "080000000000000000000000000000010d", ++ "07a11b09a76b562144418ff3ff8c2570b8", ++ "0217c05610884b63b9c6c7291678f9d341", ++ "0081baf91fdf9833c40f9c181343638399", ++ "078c6e7ea38c001f73c8134b1b4ef9e150", ++ "0400000000000000023123953a9464b54d", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect131r2", ++ "1.3.132.0.23", ++ "080000000000000000000000000000010d", ++ "03e5a88919d7cafcbf415f07c2176573b2", ++ "04b8266a46c55657ac734ce38f018f2192", ++ "0356dcd8f2f95031ad652d23951bb366a8", ++ "0648f06d867940a5366d9e265de9eb240f", ++ "0400000000000000016954a233049ba98f", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect163k1 [NIST K-163]", ++ "1.3.132.0.1", ++ "0800000000000000000000000000000000000000c9", ++ "000000000000000000000000000000000000000001", ++ "000000000000000000000000000000000000000001", ++ "02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8", ++ "0289070fb05d38ff58321f2e800536d538ccdaa3d9", ++ "04000000000000000000020108a2e0cc0d99f8a5ef", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect163r1", ++ "1.3.132.0.2", ++ "0800000000000000000000000000000000000000c9", ++ "07b6882caaefa84f9554ff8428bd88e246d2782ae2", ++ "0713612dcddcb40aab946bda29ca91f73af958afd9", ++ "0369979697ab43897789566789567f787a7876a654", ++ "00435edb42efafb2989d51fefce3c80988f41ff883", ++ "03ffffffffffffffffffff48aab689c29ca710279b", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect163r2 [NIST B-163]", ++ "1.3.132.0.15", ++ "0800000000000000000000000000000000000000c9", ++ "000000000000000000000000000000000000000001", ++ "020a601907b8c953ca1481eb10512f78744a3205fd", ++ "03f0eba16286a2d57ea0991168d4994637e8343e36", ++ "00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1", ++ "040000000000000000000292fe77e70c12a4234c33", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect193r1", ++ "1.3.132.0.24", ++ "02000000000000000000000000000000000000000000008001", ++ "0017858feb7a98975169e171f77b4087de098ac8a911df7b01", ++ "00fdfb49bfe6c3a89facadaa7a1e5bbc7cc1c2e5d831478814", ++ "01f481bc5f0ff84a74ad6cdf6fdef4bf6179625372d8c0c5e1", ++ "0025e399f2903712ccf3ea9e3a1ad17fb0b3201b6af7ce1b05", ++ "01000000000000000000000000c7f34a778f443acc920eba49", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect193r2", ++ "1.3.132.0.25", ++ "02000000000000000000000000000000000000000000008001", ++ "0163f35a5137c2ce3ea6ed8667190b0bc43ecd69977702709b", ++ "00c9bb9e8927d4d64c377e2ab2856a5b16e3efb7f61d4316ae", ++ "00d9b67d192e0367c803f39e1a7e82ca14a651350aae617e8f", ++ "01ce94335607c304ac29e7defbd9ca01f596f927224cdecf6c", ++ "010000000000000000000000015aab561b005413ccd4ee99d5", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect233k1 [NIST K-233]", ++ "1.3.132.0.26", ++ "020000000000000000000000000000000000000004000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126", ++ "01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3", ++ "008000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect233r1 [NIST B-233]", ++ "1.3.132.0.27", ++ "020000000000000000000000000000000000000004000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad", ++ "00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b", ++ "01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052", ++ "01000000000000000000000000000013e974e72f8a6922031d2603cfe0d7", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect239k1", ++ "1.3.132.0.3", ++ "800000000000000000004000000000000000000000000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "29a0b6a887a983e9730988a68727a8b2d126c44cc2cc7b2a6555193035dc", ++ "76310804f12e549bdb011c103089e73510acb275fc312a5dc6b76553f0ca", ++ "2000000000000000000000000000005a79fec67cb6e91f1c1da800e478a5", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect283k1 [NIST K-283]", ++ "1.3.132.0.16", ++ "0800000000000000000000000000000000000000000000000000000000000000000010a1", ++ "000000000000000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836", ++ "01ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259", ++ "01ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect283r1 [NIST B-283]", ++ "1.3.132.0.17", ++ "0800000000000000000000000000000000000000000000000000000000000000000010a1", ++ "000000000000000000000000000000000000000000000000000000000000000000000001", ++ "027b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5", ++ "05f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053", ++ "03676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4", ++ "03ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect409k1 [NIST K-409]", ++ "1.3.132.0.36", ++ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746", ++ "01e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b", ++ "007ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect409r1 [NIST B-409]", ++ "1.3.132.0.37", ++ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f", ++ "015d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7", ++ "0061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706", ++ "010000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect571k1 [NIST K-571]", ++ "1.3.132.0.38", ++ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "026eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972", ++ "0349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3", ++ "020000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "sect571r1 [NIST B-571]", ++ "1.3.132.0.39", ++ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a", ++ "0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19", ++ "037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b", ++ "03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb191v1", ++ "1.2.840.10045.3.0.5", ++ "800000000000000000000000000000000000000000000201", ++ "2866537b676752636a68f56554e12640276b649ef7526267", ++ "2e45ef571f00786f67b0081b9495a3d95462f5de0aa185ec", ++ "36b3daf8a23206f9c4f299d7b21a9c369137f2c84ae1aa0d", ++ "765be73433b3f95e332932e70ea245ca2418ea0ef98018fb", ++ "40000000000000000000000004a20e90c39067c893bbb9a5", ++ 2) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb191v2", ++ "1.2.840.10045.3.0.6", ++ "800000000000000000000000000000000000000000000201", ++ "401028774d7777c7b7666d1366ea432071274f89ff01e718", ++ "0620048d28bcbd03b6249c99182b7c8cd19700c362c46a01", ++ "3809b2b7cc1b28cc5a87926aad83fd28789e81e2c9e3bf10", ++ "17434386626d14f3dbf01760d9213a3e1cf37aec437d668a", ++ "20000000000000000000000050508cb89f652824e06b8173", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb191v3", ++ "1.2.840.10045.3.0.7", ++ "800000000000000000000000000000000000000000000201", ++ "6c01074756099122221056911c77d77e77a777e7e7e77fcb", ++ "71fe1af926cf847989efef8db459f66394d90f32ad3f15e8", ++ "375d4ce24fde434489de8746e71786015009e66e38a926dd", ++ "545a39176196575d985999366e6ad34ce0a77cd7127b06be", ++ "155555555555555555555555610c0b196812bfb6288a3ea3", ++ 6) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb239v1", ++ "1.2.840.10045.3.0.11", ++ "800000000000000000000000000000000000000000000000001000000001", ++ "32010857077c5431123a46b808906756f543423e8d27877578125778ac76", ++ "790408f2eedaf392b012edefb3392f30f4327c0ca3f31fc383c422aa8c16", ++ "57927098fa932e7c0a96d3fd5b706ef7e5f5c156e16b7e7c86038552e91d", ++ "61d8ee5077c33fecf6f1a16b268de469c3c7744ea9a971649fc7a9616305", ++ "2000000000000000000000000000000f4d42ffe1492a4993f1cad666e447", ++ 4) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb239v2", ++ "1.2.840.10045.3.0.12", ++ "800000000000000000000000000000000000000000000000001000000001", ++ "4230017757a767fae42398569b746325d45313af0766266479b75654e65f", ++ "5037ea654196cff0cd82b2c14a2fcf2e3ff8775285b545722f03eacdb74b", ++ "28f9d04e900069c8dc47a08534fe76d2b900b7d7ef31f5709f200c4ca205", ++ "5667334c45aff3b5a03bad9dd75e2c71a99362567d5453f7fa6e227ec833", ++ "1555555555555555555555555555553c6f2885259c31e3fcdf154624522d", ++ 6) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb239v3", ++ "1.2.840.10045.3.0.13", ++ "800000000000000000000000000000000000000000000000001000000001", ++ "01238774666a67766d6676f778e676b66999176666e687666d8766c66a9f", ++ "6a941977ba9f6a435199acfc51067ed587f519c5ecb541b8e44111de1d40", ++ "70f6e9d04d289c4e89913ce3530bfde903977d42b146d539bf1bde4e9c92", ++ "2e5a0eaf6e5e1305b9004dce5c0ed7fe59a35608f33837c816d80b79f461", ++ "0cccccccccccccccccccccccccccccac4912d2d9df903ef9888b8a0e4cff", ++ 0xA) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb359v1", ++ "1.2.840.10045.3.0.18", ++ "800000000000000000000000000000000000000000000000000000000000000000000000100000000000000001", ++ "5667676a654b20754f356ea92017d946567c46675556f19556a04616b567d223a5e05656fb549016a96656a557", ++ "2472e2d0197c49363f1fe7f5b6db075d52b6947d135d8ca445805d39bc345626089687742b6329e70680231988", ++ "3c258ef3047767e7ede0f1fdaa79daee3841366a132e163aced4ed2401df9c6bdcde98e8e707c07a2239b1b097", ++ "53d7e08529547048121e9c95f3791dd804963948f34fae7bf44ea82365dc7868fe57e4ae2de211305a407104bd", ++ "01af286bca1af286bca1af286bca1af286bca1af286bc9fb8f6b85c556892c20a7eb964fe7719e74f490758d3b", ++ 0x4C) ++ ); ++ ++ ecCurveDefinitions.add( ++ new ECCurveDefinition( ++ "X9.62 c2tnb431r1", ++ "1.2.840.10045.3.0.20", ++ "800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001", ++ "1a827ef00dd6fc0e234caf046c6a5d8a85395b236cc4ad2cf32a0cadbdc9ddf620b0eb9906d0957f6c6feacd615468df104de296cd8f", ++ "10d9b4a3d9047d8b154359abfb1b7f5485b04ceb868237ddc9deda982a679a5a919b626d4e50a8dd731b107a9962381fb5d807bf2618", ++ "120fc05d3c67a99de161d2f4092622feca701be4f50f4758714e8a87bbf2a658ef8c21e7c5efe965361f6c2999c0c247b0dbd70ce6b7", ++ "20d0af8903a96f8d5fa2c255745d3c451b302c9346d9b7e485e7bce41f6b591f3e8f6addcbb0bc4c2f947a7de1a89b625d6a598b3760", ++ "0340340340340340340340340340340340340340340340340340340323c313fab50589703b5ec68d3587fec60d161cc149c1ad4a91", ++ 0x2760) ++ ); + } + + public static String getOIDFromPublicKey(ECPublicKey ecPublicKey) { +diff -uNr openjdk/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64ELFMacroAssembler.java afu11u/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64ELFMacroAssembler.java +--- openjdk/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64ELFMacroAssembler.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64ELFMacroAssembler.java 2025-05-09 10:05:57.536290590 +0800 +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package jdk.tools.jaotc.sw64; ++ ++import jdk.tools.jaotc.StubInformation; ++import jdk.tools.jaotc.ELFMacroAssembler; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++ ++ ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.code.Register; ++ ++import static jdk.vm.ci.sw64.SW64.*; ++ ++public final class SW64ELFMacroAssembler extends SW64MacroAssembler implements ELFMacroAssembler { ++ ++ private int currentEndOfInstruction; ++ ++ public SW64ELFMacroAssembler(TargetDescription target) { ++ super(target); ++ } ++ ++ @Override ++ public int currentEndOfInstruction() { ++ return currentEndOfInstruction; ++ } ++ ++ @Override ++ public byte[] getPLTJumpCode() { ++ // The main dispatch instruction ++ addressOf(r16); ++ ldr(64, r16, SW64Address.createBaseRegisterOnlyAddress(r16)); ++ jmp(r16); ++ ++ currentEndOfInstruction = position(); ++ ++ align(8); ++ ++ return close(true); ++ } ++ ++ @Override ++ public byte[] getPLTStaticEntryCode(StubInformation stub) { ++ // The main dispatch instruction ++ addressOf(r16); ++ ldr(64, r16, SW64Address.createBaseRegisterOnlyAddress(r16)); ++ jmp(r16); ++ stub.setDispatchJumpOffset(position()); ++ ++ // C2I stub used to call interpreter. First load r12 ++ // (i.e. rmethod) with a pointer to the Method structure ... ++ addressOf(r12); ++ ldr(64, r12, SW64Address.createBaseRegisterOnlyAddress(r12)); ++ nop(); ++ stub.setMovOffset(position()); ++ ++ // ... then jump to the interpreter. ++ addressOf(r16); ++ ldr(64, r16, SW64Address.createBaseRegisterOnlyAddress(r16)); ++ jmp(r16); ++ stub.setC2IJumpOffset(position()); ++ ++ // Call to VM runtime to resolve the call. ++ stub.setResolveJumpStart(position()); ++ addressOf(r16); ++ ldr(64, r16, SW64Address.createBaseRegisterOnlyAddress(r16)); ++ jmp(r16); ++ stub.setResolveJumpOffset(position()); ++ currentEndOfInstruction = position(); ++ ++ align(8); ++ stub.setSize(position()); ++ ++ return close(true); ++ } ++ ++ @Override ++ public byte[] getPLTVirtualEntryCode(StubInformation stub) { ++ // Fixup an inline cache. ++ // Load r9 with a pointer to the Klass. ++ addressOf(r17); ++ ldr(64, r9, SW64Address.createBaseRegisterOnlyAddress(r17)); ++ nop(); ++ stub.setMovOffset(position()); ++ ++ // Jump to the method. ++ addressOf(r16); ++ ldr(64, r16, SW64Address.createBaseRegisterOnlyAddress(r16)); ++ jmp(r16); ++ stub.setDispatchJumpOffset(position()); ++ ++ // Call to VM runtime to resolve the call. ++ stub.setResolveJumpStart(position()); ++ addressOf(r16); ++ ldr(64, r16, SW64Address.createBaseRegisterOnlyAddress(r16)); ++ jmp(r16); ++ stub.setResolveJumpOffset(position()); ++ currentEndOfInstruction = position(); ++ ++ align(8); ++ stub.setSize(position()); ++ ++ return close(true); ++ } ++} +diff -uNr openjdk/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64InstructionDecoder.java afu11u/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64InstructionDecoder.java +--- openjdk/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64InstructionDecoder.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/sw64/SW64InstructionDecoder.java 2025-05-09 10:05:57.536290590 +0800 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package jdk.tools.jaotc.sw64; ++ ++import jdk.tools.jaotc.InstructionDecoder; ++ ++import jdk.vm.ci.code.TargetDescription; ++ ++public final class SW64InstructionDecoder extends InstructionDecoder { ++ ++ private int currentEndOfInstruction; ++ ++ public SW64InstructionDecoder(TargetDescription target) { ++ } ++ ++ @Override ++ public int currentEndOfInstruction() { ++ return currentEndOfInstruction; ++ } ++ ++ @Override ++ public void decodePosition(final byte[] code, int pcOffset) { ++ currentEndOfInstruction = pcOffset + 4; ++ } ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,260 @@ ++/* ++ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for binary polynomial field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Sheueling Chang-Shantz , ++ * Stephen Fung , and ++ * Douglas Stebila , Sun Microsystems Laboratories. ++ * ++ *********************************************************************** */ ++ ++#include "ec2.h" ++#include "mp_gf2m.h" ++#include "mp_gf2m-priv.h" ++#include "mpi.h" ++#include "mpi-priv.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++/* Fast reduction for polynomials over a 163-bit curve. Assumes reduction ++ * polynomial with terms {163, 7, 6, 3, 0}. */ ++mp_err ++ec_GF2m_163_mod(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit *u, z; ++ ++ if (a != r) { ++ MP_CHECKOK(mp_copy(a, r)); ++ } ++#ifdef ECL_SIXTY_FOUR_BIT ++ if (MP_USED(r) < 6) { ++ MP_CHECKOK(s_mp_pad(r, 6)); ++ } ++ u = MP_DIGITS(r); ++ MP_USED(r) = 6; ++ ++ /* u[5] only has 6 significant bits */ ++ z = u[5]; ++ u[2] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29); ++ z = u[4]; ++ u[2] ^= (z >> 28) ^ (z >> 29) ^ (z >> 32) ^ (z >> 35); ++ u[1] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29); ++ z = u[3]; ++ u[1] ^= (z >> 28) ^ (z >> 29) ^ (z >> 32) ^ (z >> 35); ++ u[0] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29); ++ z = u[2] >> 35; /* z only has 29 significant bits */ ++ u[0] ^= (z << 7) ^ (z << 6) ^ (z << 3) ^ z; ++ /* clear bits above 163 */ ++ u[5] = u[4] = u[3] = 0; ++ u[2] ^= z << 35; ++#else ++ if (MP_USED(r) < 11) { ++ MP_CHECKOK(s_mp_pad(r, 11)); ++ } ++ u = MP_DIGITS(r); ++ MP_USED(r) = 11; ++ ++ /* u[11] only has 6 significant bits */ ++ z = u[10]; ++ u[5] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3); ++ u[4] ^= (z << 29); ++ z = u[9]; ++ u[5] ^= (z >> 28) ^ (z >> 29); ++ u[4] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3); ++ u[3] ^= (z << 29); ++ z = u[8]; ++ u[4] ^= (z >> 28) ^ (z >> 29); ++ u[3] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3); ++ u[2] ^= (z << 29); ++ z = u[7]; ++ u[3] ^= (z >> 28) ^ (z >> 29); ++ u[2] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3); ++ u[1] ^= (z << 29); ++ z = u[6]; ++ u[2] ^= (z >> 28) ^ (z >> 29); ++ u[1] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3); ++ u[0] ^= (z << 29); ++ z = u[5] >> 3; /* z only has 29 significant bits */ ++ u[1] ^= (z >> 25) ^ (z >> 26); ++ u[0] ^= (z << 7) ^ (z << 6) ^ (z << 3) ^ z; ++ /* clear bits above 163 */ ++ u[11] = u[10] = u[9] = u[8] = u[7] = u[6] = 0; ++ u[5] ^= z << 3; ++#endif ++ s_mp_clamp(r); ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Fast squaring for polynomials over a 163-bit curve. Assumes reduction ++ * polynomial with terms {163, 7, 6, 3, 0}. */ ++mp_err ++ec_GF2m_163_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit *u, *v; ++ ++ v = MP_DIGITS(a); ++ ++#ifdef ECL_SIXTY_FOUR_BIT ++ if (MP_USED(a) < 3) { ++ return mp_bsqrmod(a, meth->irr_arr, r); ++ } ++ if (MP_USED(r) < 6) { ++ MP_CHECKOK(s_mp_pad(r, 6)); ++ } ++ MP_USED(r) = 6; ++#else ++ if (MP_USED(a) < 6) { ++ return mp_bsqrmod(a, meth->irr_arr, r); ++ } ++ if (MP_USED(r) < 12) { ++ MP_CHECKOK(s_mp_pad(r, 12)); ++ } ++ MP_USED(r) = 12; ++#endif ++ u = MP_DIGITS(r); ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ u[11] = gf2m_SQR1(v[5]); ++ u[10] = gf2m_SQR0(v[5]); ++ u[9] = gf2m_SQR1(v[4]); ++ u[8] = gf2m_SQR0(v[4]); ++ u[7] = gf2m_SQR1(v[3]); ++ u[6] = gf2m_SQR0(v[3]); ++#endif ++ u[5] = gf2m_SQR1(v[2]); ++ u[4] = gf2m_SQR0(v[2]); ++ u[3] = gf2m_SQR1(v[1]); ++ u[2] = gf2m_SQR0(v[1]); ++ u[1] = gf2m_SQR1(v[0]); ++ u[0] = gf2m_SQR0(v[0]); ++ return ec_GF2m_163_mod(r, r, meth); ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Fast multiplication for polynomials over a 163-bit curve. Assumes ++ * reduction polynomial with terms {163, 7, 6, 3, 0}. */ ++mp_err ++ec_GF2m_163_mul(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit a2 = 0, a1 = 0, a0, b2 = 0, b1 = 0, b0; ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ mp_digit a5 = 0, a4 = 0, a3 = 0, b5 = 0, b4 = 0, b3 = 0; ++ mp_digit rm[6]; ++#endif ++ ++ if (a == b) { ++ return ec_GF2m_163_sqr(a, r, meth); ++ } else { ++ switch (MP_USED(a)) { ++#ifdef ECL_THIRTY_TWO_BIT ++ case 6: ++ a5 = MP_DIGIT(a, 5); ++ case 5: ++ a4 = MP_DIGIT(a, 4); ++ case 4: ++ a3 = MP_DIGIT(a, 3); ++#endif ++ case 3: ++ a2 = MP_DIGIT(a, 2); ++ case 2: ++ a1 = MP_DIGIT(a, 1); ++ default: ++ a0 = MP_DIGIT(a, 0); ++ } ++ switch (MP_USED(b)) { ++#ifdef ECL_THIRTY_TWO_BIT ++ case 6: ++ b5 = MP_DIGIT(b, 5); ++ case 5: ++ b4 = MP_DIGIT(b, 4); ++ case 4: ++ b3 = MP_DIGIT(b, 3); ++#endif ++ case 3: ++ b2 = MP_DIGIT(b, 2); ++ case 2: ++ b1 = MP_DIGIT(b, 1); ++ default: ++ b0 = MP_DIGIT(b, 0); ++ } ++#ifdef ECL_SIXTY_FOUR_BIT ++ MP_CHECKOK(s_mp_pad(r, 6)); ++ s_bmul_3x3(MP_DIGITS(r), a2, a1, a0, b2, b1, b0); ++ MP_USED(r) = 6; ++ s_mp_clamp(r); ++#else ++ MP_CHECKOK(s_mp_pad(r, 12)); ++ s_bmul_3x3(MP_DIGITS(r) + 6, a5, a4, a3, b5, b4, b3); ++ s_bmul_3x3(MP_DIGITS(r), a2, a1, a0, b2, b1, b0); ++ s_bmul_3x3(rm, a5 ^ a2, a4 ^ a1, a3 ^ a0, b5 ^ b2, b4 ^ b1, ++ b3 ^ b0); ++ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 11); ++ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 10); ++ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 9); ++ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 8); ++ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 7); ++ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 6); ++ MP_DIGIT(r, 8) ^= rm[5]; ++ MP_DIGIT(r, 7) ^= rm[4]; ++ MP_DIGIT(r, 6) ^= rm[3]; ++ MP_DIGIT(r, 5) ^= rm[2]; ++ MP_DIGIT(r, 4) ^= rm[1]; ++ MP_DIGIT(r, 3) ^= rm[0]; ++ MP_USED(r) = 12; ++ s_mp_clamp(r); ++#endif ++ return ec_GF2m_163_mod(r, r, meth); ++ } ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Wire in fast field arithmetic for 163-bit curves. */ ++mp_err ++ec_group_set_gf2m163(ECGroup *group, ECCurveName name) ++{ ++ group->meth->field_mod = &ec_GF2m_163_mod; ++ group->meth->field_mul = &ec_GF2m_163_mul; ++ group->meth->field_sqr = &ec_GF2m_163_sqr; ++ return MP_OKAY; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,277 @@ ++/* ++ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for binary polynomial field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Sheueling Chang-Shantz , ++ * Stephen Fung , and ++ * Douglas Stebila , Sun Microsystems Laboratories. ++ * ++ *********************************************************************** */ ++ ++#include "ec2.h" ++#include "mp_gf2m.h" ++#include "mp_gf2m-priv.h" ++#include "mpi.h" ++#include "mpi-priv.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++/* Fast reduction for polynomials over a 193-bit curve. Assumes reduction ++ * polynomial with terms {193, 15, 0}. */ ++mp_err ++ec_GF2m_193_mod(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit *u, z; ++ ++ if (a != r) { ++ MP_CHECKOK(mp_copy(a, r)); ++ } ++#ifdef ECL_SIXTY_FOUR_BIT ++ if (MP_USED(r) < 7) { ++ MP_CHECKOK(s_mp_pad(r, 7)); ++ } ++ u = MP_DIGITS(r); ++ MP_USED(r) = 7; ++ ++ /* u[6] only has 2 significant bits */ ++ z = u[6]; ++ u[3] ^= (z << 14) ^ (z >> 1); ++ u[2] ^= (z << 63); ++ z = u[5]; ++ u[3] ^= (z >> 50); ++ u[2] ^= (z << 14) ^ (z >> 1); ++ u[1] ^= (z << 63); ++ z = u[4]; ++ u[2] ^= (z >> 50); ++ u[1] ^= (z << 14) ^ (z >> 1); ++ u[0] ^= (z << 63); ++ z = u[3] >> 1; /* z only has 63 significant bits */ ++ u[1] ^= (z >> 49); ++ u[0] ^= (z << 15) ^ z; ++ /* clear bits above 193 */ ++ u[6] = u[5] = u[4] = 0; ++ u[3] ^= z << 1; ++#else ++ if (MP_USED(r) < 13) { ++ MP_CHECKOK(s_mp_pad(r, 13)); ++ } ++ u = MP_DIGITS(r); ++ MP_USED(r) = 13; ++ ++ /* u[12] only has 2 significant bits */ ++ z = u[12]; ++ u[6] ^= (z << 14) ^ (z >> 1); ++ u[5] ^= (z << 31); ++ z = u[11]; ++ u[6] ^= (z >> 18); ++ u[5] ^= (z << 14) ^ (z >> 1); ++ u[4] ^= (z << 31); ++ z = u[10]; ++ u[5] ^= (z >> 18); ++ u[4] ^= (z << 14) ^ (z >> 1); ++ u[3] ^= (z << 31); ++ z = u[9]; ++ u[4] ^= (z >> 18); ++ u[3] ^= (z << 14) ^ (z >> 1); ++ u[2] ^= (z << 31); ++ z = u[8]; ++ u[3] ^= (z >> 18); ++ u[2] ^= (z << 14) ^ (z >> 1); ++ u[1] ^= (z << 31); ++ z = u[7]; ++ u[2] ^= (z >> 18); ++ u[1] ^= (z << 14) ^ (z >> 1); ++ u[0] ^= (z << 31); ++ z = u[6] >> 1; /* z only has 31 significant bits */ ++ u[1] ^= (z >> 17); ++ u[0] ^= (z << 15) ^ z; ++ /* clear bits above 193 */ ++ u[12] = u[11] = u[10] = u[9] = u[8] = u[7] = 0; ++ u[6] ^= z << 1; ++#endif ++ s_mp_clamp(r); ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Fast squaring for polynomials over a 193-bit curve. Assumes reduction ++ * polynomial with terms {193, 15, 0}. */ ++mp_err ++ec_GF2m_193_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit *u, *v; ++ ++ v = MP_DIGITS(a); ++ ++#ifdef ECL_SIXTY_FOUR_BIT ++ if (MP_USED(a) < 4) { ++ return mp_bsqrmod(a, meth->irr_arr, r); ++ } ++ if (MP_USED(r) < 7) { ++ MP_CHECKOK(s_mp_pad(r, 7)); ++ } ++ MP_USED(r) = 7; ++#else ++ if (MP_USED(a) < 7) { ++ return mp_bsqrmod(a, meth->irr_arr, r); ++ } ++ if (MP_USED(r) < 13) { ++ MP_CHECKOK(s_mp_pad(r, 13)); ++ } ++ MP_USED(r) = 13; ++#endif ++ u = MP_DIGITS(r); ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ u[12] = gf2m_SQR0(v[6]); ++ u[11] = gf2m_SQR1(v[5]); ++ u[10] = gf2m_SQR0(v[5]); ++ u[9] = gf2m_SQR1(v[4]); ++ u[8] = gf2m_SQR0(v[4]); ++ u[7] = gf2m_SQR1(v[3]); ++#endif ++ u[6] = gf2m_SQR0(v[3]); ++ u[5] = gf2m_SQR1(v[2]); ++ u[4] = gf2m_SQR0(v[2]); ++ u[3] = gf2m_SQR1(v[1]); ++ u[2] = gf2m_SQR0(v[1]); ++ u[1] = gf2m_SQR1(v[0]); ++ u[0] = gf2m_SQR0(v[0]); ++ return ec_GF2m_193_mod(r, r, meth); ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Fast multiplication for polynomials over a 193-bit curve. Assumes ++ * reduction polynomial with terms {193, 15, 0}. */ ++mp_err ++ec_GF2m_193_mul(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit a3 = 0, a2 = 0, a1 = 0, a0, b3 = 0, b2 = 0, b1 = 0, b0; ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ mp_digit a6 = 0, a5 = 0, a4 = 0, b6 = 0, b5 = 0, b4 = 0; ++ mp_digit rm[8]; ++#endif ++ ++ if (a == b) { ++ return ec_GF2m_193_sqr(a, r, meth); ++ } else { ++ switch (MP_USED(a)) { ++#ifdef ECL_THIRTY_TWO_BIT ++ case 7: ++ a6 = MP_DIGIT(a, 6); ++ case 6: ++ a5 = MP_DIGIT(a, 5); ++ case 5: ++ a4 = MP_DIGIT(a, 4); ++#endif ++ case 4: ++ a3 = MP_DIGIT(a, 3); ++ case 3: ++ a2 = MP_DIGIT(a, 2); ++ case 2: ++ a1 = MP_DIGIT(a, 1); ++ default: ++ a0 = MP_DIGIT(a, 0); ++ } ++ switch (MP_USED(b)) { ++#ifdef ECL_THIRTY_TWO_BIT ++ case 7: ++ b6 = MP_DIGIT(b, 6); ++ case 6: ++ b5 = MP_DIGIT(b, 5); ++ case 5: ++ b4 = MP_DIGIT(b, 4); ++#endif ++ case 4: ++ b3 = MP_DIGIT(b, 3); ++ case 3: ++ b2 = MP_DIGIT(b, 2); ++ case 2: ++ b1 = MP_DIGIT(b, 1); ++ default: ++ b0 = MP_DIGIT(b, 0); ++ } ++#ifdef ECL_SIXTY_FOUR_BIT ++ MP_CHECKOK(s_mp_pad(r, 8)); ++ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0); ++ MP_USED(r) = 8; ++ s_mp_clamp(r); ++#else ++ MP_CHECKOK(s_mp_pad(r, 14)); ++ s_bmul_3x3(MP_DIGITS(r) + 8, a6, a5, a4, b6, b5, b4); ++ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0); ++ s_bmul_4x4(rm, a3, a6 ^ a2, a5 ^ a1, a4 ^ a0, b3, b6 ^ b2, b5 ^ b1, ++ b4 ^ b0); ++ rm[7] ^= MP_DIGIT(r, 7); ++ rm[6] ^= MP_DIGIT(r, 6); ++ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 13); ++ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 12); ++ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 11); ++ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 10); ++ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 9); ++ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 8); ++ MP_DIGIT(r, 11) ^= rm[7]; ++ MP_DIGIT(r, 10) ^= rm[6]; ++ MP_DIGIT(r, 9) ^= rm[5]; ++ MP_DIGIT(r, 8) ^= rm[4]; ++ MP_DIGIT(r, 7) ^= rm[3]; ++ MP_DIGIT(r, 6) ^= rm[2]; ++ MP_DIGIT(r, 5) ^= rm[1]; ++ MP_DIGIT(r, 4) ^= rm[0]; ++ MP_USED(r) = 14; ++ s_mp_clamp(r); ++#endif ++ return ec_GF2m_193_mod(r, r, meth); ++ } ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Wire in fast field arithmetic for 193-bit curves. */ ++mp_err ++ec_group_set_gf2m193(ECGroup *group, ECCurveName name) ++{ ++ group->meth->field_mod = &ec_GF2m_193_mod; ++ group->meth->field_mul = &ec_GF2m_193_mul; ++ group->meth->field_sqr = &ec_GF2m_193_sqr; ++ return MP_OKAY; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,300 @@ ++/* ++ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for binary polynomial field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Sheueling Chang-Shantz , ++ * Stephen Fung , and ++ * Douglas Stebila , Sun Microsystems Laboratories. ++ * ++ *********************************************************************** */ ++ ++#include "ec2.h" ++#include "mp_gf2m.h" ++#include "mp_gf2m-priv.h" ++#include "mpi.h" ++#include "mpi-priv.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++/* Fast reduction for polynomials over a 233-bit curve. Assumes reduction ++ * polynomial with terms {233, 74, 0}. */ ++mp_err ++ec_GF2m_233_mod(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit *u, z; ++ ++ if (a != r) { ++ MP_CHECKOK(mp_copy(a, r)); ++ } ++#ifdef ECL_SIXTY_FOUR_BIT ++ if (MP_USED(r) < 8) { ++ MP_CHECKOK(s_mp_pad(r, 8)); ++ } ++ u = MP_DIGITS(r); ++ MP_USED(r) = 8; ++ ++ /* u[7] only has 18 significant bits */ ++ z = u[7]; ++ u[4] ^= (z << 33) ^ (z >> 41); ++ u[3] ^= (z << 23); ++ z = u[6]; ++ u[4] ^= (z >> 31); ++ u[3] ^= (z << 33) ^ (z >> 41); ++ u[2] ^= (z << 23); ++ z = u[5]; ++ u[3] ^= (z >> 31); ++ u[2] ^= (z << 33) ^ (z >> 41); ++ u[1] ^= (z << 23); ++ z = u[4]; ++ u[2] ^= (z >> 31); ++ u[1] ^= (z << 33) ^ (z >> 41); ++ u[0] ^= (z << 23); ++ z = u[3] >> 41; /* z only has 23 significant bits */ ++ u[1] ^= (z << 10); ++ u[0] ^= z; ++ /* clear bits above 233 */ ++ u[7] = u[6] = u[5] = u[4] = 0; ++ u[3] ^= z << 41; ++#else ++ if (MP_USED(r) < 15) { ++ MP_CHECKOK(s_mp_pad(r, 15)); ++ } ++ u = MP_DIGITS(r); ++ MP_USED(r) = 15; ++ ++ /* u[14] only has 18 significant bits */ ++ z = u[14]; ++ u[9] ^= (z << 1); ++ u[7] ^= (z >> 9); ++ u[6] ^= (z << 23); ++ z = u[13]; ++ u[9] ^= (z >> 31); ++ u[8] ^= (z << 1); ++ u[6] ^= (z >> 9); ++ u[5] ^= (z << 23); ++ z = u[12]; ++ u[8] ^= (z >> 31); ++ u[7] ^= (z << 1); ++ u[5] ^= (z >> 9); ++ u[4] ^= (z << 23); ++ z = u[11]; ++ u[7] ^= (z >> 31); ++ u[6] ^= (z << 1); ++ u[4] ^= (z >> 9); ++ u[3] ^= (z << 23); ++ z = u[10]; ++ u[6] ^= (z >> 31); ++ u[5] ^= (z << 1); ++ u[3] ^= (z >> 9); ++ u[2] ^= (z << 23); ++ z = u[9]; ++ u[5] ^= (z >> 31); ++ u[4] ^= (z << 1); ++ u[2] ^= (z >> 9); ++ u[1] ^= (z << 23); ++ z = u[8]; ++ u[4] ^= (z >> 31); ++ u[3] ^= (z << 1); ++ u[1] ^= (z >> 9); ++ u[0] ^= (z << 23); ++ z = u[7] >> 9; /* z only has 23 significant bits */ ++ u[3] ^= (z >> 22); ++ u[2] ^= (z << 10); ++ u[0] ^= z; ++ /* clear bits above 233 */ ++ u[14] = u[13] = u[12] = u[11] = u[10] = u[9] = u[8] = 0; ++ u[7] ^= z << 9; ++#endif ++ s_mp_clamp(r); ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Fast squaring for polynomials over a 233-bit curve. Assumes reduction ++ * polynomial with terms {233, 74, 0}. */ ++mp_err ++ec_GF2m_233_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit *u, *v; ++ ++ v = MP_DIGITS(a); ++ ++#ifdef ECL_SIXTY_FOUR_BIT ++ if (MP_USED(a) < 4) { ++ return mp_bsqrmod(a, meth->irr_arr, r); ++ } ++ if (MP_USED(r) < 8) { ++ MP_CHECKOK(s_mp_pad(r, 8)); ++ } ++ MP_USED(r) = 8; ++#else ++ if (MP_USED(a) < 8) { ++ return mp_bsqrmod(a, meth->irr_arr, r); ++ } ++ if (MP_USED(r) < 15) { ++ MP_CHECKOK(s_mp_pad(r, 15)); ++ } ++ MP_USED(r) = 15; ++#endif ++ u = MP_DIGITS(r); ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ u[14] = gf2m_SQR0(v[7]); ++ u[13] = gf2m_SQR1(v[6]); ++ u[12] = gf2m_SQR0(v[6]); ++ u[11] = gf2m_SQR1(v[5]); ++ u[10] = gf2m_SQR0(v[5]); ++ u[9] = gf2m_SQR1(v[4]); ++ u[8] = gf2m_SQR0(v[4]); ++#endif ++ u[7] = gf2m_SQR1(v[3]); ++ u[6] = gf2m_SQR0(v[3]); ++ u[5] = gf2m_SQR1(v[2]); ++ u[4] = gf2m_SQR0(v[2]); ++ u[3] = gf2m_SQR1(v[1]); ++ u[2] = gf2m_SQR0(v[1]); ++ u[1] = gf2m_SQR1(v[0]); ++ u[0] = gf2m_SQR0(v[0]); ++ return ec_GF2m_233_mod(r, r, meth); ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Fast multiplication for polynomials over a 233-bit curve. Assumes ++ * reduction polynomial with terms {233, 74, 0}. */ ++mp_err ++ec_GF2m_233_mul(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit a3 = 0, a2 = 0, a1 = 0, a0, b3 = 0, b2 = 0, b1 = 0, b0; ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ mp_digit a7 = 0, a6 = 0, a5 = 0, a4 = 0, b7 = 0, b6 = 0, b5 = 0, b4 = ++ 0; ++ mp_digit rm[8]; ++#endif ++ ++ if (a == b) { ++ return ec_GF2m_233_sqr(a, r, meth); ++ } else { ++ switch (MP_USED(a)) { ++#ifdef ECL_THIRTY_TWO_BIT ++ case 8: ++ a7 = MP_DIGIT(a, 7); ++ case 7: ++ a6 = MP_DIGIT(a, 6); ++ case 6: ++ a5 = MP_DIGIT(a, 5); ++ case 5: ++ a4 = MP_DIGIT(a, 4); ++#endif ++ case 4: ++ a3 = MP_DIGIT(a, 3); ++ case 3: ++ a2 = MP_DIGIT(a, 2); ++ case 2: ++ a1 = MP_DIGIT(a, 1); ++ default: ++ a0 = MP_DIGIT(a, 0); ++ } ++ switch (MP_USED(b)) { ++#ifdef ECL_THIRTY_TWO_BIT ++ case 8: ++ b7 = MP_DIGIT(b, 7); ++ case 7: ++ b6 = MP_DIGIT(b, 6); ++ case 6: ++ b5 = MP_DIGIT(b, 5); ++ case 5: ++ b4 = MP_DIGIT(b, 4); ++#endif ++ case 4: ++ b3 = MP_DIGIT(b, 3); ++ case 3: ++ b2 = MP_DIGIT(b, 2); ++ case 2: ++ b1 = MP_DIGIT(b, 1); ++ default: ++ b0 = MP_DIGIT(b, 0); ++ } ++#ifdef ECL_SIXTY_FOUR_BIT ++ MP_CHECKOK(s_mp_pad(r, 8)); ++ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0); ++ MP_USED(r) = 8; ++ s_mp_clamp(r); ++#else ++ MP_CHECKOK(s_mp_pad(r, 16)); ++ s_bmul_4x4(MP_DIGITS(r) + 8, a7, a6, a5, a4, b7, b6, b5, b4); ++ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0); ++ s_bmul_4x4(rm, a7 ^ a3, a6 ^ a2, a5 ^ a1, a4 ^ a0, b7 ^ b3, ++ b6 ^ b2, b5 ^ b1, b4 ^ b0); ++ rm[7] ^= MP_DIGIT(r, 7) ^ MP_DIGIT(r, 15); ++ rm[6] ^= MP_DIGIT(r, 6) ^ MP_DIGIT(r, 14); ++ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 13); ++ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 12); ++ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 11); ++ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 10); ++ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 9); ++ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 8); ++ MP_DIGIT(r, 11) ^= rm[7]; ++ MP_DIGIT(r, 10) ^= rm[6]; ++ MP_DIGIT(r, 9) ^= rm[5]; ++ MP_DIGIT(r, 8) ^= rm[4]; ++ MP_DIGIT(r, 7) ^= rm[3]; ++ MP_DIGIT(r, 6) ^= rm[2]; ++ MP_DIGIT(r, 5) ^= rm[1]; ++ MP_DIGIT(r, 4) ^= rm[0]; ++ MP_USED(r) = 16; ++ s_mp_clamp(r); ++#endif ++ return ec_GF2m_233_mod(r, r, meth); ++ } ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Wire in fast field arithmetic for 233-bit curves. */ ++mp_err ++ec_group_set_gf2m233(ECGroup *group, ECCurveName name) ++{ ++ group->meth->field_mod = &ec_GF2m_233_mod; ++ group->meth->field_mul = &ec_GF2m_233_mul; ++ group->meth->field_sqr = &ec_GF2m_233_sqr; ++ return MP_OKAY; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,349 @@ ++/* ++ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for binary polynomial field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Douglas Stebila , Sun Microsystems Laboratories ++ * ++ * Last Modified Date from the Original Code: May 2017 ++ *********************************************************************** */ ++ ++#include "ec2.h" ++#include "mplogic.h" ++#include "mp_gf2m.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ ++mp_err ++ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py) ++{ ++ ++ if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) { ++ return MP_YES; ++ } else { ++ return MP_NO; ++ } ++ ++} ++ ++/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */ ++mp_err ++ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py) ++{ ++ mp_zero(px); ++ mp_zero(py); ++ return MP_OKAY; ++} ++ ++/* Computes R = P + Q based on IEEE P1363 A.10.2. Elliptic curve points P, ++ * Q, and R can all be identical. Uses affine coordinates. */ ++mp_err ++ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx, ++ const mp_int *qy, mp_int *rx, mp_int *ry, ++ const ECGroup *group) ++{ ++ mp_err res = MP_OKAY; ++ mp_int lambda, tempx, tempy; ++ ++ MP_DIGITS(&lambda) = 0; ++ MP_DIGITS(&tempx) = 0; ++ MP_DIGITS(&tempy) = 0; ++ MP_CHECKOK(mp_init(&lambda, FLAG(px))); ++ MP_CHECKOK(mp_init(&tempx, FLAG(px))); ++ MP_CHECKOK(mp_init(&tempy, FLAG(px))); ++ /* if P = inf, then R = Q */ ++ if (ec_GF2m_pt_is_inf_aff(px, py) == 0) { ++ MP_CHECKOK(mp_copy(qx, rx)); ++ MP_CHECKOK(mp_copy(qy, ry)); ++ res = MP_OKAY; ++ goto CLEANUP; ++ } ++ /* if Q = inf, then R = P */ ++ if (ec_GF2m_pt_is_inf_aff(qx, qy) == 0) { ++ MP_CHECKOK(mp_copy(px, rx)); ++ MP_CHECKOK(mp_copy(py, ry)); ++ res = MP_OKAY; ++ goto CLEANUP; ++ } ++ /* if px != qx, then lambda = (py+qy) / (px+qx), tempx = a + lambda^2 ++ * + lambda + px + qx */ ++ if (mp_cmp(px, qx) != 0) { ++ MP_CHECKOK(group->meth->field_add(py, qy, &tempy, group->meth)); ++ MP_CHECKOK(group->meth->field_add(px, qx, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_div(&tempy, &tempx, &lambda, group->meth)); ++ MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempx, &lambda, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempx, &group->curvea, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempx, px, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempx, qx, &tempx, group->meth)); ++ } else { ++ /* if py != qy or qx = 0, then R = inf */ ++ if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qx) == 0)) { ++ mp_zero(rx); ++ mp_zero(ry); ++ res = MP_OKAY; ++ goto CLEANUP; ++ } ++ /* lambda = qx + qy / qx */ ++ MP_CHECKOK(group->meth->field_div(qy, qx, &lambda, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&lambda, qx, &lambda, group->meth)); ++ /* tempx = a + lambda^2 + lambda */ ++ MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempx, &lambda, &tempx, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempx, &group->curvea, &tempx, group->meth)); ++ } ++ /* ry = (qx + tempx) * lambda + tempx + qy */ ++ MP_CHECKOK(group->meth->field_add(qx, &tempx, &tempy, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_mul(&tempy, &lambda, &tempy, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_add(&tempy, &tempx, &tempy, group->meth)); ++ MP_CHECKOK(group->meth->field_add(&tempy, qy, ry, group->meth)); ++ /* rx = tempx */ ++ MP_CHECKOK(mp_copy(&tempx, rx)); ++ ++ CLEANUP: ++ mp_clear(&lambda); ++ mp_clear(&tempx); ++ mp_clear(&tempy); ++ return res; ++} ++ ++/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be ++ * identical. Uses affine coordinates. */ ++mp_err ++ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx, ++ const mp_int *qy, mp_int *rx, mp_int *ry, ++ const ECGroup *group) ++{ ++ mp_err res = MP_OKAY; ++ mp_int nqy; ++ ++ MP_DIGITS(&nqy) = 0; ++ MP_CHECKOK(mp_init(&nqy, FLAG(px))); ++ /* nqy = qx+qy */ ++ MP_CHECKOK(group->meth->field_add(qx, qy, &nqy, group->meth)); ++ MP_CHECKOK(group->point_add(px, py, qx, &nqy, rx, ry, group)); ++ CLEANUP: ++ mp_clear(&nqy); ++ return res; ++} ++ ++/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses ++ * affine coordinates. */ ++mp_err ++ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx, ++ mp_int *ry, const ECGroup *group) ++{ ++ return group->point_add(px, py, px, py, rx, ry, group); ++} ++ ++/* by default, this routine is unused and thus doesn't need to be compiled */ ++#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF ++/* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and ++ * R can be identical. Uses affine coordinates. */ ++mp_err ++ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py, ++ mp_int *rx, mp_int *ry, const ECGroup *group) ++{ ++ mp_err res = MP_OKAY; ++ mp_int k, k3, qx, qy, sx, sy; ++ int b1, b3, i, l; ++ ++ MP_DIGITS(&k) = 0; ++ MP_DIGITS(&k3) = 0; ++ MP_DIGITS(&qx) = 0; ++ MP_DIGITS(&qy) = 0; ++ MP_DIGITS(&sx) = 0; ++ MP_DIGITS(&sy) = 0; ++ MP_CHECKOK(mp_init(&k)); ++ MP_CHECKOK(mp_init(&k3)); ++ MP_CHECKOK(mp_init(&qx)); ++ MP_CHECKOK(mp_init(&qy)); ++ MP_CHECKOK(mp_init(&sx)); ++ MP_CHECKOK(mp_init(&sy)); ++ ++ /* if n = 0 then r = inf */ ++ if (mp_cmp_z(n) == 0) { ++ mp_zero(rx); ++ mp_zero(ry); ++ res = MP_OKAY; ++ goto CLEANUP; ++ } ++ /* Q = P, k = n */ ++ MP_CHECKOK(mp_copy(px, &qx)); ++ MP_CHECKOK(mp_copy(py, &qy)); ++ MP_CHECKOK(mp_copy(n, &k)); ++ /* if n < 0 then Q = -Q, k = -k */ ++ if (mp_cmp_z(n) < 0) { ++ MP_CHECKOK(group->meth->field_add(&qx, &qy, &qy, group->meth)); ++ MP_CHECKOK(mp_neg(&k, &k)); ++ } ++#ifdef ECL_DEBUG /* basic double and add method */ ++ l = mpl_significant_bits(&k) - 1; ++ MP_CHECKOK(mp_copy(&qx, &sx)); ++ MP_CHECKOK(mp_copy(&qy, &sy)); ++ for (i = l - 1; i >= 0; i--) { ++ /* S = 2S */ ++ MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group)); ++ /* if k_i = 1, then S = S + Q */ ++ if (mpl_get_bit(&k, i) != 0) { ++ MP_CHECKOK(group-> ++ point_add(&sx, &sy, &qx, &qy, &sx, &sy, group)); ++ } ++ } ++#else /* double and add/subtract method from ++ * standard */ ++ /* k3 = 3 * k */ ++ MP_CHECKOK(mp_set_int(&k3, 3)); ++ MP_CHECKOK(mp_mul(&k, &k3, &k3)); ++ /* S = Q */ ++ MP_CHECKOK(mp_copy(&qx, &sx)); ++ MP_CHECKOK(mp_copy(&qy, &sy)); ++ /* l = index of high order bit in binary representation of 3*k */ ++ l = mpl_significant_bits(&k3) - 1; ++ /* for i = l-1 downto 1 */ ++ for (i = l - 1; i >= 1; i--) { ++ /* S = 2S */ ++ MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group)); ++ b3 = MP_GET_BIT(&k3, i); ++ b1 = MP_GET_BIT(&k, i); ++ /* if k3_i = 1 and k_i = 0, then S = S + Q */ ++ if ((b3 == 1) && (b1 == 0)) { ++ MP_CHECKOK(group-> ++ point_add(&sx, &sy, &qx, &qy, &sx, &sy, group)); ++ /* if k3_i = 0 and k_i = 1, then S = S - Q */ ++ } else if ((b3 == 0) && (b1 == 1)) { ++ MP_CHECKOK(group-> ++ point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group)); ++ } ++ } ++#endif ++ /* output S */ ++ MP_CHECKOK(mp_copy(&sx, rx)); ++ MP_CHECKOK(mp_copy(&sy, ry)); ++ ++ CLEANUP: ++ mp_clear(&k); ++ mp_clear(&k3); ++ mp_clear(&qx); ++ mp_clear(&qy); ++ mp_clear(&sx); ++ mp_clear(&sy); ++ return res; ++} ++#endif ++ ++/* Validates a point on a GF2m curve. */ ++mp_err ++ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group) ++{ ++ mp_err res = MP_NO; ++ mp_int accl, accr, tmp, pxt, pyt; ++ ++ MP_DIGITS(&accl) = 0; ++ MP_DIGITS(&accr) = 0; ++ MP_DIGITS(&tmp) = 0; ++ MP_DIGITS(&pxt) = 0; ++ MP_DIGITS(&pyt) = 0; ++ MP_CHECKOK(mp_init(&accl, FLAG(px))); ++ MP_CHECKOK(mp_init(&accr, FLAG(px))); ++ MP_CHECKOK(mp_init(&tmp, FLAG(px))); ++ MP_CHECKOK(mp_init(&pxt, FLAG(px))); ++ MP_CHECKOK(mp_init(&pyt, FLAG(px))); ++ ++ /* 1: Verify that publicValue is not the point at infinity */ ++ if (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES) { ++ res = MP_NO; ++ goto CLEANUP; ++ } ++ /* 2: Verify that the coordinates of publicValue are elements ++ * of the field. ++ */ ++ if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) || ++ (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) { ++ res = MP_NO; ++ goto CLEANUP; ++ } ++ /* 3: Verify that publicValue is on the curve. */ ++ if (group->meth->field_enc) { ++ group->meth->field_enc(px, &pxt, group->meth); ++ group->meth->field_enc(py, &pyt, group->meth); ++ } else { ++ mp_copy(px, &pxt); ++ mp_copy(py, &pyt); ++ } ++ /* left-hand side: y^2 + x*y */ ++ MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) ); ++ MP_CHECKOK( group->meth->field_mul(&pxt, &pyt, &tmp, group->meth) ); ++ MP_CHECKOK( group->meth->field_add(&accl, &tmp, &accl, group->meth) ); ++ /* right-hand side: x^3 + a*x^2 + b */ ++ MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) ); ++ MP_CHECKOK( group->meth->field_mul(&pxt, &tmp, &accr, group->meth) ); ++ MP_CHECKOK( group->meth->field_mul(&group->curvea, &tmp, &tmp, group->meth) ); ++ MP_CHECKOK( group->meth->field_add(&tmp, &accr, &accr, group->meth) ); ++ MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->meth) ); ++ /* check LHS - RHS == 0 */ ++ MP_CHECKOK( group->meth->field_add(&accl, &accr, &accr, group->meth) ); ++ if (mp_cmp_z(&accr) != 0) { ++ res = MP_NO; ++ goto CLEANUP; ++ } ++ /* 4: Verify that the order of the curve times the publicValue ++ * is the point at infinity. ++ */ ++ /* timing mitigation is not supported */ ++ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) ); ++ if (ec_GF2m_pt_is_inf_aff(&pxt, &pyt) != MP_YES) { ++ res = MP_NO; ++ goto CLEANUP; ++ } ++ ++ res = MP_YES; ++ ++CLEANUP: ++ mp_clear(&accl); ++ mp_clear(&accr); ++ mp_clear(&tmp); ++ mp_clear(&pxt); ++ mp_clear(&pyt); ++ return res; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,126 @@ ++/* ++ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for binary polynomial field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Douglas Stebila , Sun Microsystems Laboratories ++ * ++ * Last Modified Date from the Original Code: May 2017 ++ *********************************************************************** */ ++ ++#ifndef _EC2_H ++#define _EC2_H ++ ++#include "ecl-priv.h" ++ ++/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ ++mp_err ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py); ++ ++/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */ ++mp_err ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py); ++ ++/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx, ++ * qy). Uses affine coordinates. */ ++mp_err ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py, ++ const mp_int *qx, const mp_int *qy, mp_int *rx, ++ mp_int *ry, const ECGroup *group); ++ ++/* Computes R = P - Q. Uses affine coordinates. */ ++mp_err ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py, ++ const mp_int *qx, const mp_int *qy, mp_int *rx, ++ mp_int *ry, const ECGroup *group); ++ ++/* Computes R = 2P. Uses affine coordinates. */ ++mp_err ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx, ++ mp_int *ry, const ECGroup *group); ++ ++/* Validates a point on a GF2m curve. */ ++mp_err ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group); ++ ++/* by default, this routine is unused and thus doesn't need to be compiled */ ++#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF ++/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters ++ * a, b and p are the elliptic curve coefficients and the irreducible that ++ * determines the field GF2m. Uses affine coordinates. */ ++mp_err ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px, ++ const mp_int *py, mp_int *rx, mp_int *ry, ++ const ECGroup *group); ++#endif ++ ++/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters ++ * a, b and p are the elliptic curve coefficients and the irreducible that ++ * determines the field GF2m. Uses Montgomery projective coordinates. */ ++mp_err ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, ++ const mp_int *py, mp_int *rx, mp_int *ry, ++ const ECGroup *group, int timing); ++ ++#ifdef ECL_ENABLE_GF2M_PROJ ++/* Converts a point P(px, py) from affine coordinates to projective ++ * coordinates R(rx, ry, rz). */ ++mp_err ec_GF2m_pt_aff2proj(const mp_int *px, const mp_int *py, mp_int *rx, ++ mp_int *ry, mp_int *rz, const ECGroup *group); ++ ++/* Converts a point P(px, py, pz) from projective coordinates to affine ++ * coordinates R(rx, ry). */ ++mp_err ec_GF2m_pt_proj2aff(const mp_int *px, const mp_int *py, ++ const mp_int *pz, mp_int *rx, mp_int *ry, ++ const ECGroup *group); ++ ++/* Checks if point P(px, py, pz) is at infinity. Uses projective ++ * coordinates. */ ++mp_err ec_GF2m_pt_is_inf_proj(const mp_int *px, const mp_int *py, ++ const mp_int *pz); ++ ++/* Sets P(px, py, pz) to be the point at infinity. Uses projective ++ * coordinates. */ ++mp_err ec_GF2m_pt_set_inf_proj(mp_int *px, mp_int *py, mp_int *pz); ++ ++/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is ++ * (qx, qy, qz). Uses projective coordinates. */ ++mp_err ec_GF2m_pt_add_proj(const mp_int *px, const mp_int *py, ++ const mp_int *pz, const mp_int *qx, ++ const mp_int *qy, mp_int *rx, mp_int *ry, ++ mp_int *rz, const ECGroup *group); ++ ++/* Computes R = 2P. Uses projective coordinates. */ ++mp_err ec_GF2m_pt_dbl_proj(const mp_int *px, const mp_int *py, ++ const mp_int *pz, mp_int *rx, mp_int *ry, ++ mp_int *rz, const ECGroup *group); ++ ++/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters ++ * a, b and p are the elliptic curve coefficients and the prime that ++ * determines the field GF2m. Uses projective coordinates. */ ++mp_err ec_GF2m_pt_mul_proj(const mp_int *n, const mp_int *px, ++ const mp_int *py, mp_int *rx, mp_int *ry, ++ const ECGroup *group); ++#endif ++ ++#endif /* _EC2_H */ +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,278 @@ ++/* ++ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for binary polynomial field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Sheueling Chang-Shantz , ++ * Stephen Fung , and ++ * Douglas Stebila , Sun Microsystems Laboratories. ++ * ++ * Last Modified Date from the Original Code: May 2017 ++ *********************************************************************** */ ++ ++#include "ec2.h" ++#include "mplogic.h" ++#include "mp_gf2m.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery ++ * projective coordinates. Uses algorithm Mdouble in appendix of Lopez, J. ++ * and Dahab, R. "Fast multiplication on elliptic curves over GF(2^m) ++ * without precomputation". modified to not require precomputation of ++ * c=b^{2^{m-1}}. */ ++static mp_err ++gf2m_Mdouble(mp_int *x, mp_int *z, const ECGroup *group, int kmflag) ++{ ++ mp_err res = MP_OKAY; ++ mp_int t1; ++ ++ MP_DIGITS(&t1) = 0; ++ MP_CHECKOK(mp_init(&t1, kmflag)); ++ ++ MP_CHECKOK(group->meth->field_sqr(x, x, group->meth)); ++ MP_CHECKOK(group->meth->field_sqr(z, &t1, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(x, &t1, z, group->meth)); ++ MP_CHECKOK(group->meth->field_sqr(x, x, group->meth)); ++ MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth)); ++ MP_CHECKOK(group->meth-> ++ field_mul(&group->curveb, &t1, &t1, group->meth)); ++ MP_CHECKOK(group->meth->field_add(x, &t1, x, group->meth)); ++ ++ CLEANUP: ++ mp_clear(&t1); ++ return res; ++} ++ ++/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in ++ * Montgomery projective coordinates. Uses algorithm Madd in appendix of ++ * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over ++ * GF(2^m) without precomputation". */ ++static mp_err ++gf2m_Madd(const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, mp_int *z2, ++ const ECGroup *group, int kmflag) ++{ ++ mp_err res = MP_OKAY; ++ mp_int t1, t2; ++ ++ MP_DIGITS(&t1) = 0; ++ MP_DIGITS(&t2) = 0; ++ MP_CHECKOK(mp_init(&t1, kmflag)); ++ MP_CHECKOK(mp_init(&t2, kmflag)); ++ ++ MP_CHECKOK(mp_copy(x, &t1)); ++ MP_CHECKOK(group->meth->field_mul(x1, z2, x1, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(z1, x2, z1, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(x1, z1, &t2, group->meth)); ++ MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); ++ MP_CHECKOK(group->meth->field_sqr(z1, z1, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(z1, &t1, x1, group->meth)); ++ MP_CHECKOK(group->meth->field_add(x1, &t2, x1, group->meth)); ++ ++ CLEANUP: ++ mp_clear(&t1); ++ mp_clear(&t2); ++ return res; ++} ++ ++/* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2) ++ * using Montgomery point multiplication algorithm Mxy() in appendix of ++ * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over ++ * GF(2^m) without precomputation". Returns: 0 on error 1 if return value ++ * should be the point at infinity 2 otherwise */ ++static int ++gf2m_Mxy(const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1, ++ mp_int *x2, mp_int *z2, const ECGroup *group) ++{ ++ mp_err res = MP_OKAY; ++ int ret = 0; ++ mp_int t3, t4, t5; ++ ++ MP_DIGITS(&t3) = 0; ++ MP_DIGITS(&t4) = 0; ++ MP_DIGITS(&t5) = 0; ++ MP_CHECKOK(mp_init(&t3, FLAG(x2))); ++ MP_CHECKOK(mp_init(&t4, FLAG(x2))); ++ MP_CHECKOK(mp_init(&t5, FLAG(x2))); ++ ++ if (mp_cmp_z(z1) == 0) { ++ mp_zero(x2); ++ mp_zero(z2); ++ ret = 1; ++ goto CLEANUP; ++ } ++ ++ if (mp_cmp_z(z2) == 0) { ++ MP_CHECKOK(mp_copy(x, x2)); ++ MP_CHECKOK(group->meth->field_add(x, y, z2, group->meth)); ++ ret = 2; ++ goto CLEANUP; ++ } ++ ++ MP_CHECKOK(mp_set_int(&t5, 1)); ++ if (group->meth->field_enc) { ++ MP_CHECKOK(group->meth->field_enc(&t5, &t5, group->meth)); ++ } ++ ++ MP_CHECKOK(group->meth->field_mul(z1, z2, &t3, group->meth)); ++ ++ MP_CHECKOK(group->meth->field_mul(z1, x, z1, group->meth)); ++ MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(z2, x, z2, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(z2, x1, x1, group->meth)); ++ MP_CHECKOK(group->meth->field_add(z2, x2, z2, group->meth)); ++ ++ MP_CHECKOK(group->meth->field_mul(z2, z1, z2, group->meth)); ++ MP_CHECKOK(group->meth->field_sqr(x, &t4, group->meth)); ++ MP_CHECKOK(group->meth->field_add(&t4, y, &t4, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(&t4, &t3, &t4, group->meth)); ++ MP_CHECKOK(group->meth->field_add(&t4, z2, &t4, group->meth)); ++ ++ MP_CHECKOK(group->meth->field_mul(&t3, x, &t3, group->meth)); ++ MP_CHECKOK(group->meth->field_div(&t5, &t3, &t3, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(&t3, &t4, &t4, group->meth)); ++ MP_CHECKOK(group->meth->field_mul(x1, &t3, x2, group->meth)); ++ MP_CHECKOK(group->meth->field_add(x2, x, z2, group->meth)); ++ ++ MP_CHECKOK(group->meth->field_mul(z2, &t4, z2, group->meth)); ++ MP_CHECKOK(group->meth->field_add(z2, y, z2, group->meth)); ++ ++ ret = 2; ++ ++ CLEANUP: ++ mp_clear(&t3); ++ mp_clear(&t4); ++ mp_clear(&t5); ++ if (res == MP_OKAY) { ++ return ret; ++ } else { ++ return 0; ++ } ++} ++ ++/* Computes R = nP based on algorithm 2P of Lopex, J. and Dahab, R. "Fast ++ * multiplication on elliptic curves over GF(2^m) without ++ * precomputation". Elliptic curve points P and R can be identical. Uses ++ * Montgomery projective coordinates. The timing parameter is ignored ++ * because this algorithm resists timing attacks by default. */ ++mp_err ++ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, const mp_int *py, ++ mp_int *rx, mp_int *ry, const ECGroup *group, ++ int timing) ++{ ++ mp_err res = MP_OKAY; ++ mp_int x1, x2, z1, z2; ++ int i, j; ++ mp_digit top_bit, mask; ++ ++ MP_DIGITS(&x1) = 0; ++ MP_DIGITS(&x2) = 0; ++ MP_DIGITS(&z1) = 0; ++ MP_DIGITS(&z2) = 0; ++ MP_CHECKOK(mp_init(&x1, FLAG(n))); ++ MP_CHECKOK(mp_init(&x2, FLAG(n))); ++ MP_CHECKOK(mp_init(&z1, FLAG(n))); ++ MP_CHECKOK(mp_init(&z2, FLAG(n))); ++ ++ /* if result should be point at infinity */ ++ if ((mp_cmp_z(n) == 0) || (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES)) { ++ MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry)); ++ goto CLEANUP; ++ } ++ ++ MP_CHECKOK(mp_copy(px, &x1)); /* x1 = px */ ++ MP_CHECKOK(mp_set_int(&z1, 1)); /* z1 = 1 */ ++ MP_CHECKOK(group->meth->field_sqr(&x1, &z2, group->meth)); /* z2 = ++ * x1^2 = ++ * px^2 */ ++ MP_CHECKOK(group->meth->field_sqr(&z2, &x2, group->meth)); ++ MP_CHECKOK(group->meth->field_add(&x2, &group->curveb, &x2, group->meth)); /* x2 ++ * = ++ * px^4 ++ * + ++ * b ++ */ ++ ++ /* find top-most bit and go one past it */ ++ i = MP_USED(n) - 1; ++ j = MP_DIGIT_BIT - 1; ++ top_bit = 1; ++ top_bit <<= MP_DIGIT_BIT - 1; ++ mask = top_bit; ++ while (!(MP_DIGITS(n)[i] & mask)) { ++ mask >>= 1; ++ j--; ++ } ++ mask >>= 1; ++ j--; ++ ++ /* if top most bit was at word break, go to next word */ ++ if (!mask) { ++ i--; ++ j = MP_DIGIT_BIT - 1; ++ mask = top_bit; ++ } ++ ++ for (; i >= 0; i--) { ++ for (; j >= 0; j--) { ++ if (MP_DIGITS(n)[i] & mask) { ++ MP_CHECKOK(gf2m_Madd(px, &x1, &z1, &x2, &z2, group, FLAG(n))); ++ MP_CHECKOK(gf2m_Mdouble(&x2, &z2, group, FLAG(n))); ++ } else { ++ MP_CHECKOK(gf2m_Madd(px, &x2, &z2, &x1, &z1, group, FLAG(n))); ++ MP_CHECKOK(gf2m_Mdouble(&x1, &z1, group, FLAG(n))); ++ } ++ mask >>= 1; ++ } ++ j = MP_DIGIT_BIT - 1; ++ mask = top_bit; ++ } ++ ++ /* convert out of "projective" coordinates */ ++ i = gf2m_Mxy(px, py, &x1, &z1, &x2, &z2, group); ++ if (i == 0) { ++ res = MP_BADARG; ++ goto CLEANUP; ++ } else if (i == 1) { ++ MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry)); ++ } else { ++ MP_CHECKOK(mp_copy(&x2, rx)); ++ MP_CHECKOK(mp_copy(&z2, ry)); ++ } ++ ++ CLEANUP: ++ mp_clear(&x1); ++ mp_clear(&x2); ++ mp_clear(&z1); ++ mp_clear(&z2); ++ return res; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.c 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.c 2025-05-09 10:05:57.616290593 +0800 +@@ -39,6 +39,7 @@ + #include "mplogic.h" + #include "ecl.h" + #include "ecl-priv.h" ++#include "ec2.h" + #include "ecp.h" + #ifndef _KERNEL + #include +@@ -169,6 +170,50 @@ + return group; + } + ++#ifdef NSS_ECC_MORE_THAN_SUITE_B ++/* Construct a generic ECGroup for elliptic curves over binary polynomial ++ * fields. */ ++ECGroup * ++ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5], ++ const mp_int *curvea, const mp_int *curveb, ++ const mp_int *genx, const mp_int *geny, ++ const mp_int *order, int cofactor) ++{ ++ mp_err res = MP_OKAY; ++ ECGroup *group = NULL; ++ ++ group = ECGroup_new(FLAG(irr)); ++ if (group == NULL) ++ return NULL; ++ ++ group->meth = GFMethod_consGF2m(irr, irr_arr); ++ if (group->meth == NULL) { ++ res = MP_MEM; ++ goto CLEANUP; ++ } ++ MP_CHECKOK(mp_copy(curvea, &group->curvea)); ++ MP_CHECKOK(mp_copy(curveb, &group->curveb)); ++ MP_CHECKOK(mp_copy(genx, &group->genx)); ++ MP_CHECKOK(mp_copy(geny, &group->geny)); ++ MP_CHECKOK(mp_copy(order, &group->order)); ++ group->cofactor = cofactor; ++ group->point_add = &ec_GF2m_pt_add_aff; ++ group->point_sub = &ec_GF2m_pt_sub_aff; ++ group->point_dbl = &ec_GF2m_pt_dbl_aff; ++ group->point_mul = &ec_GF2m_pt_mul_mont; ++ group->base_point_mul = NULL; ++ group->points_mul = &ec_pts_mul_basic; ++ group->validate_point = &ec_GF2m_validate_point; ++ ++ CLEANUP: ++ if (res != MP_OKAY) { ++ ECGroup_free(group); ++ return NULL; ++ } ++ return group; ++} ++#endif ++ + /* Construct ECGroup from hex parameters and name, if any. Called by + * ECGroup_fromHex and ECGroup_fromName. */ + ECGroup * +@@ -209,10 +254,85 @@ + + /* determine which optimizations (if any) to use */ + if (params->field == ECField_GFp) { ++#ifdef NSS_ECC_MORE_THAN_SUITE_B ++ switch (name) { ++#ifdef ECL_USE_FP ++ case ECCurve_SECG_PRIME_160R1: ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_secp160r1_fp(group)); ++ break; ++#endif ++ case ECCurve_SECG_PRIME_192R1: ++#ifdef ECL_USE_FP ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_nistp192_fp(group)); ++#else ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_gfp192(group, name)); ++#endif ++ break; ++ case ECCurve_SECG_PRIME_224R1: ++#ifdef ECL_USE_FP ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_nistp224_fp(group)); ++#else ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_gfp224(group, name)); ++#endif ++ break; ++ case ECCurve_SECG_PRIME_256R1: ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_gfp256(group, name)); ++ break; ++ case ECCurve_SECG_PRIME_521R1: ++ group = ++ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, ++ &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ MP_CHECKOK(ec_group_set_gfp521(group, name)); ++ break; ++ default: ++ /* use generic arithmetic */ ++#endif + group = + ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, + &order, params->cofactor); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++#ifdef NSS_ECC_MORE_THAN_SUITE_B ++ } ++ } else if (params->field == ECField_GF2m) { ++ group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor); ++ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } ++ if ((name == ECCurve_NIST_K163) || ++ (name == ECCurve_NIST_B163) || ++ (name == ECCurve_SECG_CHAR2_163R1)) { ++ MP_CHECKOK(ec_group_set_gf2m163(group, name)); ++ } else if ((name == ECCurve_SECG_CHAR2_193R1) || ++ (name == ECCurve_SECG_CHAR2_193R2)) { ++ MP_CHECKOK(ec_group_set_gf2m193(group, name)); ++ } else if ((name == ECCurve_NIST_K233) || ++ (name == ECCurve_NIST_B233)) { ++ MP_CHECKOK(ec_group_set_gf2m233(group, name)); ++ } ++#endif + } else { + res = MP_UNDEF; + goto CLEANUP; +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h 2025-05-09 10:05:57.616290593 +0800 +@@ -44,6 +44,25 @@ + #endif + + /* NIST prime curves */ ++static const ECCurveParams ecCurve_NIST_P192 = { ++ "NIST-P192", ECField_GFp, 192, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", ++ "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", ++ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", ++ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", ++ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", 1 ++}; ++ ++static const ECCurveParams ecCurve_NIST_P224 = { ++ "NIST-P224", ECField_GFp, 224, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", ++ "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", ++ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", ++ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", 1 ++}; + + static const ECCurveParams ecCurve_NIST_P256 = { + "NIST-P256", ECField_GFp, 256, +@@ -77,7 +96,411 @@ + 1 + }; + ++/* NIST binary curves */ ++static const ECCurveParams ecCurve_NIST_K163 = { ++ "NIST-K163", ECField_GF2m, 163, ++ "0800000000000000000000000000000000000000C9", ++ "000000000000000000000000000000000000000001", ++ "000000000000000000000000000000000000000001", ++ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8", ++ "0289070FB05D38FF58321F2E800536D538CCDAA3D9", ++ "04000000000000000000020108A2E0CC0D99F8A5EF", 2 ++}; ++ ++static const ECCurveParams ecCurve_NIST_B163 = { ++ "NIST-B163", ECField_GF2m, 163, ++ "0800000000000000000000000000000000000000C9", ++ "000000000000000000000000000000000000000001", ++ "020A601907B8C953CA1481EB10512F78744A3205FD", ++ "03F0EBA16286A2D57EA0991168D4994637E8343E36", ++ "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", ++ "040000000000000000000292FE77E70C12A4234C33", 2 ++}; ++ ++static const ECCurveParams ecCurve_NIST_K233 = { ++ "NIST-K233", ECField_GF2m, 233, ++ "020000000000000000000000000000000000000004000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126", ++ "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", ++ "008000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", 4 ++}; ++ ++static const ECCurveParams ecCurve_NIST_B233 = { ++ "NIST-B233", ECField_GF2m, 233, ++ "020000000000000000000000000000000000000004000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", ++ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B", ++ "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", ++ "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 2 ++}; ++ ++static const ECCurveParams ecCurve_NIST_K283 = { ++ "NIST-K283", ECField_GF2m, 283, ++ "0800000000000000000000000000000000000000000000000000000000000000000010A1", ++ "000000000000000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836", ++ "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", ++ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", 4 ++}; ++ ++static const ECCurveParams ecCurve_NIST_B283 = { ++ "NIST-B283", ECField_GF2m, 283, ++ "0800000000000000000000000000000000000000000000000000000000000000000010A1", ++ "000000000000000000000000000000000000000000000000000000000000000000000001", ++ "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", ++ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", ++ "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", ++ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", 2 ++}; ++ ++static const ECCurveParams ecCurve_NIST_K409 = { ++ "NIST-K409", ECField_GF2m, 409, ++ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746", ++ "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", ++ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", 4 ++}; ++ ++static const ECCurveParams ecCurve_NIST_B409 = { ++ "NIST-B409", ECField_GF2m, 409, ++ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", ++ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", ++ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7", ++ "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", ++ "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", 2 ++}; ++ ++static const ECCurveParams ecCurve_NIST_K571 = { ++ "NIST-K571", ECField_GF2m, 571, ++ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972", ++ "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", ++ "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", 4 ++}; ++ ++static const ECCurveParams ecCurve_NIST_B571 = { ++ "NIST-B571", ECField_GF2m, 571, ++ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", ++ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", ++ "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", ++ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19", ++ "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", ++ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", 2 ++}; ++ ++/* ANSI X9.62 prime curves */ ++static const ECCurveParams ecCurve_X9_62_PRIME_192V2 = { ++ "X9.62 P-192V2", ECField_GFp, 192, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", ++ "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", ++ "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", ++ "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", ++ "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", 1 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_PRIME_192V3 = { ++ "X9.62 P-192V3", ECField_GFp, 192, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", ++ "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", ++ "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", ++ "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", ++ "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", 1 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_PRIME_239V1 = { ++ "X9.62 P-239V1", ECField_GFp, 239, ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", ++ "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", ++ "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", ++ "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", 1 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_PRIME_239V2 = { ++ "X9.62 P-239V2", ECField_GFp, 239, ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", ++ "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", ++ "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", ++ "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", ++ "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", 1 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_PRIME_239V3 = { ++ "X9.62 P-239V3", ECField_GFp, 239, ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", ++ "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", ++ "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", ++ "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", ++ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", 1 ++}; ++ ++/* ANSI X9.62 binary curves */ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V1 = { ++ "X9.62 C2-PNB163V1", ECField_GF2m, 163, ++ "080000000000000000000000000000000000000107", ++ "072546B5435234A422E0789675F432C89435DE5242", ++ "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", ++ "07AF69989546103D79329FCC3D74880F33BBE803CB", ++ "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F", ++ "0400000000000000000001E60FC8821CC74DAEAFC1", 2 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V2 = { ++ "X9.62 C2-PNB163V2", ECField_GF2m, 163, ++ "080000000000000000000000000000000000000107", ++ "0108B39E77C4B108BED981ED0E890E117C511CF072", ++ "0667ACEB38AF4E488C407433FFAE4F1C811638DF20", ++ "0024266E4EB5106D0A964D92C4860E2671DB9B6CC5", ++ "079F684DDF6684C5CD258B3890021B2386DFD19FC5", ++ "03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 2 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V3 = { ++ "X9.62 C2-PNB163V3", ECField_GF2m, 163, ++ "080000000000000000000000000000000000000107", ++ "07A526C63D3E25A256A007699F5447E32AE456B50E", ++ "03F7061798EB99E238FD6F1BF95B48FEEB4854252B", ++ "02F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB", ++ "05B935590C155E17EA48EB3FF3718B893DF59A05D0", ++ "03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 2 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB176V1 = { ++ "X9.62 C2-PNB176V1", ECField_GF2m, 176, ++ "0100000000000000000000000000000000080000000007", ++ "E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", ++ "5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", ++ "8D16C2866798B600F9F08BB4A8E860F3298CE04A5798", ++ "6FA4539C2DADDDD6BAB5167D61B436E1D92BB16A562C", ++ "00010092537397ECA4F6145799D62B0A19CE06FE26AD", 0xFF6E ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V1 = { ++ "X9.62 C2-TNB191V1", ECField_GF2m, 191, ++ "800000000000000000000000000000000000000000000201", ++ "2866537B676752636A68F56554E12640276B649EF7526267", ++ "2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", ++ "36B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D", ++ "765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB", ++ "40000000000000000000000004A20E90C39067C893BBB9A5", 2 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V2 = { ++ "X9.62 C2-TNB191V2", ECField_GF2m, 191, ++ "800000000000000000000000000000000000000000000201", ++ "401028774D7777C7B7666D1366EA432071274F89FF01E718", ++ "0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", ++ "3809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10", ++ "17434386626D14F3DBF01760D9213A3E1CF37AEC437D668A", ++ "20000000000000000000000050508CB89F652824E06B8173", 4 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V3 = { ++ "X9.62 C2-TNB191V3", ECField_GF2m, 191, ++ "800000000000000000000000000000000000000000000201", ++ "6C01074756099122221056911C77D77E77A777E7E7E77FCB", ++ "71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", ++ "375D4CE24FDE434489DE8746E71786015009E66E38A926DD", ++ "545A39176196575D985999366E6AD34CE0A77CD7127B06BE", ++ "155555555555555555555555610C0B196812BFB6288A3EA3", 6 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB208W1 = { ++ "X9.62 C2-PNB208W1", ECField_GF2m, 208, ++ "010000000000000000000000000000000800000000000000000007", ++ "0000000000000000000000000000000000000000000000000000", ++ "C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", ++ "89FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A", ++ "0F55B51A06E78E9AC38A035FF520D8B01781BEB1A6BB08617DE3", ++ "000101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 0xFE48 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V1 = { ++ "X9.62 C2-TNB239V1", ECField_GF2m, 239, ++ "800000000000000000000000000000000000000000000000001000000001", ++ "32010857077C5431123A46B808906756F543423E8D27877578125778AC76", ++ "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", ++ "57927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D", ++ "61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305", ++ "2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 4 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V2 = { ++ "X9.62 C2-TNB239V2", ECField_GF2m, 239, ++ "800000000000000000000000000000000000000000000000001000000001", ++ "4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", ++ "5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", ++ "28F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205", ++ "5667334C45AFF3B5A03BAD9DD75E2C71A99362567D5453F7FA6E227EC833", ++ "1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 6 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V3 = { ++ "X9.62 C2-TNB239V3", ECField_GF2m, 239, ++ "800000000000000000000000000000000000000000000000001000000001", ++ "01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", ++ "6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", ++ "70F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92", ++ "2E5A0EAF6E5E1305B9004DCE5C0ED7FE59A35608F33837C816D80B79F461", ++ "0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 0xA ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB272W1 = { ++ "X9.62 C2-PNB272W1", ECField_GF2m, 272, ++ "010000000000000000000000000000000000000000000000000000010000000000000B", ++ "91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", ++ "7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", ++ "6108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D", ++ "10C7695716851EEF6BA7F6872E6142FBD241B830FF5EFCACECCAB05E02005DDE9D23", ++ "000100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", ++ 0xFF06 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB304W1 = { ++ "X9.62 C2-PNB304W1", ECField_GF2m, 304, ++ "010000000000000000000000000000000000000000000000000000000000000000000000000807", ++ "FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", ++ "BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", ++ "197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614", ++ "E19FBEB76E0DA171517ECF401B50289BF014103288527A9B416A105E80260B549FDC1B92C03B", ++ "000101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 0xFE2E ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB359V1 = { ++ "X9.62 C2-TNB359V1", ECField_GF2m, 359, ++ "800000000000000000000000000000000000000000000000000000000000000000000000100000000000000001", ++ "5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", ++ "2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", ++ "3C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097", ++ "53D7E08529547048121E9C95F3791DD804963948F34FAE7BF44EA82365DC7868FE57E4AE2DE211305A407104BD", ++ "01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 0x4C ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_PNB368W1 = { ++ "X9.62 C2-PNB368W1", ECField_GF2m, 368, ++ "0100000000000000000000000000000000000000000000000000000000000000000000002000000000000000000007", ++ "E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", ++ "FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", ++ "1085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F", ++ "7B3EB1BDDCBA62D5D8B2059B525797FC73822C59059C623A45FF3843CEE8F87CD1855ADAA81E2A0750B80FDA2310", ++ "00010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 0xFF70 ++}; ++ ++static const ECCurveParams ecCurve_X9_62_CHAR2_TNB431R1 = { ++ "X9.62 C2-TNB431R1", ECField_GF2m, 431, ++ "800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001", ++ "1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", ++ "10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", ++ "120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7", ++ "20D0AF8903A96F8D5FA2C255745D3C451B302C9346D9B7E485E7BCE41F6B591F3E8F6ADDCBB0BC4C2F947A7DE1A89B625D6A598B3760", ++ "0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 0x2760 ++}; ++ + /* SEC2 prime curves */ ++static const ECCurveParams ecCurve_SECG_PRIME_112R1 = { ++ "SECP-112R1", ECField_GFp, 112, ++ "DB7C2ABF62E35E668076BEAD208B", ++ "DB7C2ABF62E35E668076BEAD2088", ++ "659EF8BA043916EEDE8911702B22", ++ "09487239995A5EE76B55F9C2F098", ++ "A89CE5AF8724C0A23E0E0FF77500", ++ "DB7C2ABF62E35E7628DFAC6561C5", 1 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_112R2 = { ++ "SECP-112R2", ECField_GFp, 112, ++ "DB7C2ABF62E35E668076BEAD208B", ++ "6127C24C05F38A0AAAF65C0EF02C", ++ "51DEF1815DB5ED74FCC34C85D709", ++ "4BA30AB5E892B4E1649DD0928643", ++ "adcd46f5882e3747def36e956e97", ++ "36DF0AAFD8B8D7597CA10520D04B", 4 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_128R1 = { ++ "SECP-128R1", ECField_GFp, 128, ++ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", ++ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", ++ "E87579C11079F43DD824993C2CEE5ED3", ++ "161FF7528B899B2D0C28607CA52C5B86", ++ "CF5AC8395BAFEB13C02DA292DDED7A83", ++ "FFFFFFFE0000000075A30D1B9038A115", 1 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_128R2 = { ++ "SECP-128R2", ECField_GFp, 128, ++ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", ++ "D6031998D1B3BBFEBF59CC9BBFF9AEE1", ++ "5EEEFCA380D02919DC2C6558BB6D8A5D", ++ "7B6AA5D85E572983E6FB32A7CDEBC140", ++ "27B6916A894D3AEE7106FE805FC34B44", ++ "3FFFFFFF7FFFFFFFBE0024720613B5A3", 4 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_160K1 = { ++ "SECP-160K1", ECField_GFp, 160, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", ++ "0000000000000000000000000000000000000000", ++ "0000000000000000000000000000000000000007", ++ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", ++ "938CF935318FDCED6BC28286531733C3F03C4FEE", ++ "0100000000000000000001B8FA16DFAB9ACA16B6B3", 1 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_160R1 = { ++ "SECP-160R1", ECField_GFp, 160, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", ++ "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", ++ "4A96B5688EF573284664698968C38BB913CBFC82", ++ "23A628553168947D59DCC912042351377AC5FB32", ++ "0100000000000000000001F4C8F927AED3CA752257", 1 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_160R2 = { ++ "SECP-160R2", ECField_GFp, 160, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", ++ "B4E134D3FB59EB8BAB57274904664D5AF50388BA", ++ "52DCB034293A117E1F4FF11B30F7199D3144CE6D", ++ "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", ++ "0100000000000000000000351EE786A818F3A1A16B", 1 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_192K1 = { ++ "SECP-192K1", ECField_GFp, 192, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", ++ "000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000003", ++ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", ++ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", ++ "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 1 ++}; ++ ++static const ECCurveParams ecCurve_SECG_PRIME_224K1 = { ++ "SECP-224K1", ECField_GFp, 224, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", ++ "00000000000000000000000000000000000000000000000000000000", ++ "00000000000000000000000000000000000000000000000000000005", ++ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", ++ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", ++ "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 1 ++}; ++ + static const ECCurveParams ecCurve_SECG_PRIME_256K1 = { + "SECP-256K1", ECField_GFp, 256, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", +@@ -88,70 +511,222 @@ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 1 + }; + ++/* SEC2 binary curves */ ++static const ECCurveParams ecCurve_SECG_CHAR2_113R1 = { ++ "SECT-113R1", ECField_GF2m, 113, ++ "020000000000000000000000000201", ++ "003088250CA6E7C7FE649CE85820F7", ++ "00E8BEE4D3E2260744188BE0E9C723", ++ "009D73616F35F4AB1407D73562C10F", ++ "00A52830277958EE84D1315ED31886", ++ "0100000000000000D9CCEC8A39E56F", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_113R2 = { ++ "SECT-113R2", ECField_GF2m, 113, ++ "020000000000000000000000000201", ++ "00689918DBEC7E5A0DD6DFC0AA55C7", ++ "0095E9A9EC9B297BD4BF36E059184F", ++ "01A57A6A7B26CA5EF52FCDB8164797", ++ "00B3ADC94ED1FE674C06E695BABA1D", ++ "010000000000000108789B2496AF93", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_131R1 = { ++ "SECT-131R1", ECField_GF2m, 131, ++ "080000000000000000000000000000010D", ++ "07A11B09A76B562144418FF3FF8C2570B8", ++ "0217C05610884B63B9C6C7291678F9D341", ++ "0081BAF91FDF9833C40F9C181343638399", ++ "078C6E7EA38C001F73C8134B1B4EF9E150", ++ "0400000000000000023123953A9464B54D", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_131R2 = { ++ "SECT-131R2", ECField_GF2m, 131, ++ "080000000000000000000000000000010D", ++ "03E5A88919D7CAFCBF415F07C2176573B2", ++ "04B8266A46C55657AC734CE38F018F2192", ++ "0356DCD8F2F95031AD652D23951BB366A8", ++ "0648F06D867940A5366D9E265DE9EB240F", ++ "0400000000000000016954A233049BA98F", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_163R1 = { ++ "SECT-163R1", ECField_GF2m, 163, ++ "0800000000000000000000000000000000000000C9", ++ "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2", ++ "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9", ++ "0369979697AB43897789566789567F787A7876A654", ++ "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883", ++ "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_193R1 = { ++ "SECT-193R1", ECField_GF2m, 193, ++ "02000000000000000000000000000000000000000000008001", ++ "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01", ++ "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814", ++ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1", ++ "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05", ++ "01000000000000000000000000C7F34A778F443ACC920EBA49", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_193R2 = { ++ "SECT-193R2", ECField_GF2m, 193, ++ "02000000000000000000000000000000000000000000008001", ++ "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B", ++ "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE", ++ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F", ++ "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C", ++ "010000000000000000000000015AAB561B005413CCD4EE99D5", 2 ++}; ++ ++static const ECCurveParams ecCurve_SECG_CHAR2_239K1 = { ++ "SECT-239K1", ECField_GF2m, 239, ++ "800000000000000000004000000000000000000000000000000000000001", ++ "000000000000000000000000000000000000000000000000000000000000", ++ "000000000000000000000000000000000000000000000000000000000001", ++ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC", ++ "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA", ++ "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", 4 ++}; ++ ++/* WTLS curves */ ++static const ECCurveParams ecCurve_WTLS_1 = { ++ "WTLS-1", ECField_GF2m, 113, ++ "020000000000000000000000000201", ++ "000000000000000000000000000001", ++ "000000000000000000000000000001", ++ "01667979A40BA497E5D5C270780617", ++ "00F44B4AF1ECC2630E08785CEBCC15", ++ "00FFFFFFFFFFFFFFFDBF91AF6DEA73", 2 ++}; ++ ++static const ECCurveParams ecCurve_WTLS_8 = { ++ "WTLS-8", ECField_GFp, 112, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFDE7", ++ "0000000000000000000000000000", ++ "0000000000000000000000000003", ++ "0000000000000000000000000001", ++ "0000000000000000000000000002", ++ "0100000000000001ECEA551AD837E9", 1 ++}; ++ ++static const ECCurveParams ecCurve_WTLS_9 = { ++ "WTLS-9", ECField_GFp, 160, ++ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC808F", ++ "0000000000000000000000000000000000000000", ++ "0000000000000000000000000000000000000003", ++ "0000000000000000000000000000000000000001", ++ "0000000000000000000000000000000000000002", ++ "0100000000000000000001CDC98AE0E2DE574ABF33", 1 ++}; ++ ++static const ECCurveParams ecCurve_BrainpoolP256r1 = { ++ "brainpoolP256r1", ECField_GFp, 256, ++ "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", ++ "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", ++ "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", ++ "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", ++ "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", ++ "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 1 ++}; ++ ++static const ECCurveParams ecCurve_BrainpoolP320r1 = { ++ "brainpoolP320r1", ECField_GFp, 320, ++ "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", ++ "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", ++ "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", ++ "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", ++ "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", ++ "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 1 ++}; ++ ++static const ECCurveParams ecCurve_BrainpoolP384r1 = { ++ "brainpoolP384r1", ECField_GFp, 384, ++ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", ++ "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", ++ "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", ++ "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", ++ "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", ++ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 1 ++}; ++ ++static const ECCurveParams ecCurve_BrainpoolP512r1 = { ++ "brainpoolP512r1", ECField_GFp, 512, ++ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", ++ "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", ++ "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", ++ "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", ++ "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", ++ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 1 ++}; ++ + /* mapping between ECCurveName enum and pointers to ECCurveParams */ + static const ECCurveParams *ecCurve_map[] = { + NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ ++ &ecCurve_NIST_P192, /* ECCurve_NIST_P192 */ ++ &ecCurve_NIST_P224, /* ECCurve_NIST_P224 */ + &ecCurve_NIST_P256, /* ECCurve_NIST_P256 */ + &ecCurve_NIST_P384, /* ECCurve_NIST_P384 */ + &ecCurve_NIST_P521, /* ECCurve_NIST_P521 */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ ++ &ecCurve_NIST_K163, /* ECCurve_NIST_K163 */ ++ &ecCurve_NIST_B163, /* ECCurve_NIST_B163 */ ++ &ecCurve_NIST_K233, /* ECCurve_NIST_K233 */ ++ &ecCurve_NIST_B233, /* ECCurve_NIST_B233 */ ++ &ecCurve_NIST_K283, /* ECCurve_NIST_K283 */ ++ &ecCurve_NIST_B283, /* ECCurve_NIST_B283 */ ++ &ecCurve_NIST_K409, /* ECCurve_NIST_K409 */ ++ &ecCurve_NIST_B409, /* ECCurve_NIST_B409 */ ++ &ecCurve_NIST_K571, /* ECCurve_NIST_K571 */ ++ &ecCurve_NIST_B571, /* ECCurve_NIST_B571 */ ++ &ecCurve_X9_62_PRIME_192V2, /* ECCurve_X9_62_PRIME_192V2 */ ++ &ecCurve_X9_62_PRIME_192V3, /* ECCurve_X9_62_PRIME_192V3 */ ++ &ecCurve_X9_62_PRIME_239V1, /* ECCurve_X9_62_PRIME_239V1 */ ++ &ecCurve_X9_62_PRIME_239V2, /* ECCurve_X9_62_PRIME_239V2 */ ++ &ecCurve_X9_62_PRIME_239V3, /* ECCurve_X9_62_PRIME_239V3 */ ++ &ecCurve_X9_62_CHAR2_PNB163V1, /* ECCurve_X9_62_CHAR2_PNB163V1 */ ++ &ecCurve_X9_62_CHAR2_PNB163V2, /* ECCurve_X9_62_CHAR2_PNB163V2 */ ++ &ecCurve_X9_62_CHAR2_PNB163V3, /* ECCurve_X9_62_CHAR2_PNB163V3 */ ++ &ecCurve_X9_62_CHAR2_PNB176V1, /* ECCurve_X9_62_CHAR2_PNB176V1 */ ++ &ecCurve_X9_62_CHAR2_TNB191V1, /* ECCurve_X9_62_CHAR2_TNB191V1 */ ++ &ecCurve_X9_62_CHAR2_TNB191V2, /* ECCurve_X9_62_CHAR2_TNB191V2 */ ++ &ecCurve_X9_62_CHAR2_TNB191V3, /* ECCurve_X9_62_CHAR2_TNB191V3 */ ++ &ecCurve_X9_62_CHAR2_PNB208W1, /* ECCurve_X9_62_CHAR2_PNB208W1 */ ++ &ecCurve_X9_62_CHAR2_TNB239V1, /* ECCurve_X9_62_CHAR2_TNB239V1 */ ++ &ecCurve_X9_62_CHAR2_TNB239V2, /* ECCurve_X9_62_CHAR2_TNB239V2 */ ++ &ecCurve_X9_62_CHAR2_TNB239V3, /* ECCurve_X9_62_CHAR2_TNB239V3 */ ++ &ecCurve_X9_62_CHAR2_PNB272W1, /* ECCurve_X9_62_CHAR2_PNB272W1 */ ++ &ecCurve_X9_62_CHAR2_PNB304W1, /* ECCurve_X9_62_CHAR2_PNB304W1 */ ++ &ecCurve_X9_62_CHAR2_TNB359V1, /* ECCurve_X9_62_CHAR2_TNB359V1 */ ++ &ecCurve_X9_62_CHAR2_PNB368W1, /* ECCurve_X9_62_CHAR2_PNB368W1 */ ++ &ecCurve_X9_62_CHAR2_TNB431R1, /* ECCurve_X9_62_CHAR2_TNB431R1 */ ++ &ecCurve_SECG_PRIME_112R1, /* ECCurve_SECG_PRIME_112R1 */ ++ &ecCurve_SECG_PRIME_112R2, /* ECCurve_SECG_PRIME_112R2 */ ++ &ecCurve_SECG_PRIME_128R1, /* ECCurve_SECG_PRIME_128R1 */ ++ &ecCurve_SECG_PRIME_128R2, /* ECCurve_SECG_PRIME_128R2 */ ++ &ecCurve_SECG_PRIME_160K1, /* ECCurve_SECG_PRIME_160K1 */ ++ &ecCurve_SECG_PRIME_160R1, /* ECCurve_SECG_PRIME_160R1 */ ++ &ecCurve_SECG_PRIME_160R2, /* ECCurve_SECG_PRIME_160R2 */ ++ &ecCurve_SECG_PRIME_192K1, /* ECCurve_SECG_PRIME_192K1 */ ++ &ecCurve_SECG_PRIME_224K1, /* ECCurve_SECG_PRIME_224K1 */ + &ecCurve_SECG_PRIME_256K1, /* ECCurve_SECG_PRIME_256K1 */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ +- NULL, /* ECCurve_noName */ ++ &ecCurve_SECG_CHAR2_113R1, /* ECCurve_SECG_CHAR2_113R1 */ ++ &ecCurve_SECG_CHAR2_113R2, /* ECCurve_SECG_CHAR2_113R2 */ ++ &ecCurve_SECG_CHAR2_131R1, /* ECCurve_SECG_CHAR2_131R1 */ ++ &ecCurve_SECG_CHAR2_131R2, /* ECCurve_SECG_CHAR2_131R2 */ ++ &ecCurve_SECG_CHAR2_163R1, /* ECCurve_SECG_CHAR2_163R1 */ ++ &ecCurve_SECG_CHAR2_193R1, /* ECCurve_SECG_CHAR2_193R1 */ ++ &ecCurve_SECG_CHAR2_193R2, /* ECCurve_SECG_CHAR2_193R2 */ ++ &ecCurve_SECG_CHAR2_239K1, /* ECCurve_SECG_CHAR2_239K1 */ ++ &ecCurve_WTLS_1, /* ECCurve_WTLS_1 */ ++ &ecCurve_WTLS_8, /* ECCurve_WTLS_8 */ ++ &ecCurve_WTLS_9, /* ECCurve_WTLS_9 */ ++ &ecCurve_BrainpoolP256r1, /* ECCurve_BrainpoolP256r1 */ ++ &ecCurve_BrainpoolP320r1, /* ECCurve_BrainpoolP320r1 */ ++ &ecCurve_BrainpoolP384r1, /* ECCurve_brainpoolP384r1 */ ++ &ecCurve_BrainpoolP512r1, /* ECCurve_brainpoolP512r1 */ + NULL /* ECCurve_pastLastCurve */ + }; + +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,517 @@ ++/* ++ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for prime field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Douglas Stebila , Sun Microsystems Laboratories ++ * ++ *********************************************************************** */ ++ ++#include "ecp.h" ++#include "mpi.h" ++#include "mplogic.h" ++#include "mpi-priv.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++#define ECP192_DIGITS ECL_CURVE_DIGITS(192) ++ ++/* Fast modular reduction for p192 = 2^192 - 2^64 - 1. a can be r. Uses ++ * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software ++ * Implementation of the NIST Elliptic Curves over Prime Fields. */ ++mp_err ++ec_GFp_nistp192_mod(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_size a_used = MP_USED(a); ++ mp_digit r3; ++#ifndef MPI_AMD64_ADD ++ mp_digit carry; ++#endif ++#ifdef ECL_THIRTY_TWO_BIT ++ mp_digit a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; ++ mp_digit r0a, r0b, r1a, r1b, r2a, r2b; ++#else ++ mp_digit a5 = 0, a4 = 0, a3 = 0; ++ mp_digit r0, r1, r2; ++#endif ++ ++ /* reduction not needed if a is not larger than field size */ ++ if (a_used < ECP192_DIGITS) { ++ if (a == r) { ++ return MP_OKAY; ++ } ++ return mp_copy(a, r); ++ } ++ ++ /* for polynomials larger than twice the field size, use regular ++ * reduction */ ++ if (a_used > ECP192_DIGITS*2) { ++ MP_CHECKOK(mp_mod(a, &meth->irr, r)); ++ } else { ++ /* copy out upper words of a */ ++ ++#ifdef ECL_THIRTY_TWO_BIT ++ ++ /* in all the math below, ++ * nXb is most signifiant, nXa is least significant */ ++ switch (a_used) { ++ case 12: ++ a5b = MP_DIGIT(a, 11); ++ case 11: ++ a5a = MP_DIGIT(a, 10); ++ case 10: ++ a4b = MP_DIGIT(a, 9); ++ case 9: ++ a4a = MP_DIGIT(a, 8); ++ case 8: ++ a3b = MP_DIGIT(a, 7); ++ case 7: ++ a3a = MP_DIGIT(a, 6); ++ } ++ ++ ++ r2b= MP_DIGIT(a, 5); ++ r2a= MP_DIGIT(a, 4); ++ r1b = MP_DIGIT(a, 3); ++ r1a = MP_DIGIT(a, 2); ++ r0b = MP_DIGIT(a, 1); ++ r0a = MP_DIGIT(a, 0); ++ ++ /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */ ++ MP_ADD_CARRY(r0a, a3a, r0a, 0, carry); ++ MP_ADD_CARRY(r0b, a3b, r0b, carry, carry); ++ MP_ADD_CARRY(r1a, a3a, r1a, carry, carry); ++ MP_ADD_CARRY(r1b, a3b, r1b, carry, carry); ++ MP_ADD_CARRY(r2a, a4a, r2a, carry, carry); ++ MP_ADD_CARRY(r2b, a4b, r2b, carry, carry); ++ r3 = carry; carry = 0; ++ MP_ADD_CARRY(r0a, a5a, r0a, 0, carry); ++ MP_ADD_CARRY(r0b, a5b, r0b, carry, carry); ++ MP_ADD_CARRY(r1a, a5a, r1a, carry, carry); ++ MP_ADD_CARRY(r1b, a5b, r1b, carry, carry); ++ MP_ADD_CARRY(r2a, a5a, r2a, carry, carry); ++ MP_ADD_CARRY(r2b, a5b, r2b, carry, carry); ++ r3 += carry; ++ MP_ADD_CARRY(r1a, a4a, r1a, 0, carry); ++ MP_ADD_CARRY(r1b, a4b, r1b, carry, carry); ++ MP_ADD_CARRY(r2a, 0, r2a, carry, carry); ++ MP_ADD_CARRY(r2b, 0, r2b, carry, carry); ++ r3 += carry; ++ ++ /* reduce out the carry */ ++ while (r3) { ++ MP_ADD_CARRY(r0a, r3, r0a, 0, carry); ++ MP_ADD_CARRY(r0b, 0, r0b, carry, carry); ++ MP_ADD_CARRY(r1a, r3, r1a, carry, carry); ++ MP_ADD_CARRY(r1b, 0, r1b, carry, carry); ++ MP_ADD_CARRY(r2a, 0, r2a, carry, carry); ++ MP_ADD_CARRY(r2b, 0, r2b, carry, carry); ++ r3 = carry; ++ } ++ ++ /* check for final reduction */ ++ /* ++ * our field is 0xffffffffffffffff, 0xfffffffffffffffe, ++ * 0xffffffffffffffff. That means we can only be over and need ++ * one more reduction ++ * if r2 == 0xffffffffffffffffff (same as r2+1 == 0) ++ * and ++ * r1 == 0xffffffffffffffffff or ++ * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff ++ * In all cases, we subtract the field (or add the 2's ++ * complement value (1,1,0)). (r0, r1, r2) ++ */ ++ if (((r2b == 0xffffffff) && (r2a == 0xffffffff) ++ && (r1b == 0xffffffff) ) && ++ ((r1a == 0xffffffff) || ++ (r1a == 0xfffffffe) && (r0a == 0xffffffff) && ++ (r0b == 0xffffffff)) ) { ++ /* do a quick subtract */ ++ MP_ADD_CARRY(r0a, 1, r0a, 0, carry); ++ r0b += carry; ++ r1a = r1b = r2a = r2b = 0; ++ } ++ ++ /* set the lower words of r */ ++ if (a != r) { ++ MP_CHECKOK(s_mp_pad(r, 6)); ++ } ++ MP_DIGIT(r, 5) = r2b; ++ MP_DIGIT(r, 4) = r2a; ++ MP_DIGIT(r, 3) = r1b; ++ MP_DIGIT(r, 2) = r1a; ++ MP_DIGIT(r, 1) = r0b; ++ MP_DIGIT(r, 0) = r0a; ++ MP_USED(r) = 6; ++#else ++ switch (a_used) { ++ case 6: ++ a5 = MP_DIGIT(a, 5); ++ case 5: ++ a4 = MP_DIGIT(a, 4); ++ case 4: ++ a3 = MP_DIGIT(a, 3); ++ } ++ ++ r2 = MP_DIGIT(a, 2); ++ r1 = MP_DIGIT(a, 1); ++ r0 = MP_DIGIT(a, 0); ++ ++ /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */ ++#ifndef MPI_AMD64_ADD ++ MP_ADD_CARRY_ZERO(r0, a3, r0, carry); ++ MP_ADD_CARRY(r1, a3, r1, carry, carry); ++ MP_ADD_CARRY(r2, a4, r2, carry, carry); ++ r3 = carry; ++ MP_ADD_CARRY_ZERO(r0, a5, r0, carry); ++ MP_ADD_CARRY(r1, a5, r1, carry, carry); ++ MP_ADD_CARRY(r2, a5, r2, carry, carry); ++ r3 += carry; ++ MP_ADD_CARRY_ZERO(r1, a4, r1, carry); ++ MP_ADD_CARRY(r2, 0, r2, carry, carry); ++ r3 += carry; ++ ++#else ++ r2 = MP_DIGIT(a, 2); ++ r1 = MP_DIGIT(a, 1); ++ r0 = MP_DIGIT(a, 0); ++ ++ /* set the lower words of r */ ++ __asm__ ( ++ "xorq %3,%3 \n\t" ++ "addq %4,%0 \n\t" ++ "adcq %4,%1 \n\t" ++ "adcq %5,%2 \n\t" ++ "adcq $0,%3 \n\t" ++ "addq %6,%0 \n\t" ++ "adcq %6,%1 \n\t" ++ "adcq %6,%2 \n\t" ++ "adcq $0,%3 \n\t" ++ "addq %5,%1 \n\t" ++ "adcq $0,%2 \n\t" ++ "adcq $0,%3 \n\t" ++ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3), ++ "=r"(a4), "=r"(a5) ++ : "0" (r0), "1" (r1), "2" (r2), "3" (r3), ++ "4" (a3), "5" (a4), "6"(a5) ++ : "%cc" ); ++#endif ++ ++ /* reduce out the carry */ ++ while (r3) { ++#ifndef MPI_AMD64_ADD ++ MP_ADD_CARRY_ZERO(r0, r3, r0, carry); ++ MP_ADD_CARRY(r1, r3, r1, carry, carry); ++ MP_ADD_CARRY(r2, 0, r2, carry, carry); ++ r3 = carry; ++#else ++ a3=r3; ++ __asm__ ( ++ "xorq %3,%3 \n\t" ++ "addq %4,%0 \n\t" ++ "adcq %4,%1 \n\t" ++ "adcq $0,%2 \n\t" ++ "adcq $0,%3 \n\t" ++ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3) ++ : "0" (r0), "1" (r1), "2" (r2), "3" (r3), "4"(a3) ++ : "%cc" ); ++#endif ++ } ++ ++ /* check for final reduction */ ++ /* ++ * our field is 0xffffffffffffffff, 0xfffffffffffffffe, ++ * 0xffffffffffffffff. That means we can only be over and need ++ * one more reduction ++ * if r2 == 0xffffffffffffffffff (same as r2+1 == 0) ++ * and ++ * r1 == 0xffffffffffffffffff or ++ * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff ++ * In all cases, we subtract the field (or add the 2's ++ * complement value (1,1,0)). (r0, r1, r2) ++ */ ++ if (r3 || ((r2 == MP_DIGIT_MAX) && ++ ((r1 == MP_DIGIT_MAX) || ++ ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) { ++ /* do a quick subtract */ ++ r0++; ++ r1 = r2 = 0; ++ } ++ /* set the lower words of r */ ++ if (a != r) { ++ MP_CHECKOK(s_mp_pad(r, 3)); ++ } ++ MP_DIGIT(r, 2) = r2; ++ MP_DIGIT(r, 1) = r1; ++ MP_DIGIT(r, 0) = r0; ++ MP_USED(r) = 3; ++#endif ++ } ++ ++ CLEANUP: ++ return res; ++} ++ ++#ifndef ECL_THIRTY_TWO_BIT ++/* Compute the sum of 192 bit curves. Do the work in-line since the ++ * number of words are so small, we don't want to overhead of mp function ++ * calls. Uses optimized modular reduction for p192. ++ */ ++mp_err ++ec_GFp_nistp192_add(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit a0 = 0, a1 = 0, a2 = 0; ++ mp_digit r0 = 0, r1 = 0, r2 = 0; ++ mp_digit carry; ++ ++ switch(MP_USED(a)) { ++ case 3: ++ a2 = MP_DIGIT(a,2); ++ case 2: ++ a1 = MP_DIGIT(a,1); ++ case 1: ++ a0 = MP_DIGIT(a,0); ++ } ++ switch(MP_USED(b)) { ++ case 3: ++ r2 = MP_DIGIT(b,2); ++ case 2: ++ r1 = MP_DIGIT(b,1); ++ case 1: ++ r0 = MP_DIGIT(b,0); ++ } ++ ++#ifndef MPI_AMD64_ADD ++ MP_ADD_CARRY_ZERO(a0, r0, r0, carry); ++ MP_ADD_CARRY(a1, r1, r1, carry, carry); ++ MP_ADD_CARRY(a2, r2, r2, carry, carry); ++#else ++ __asm__ ( ++ "xorq %3,%3 \n\t" ++ "addq %4,%0 \n\t" ++ "adcq %5,%1 \n\t" ++ "adcq %6,%2 \n\t" ++ "adcq $0,%3 \n\t" ++ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry) ++ : "r" (a0), "r" (a1), "r" (a2), "0" (r0), ++ "1" (r1), "2" (r2) ++ : "%cc" ); ++#endif ++ ++ /* Do quick 'subract' if we've gone over ++ * (add the 2's complement of the curve field) */ ++ if (carry || ((r2 == MP_DIGIT_MAX) && ++ ((r1 == MP_DIGIT_MAX) || ++ ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) { ++#ifndef MPI_AMD64_ADD ++ MP_ADD_CARRY_ZERO(r0, 1, r0, carry); ++ MP_ADD_CARRY(r1, 1, r1, carry, carry); ++ MP_ADD_CARRY(r2, 0, r2, carry, carry); ++#else ++ __asm__ ( ++ "addq $1,%0 \n\t" ++ "adcq $1,%1 \n\t" ++ "adcq $0,%2 \n\t" ++ : "=r"(r0), "=r"(r1), "=r"(r2) ++ : "0" (r0), "1" (r1), "2" (r2) ++ : "%cc" ); ++#endif ++ } ++ ++ ++ MP_CHECKOK(s_mp_pad(r, 3)); ++ MP_DIGIT(r, 2) = r2; ++ MP_DIGIT(r, 1) = r1; ++ MP_DIGIT(r, 0) = r0; ++ MP_SIGN(r) = MP_ZPOS; ++ MP_USED(r) = 3; ++ s_mp_clamp(r); ++ ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Compute the diff of 192 bit curves. Do the work in-line since the ++ * number of words are so small, we don't want to overhead of mp function ++ * calls. Uses optimized modular reduction for p192. ++ */ ++mp_err ++ec_GFp_nistp192_sub(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_digit b0 = 0, b1 = 0, b2 = 0; ++ mp_digit r0 = 0, r1 = 0, r2 = 0; ++ mp_digit borrow; ++ ++ switch(MP_USED(a)) { ++ case 3: ++ r2 = MP_DIGIT(a,2); ++ case 2: ++ r1 = MP_DIGIT(a,1); ++ case 1: ++ r0 = MP_DIGIT(a,0); ++ } ++ ++ switch(MP_USED(b)) { ++ case 3: ++ b2 = MP_DIGIT(b,2); ++ case 2: ++ b1 = MP_DIGIT(b,1); ++ case 1: ++ b0 = MP_DIGIT(b,0); ++ } ++ ++#ifndef MPI_AMD64_ADD ++ MP_SUB_BORROW(r0, b0, r0, 0, borrow); ++ MP_SUB_BORROW(r1, b1, r1, borrow, borrow); ++ MP_SUB_BORROW(r2, b2, r2, borrow, borrow); ++#else ++ __asm__ ( ++ "xorq %3,%3 \n\t" ++ "subq %4,%0 \n\t" ++ "sbbq %5,%1 \n\t" ++ "sbbq %6,%2 \n\t" ++ "adcq $0,%3 \n\t" ++ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(borrow) ++ : "r" (b0), "r" (b1), "r" (b2), "0" (r0), ++ "1" (r1), "2" (r2) ++ : "%cc" ); ++#endif ++ ++ /* Do quick 'add' if we've gone under 0 ++ * (subtract the 2's complement of the curve field) */ ++ if (borrow) { ++#ifndef MPI_AMD64_ADD ++ MP_SUB_BORROW(r0, 1, r0, 0, borrow); ++ MP_SUB_BORROW(r1, 1, r1, borrow, borrow); ++ MP_SUB_BORROW(r2, 0, r2, borrow, borrow); ++#else ++ __asm__ ( ++ "subq $1,%0 \n\t" ++ "sbbq $1,%1 \n\t" ++ "sbbq $0,%2 \n\t" ++ : "=r"(r0), "=r"(r1), "=r"(r2) ++ : "0" (r0), "1" (r1), "2" (r2) ++ : "%cc" ); ++#endif ++ } ++ ++ MP_CHECKOK(s_mp_pad(r, 3)); ++ MP_DIGIT(r, 2) = r2; ++ MP_DIGIT(r, 1) = r1; ++ MP_DIGIT(r, 0) = r0; ++ MP_SIGN(r) = MP_ZPOS; ++ MP_USED(r) = 3; ++ s_mp_clamp(r); ++ ++ CLEANUP: ++ return res; ++} ++ ++#endif ++ ++/* Compute the square of polynomial a, reduce modulo p192. Store the ++ * result in r. r could be a. Uses optimized modular reduction for p192. ++ */ ++mp_err ++ec_GFp_nistp192_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ ++ MP_CHECKOK(mp_sqr(a, r)); ++ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); ++ CLEANUP: ++ return res; ++} ++ ++/* Compute the product of two polynomials a and b, reduce modulo p192. ++ * Store the result in r. r could be a or b; a could be b. Uses ++ * optimized modular reduction for p192. */ ++mp_err ++ec_GFp_nistp192_mul(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ ++ MP_CHECKOK(mp_mul(a, b, r)); ++ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); ++ CLEANUP: ++ return res; ++} ++ ++/* Divides two field elements. If a is NULL, then returns the inverse of ++ * b. */ ++mp_err ++ec_GFp_nistp192_div(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_int t; ++ ++ /* If a is NULL, then return the inverse of b, otherwise return a/b. */ ++ if (a == NULL) { ++ return mp_invmod(b, &meth->irr, r); ++ } else { ++ /* MPI doesn't support divmod, so we implement it using invmod and ++ * mulmod. */ ++ MP_CHECKOK(mp_init(&t, FLAG(b))); ++ MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); ++ MP_CHECKOK(mp_mul(a, &t, r)); ++ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); ++ CLEANUP: ++ mp_clear(&t); ++ return res; ++ } ++} ++ ++/* Wire in fast field arithmetic and precomputation of base point for ++ * named curves. */ ++mp_err ++ec_group_set_gfp192(ECGroup *group, ECCurveName name) ++{ ++ if (name == ECCurve_NIST_P192) { ++ group->meth->field_mod = &ec_GFp_nistp192_mod; ++ group->meth->field_mul = &ec_GFp_nistp192_mul; ++ group->meth->field_sqr = &ec_GFp_nistp192_sqr; ++ group->meth->field_div = &ec_GFp_nistp192_div; ++#ifndef ECL_THIRTY_TWO_BIT ++ group->meth->field_add = &ec_GFp_nistp192_add; ++ group->meth->field_sub = &ec_GFp_nistp192_sub; ++#endif ++ } ++ return MP_OKAY; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c 2025-05-09 10:05:57.616290593 +0800 +@@ -0,0 +1,373 @@ ++/* ++ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, 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. ++ */ ++ ++/* ********************************************************************* ++ * ++ * The Original Code is the elliptic curve math library for prime field curves. ++ * ++ * The Initial Developer of the Original Code is ++ * Sun Microsystems, Inc. ++ * Portions created by the Initial Developer are Copyright (C) 2003 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Douglas Stebila , Sun Microsystems Laboratories ++ * ++ *********************************************************************** */ ++ ++#include "ecp.h" ++#include "mpi.h" ++#include "mplogic.h" ++#include "mpi-priv.h" ++#ifndef _KERNEL ++#include ++#endif ++ ++#define ECP224_DIGITS ECL_CURVE_DIGITS(224) ++ ++/* Fast modular reduction for p224 = 2^224 - 2^96 + 1. a can be r. Uses ++ * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software ++ * Implementation of the NIST Elliptic Curves over Prime Fields. */ ++mp_err ++ec_GFp_nistp224_mod(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_size a_used = MP_USED(a); ++ ++ int r3b; ++ mp_digit carry; ++#ifdef ECL_THIRTY_TWO_BIT ++ mp_digit a6a = 0, a6b = 0, ++ a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; ++ mp_digit r0a, r0b, r1a, r1b, r2a, r2b, r3a; ++#else ++ mp_digit a6 = 0, a5 = 0, a4 = 0, a3b = 0, a5a = 0; ++ mp_digit a6b = 0, a6a_a5b = 0, a5b = 0, a5a_a4b = 0, a4a_a3b = 0; ++ mp_digit r0, r1, r2, r3; ++#endif ++ ++ /* reduction not needed if a is not larger than field size */ ++ if (a_used < ECP224_DIGITS) { ++ if (a == r) return MP_OKAY; ++ return mp_copy(a, r); ++ } ++ /* for polynomials larger than twice the field size, use regular ++ * reduction */ ++ if (a_used > ECL_CURVE_DIGITS(224*2)) { ++ MP_CHECKOK(mp_mod(a, &meth->irr, r)); ++ } else { ++#ifdef ECL_THIRTY_TWO_BIT ++ /* copy out upper words of a */ ++ switch (a_used) { ++ case 14: ++ a6b = MP_DIGIT(a, 13); ++ case 13: ++ a6a = MP_DIGIT(a, 12); ++ case 12: ++ a5b = MP_DIGIT(a, 11); ++ case 11: ++ a5a = MP_DIGIT(a, 10); ++ case 10: ++ a4b = MP_DIGIT(a, 9); ++ case 9: ++ a4a = MP_DIGIT(a, 8); ++ case 8: ++ a3b = MP_DIGIT(a, 7); ++ } ++ r3a = MP_DIGIT(a, 6); ++ r2b= MP_DIGIT(a, 5); ++ r2a= MP_DIGIT(a, 4); ++ r1b = MP_DIGIT(a, 3); ++ r1a = MP_DIGIT(a, 2); ++ r0b = MP_DIGIT(a, 1); ++ r0a = MP_DIGIT(a, 0); ++ ++ ++ /* implement r = (a3a,a2,a1,a0) ++ +(a5a, a4,a3b, 0) ++ +( 0, a6,a5b, 0) ++ -( 0 0, 0|a6b, a6a|a5b ) ++ -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ ++ MP_ADD_CARRY (r1b, a3b, r1b, 0, carry); ++ MP_ADD_CARRY (r2a, a4a, r2a, carry, carry); ++ MP_ADD_CARRY (r2b, a4b, r2b, carry, carry); ++ MP_ADD_CARRY (r3a, a5a, r3a, carry, carry); ++ r3b = carry; ++ MP_ADD_CARRY (r1b, a5b, r1b, 0, carry); ++ MP_ADD_CARRY (r2a, a6a, r2a, carry, carry); ++ MP_ADD_CARRY (r2b, a6b, r2b, carry, carry); ++ MP_ADD_CARRY (r3a, 0, r3a, carry, carry); ++ r3b += carry; ++ MP_SUB_BORROW(r0a, a3b, r0a, 0, carry); ++ MP_SUB_BORROW(r0b, a4a, r0b, carry, carry); ++ MP_SUB_BORROW(r1a, a4b, r1a, carry, carry); ++ MP_SUB_BORROW(r1b, a5a, r1b, carry, carry); ++ MP_SUB_BORROW(r2a, a5b, r2a, carry, carry); ++ MP_SUB_BORROW(r2b, a6a, r2b, carry, carry); ++ MP_SUB_BORROW(r3a, a6b, r3a, carry, carry); ++ r3b -= carry; ++ MP_SUB_BORROW(r0a, a5b, r0a, 0, carry); ++ MP_SUB_BORROW(r0b, a6a, r0b, carry, carry); ++ MP_SUB_BORROW(r1a, a6b, r1a, carry, carry); ++ if (carry) { ++ MP_SUB_BORROW(r1b, 0, r1b, carry, carry); ++ MP_SUB_BORROW(r2a, 0, r2a, carry, carry); ++ MP_SUB_BORROW(r2b, 0, r2b, carry, carry); ++ MP_SUB_BORROW(r3a, 0, r3a, carry, carry); ++ r3b -= carry; ++ } ++ ++ while (r3b > 0) { ++ int tmp; ++ MP_ADD_CARRY(r1b, r3b, r1b, 0, carry); ++ if (carry) { ++ MP_ADD_CARRY(r2a, 0, r2a, carry, carry); ++ MP_ADD_CARRY(r2b, 0, r2b, carry, carry); ++ MP_ADD_CARRY(r3a, 0, r3a, carry, carry); ++ } ++ tmp = carry; ++ MP_SUB_BORROW(r0a, r3b, r0a, 0, carry); ++ if (carry) { ++ MP_SUB_BORROW(r0b, 0, r0b, carry, carry); ++ MP_SUB_BORROW(r1a, 0, r1a, carry, carry); ++ MP_SUB_BORROW(r1b, 0, r1b, carry, carry); ++ MP_SUB_BORROW(r2a, 0, r2a, carry, carry); ++ MP_SUB_BORROW(r2b, 0, r2b, carry, carry); ++ MP_SUB_BORROW(r3a, 0, r3a, carry, carry); ++ tmp -= carry; ++ } ++ r3b = tmp; ++ } ++ ++ while (r3b < 0) { ++ mp_digit maxInt = MP_DIGIT_MAX; ++ MP_ADD_CARRY (r0a, 1, r0a, 0, carry); ++ MP_ADD_CARRY (r0b, 0, r0b, carry, carry); ++ MP_ADD_CARRY (r1a, 0, r1a, carry, carry); ++ MP_ADD_CARRY (r1b, maxInt, r1b, carry, carry); ++ MP_ADD_CARRY (r2a, maxInt, r2a, carry, carry); ++ MP_ADD_CARRY (r2b, maxInt, r2b, carry, carry); ++ MP_ADD_CARRY (r3a, maxInt, r3a, carry, carry); ++ r3b += carry; ++ } ++ /* check for final reduction */ ++ /* now the only way we are over is if the top 4 words are all ones */ ++ if ((r3a == MP_DIGIT_MAX) && (r2b == MP_DIGIT_MAX) ++ && (r2a == MP_DIGIT_MAX) && (r1b == MP_DIGIT_MAX) && ++ ((r1a != 0) || (r0b != 0) || (r0a != 0)) ) { ++ /* one last subraction */ ++ MP_SUB_BORROW(r0a, 1, r0a, 0, carry); ++ MP_SUB_BORROW(r0b, 0, r0b, carry, carry); ++ MP_SUB_BORROW(r1a, 0, r1a, carry, carry); ++ r1b = r2a = r2b = r3a = 0; ++ } ++ ++ ++ if (a != r) { ++ MP_CHECKOK(s_mp_pad(r, 7)); ++ } ++ /* set the lower words of r */ ++ MP_SIGN(r) = MP_ZPOS; ++ MP_USED(r) = 7; ++ MP_DIGIT(r, 6) = r3a; ++ MP_DIGIT(r, 5) = r2b; ++ MP_DIGIT(r, 4) = r2a; ++ MP_DIGIT(r, 3) = r1b; ++ MP_DIGIT(r, 2) = r1a; ++ MP_DIGIT(r, 1) = r0b; ++ MP_DIGIT(r, 0) = r0a; ++#else ++ /* copy out upper words of a */ ++ switch (a_used) { ++ case 7: ++ a6 = MP_DIGIT(a, 6); ++ a6b = a6 >> 32; ++ a6a_a5b = a6 << 32; ++ case 6: ++ a5 = MP_DIGIT(a, 5); ++ a5b = a5 >> 32; ++ a6a_a5b |= a5b; ++ a5b = a5b << 32; ++ a5a_a4b = a5 << 32; ++ a5a = a5 & 0xffffffff; ++ case 5: ++ a4 = MP_DIGIT(a, 4); ++ a5a_a4b |= a4 >> 32; ++ a4a_a3b = a4 << 32; ++ case 4: ++ a3b = MP_DIGIT(a, 3) >> 32; ++ a4a_a3b |= a3b; ++ a3b = a3b << 32; ++ } ++ ++ r3 = MP_DIGIT(a, 3) & 0xffffffff; ++ r2 = MP_DIGIT(a, 2); ++ r1 = MP_DIGIT(a, 1); ++ r0 = MP_DIGIT(a, 0); ++ ++ /* implement r = (a3a,a2,a1,a0) ++ +(a5a, a4,a3b, 0) ++ +( 0, a6,a5b, 0) ++ -( 0 0, 0|a6b, a6a|a5b ) ++ -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ ++ MP_ADD_CARRY_ZERO (r1, a3b, r1, carry); ++ MP_ADD_CARRY (r2, a4 , r2, carry, carry); ++ MP_ADD_CARRY (r3, a5a, r3, carry, carry); ++ MP_ADD_CARRY_ZERO (r1, a5b, r1, carry); ++ MP_ADD_CARRY (r2, a6 , r2, carry, carry); ++ MP_ADD_CARRY (r3, 0, r3, carry, carry); ++ ++ MP_SUB_BORROW(r0, a4a_a3b, r0, 0, carry); ++ MP_SUB_BORROW(r1, a5a_a4b, r1, carry, carry); ++ MP_SUB_BORROW(r2, a6a_a5b, r2, carry, carry); ++ MP_SUB_BORROW(r3, a6b , r3, carry, carry); ++ MP_SUB_BORROW(r0, a6a_a5b, r0, 0, carry); ++ MP_SUB_BORROW(r1, a6b , r1, carry, carry); ++ if (carry) { ++ MP_SUB_BORROW(r2, 0, r2, carry, carry); ++ MP_SUB_BORROW(r3, 0, r3, carry, carry); ++ } ++ ++ ++ /* if the value is negative, r3 has a 2's complement ++ * high value */ ++ r3b = (int)(r3 >>32); ++ while (r3b > 0) { ++ r3 &= 0xffffffff; ++ MP_ADD_CARRY_ZERO(r1,((mp_digit)r3b) << 32, r1, carry); ++ if (carry) { ++ MP_ADD_CARRY(r2, 0, r2, carry, carry); ++ MP_ADD_CARRY(r3, 0, r3, carry, carry); ++ } ++ MP_SUB_BORROW(r0, r3b, r0, 0, carry); ++ if (carry) { ++ MP_SUB_BORROW(r1, 0, r1, carry, carry); ++ MP_SUB_BORROW(r2, 0, r2, carry, carry); ++ MP_SUB_BORROW(r3, 0, r3, carry, carry); ++ } ++ r3b = (int)(r3 >>32); ++ } ++ ++ while (r3b < 0) { ++ MP_ADD_CARRY_ZERO (r0, 1, r0, carry); ++ MP_ADD_CARRY (r1, MP_DIGIT_MAX <<32, r1, carry, carry); ++ MP_ADD_CARRY (r2, MP_DIGIT_MAX, r2, carry, carry); ++ MP_ADD_CARRY (r3, MP_DIGIT_MAX >> 32, r3, carry, carry); ++ r3b = (int)(r3 >>32); ++ } ++ /* check for final reduction */ ++ /* now the only way we are over is if the top 4 words are all ones */ ++ if ((r3 == (MP_DIGIT_MAX >> 32)) && (r2 == MP_DIGIT_MAX) ++ && ((r1 & MP_DIGIT_MAX << 32)== MP_DIGIT_MAX << 32) && ++ ((r1 != MP_DIGIT_MAX << 32 ) || (r0 != 0)) ) { ++ /* one last subraction */ ++ MP_SUB_BORROW(r0, 1, r0, 0, carry); ++ MP_SUB_BORROW(r1, 0, r1, carry, carry); ++ r2 = r3 = 0; ++ } ++ ++ ++ if (a != r) { ++ MP_CHECKOK(s_mp_pad(r, 4)); ++ } ++ /* set the lower words of r */ ++ MP_SIGN(r) = MP_ZPOS; ++ MP_USED(r) = 4; ++ MP_DIGIT(r, 3) = r3; ++ MP_DIGIT(r, 2) = r2; ++ MP_DIGIT(r, 1) = r1; ++ MP_DIGIT(r, 0) = r0; ++#endif ++ } ++ ++ CLEANUP: ++ return res; ++} ++ ++/* Compute the square of polynomial a, reduce modulo p224. Store the ++ * result in r. r could be a. Uses optimized modular reduction for p224. ++ */ ++mp_err ++ec_GFp_nistp224_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ ++ MP_CHECKOK(mp_sqr(a, r)); ++ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); ++ CLEANUP: ++ return res; ++} ++ ++/* Compute the product of two polynomials a and b, reduce modulo p224. ++ * Store the result in r. r could be a or b; a could be b. Uses ++ * optimized modular reduction for p224. */ ++mp_err ++ec_GFp_nistp224_mul(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ ++ MP_CHECKOK(mp_mul(a, b, r)); ++ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); ++ CLEANUP: ++ return res; ++} ++ ++/* Divides two field elements. If a is NULL, then returns the inverse of ++ * b. */ ++mp_err ++ec_GFp_nistp224_div(const mp_int *a, const mp_int *b, mp_int *r, ++ const GFMethod *meth) ++{ ++ mp_err res = MP_OKAY; ++ mp_int t; ++ ++ /* If a is NULL, then return the inverse of b, otherwise return a/b. */ ++ if (a == NULL) { ++ return mp_invmod(b, &meth->irr, r); ++ } else { ++ /* MPI doesn't support divmod, so we implement it using invmod and ++ * mulmod. */ ++ MP_CHECKOK(mp_init(&t, FLAG(b))); ++ MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); ++ MP_CHECKOK(mp_mul(a, &t, r)); ++ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); ++ CLEANUP: ++ mp_clear(&t); ++ return res; ++ } ++} ++ ++/* Wire in fast field arithmetic and precomputation of base point for ++ * named curves. */ ++mp_err ++ec_group_set_gfp224(ECGroup *group, ECCurveName name) ++{ ++ if (name == ECCurve_NIST_P224) { ++ group->meth->field_mod = &ec_GFp_nistp224_mod; ++ group->meth->field_mul = &ec_GFp_nistp224_mul; ++ group->meth->field_sqr = &ec_GFp_nistp224_sqr; ++ group->meth->field_div = &ec_GFp_nistp224_div; ++ } ++ return MP_OKAY; ++} +diff -uNr openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/oid.c afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/oid.c +--- openjdk/src/jdk.crypto.ec/share/native/libsunec/impl/oid.c 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/src/jdk.crypto.ec/share/native/libsunec/impl/oid.c 2025-05-09 10:05:57.616290593 +0800 +@@ -73,13 +73,87 @@ + /* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the + * same as secp256r1 + */ ++CONST_OID ansiX962prime192v1[] = { ANSI_X962_GFp_OID, 0x01 }; ++CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 }; ++CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 }; ++CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 }; ++CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 }; ++CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 }; + CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 }; + + /* SECG prime curve OIDs */ ++CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 }; ++CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 }; ++CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c }; ++CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d }; ++CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 }; ++CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 }; ++CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e }; ++CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f }; ++CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 }; ++CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 }; + CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a }; + CONST_OID secgECsecp384r1[] = { SECG_OID, 0x22 }; + CONST_OID secgECsecp521r1[] = { SECG_OID, 0x23 }; + ++/* SECG characterisitic two curve OIDs */ ++CONST_OID secgECsect113r1[] = {SECG_OID, 0x04 }; ++CONST_OID secgECsect113r2[] = {SECG_OID, 0x05 }; ++CONST_OID secgECsect131r1[] = {SECG_OID, 0x16 }; ++CONST_OID secgECsect131r2[] = {SECG_OID, 0x17 }; ++CONST_OID secgECsect163k1[] = {SECG_OID, 0x01 }; ++CONST_OID secgECsect163r1[] = {SECG_OID, 0x02 }; ++CONST_OID secgECsect163r2[] = {SECG_OID, 0x0f }; ++CONST_OID secgECsect193r1[] = {SECG_OID, 0x18 }; ++CONST_OID secgECsect193r2[] = {SECG_OID, 0x19 }; ++CONST_OID secgECsect233k1[] = {SECG_OID, 0x1a }; ++CONST_OID secgECsect233r1[] = {SECG_OID, 0x1b }; ++CONST_OID secgECsect239k1[] = {SECG_OID, 0x03 }; ++CONST_OID secgECsect283k1[] = {SECG_OID, 0x10 }; ++CONST_OID secgECsect283r1[] = {SECG_OID, 0x11 }; ++CONST_OID secgECsect409k1[] = {SECG_OID, 0x24 }; ++CONST_OID secgECsect409r1[] = {SECG_OID, 0x25 }; ++CONST_OID secgECsect571k1[] = {SECG_OID, 0x26 }; ++CONST_OID secgECsect571r1[] = {SECG_OID, 0x27 }; ++ ++/* ANSI X9.62 characteristic two curve OIDs */ ++CONST_OID ansiX962c2pnb163v1[] = { ANSI_X962_GF2m_OID, 0x01 }; ++CONST_OID ansiX962c2pnb163v2[] = { ANSI_X962_GF2m_OID, 0x02 }; ++CONST_OID ansiX962c2pnb163v3[] = { ANSI_X962_GF2m_OID, 0x03 }; ++CONST_OID ansiX962c2pnb176v1[] = { ANSI_X962_GF2m_OID, 0x04 }; ++CONST_OID ansiX962c2tnb191v1[] = { ANSI_X962_GF2m_OID, 0x05 }; ++CONST_OID ansiX962c2tnb191v2[] = { ANSI_X962_GF2m_OID, 0x06 }; ++CONST_OID ansiX962c2tnb191v3[] = { ANSI_X962_GF2m_OID, 0x07 }; ++CONST_OID ansiX962c2onb191v4[] = { ANSI_X962_GF2m_OID, 0x08 }; ++CONST_OID ansiX962c2onb191v5[] = { ANSI_X962_GF2m_OID, 0x09 }; ++CONST_OID ansiX962c2pnb208w1[] = { ANSI_X962_GF2m_OID, 0x0a }; ++CONST_OID ansiX962c2tnb239v1[] = { ANSI_X962_GF2m_OID, 0x0b }; ++CONST_OID ansiX962c2tnb239v2[] = { ANSI_X962_GF2m_OID, 0x0c }; ++CONST_OID ansiX962c2tnb239v3[] = { ANSI_X962_GF2m_OID, 0x0d }; ++CONST_OID ansiX962c2onb239v4[] = { ANSI_X962_GF2m_OID, 0x0e }; ++CONST_OID ansiX962c2onb239v5[] = { ANSI_X962_GF2m_OID, 0x0f }; ++CONST_OID ansiX962c2pnb272w1[] = { ANSI_X962_GF2m_OID, 0x10 }; ++CONST_OID ansiX962c2pnb304w1[] = { ANSI_X962_GF2m_OID, 0x11 }; ++CONST_OID ansiX962c2tnb359v1[] = { ANSI_X962_GF2m_OID, 0x12 }; ++CONST_OID ansiX962c2pnb368w1[] = { ANSI_X962_GF2m_OID, 0x13 }; ++CONST_OID ansiX962c2tnb431r1[] = { ANSI_X962_GF2m_OID, 0x14 }; ++ ++/* TeleTrusT ECC Brainpool prime curve OIDs */ ++CONST_OID brainpoolP160r1[] = { ECC_BRAINPOOL_EC_V1, 0x01 }; ++CONST_OID brainpoolP160t1[] = { ECC_BRAINPOOL_EC_V1, 0x02 }; ++CONST_OID brainpoolP192r1[] = { ECC_BRAINPOOL_EC_V1, 0x03 }; ++CONST_OID brainpoolP192t1[] = { ECC_BRAINPOOL_EC_V1, 0x04 }; ++CONST_OID brainpoolP224r1[] = { ECC_BRAINPOOL_EC_V1, 0x05 }; ++CONST_OID brainpoolP224t1[] = { ECC_BRAINPOOL_EC_V1, 0x06 }; ++CONST_OID brainpoolP256r1[] = { ECC_BRAINPOOL_EC_V1, 0x07 }; ++CONST_OID brainpoolP256t1[] = { ECC_BRAINPOOL_EC_V1, 0x08 }; ++CONST_OID brainpoolP320r1[] = { ECC_BRAINPOOL_EC_V1, 0x09 }; ++CONST_OID brainpoolP320t1[] = { ECC_BRAINPOOL_EC_V1, 0x0a }; ++CONST_OID brainpoolP384r1[] = { ECC_BRAINPOOL_EC_V1, 0x0b }; ++CONST_OID brainpoolP384t1[] = { ECC_BRAINPOOL_EC_V1, 0x0c }; ++CONST_OID brainpoolP512r1[] = { ECC_BRAINPOOL_EC_V1, 0x0d }; ++CONST_OID brainpoolP512t1[] = { ECC_BRAINPOOL_EC_V1, 0x0e }; ++ + #define OI(x) { siDEROID, (unsigned char *)x, sizeof x } + #ifndef SECOID_NO_STRINGS + #define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext } +@@ -100,18 +174,30 @@ + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( ansiX962prime192v1, ECCurve_NIST_P192, ++ "ANSI X9.62 elliptic curve prime192v1 (aka secp192r1, NIST P-192)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962prime192v2, ECCurve_X9_62_PRIME_192V2, ++ "ANSI X9.62 elliptic curve prime192v2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962prime192v3, ECCurve_X9_62_PRIME_192V3, ++ "ANSI X9.62 elliptic curve prime192v3", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962prime239v1, ECCurve_X9_62_PRIME_239V1, ++ "ANSI X9.62 elliptic curve prime239v1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962prime239v2, ECCurve_X9_62_PRIME_239V2, ++ "ANSI X9.62 elliptic curve prime239v2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962prime239v3, ECCurve_X9_62_PRIME_239V3, ++ "ANSI X9.62 elliptic curve prime239v3", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + OD( ansiX962prime256v1, ECCurve_NIST_P256, + "ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)", + CKM_INVALID_MECHANISM, +@@ -122,24 +208,42 @@ + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( secgECsect163k1, ECCurve_NIST_K163, ++ "SECG elliptic curve sect163k1 (aka NIST K-163)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect163r1, ECCurve_SECG_CHAR2_163R1, ++ "SECG elliptic curve sect163r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect239k1, ECCurve_SECG_CHAR2_239K1, ++ "SECG elliptic curve sect239k1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect113r1, ECCurve_SECG_CHAR2_113R1, ++ "SECG elliptic curve sect113r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect113r2, ECCurve_SECG_CHAR2_113R2, ++ "SECG elliptic curve sect113r2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp112r1, ECCurve_SECG_PRIME_112R1, ++ "SECG elliptic curve secp112r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp112r2, ECCurve_SECG_PRIME_112R2, ++ "SECG elliptic curve secp112r2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp160r1, ECCurve_SECG_PRIME_160R1, ++ "SECG elliptic curve secp160r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp160k1, ECCurve_SECG_PRIME_160K1, ++ "SECG elliptic curve secp160k1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + OD( secgECsecp256k1, ECCurve_SECG_PRIME_256K1, + "SECG elliptic curve secp256k1", + CKM_INVALID_MECHANISM, +@@ -152,6 +256,18 @@ + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( secgECsect163r2, ECCurve_NIST_B163, ++ "SECG elliptic curve sect163r2 (aka NIST B-163)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect283k1, ECCurve_NIST_K283, ++ "SECG elliptic curve sect283k1 (aka NIST K-283)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect283r1, ECCurve_NIST_B283, ++ "SECG elliptic curve sect283r1 (aka NIST B-283)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, NULL, 0 }, ECCurve_noName, +@@ -160,36 +276,54 @@ + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( secgECsect131r1, ECCurve_SECG_CHAR2_131R1, ++ "SECG elliptic curve sect131r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect131r2, ECCurve_SECG_CHAR2_131R2, ++ "SECG elliptic curve sect131r2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect193r1, ECCurve_SECG_CHAR2_193R1, ++ "SECG elliptic curve sect193r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect193r2, ECCurve_SECG_CHAR2_193R2, ++ "SECG elliptic curve sect193r2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect233k1, ECCurve_NIST_K233, ++ "SECG elliptic curve sect233k1 (aka NIST K-233)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect233r1, ECCurve_NIST_B233, ++ "SECG elliptic curve sect233r1 (aka NIST B-233)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp128r1, ECCurve_SECG_PRIME_128R1, ++ "SECG elliptic curve secp128r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp128r2, ECCurve_SECG_PRIME_128R2, ++ "SECG elliptic curve secp128r2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp160r2, ECCurve_SECG_PRIME_160R2, ++ "SECG elliptic curve secp160r2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp192k1, ECCurve_SECG_PRIME_192K1, ++ "SECG elliptic curve secp192k1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp224k1, ECCurve_SECG_PRIME_224K1, ++ "SECG elliptic curve secp224k1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsecp224r1, ECCurve_NIST_P224, ++ "SECG elliptic curve secp224r1 (aka NIST P-224)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + OD( secgECsecp384r1, ECCurve_NIST_P384, + "SECG elliptic curve secp384r1 (aka NIST P-384)", + CKM_INVALID_MECHANISM, +@@ -198,14 +332,22 @@ + "SECG elliptic curve secp521r1 (aka NIST P-521)", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION } ++ OD( secgECsect409k1, ECCurve_NIST_K409, ++ "SECG elliptic curve sect409k1 (aka NIST K-409)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect409r1, ECCurve_NIST_B409, ++ "SECG elliptic curve sect409r1 (aka NIST B-409)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect571k1, ECCurve_NIST_K571, ++ "SECG elliptic curve sect571k1 (aka NIST K-571)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( secgECsect571r1, ECCurve_NIST_B571, ++ "SECG elliptic curve sect571r1 (aka NIST B-571)", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ) + }; + + static SECOidData ANSI_oids[] = { +@@ -213,46 +355,78 @@ + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + + /* ANSI X9.62 named elliptic curves (characteristic two field) */ ++ OD( ansiX962c2pnb163v1, ECCurve_X9_62_CHAR2_PNB163V1, ++ "ANSI X9.62 elliptic curve c2pnb163v1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2pnb163v2, ECCurve_X9_62_CHAR2_PNB163V2, ++ "ANSI X9.62 elliptic curve c2pnb163v2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2pnb163v3, ECCurve_X9_62_CHAR2_PNB163V3, ++ "ANSI X9.62 elliptic curve c2pnb163v3", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2pnb176v1, ECCurve_X9_62_CHAR2_PNB176V1, ++ "ANSI X9.62 elliptic curve c2pnb176v1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb191v1, ECCurve_X9_62_CHAR2_TNB191V1, ++ "ANSI X9.62 elliptic curve c2tnb191v1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb191v2, ECCurve_X9_62_CHAR2_TNB191V2, ++ "ANSI X9.62 elliptic curve c2tnb191v2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb191v3, ECCurve_X9_62_CHAR2_TNB191V3, ++ "ANSI X9.62 elliptic curve c2tnb191v3", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( ansiX962c2pnb208w1, ECCurve_X9_62_CHAR2_PNB208W1, ++ "ANSI X9.62 elliptic curve c2pnb208w1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb239v1, ECCurve_X9_62_CHAR2_TNB239V1, ++ "ANSI X9.62 elliptic curve c2tnb239v1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb239v2, ECCurve_X9_62_CHAR2_TNB239V2, ++ "ANSI X9.62 elliptic curve c2tnb239v2", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb239v3, ECCurve_X9_62_CHAR2_TNB239V3, ++ "ANSI X9.62 elliptic curve c2tnb239v3", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, +- { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION } ++ OD( ansiX962c2pnb272w1, ECCurve_X9_62_CHAR2_PNB272W1, ++ "ANSI X9.62 elliptic curve c2pnb272w1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2pnb304w1, ECCurve_X9_62_CHAR2_PNB304W1, ++ "ANSI X9.62 elliptic curve c2pnb304w1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb359v1, ECCurve_X9_62_CHAR2_TNB359V1, ++ "ANSI X9.62 elliptic curve c2tnb359v1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2pnb368w1, ECCurve_X9_62_CHAR2_PNB368W1, ++ "ANSI X9.62 elliptic curve c2pnb368w1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), ++ OD( ansiX962c2tnb431r1, ECCurve_X9_62_CHAR2_TNB431R1, ++ "ANSI X9.62 elliptic curve c2tnb431r1", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ) + }; + + static SECOidData BRAINPOOL_oids[] = { +@@ -272,14 +446,31 @@ + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( brainpoolP256r1, ECCurve_BrainpoolP256r1, ++ "brainpoolP256r1 domain parameter set", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( brainpoolP320r1, ECCurve_BrainpoolP320r1, ++ "brainpoolP320r1 domain parameter set", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( brainpoolP384r1, ECCurve_BrainpoolP384r1, ++ "brainpoolP384r1 domain parameter set", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, ++ OD( brainpoolP512r1, ECCurve_BrainpoolP512r1, ++ "brainpoolP512r1 domain parameter set", ++ CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION ), + { { siDEROID, NULL, 0 }, ECCurve_noName, +- "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION } ++ "Unknown OID", CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION } + }; + + int +diff -uNr openjdk/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h afu11u/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h +--- openjdk/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h 2025-05-09 10:06:54.428292512 +0800 +@@ -44,6 +44,10 @@ + #include + #define user_regs_struct pt_regs + #endif ++#if defined(sw64) ++#include ++#define user_regs_struct user_pt_regs ++#endif + + // This C bool type must be int for compatibility with Linux calls and + // it would be a mistake to equivalence it to C++ bool on many platforms +diff -uNr openjdk/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c afu11u/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c +--- openjdk/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c 2025-05-09 10:06:54.428292512 +0800 +@@ -58,6 +58,10 @@ + #include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h" + #endif + ++#ifdef sw64 ++#include "sun_jvm_hotspot_debugger_sw64_SW64ThreadContext.h" ++#endif ++ + static jfieldID p_ps_prochandle_ID = 0; + static jfieldID threadList_ID = 0; + static jfieldID loadObjectList_ID = 0; +@@ -397,7 +401,7 @@ + return (err == PS_OK)? array : 0; + } + +-#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(ppc64le) || defined(aarch64) ++#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(ppc64le) || defined(aarch64) || defined(sw64) + JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 + (JNIEnv *env, jobject this_obj, jint lwp_id) { + +@@ -428,7 +432,9 @@ + #if defined(ppc64) || defined(ppc64le) + #define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG + #endif +- ++#ifdef sw64 ++#define NPRGREG sun_jvm_hotspot_debugger_sw64_SW64ThreadContext_NPRGREG ++#endif + + array = (*env)->NewLongArray(env, NPRGREG); + CHECK_EXCEPTION_(0); +@@ -574,6 +580,20 @@ + + #endif + ++#ifdef sw64 ++ ++#define REG_INDEX(reg) sun_jvm_hotspot_debugger_sw64_SW64ThreadContext_##reg ++ ++ { ++ int i; ++ for (i = 0; i < 31; i++) ++ regs[i] = gregs.regs[i]; ++ regs[REG_INDEX(PC)] = gregs.pc; ++ regs[REG_INDEX(PSTATE)] = gregs.pstate; ++ } ++ ++#endif /* sw64 */ ++ + (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); + return array; + } +diff -uNr openjdk/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c afu11u/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c +--- openjdk/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c 2025-05-09 10:06:54.428292512 +0800 +@@ -141,6 +141,9 @@ + #elif defined(PT_GETREGS) + #define PTRACE_GETREGS_REQ PT_GETREGS + #endif ++#if defined(sw64) ++ #undef PTRACE_GETREGS_REQ ++#endif + + #ifdef PTRACE_GETREGS_REQ + if (ptrace_getregs(PTRACE_GETREGS_REQ, pid, user, NULL) < 0) { +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java 2025-05-09 10:06:54.428292512 +0800 +@@ -35,11 +35,13 @@ + import sun.jvm.hotspot.debugger.aarch64.*; + import sun.jvm.hotspot.debugger.sparc.*; + import sun.jvm.hotspot.debugger.ppc64.*; ++import sun.jvm.hotspot.debugger.sw64.*; + import sun.jvm.hotspot.debugger.linux.x86.*; + import sun.jvm.hotspot.debugger.linux.amd64.*; + import sun.jvm.hotspot.debugger.linux.sparc.*; + import sun.jvm.hotspot.debugger.linux.ppc64.*; + import sun.jvm.hotspot.debugger.linux.aarch64.*; ++import sun.jvm.hotspot.debugger.linux.sw64.*; + import sun.jvm.hotspot.utilities.*; + + class LinuxCDebugger implements CDebugger { +@@ -116,6 +118,13 @@ + Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); + if (pc == null) return null; + return new LinuxAARCH64CFrame(dbg, fp, pc); ++ } else if (cpu.equals("sw64")) { ++ SW64ThreadContext context = (SW64ThreadContext) thread.getContext(); ++ Address fp = context.getRegisterAsAddress(SW64ThreadContext.FP); ++ if (fp == null) return null; ++ Address pc = context.getRegisterAsAddress(SW64ThreadContext.PC); ++ if (pc == null) return null; ++ return new LinuxSW64CFrame(dbg, fp, pc); + } else { + // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu + ThreadContext context = (ThreadContext) thread.getContext(); +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64CFrame.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64CFrame.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64CFrame.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64CFrame.java 2025-05-09 10:05:57.648290594 +0800 +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.linux.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.debugger.linux.*; ++import sun.jvm.hotspot.debugger.cdbg.*; ++import sun.jvm.hotspot.debugger.cdbg.basic.*; ++ ++final public class LinuxSW64CFrame extends BasicCFrame { ++ public LinuxSW64CFrame(LinuxDebugger dbg, Address fp, Address pc) { ++ super(dbg.getCDebugger()); ++ this.fp = fp; ++ this.pc = pc; ++ this.dbg = dbg; ++ } ++ ++ // override base class impl to avoid ELF parsing ++ public ClosestSymbol closestSymbolToPC() { ++ // try native lookup in debugger. ++ return dbg.lookup(dbg.getAddressValue(pc())); ++ } ++ ++ public Address pc() { ++ return pc; ++ } ++ ++ public Address localVariableBase() { ++ return fp; ++ } ++ ++ public CFrame sender(ThreadProxy thread) { ++ SW64ThreadContext context = (SW64ThreadContext) thread.getContext(); ++ Address rsp = context.getRegisterAsAddress(SW64ThreadContext.SP); ++ ++ if ((fp == null) || fp.lessThan(rsp)) { ++ return null; ++ } ++ ++ // Check alignment of fp ++ if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) { ++ return null; ++ } ++ ++ Address nextFP = fp.getAddressAt(0 * ADDRESS_SIZE); ++ if (nextFP == null || nextFP.lessThanOrEqual(fp)) { ++ return null; ++ } ++ Address nextPC = fp.getAddressAt(1 * ADDRESS_SIZE); ++ if (nextPC == null) { ++ return null; ++ } ++ return new LinuxSW64CFrame(dbg, nextFP, nextPC); ++ } ++ ++ // package/class internals only ++ private static final int ADDRESS_SIZE = 8; ++ private Address pc; ++ private Address sp; ++ private Address fp; ++ private LinuxDebugger dbg; ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64ThreadContext.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64ThreadContext.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64ThreadContext.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sw64/LinuxSW64ThreadContext.java 2025-05-09 10:05:57.648290594 +0800 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.linux.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.debugger.linux.*; ++ ++public class LinuxSW64ThreadContext extends SW64ThreadContext { ++ private LinuxDebugger debugger; ++ ++ public LinuxSW64ThreadContext(LinuxDebugger debugger) { ++ super(); ++ this.debugger = debugger; ++ } ++ ++ public void setRegisterAsAddress(int index, Address value) { ++ setRegister(index, debugger.getAddressValue(value)); ++ } ++ ++ public Address getRegisterAsAddress(int index) { ++ return debugger.newAddress(getRegister(index)); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSW64.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSW64.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSW64.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSW64.java 2025-05-09 10:06:54.428292512 +0800 +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2024, 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. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger; ++ ++public class MachineDescriptionSW64 extends MachineDescriptionTwosComplement implements MachineDescription { ++ public long getAddressSize() { ++ return 8; ++ } ++ ++ public boolean isLP64() { ++ return true; ++ } ++ ++ public boolean isBigEndian() { ++ return false; ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java 2025-05-09 10:05:57.652290594 +0800 +@@ -34,11 +34,13 @@ + import sun.jvm.hotspot.debugger.proc.aarch64.*; + import sun.jvm.hotspot.debugger.proc.sparc.*; + import sun.jvm.hotspot.debugger.proc.ppc64.*; ++import sun.jvm.hotspot.debugger.proc.sw64.*; + import sun.jvm.hotspot.debugger.proc.x86.*; + import sun.jvm.hotspot.debugger.ppc64.*; + import sun.jvm.hotspot.debugger.amd64.*; + import sun.jvm.hotspot.debugger.aarch64.*; + import sun.jvm.hotspot.debugger.sparc.*; ++import sun.jvm.hotspot.debugger.sw64.*; + import sun.jvm.hotspot.debugger.x86.*; + import sun.jvm.hotspot.utilities.*; + +@@ -90,6 +92,10 @@ + threadFactory = new ProcAMD64ThreadFactory(this); + pcRegIndex = AMD64ThreadContext.RIP; + fpRegIndex = AMD64ThreadContext.RBP; ++ } else if (cpu.equals("sw64") || cpu.equals("sw_64")) { ++ threadFactory = new ProcSW64ThreadFactory(this); ++ pcRegIndex = SW64ThreadContext.PC; ++ fpRegIndex = SW64ThreadContext.FP; + } else if (cpu.equals("aarch64")) { + threadFactory = new ProcAARCH64ThreadFactory(this); + pcRegIndex = AARCH64ThreadContext.PC; +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadContext.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadContext.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadContext.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadContext.java 2025-05-09 10:05:57.652290594 +0800 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.proc.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.debugger.proc.*; ++ ++public class ProcSW64ThreadContext extends SW64ThreadContext { ++ private ProcDebugger debugger; ++ ++ public ProcSW64ThreadContext(ProcDebugger debugger) { ++ super(); ++ this.debugger = debugger; ++ } ++ ++ public void setRegisterAsAddress(int index, Address value) { ++ setRegister(index, debugger.getAddressValue(value)); ++ } ++ ++ public Address getRegisterAsAddress(int index) { ++ return debugger.newAddress(getRegister(index)); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadFactory.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadFactory.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadFactory.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64ThreadFactory.java 2025-05-09 10:05:57.652290594 +0800 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.proc.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.proc.*; ++ ++public class ProcSW64ThreadFactory implements ProcThreadFactory { ++ private ProcDebugger debugger; ++ ++ public ProcSW64ThreadFactory(ProcDebugger debugger) { ++ this.debugger = debugger; ++ } ++ ++ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) { ++ return new ProcSW64Thread(debugger, threadIdentifierAddr); ++ } ++ ++ public ThreadProxy createThreadWrapper(long id) { ++ return new ProcSW64Thread(debugger, id); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64Thread.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64Thread.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64Thread.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sw64/ProcSW64Thread.java 2025-05-09 10:05:57.652290594 +0800 +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.proc.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.debugger.proc.*; ++import sun.jvm.hotspot.utilities.*; ++ ++public class ProcSW64Thread implements ThreadProxy { ++ private ProcDebugger debugger; ++ private int id; ++ ++ public ProcSW64Thread(ProcDebugger debugger, Address addr) { ++ this.debugger = debugger; ++ ++ // FIXME: the size here should be configurable. However, making it ++ // so would produce a dependency on the "types" package from the ++ // debugger package, which is not desired. ++ this.id = (int) addr.getCIntegerAt(0, 4, true); ++ } ++ ++ public ProcSW64Thread(ProcDebugger debugger, long id) { ++ this.debugger = debugger; ++ this.id = (int) id; ++ } ++ ++ public ThreadContext getContext() throws IllegalThreadStateException { ++ ProcSW64ThreadContext context = new ProcSW64ThreadContext(debugger); ++ long[] regs = debugger.getThreadIntegerRegisterSet(id); ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(regs.length == SW64ThreadContext.NPRGREG, "size mismatch"); ++ } ++ for (int i = 0; i < regs.length; i++) { ++ context.setRegister(i, regs[i]); ++ } ++ return context; ++ } ++ ++ public boolean canSetContext() throws DebuggerException { ++ return false; ++ } ++ ++ public void setContext(ThreadContext context) ++ throws IllegalThreadStateException, DebuggerException { ++ throw new DebuggerException("Unimplemented"); ++ } ++ ++ public String toString() { ++ return "t@" + id; ++ } ++ ++ public boolean equals(Object obj) { ++ if ((obj == null) || !(obj instanceof ProcSW64Thread)) { ++ return false; ++ } ++ ++ return (((ProcSW64Thread) obj).id == id); ++ } ++ ++ public int hashCode() { ++ return id; ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java 2025-05-09 10:05:57.652290594 +0800 +@@ -31,6 +31,7 @@ + import sun.jvm.hotspot.debugger.*; + import sun.jvm.hotspot.debugger.cdbg.*; + import sun.jvm.hotspot.debugger.remote.sparc.*; ++import sun.jvm.hotspot.debugger.remote.sw64.*; + import sun.jvm.hotspot.debugger.remote.x86.*; + import sun.jvm.hotspot.debugger.remote.amd64.*; + import sun.jvm.hotspot.debugger.remote.ppc64.*; +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadContext.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadContext.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadContext.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadContext.java 2025-05-09 10:05:57.652290594 +0800 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.remote.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.debugger.remote.*; ++ ++public class RemoteSW64ThreadContext extends SW64ThreadContext { ++ private RemoteDebuggerClient debugger; ++ ++ public RemoteSW64ThreadContext(RemoteDebuggerClient debugger) { ++ super(); ++ this.debugger = debugger; ++ } ++ ++ public void setRegisterAsAddress(int index, Address value) { ++ setRegister(index, debugger.getAddressValue(value)); ++ } ++ ++ public Address getRegisterAsAddress(int index) { ++ return debugger.newAddress(getRegister(index)); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadFactory.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadFactory.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadFactory.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64ThreadFactory.java 2025-05-09 10:05:57.652290594 +0800 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.remote.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.remote.*; ++ ++public class RemoteSW64ThreadFactory implements RemoteThreadFactory { ++ private RemoteDebuggerClient debugger; ++ ++ public RemoteSW64ThreadFactory(RemoteDebuggerClient debugger) { ++ this.debugger = debugger; ++ } ++ ++ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) { ++ return new RemoteSW64Thread(debugger, threadIdentifierAddr); ++ } ++ ++ public ThreadProxy createThreadWrapper(long id) { ++ return new RemoteSW64Thread(debugger, id); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64Thread.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64Thread.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64Thread.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sw64/RemoteSW64Thread.java 2025-05-09 10:05:57.652290594 +0800 +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.remote.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.debugger.remote.*; ++import sun.jvm.hotspot.utilities.*; ++ ++public class RemoteSW64Thread extends RemoteThread { ++ public RemoteSW64Thread(RemoteDebuggerClient debugger, Address addr) { ++ super(debugger, addr); ++ } ++ ++ public RemoteSW64Thread(RemoteDebuggerClient debugger, long id) { ++ super(debugger, id); ++ } ++ ++ public ThreadContext getContext() throws IllegalThreadStateException { ++ RemoteSW64ThreadContext context = new RemoteSW64ThreadContext(debugger); ++ long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) : ++ debugger.getThreadIntegerRegisterSet(id); ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(regs.length == SW64ThreadContext.NPRGREG, "size of register set must match"); ++ } ++ for (int i = 0; i < regs.length; i++) { ++ context.setRegister(i, regs[i]); ++ } ++ return context; ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/sw64/SW64ThreadContext.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/sw64/SW64ThreadContext.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/sw64/SW64ThreadContext.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/sw64/SW64ThreadContext.java 2025-05-09 10:06:54.428292512 +0800 +@@ -0,0 +1,143 @@ ++/* ++ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.debugger.sw64; ++ ++import java.lang.annotation.Native; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.cdbg.*; ++ ++/** Specifies the thread context on sw64 platforms; only a sub-portion ++ * of the context is guaranteed to be present on all operating ++ * systems. */ ++ ++public abstract class SW64ThreadContext implements ThreadContext { ++ // Taken from /usr/include/asm/sigcontext.h on Linux/SW64. ++ ++ // /* ++ // * Signal context structure - contains all info to do with the state ++ // * before the signal handler was invoked. ++ // */ ++ // struct sigcontext { ++ // __u64 fault_address; ++ // /* sw64 registers */ ++ // __u64 regs[31]; ++ // __u64 pc; ++ // __u64 pstate; ++ // /* 4K reserved for FP/SIMD state and future expansion */ ++ // __u8 __reserved[4096] __attribute__((__aligned__(16))); ++ // }; ++ ++ // NOTE: the indices for the various registers must be maintained as ++ // listed across various operating systems. However, only a small ++ // subset of the registers' values are guaranteed to be present (and ++ // must be present for the SA's stack walking to work) ++ ++ // One instance of the Native annotation is enough to trigger header generation ++ // for this file. ++ @Native ++ public static final int V0 = 0; ++ public static final int T0 = 1; ++ public static final int T1 = 2; ++ public static final int T2 = 3; ++ public static final int T3 = 4; ++ public static final int T4 = 5; ++ public static final int T5 = 6; ++ public static final int T6 = 7; ++ public static final int T7 = 8; ++ public static final int S0 = 9; ++ public static final int S1 = 10; ++ public static final int S2 = 11; ++ public static final int S3 = 12; ++ public static final int S4 = 13; ++ public static final int S5 = 14; ++ public static final int FP = 15; ++ public static final int A0 = 16; ++ public static final int A1 = 17; ++ public static final int A2 = 18; ++ public static final int A3 = 19; ++ public static final int A4 = 20; ++ public static final int A5 = 21; ++ public static final int T8 = 22; ++ public static final int T9 = 23; ++ public static final int T10 = 24; ++ public static final int T11 = 25; ++ public static final int RA = 26; ++ public static final int T12 = 27; ++ public static final int AT = 28; ++ public static final int GP = 29; ++ public static final int SP = 30; ++ public static final int PC = 31; ++ public static final int PSTATE = 32; ++ ++ public static final int NPRGREG = 33; ++ ++ private static final String[] regNames = { ++ "V0", "T0", "T1", "T2", ++ "T3", "T4", "T5", "T6", ++ "T7", "S0", "S1", "S2", ++ "S3", "S4", "S5", "FP", ++ "A0", "A1", "A2", "A3", ++ "A4", "A5", "T8", "T9", ++ "T10", "T11", "RA", "T12", ++ "AT", "GP", "SP", "PC", ++ "PSTATE", ++ }; ++ ++ private long[] data; ++ ++ public SW64ThreadContext() { ++ data = new long[NPRGREG]; ++ } ++ ++ public int getNumRegisters() { ++ return NPRGREG; ++ } ++ ++ public String getRegisterName(int index) { ++ return regNames[index]; ++ } ++ ++ public void setRegister(int index, long value) { ++ data[index] = value; ++ } ++ ++ public long getRegister(int index) { ++ return data[index]; ++ } ++ ++ public CFrame getTopFrame(Debugger dbg) { ++ return null; ++ } ++ ++ /** This can't be implemented in this class since we would have to ++ * tie the implementation to, for example, the debugging system */ ++ public abstract void setRegisterAsAddress(int index, Address value); ++ ++ /** This can't be implemented in this class since we would have to ++ * tie the implementation to, for example, the debugging system */ ++ public abstract Address getRegisterAsAddress(int index); ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java 2025-05-09 10:06:54.428292512 +0800 +@@ -36,6 +36,7 @@ + import sun.jvm.hotspot.debugger.MachineDescriptionAMD64; + import sun.jvm.hotspot.debugger.MachineDescriptionPPC64; + import sun.jvm.hotspot.debugger.MachineDescriptionAArch64; ++import sun.jvm.hotspot.debugger.MachineDescriptionSW64; + import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86; + import sun.jvm.hotspot.debugger.MachineDescriptionSPARC32Bit; + import sun.jvm.hotspot.debugger.MachineDescriptionSPARC64Bit; +@@ -592,6 +593,8 @@ + machDesc = new MachineDescriptionPPC64(); + } else if (cpu.equals("aarch64")) { + machDesc = new MachineDescriptionAArch64(); ++ } else if (cpu.equals("sw64")) { ++ machDesc = new MachineDescriptionSW64(); + } else if (cpu.equals("sparc")) { + if (LinuxDebuggerLocal.getAddressSize()==8) { + machDesc = new MachineDescriptionSPARC64Bit(); +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java 2025-05-09 10:06:54.428292512 +0800 +@@ -997,7 +997,7 @@ + curFrame.getFP(), + anno)); + } else { +- // For C2, which has null frame pointers on x86/amd64/aarch64 ++ // For C2, which has null frame pointers on x86/amd64/aarch64/sw64 + CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC()); + Address sp = curFrame.getSP(); + if (Assert.ASSERTS_ENABLED) { +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_sw64/LinuxSW64JavaThreadPDAccess.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_sw64/LinuxSW64JavaThreadPDAccess.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_sw64/LinuxSW64JavaThreadPDAccess.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_sw64/LinuxSW64JavaThreadPDAccess.java 2025-05-09 10:05:57.680290595 +0800 +@@ -0,0 +1,132 @@ ++/* ++ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.runtime.linux_sw64; ++ ++import java.io.*; ++import java.util.*; ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.runtime.*; ++import sun.jvm.hotspot.runtime.sw64.*; ++import sun.jvm.hotspot.types.*; ++import sun.jvm.hotspot.utilities.*; ++ ++public class LinuxSW64JavaThreadPDAccess implements JavaThreadPDAccess { ++ private static AddressField lastJavaFPField; ++ private static AddressField osThreadField; ++ ++ // Field from OSThread ++ private static CIntegerField osThreadThreadIDField; ++ ++ // This is currently unneeded but is being kept in case we change ++ // the currentFrameGuess algorithm ++ private static final long GUESS_SCAN_RANGE = 128 * 1024; ++ ++ static { ++ VM.registerVMInitializedObserver(new Observer() { ++ public void update(Observable o, Object data) { ++ initialize(VM.getVM().getTypeDataBase()); ++ } ++ }); ++ } ++ ++ private static synchronized void initialize(TypeDataBase db) { ++ Type type = db.lookupType("JavaThread"); ++ osThreadField = type.getAddressField("_osthread"); ++ ++ Type anchorType = db.lookupType("JavaFrameAnchor"); ++ lastJavaFPField = anchorType.getAddressField("_last_Java_fp"); ++ ++ Type osThreadType = db.lookupType("OSThread"); ++ osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id"); ++ } ++ ++ public Address getLastJavaFP(Address addr) { ++ return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset())); ++ } ++ ++ public Address getLastJavaPC(Address addr) { ++ return null; ++ } ++ ++ public Address getBaseOfStackPointer(Address addr) { ++ return null; ++ } ++ ++ public Frame getLastFramePD(JavaThread thread, Address addr) { ++ Address fp = thread.getLastJavaFP(); ++ if (fp == null) { ++ return null; // no information ++ } ++ return new SW64Frame(thread.getLastJavaSP(), fp); ++ } ++ ++ public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) { ++ return new SW64RegisterMap(thread, updateMap); ++ } ++ ++ public Frame getCurrentFrameGuess(JavaThread thread, Address addr) { ++ ThreadProxy t = getThreadProxy(addr); ++ SW64ThreadContext context = (SW64ThreadContext) t.getContext(); ++ SW64CurrentFrameGuess guesser = new SW64CurrentFrameGuess(context, thread); ++ if (!guesser.run(GUESS_SCAN_RANGE)) { ++ return null; ++ } ++ if (guesser.getPC() == null) { ++ return new SW64Frame(guesser.getSP(), guesser.getFP()); ++ } else { ++ return new SW64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC()); ++ } ++ } ++ ++ public void printThreadIDOn(Address addr, PrintStream tty) { ++ tty.print(getThreadProxy(addr)); ++ } ++ ++ public void printInfoOn(Address threadAddr, PrintStream tty) { ++ tty.print("Thread id: "); ++ printThreadIDOn(threadAddr, tty); ++// tty.println("\nPostJavaState: " + getPostJavaState(threadAddr)); ++ } ++ ++ public Address getLastSP(Address addr) { ++ ThreadProxy t = getThreadProxy(addr); ++ SW64ThreadContext context = (SW64ThreadContext) t.getContext(); ++ return context.getRegisterAsAddress(SW64ThreadContext.SP); ++ } ++ ++ public ThreadProxy getThreadProxy(Address addr) { ++ // Addr is the address of the JavaThread. ++ // Fetch the OSThread (for now and for simplicity, not making a ++ // separate "OSThread" class in this package) ++ Address osThreadAddr = osThreadField.getValue(addr); ++ // Get the address of the _thread_id from the OSThread ++ Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset()); ++ ++ JVMDebugger debugger = VM.getVM().getDebugger(); ++ return debugger.getThreadForIdentifierAddress(threadIdAddr); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64CurrentFrameGuess.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64CurrentFrameGuess.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64CurrentFrameGuess.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64CurrentFrameGuess.java 2025-05-09 10:05:57.680290595 +0800 +@@ -0,0 +1,250 @@ ++/* ++ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, 2019, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.runtime.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.debugger.sw64.*; ++import sun.jvm.hotspot.code.*; ++import sun.jvm.hotspot.interpreter.*; ++import sun.jvm.hotspot.runtime.*; ++import sun.jvm.hotspot.runtime.sw64.*; ++ ++/**

Should be able to be used on all sw64 platforms we support ++ (Linux/sw64) to implement JavaThread's "currentFrameGuess()" ++ functionality. Input is an SW64ThreadContext; output is SP, FP, ++ and PC for an SW64Frame. Instantiation of the SW64Frame is ++ left to the caller, since we may need to subclass SW64Frame to ++ support signal handler frames on Unix platforms.

++ ++

Algorithm is to walk up the stack within a given range (say, ++ 512K at most) looking for a plausible PC and SP for a Java frame, ++ also considering those coming in from the context. If we find a PC ++ that belongs to the VM (i.e., in generated code like the ++ interpreter or CodeCache) then we try to find an associated FP. ++ We repeat this until we either find a complete frame or run out of ++ stack to look at.

*/ ++ ++public class SW64CurrentFrameGuess { ++ private SW64ThreadContext context; ++ private JavaThread thread; ++ private Address spFound; ++ private Address fpFound; ++ private Address pcFound; ++ ++ private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.sw64.SW64Frame.DEBUG") ++ != null; ++ ++ public SW64CurrentFrameGuess(SW64ThreadContext context, ++ JavaThread thread) { ++ this.context = context; ++ this.thread = thread; ++ } ++ ++ /** Returns false if not able to find a frame within a reasonable range. */ ++ public boolean run(long regionInBytesToSearch) { ++ Address sp = context.getRegisterAsAddress(SW64ThreadContext.SP); ++ Address pc = context.getRegisterAsAddress(SW64ThreadContext.PC); ++ Address fp = context.getRegisterAsAddress(SW64ThreadContext.FP); ++ if (sp == null) { ++ // Bail out if no last java frame either ++ if (thread.getLastJavaSP() != null) { ++ setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); ++ return true; ++ } ++ return false; ++ } ++ Address end = sp.addOffsetTo(regionInBytesToSearch); ++ VM vm = VM.getVM(); ++ ++ setValues(null, null, null); // Assume we're not going to find anything ++ ++ if (vm.isJavaPCDbg(pc)) { ++ if (vm.isClientCompiler()) { ++ // If the topmost frame is a Java frame, we are (pretty much) ++ // guaranteed to have a viable FP. We should be more robust ++ // than this (we have the potential for losing entire threads' ++ // stack traces) but need to see how much work we really have ++ // to do here. Searching the stack for an (SP, FP) pair is ++ // hard since it's easy to misinterpret inter-frame stack ++ // pointers as base-of-frame pointers; we also don't know the ++ // sizes of C1 frames (not registered in the nmethod) so can't ++ // derive them from SP. ++ ++ setValues(sp, fp, pc); ++ return true; ++ } else { ++ if (vm.getInterpreter().contains(pc)) { ++ if (DEBUG) { ++ System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " + ++ sp + ", fp = " + fp + ", pc = " + pc); ++ } ++ setValues(sp, fp, pc); ++ return true; ++ } ++ ++ // For the server compiler, FP is not guaranteed to be valid ++ // for compiled code. In addition, an earlier attempt at a ++ // non-searching algorithm (see below) failed because the ++ // stack pointer from the thread context was pointing ++ // (considerably) beyond the ostensible end of the stack, into ++ // garbage; walking from the topmost frame back caused a crash. ++ // ++ // This algorithm takes the current PC as a given and tries to ++ // find the correct corresponding SP by walking up the stack ++ // and repeatedly performing stackwalks (very inefficient). ++ // ++ // FIXME: there is something wrong with stackwalking across ++ // adapter frames...this is likely to be the root cause of the ++ // failure with the simpler algorithm below. ++ ++ for (long offset = 0; ++ offset < regionInBytesToSearch; ++ offset += vm.getAddressSize()) { ++ try { ++ Address curSP = sp.addOffsetTo(offset); ++ Frame frame = new SW64Frame(curSP, null, pc); ++ RegisterMap map = thread.newRegisterMap(false); ++ while (frame != null) { ++ if (frame.isEntryFrame() && frame.entryFrameIsFirst()) { ++ // We were able to traverse all the way to the ++ // bottommost Java frame. ++ // This sp looks good. Keep it. ++ if (DEBUG) { ++ System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc); ++ } ++ setValues(curSP, null, pc); ++ return true; ++ } ++ frame = frame.sender(map); ++ } ++ } catch (Exception e) { ++ if (DEBUG) { ++ System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset); ++ } ++ // Bad SP. Try another. ++ } ++ } ++ ++ // Were not able to find a plausible SP to go with this PC. ++ // Bail out. ++ return false; ++ ++ /* ++ // Original algorithm which does not work because SP was ++ // pointing beyond where it should have: ++ ++ // For the server compiler, FP is not guaranteed to be valid ++ // for compiled code. We see whether the PC is in the ++ // interpreter and take care of that, otherwise we run code ++ // (unfortunately) duplicated from SW64Frame.senderForCompiledFrame. ++ ++ CodeCache cc = vm.getCodeCache(); ++ if (cc.contains(pc)) { ++ CodeBlob cb = cc.findBlob(pc); ++ ++ // See if we can derive a frame pointer from SP and PC ++ // NOTE: This is the code duplicated from SW64Frame ++ Address saved_fp = null; ++ int llink_offset = cb.getLinkOffset(); ++ if (llink_offset >= 0) { ++ // Restore base-pointer, since next frame might be an interpreter frame. ++ Address fp_addr = sp.addOffsetTo(VM.getVM().getAddressSize() * llink_offset); ++ saved_fp = fp_addr.getAddressAt(0); ++ } ++ ++ setValues(sp, saved_fp, pc); ++ return true; ++ } ++ */ ++ } ++ } else { ++ // If the current program counter was not known to us as a Java ++ // PC, we currently assume that we are in the run-time system ++ // and attempt to look to thread-local storage for saved SP and ++ // FP. Note that if these are null (because we were, in fact, ++ // in Java code, i.e., vtable stubs or similar, and the SA ++ // didn't have enough insight into the target VM to understand ++ // that) then we are going to lose the entire stack trace for ++ // the thread, which is sub-optimal. FIXME. ++ ++ if (DEBUG) { ++ System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " + ++ thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP()); ++ } ++ if (thread.getLastJavaSP() == null) { ++ return false; // No known Java frames on stack ++ } ++ ++ // The runtime has a nasty habit of not saving fp in the frame ++ // anchor, leaving us to grovel about in the stack to find a ++ // plausible address. Fortunately, this only happens in ++ // compiled code; there we always have a valid PC, and we always ++ // push LR and FP onto the stack as a pair, with FP at the lower ++ // address. ++ pc = thread.getLastJavaPC(); ++ fp = thread.getLastJavaFP(); ++ sp = thread.getLastJavaSP(); ++ ++ if (fp == null) { ++ CodeCache cc = vm.getCodeCache(); ++ if (cc.contains(pc)) { ++ CodeBlob cb = cc.findBlob(pc); ++ if (DEBUG) { ++ System.out.println("FP is null. Found blob frame size " + cb.getFrameSize()); ++ } ++ // See if we can derive a frame pointer from SP and PC ++ long link_offset = cb.getFrameSize() - 2 * VM.getVM().getAddressSize(); ++ if (link_offset >= 0) { ++ fp = sp.addOffsetTo(link_offset); ++ } ++ } ++ } ++ ++ // We found a PC in the frame anchor. Check that it's plausible, and ++ // if it is, use it. ++ if (vm.isJavaPCDbg(pc)) { ++ setValues(sp, fp, pc); ++ } else { ++ setValues(sp, fp, null); ++ } ++ ++ return true; ++ } ++ } ++ ++ public Address getSP() { return spFound; } ++ public Address getFP() { return fpFound; } ++ /** May be null if getting values from thread-local storage; take ++ care to call the correct SW64Frame constructor to recover this if ++ necessary */ ++ public Address getPC() { return pcFound; } ++ ++ private void setValues(Address sp, Address fp, Address pc) { ++ spFound = sp; ++ fpFound = fp; ++ pcFound = pc; ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64Frame.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64Frame.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64Frame.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64Frame.java 2025-05-09 10:06:54.432292512 +0800 +@@ -0,0 +1,564 @@ ++/* ++ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, 2019, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.runtime.sw64; ++ ++import java.util.*; ++import sun.jvm.hotspot.code.*; ++import sun.jvm.hotspot.compiler.*; ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.oops.*; ++import sun.jvm.hotspot.runtime.*; ++import sun.jvm.hotspot.types.*; ++import sun.jvm.hotspot.utilities.*; ++ ++/** Specialization of and implementation of abstract methods of the ++ Frame class for the sw64 family of CPUs. */ ++ ++public class SW64Frame extends Frame { ++ private static final boolean DEBUG; ++ static { ++ DEBUG = System.getProperty("sun.jvm.hotspot.runtime.sw64.SW64Frame.DEBUG") != null; ++ } ++ ++ // All frames ++ private static final int LINK_OFFSET = 0; ++ private static final int RETURN_ADDR_OFFSET = 1; ++ private static final int SENDER_SP_OFFSET = 2; ++ ++ // Interpreter frames ++ private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -1; ++ private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1; ++ private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET - 1; // -3 ++ private static int INTERPRETER_FRAME_MIRROR_OFFSET; ++ private static int INTERPRETER_FRAME_MDX_OFFSET; // Non-core builds only ++ private static int INTERPRETER_FRAME_CACHE_OFFSET; ++ private static int INTERPRETER_FRAME_LOCALS_OFFSET; ++ private static int INTERPRETER_FRAME_BCX_OFFSET; ++ private static int INTERPRETER_FRAME_INITIAL_SP_OFFSET; ++ private static int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET; ++ private static int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET; ++ ++ // Entry frames ++ private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET = -6; ++ ++ // Native frames ++ private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET = 2; ++ ++ private static VMReg fp = new VMReg(29); ++ ++ static { ++ VM.registerVMInitializedObserver(new Observer() { ++ public void update(Observable o, Object data) { ++ initialize(VM.getVM().getTypeDataBase()); ++ } ++ }); ++ } ++ ++ private static synchronized void initialize(TypeDataBase db) { ++ INTERPRETER_FRAME_MIRROR_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1; // -4 ++ INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_MIRROR_OFFSET - 1; // -5 // Non-core builds only ++ INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1; // -6 ++ INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1; // -7 ++ INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1; // -8 ++ INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1; // -9 ++ INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET ; // -9 ++ INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET; // -9 ++ } ++ ++ ++ // an additional field beyond sp and pc: ++ Address raw_fp; // frame pointer ++ private Address raw_unextendedSP; ++ ++ private SW64Frame() { ++ } ++ ++ private void adjustForDeopt() { ++ if ( pc != null) { ++ // Look for a deopt pc and if it is deopted convert to original pc ++ CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); ++ if (cb != null && cb.isJavaMethod()) { ++ NMethod nm = (NMethod) cb; ++ if (pc.equals(nm.deoptHandlerBegin())) { ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); ++ } ++ // adjust pc if frame is deoptimized. ++ pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); ++ deoptimized = true; ++ } ++ } ++ } ++ } ++ ++ public SW64Frame(Address raw_sp, Address raw_fp, Address pc) { ++ this.raw_sp = raw_sp; ++ this.raw_unextendedSP = raw_sp; ++ this.raw_fp = raw_fp; ++ this.pc = pc; ++ adjustUnextendedSP(); ++ ++ // Frame must be fully constructed before this call ++ adjustForDeopt(); ++ ++ if (DEBUG) { ++ System.out.println("SW64Frame(sp, fp, pc): " + this); ++ dumpStack(); ++ } ++ } ++ ++ public SW64Frame(Address raw_sp, Address raw_fp) { ++ this.raw_sp = raw_sp; ++ this.raw_unextendedSP = raw_sp; ++ this.raw_fp = raw_fp; ++ ++ // We cannot assume SP[-1] always contains a valid return PC (e.g. if ++ // the callee is a C/C++ compiled frame). If the PC is not known to ++ // Java then this.pc is null. ++ Address savedPC = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize()); ++ if (VM.getVM().isJavaPCDbg(savedPC)) { ++ this.pc = savedPC; ++ } ++ ++ adjustUnextendedSP(); ++ ++ // Frame must be fully constructed before this call ++ adjustForDeopt(); ++ ++ if (DEBUG) { ++ System.out.println("SW64Frame(sp, fp): " + this); ++ dumpStack(); ++ } ++ } ++ ++ public SW64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) { ++ this.raw_sp = raw_sp; ++ this.raw_unextendedSP = raw_unextendedSp; ++ this.raw_fp = raw_fp; ++ this.pc = pc; ++ adjustUnextendedSP(); ++ ++ // Frame must be fully constructed before this call ++ adjustForDeopt(); ++ ++ if (DEBUG) { ++ System.out.println("SW64Frame(sp, unextendedSP, fp, pc): " + this); ++ dumpStack(); ++ } ++ ++ } ++ ++ public Object clone() { ++ SW64Frame frame = new SW64Frame(); ++ frame.raw_sp = raw_sp; ++ frame.raw_unextendedSP = raw_unextendedSP; ++ frame.raw_fp = raw_fp; ++ frame.pc = pc; ++ frame.deoptimized = deoptimized; ++ return frame; ++ } ++ ++ public boolean equals(Object arg) { ++ if (arg == null) { ++ return false; ++ } ++ ++ if (!(arg instanceof SW64Frame)) { ++ return false; ++ } ++ ++ SW64Frame other = (SW64Frame) arg; ++ ++ return (AddressOps.equal(getSP(), other.getSP()) && ++ AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) && ++ AddressOps.equal(getFP(), other.getFP()) && ++ AddressOps.equal(getPC(), other.getPC())); ++ } ++ ++ public int hashCode() { ++ if (raw_sp == null) { ++ return 0; ++ } ++ ++ return raw_sp.hashCode(); ++ } ++ ++ public String toString() { ++ return "sp: " + (getSP() == null? "null" : getSP().toString()) + ++ ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) + ++ ", fp: " + (getFP() == null? "null" : getFP().toString()) + ++ ", pc: " + (pc == null? "null" : pc.toString()); ++ } ++ ++ // accessors for the instance variables ++ public Address getFP() { return raw_fp; } ++ public Address getSP() { return raw_sp; } ++ public Address getID() { return raw_sp; } ++ ++ // FIXME: not implemented yet ++ public boolean isSignalHandlerFrameDbg() { return false; } ++ public int getSignalNumberDbg() { return 0; } ++ public String getSignalNameDbg() { return null; } ++ ++ public boolean isInterpretedFrameValid() { ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(isInterpretedFrame(), "Not an interpreted frame"); ++ } ++ ++ // These are reasonable sanity checks ++ if (getFP() == null || getFP().andWithMask(0x3) != null) { ++ return false; ++ } ++ ++ if (getSP() == null || getSP().andWithMask(0x3) != null) { ++ return false; ++ } ++ ++ if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) { ++ return false; ++ } ++ ++ // These are hacks to keep us out of trouble. ++ // The problem with these is that they mask other problems ++ if (getFP().lessThanOrEqual(getSP())) { ++ // this attempts to deal with unsigned comparison above ++ return false; ++ } ++ ++ if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) { ++ // stack frames shouldn't be large. ++ return false; ++ } ++ ++ return true; ++ } ++ ++ // FIXME: not applicable in current system ++ // void patch_pc(Thread* thread, address pc); ++ ++ public Frame sender(RegisterMap regMap, CodeBlob cb) { ++ SW64RegisterMap map = (SW64RegisterMap) regMap; ++ ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(map != null, "map must be set"); ++ } ++ ++ // Default is we done have to follow them. The sender_for_xxx will ++ // update it accordingly ++ map.setIncludeArgumentOops(false); ++ ++ if (isEntryFrame()) return senderForEntryFrame(map); ++ if (isInterpretedFrame()) return senderForInterpreterFrame(map); ++ ++ if(cb == null) { ++ cb = VM.getVM().getCodeCache().findBlob(getPC()); ++ } else { ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same"); ++ } ++ } ++ ++ if (cb != null) { ++ return senderForCompiledFrame(map, cb); ++ } ++ ++ // Must be native-compiled frame, i.e. the marshaling code for native ++ // methods that exists in the core system. ++ return new SW64Frame(getSenderSP(), getLink(), getSenderPC()); ++ } ++ ++ private Frame senderForEntryFrame(SW64RegisterMap map) { ++ if (DEBUG) { ++ System.out.println("senderForEntryFrame"); ++ } ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(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 ++ SW64JavaCallWrapper jcw = (SW64JavaCallWrapper) getEntryFrameCallWrapper(); ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero"); ++ Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack"); ++ } ++ SW64Frame fr; ++ if (jcw.getLastJavaPC() != null) { ++ fr = new SW64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC()); ++ } else { ++ fr = new SW64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP()); ++ } ++ map.clear(); ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); ++ } ++ return fr; ++ } ++ ++ //------------------------------------------------------------------------------ ++ // frame::adjust_unextended_sp ++ private void adjustUnextendedSP() { ++ // If we are returning to a compiled MethodHandle call site, the ++ // saved_fp will in fact be a saved value of the unextended SP. The ++ // simplest way to tell whether we are returning to such a call site ++ // is as follows: ++ ++ CodeBlob cb = cb(); ++ NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); ++ if (senderNm != null) { ++ // If the sender PC is a deoptimization point, get the original ++ // PC. For MethodHandle call site the unextended_sp is stored in ++ // saved_fp. ++ if (senderNm.isDeoptMhEntry(getPC())) { ++ // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP())); ++ raw_unextendedSP = getFP(); ++ } ++ else if (senderNm.isDeoptEntry(getPC())) { ++ // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp)); ++ } ++ else if (senderNm.isMethodHandleReturn(getPC())) { ++ raw_unextendedSP = getFP(); ++ } ++ } ++ } ++ ++ private Frame senderForInterpreterFrame(SW64RegisterMap map) { ++ if (DEBUG) { ++ System.out.println("senderForInterpreterFrame"); ++ } ++ Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); ++ Address sp = addressOfStackSlot(SENDER_SP_OFFSET); ++ // We do not need to update the callee-save register mapping because above ++ // us is either another interpreter frame or a converter-frame, but never ++ // directly a compiled frame. ++ // 11/24/04 SFG. With the removal of adapter frames this is no longer true. ++ // However c2 no longer uses callee save register for java calls so there ++ // are no callee register to find. ++ ++ if (map.getUpdateMap()) ++ updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET)); ++ ++ return new SW64Frame(sp, unextendedSP, getLink(), getSenderPC()); ++ } ++ ++ private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) { ++ map.setLocation(fp, savedFPAddr); ++ } ++ ++ private Frame senderForCompiledFrame(SW64RegisterMap map, CodeBlob cb) { ++ if (DEBUG) { ++ System.out.println("senderForCompiledFrame"); ++ } ++ ++ // ++ // NOTE: some of this code is (unfortunately) duplicated SW64CurrentFrameGuess ++ // ++ ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(map != null, "map must be set"); ++ } ++ ++ // frame owned by optimizing compiler ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size"); ++ } ++ Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); ++ ++ // The return_address is always the word on the stack ++ Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize()); ++ ++ // This is the saved value of FP which may or may not really be an FP. ++ // It is only an FP if the sender is an interpreter frame. ++ Address savedFPAddr = senderSP.addOffsetTo(- SENDER_SP_OFFSET * VM.getVM().getAddressSize()); ++ ++ if (map.getUpdateMap()) { ++ // 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.setIncludeArgumentOops(cb.callerMustGCArguments()); ++ ++ if (cb.getOopMaps() != null) { ++ ImmutableOopMapSet.updateRegisterMap(this, cb, map, true); ++ } ++ ++ // Since the prolog does the save and restore of FP there is no oopmap ++ // for it so we must fill in its location as if there was an oopmap entry ++ // since if our caller was compiled code there could be live jvm state in it. ++ updateMapWithSavedLink(map, savedFPAddr); ++ } ++ ++ return new SW64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC); ++ } ++ ++ protected boolean hasSenderPD() { ++ return true; ++ } ++ ++ public long frameSize() { ++ return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize()); ++ } ++ ++ public Address getLink() { ++ try { ++ if (DEBUG) { ++ System.out.println("Reading link at " + addressOfStackSlot(LINK_OFFSET) ++ + " = " + addressOfStackSlot(LINK_OFFSET).getAddressAt(0)); ++ } ++ return addressOfStackSlot(LINK_OFFSET).getAddressAt(0); ++ } catch (Exception e) { ++ if (DEBUG) ++ System.out.println("Returning null"); ++ return null; ++ } ++ } ++ ++ // FIXME: not implementable yet ++ //inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } ++ ++ public Address getUnextendedSP() { return raw_unextendedSP; } ++ ++ // Return address: ++ public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); } ++ public Address getSenderPC() { return getSenderPCAddr().getAddressAt(0); } ++ ++ // return address of param, zero origin index. ++ public Address getNativeParamAddr(int idx) { ++ return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx); ++ } ++ ++ public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); } ++ ++ public Address addressOfInterpreterFrameLocals() { ++ return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET); ++ } ++ ++ private Address addressOfInterpreterFrameBCX() { ++ return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET); ++ } ++ ++ public int getInterpreterFrameBCI() { ++ // FIXME: this is not atomic with respect to GC and is unsuitable ++ // for use in a non-debugging, or reflective, system. Need to ++ // figure out how to express this. ++ Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0); ++ Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0); ++ Method method = (Method)Metadata.instantiateWrapperFor(methodHandle); ++ return bcpToBci(bcp, method); ++ } ++ ++ public Address addressOfInterpreterFrameMDX() { ++ return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET); ++ } ++ ++ // FIXME ++ //inline int frame::interpreter_frame_monitor_size() { ++ // return BasicObjectLock::size(); ++ //} ++ ++ // expression stack ++ // (the max_stack arguments are used by the GC; see class FrameClosure) ++ ++ public Address addressOfInterpreterFrameExpressionStack() { ++ Address monitorEnd = interpreterFrameMonitorEnd().address(); ++ return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize()); ++ } ++ ++ public int getInterpreterFrameExpressionStackDirection() { return -1; } ++ ++ // top of expression stack ++ public Address addressOfInterpreterFrameTOS() { ++ return getSP(); ++ } ++ ++ /** Expression stack from top down */ ++ public Address addressOfInterpreterFrameTOSAt(int slot) { ++ return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize()); ++ } ++ ++ public Address getInterpreterFrameSenderSP() { ++ if (Assert.ASSERTS_ENABLED) { ++ Assert.that(isInterpretedFrame(), "interpreted frame expected"); ++ } ++ return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); ++ } ++ ++ // Monitors ++ public BasicObjectLock interpreterFrameMonitorBegin() { ++ return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET)); ++ } ++ ++ public BasicObjectLock interpreterFrameMonitorEnd() { ++ Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0); ++ if (Assert.ASSERTS_ENABLED) { ++ // make sure the pointer points inside the frame ++ Assert.that(AddressOps.gt(getFP(), result), "result must < than frame pointer"); ++ Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer"); ++ } ++ return new BasicObjectLock(result); ++ } ++ ++ public int interpreterFrameMonitorSize() { ++ return BasicObjectLock.size(); ++ } ++ ++ // Method ++ public Address addressOfInterpreterFrameMethod() { ++ return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET); ++ } ++ ++ // Constant pool cache ++ public Address addressOfInterpreterFrameCPCache() { ++ return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET); ++ } ++ ++ // Entry frames ++ public JavaCallWrapper getEntryFrameCallWrapper() { ++ return new SW64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0)); ++ } ++ ++ protected Address addressOfSavedOopResult() { ++ // offset is 2 for compiler2 and 3 for compiler1 ++ return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) * ++ VM.getVM().getAddressSize()); ++ } ++ ++ protected Address addressOfSavedReceiver() { ++ return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); ++ } ++ ++ private void dumpStack() { ++ for (Address addr = getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); ++ AddressOps.lt(addr, getSP()); ++ addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { ++ System.out.println(addr + ": " + addr.getAddressAt(0)); ++ } ++ System.out.println("-----------------------"); ++ for (Address addr = getSP(); ++ AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize())); ++ addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { ++ System.out.println(addr + ": " + addr.getAddressAt(0)); ++ } ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64JavaCallWrapper.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64JavaCallWrapper.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64JavaCallWrapper.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64JavaCallWrapper.java 2025-05-09 10:05:57.680290595 +0800 +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.runtime.sw64; ++ ++import java.util.*; ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.types.*; ++import sun.jvm.hotspot.runtime.*; ++ ++public class SW64JavaCallWrapper extends JavaCallWrapper { ++ private static AddressField lastJavaFPField; ++ ++ static { ++ VM.registerVMInitializedObserver(new Observer() { ++ public void update(Observable o, Object data) { ++ initialize(VM.getVM().getTypeDataBase()); ++ } ++ }); ++ } ++ ++ private static synchronized void initialize(TypeDataBase db) { ++ Type type = db.lookupType("JavaFrameAnchor"); ++ ++ lastJavaFPField = type.getAddressField("_last_Java_fp"); ++ } ++ ++ public SW64JavaCallWrapper(Address addr) { ++ super(addr); ++ } ++ ++ public Address getLastJavaFP() { ++ return lastJavaFPField.getValue(addr.addOffsetTo(anchorField.getOffset())); ++ } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64RegisterMap.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64RegisterMap.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64RegisterMap.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sw64/SW64RegisterMap.java 2025-05-09 10:05:57.680290595 +0800 +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, Red Hat Inc. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sun.jvm.hotspot.runtime.sw64; ++ ++import sun.jvm.hotspot.debugger.*; ++import sun.jvm.hotspot.runtime.*; ++ ++public class SW64RegisterMap extends RegisterMap { ++ ++ /** This is the only public constructor */ ++ public SW64RegisterMap(JavaThread thread, boolean updateMap) { ++ super(thread, updateMap); ++ } ++ ++ protected SW64RegisterMap(RegisterMap map) { ++ super(map); ++ } ++ ++ public Object clone() { ++ SW64RegisterMap retval = new SW64RegisterMap(this); ++ return retval; ++ } ++ ++ // no PD state to clear or copy: ++ protected void clearPD() {} ++ protected void initializePD() {} ++ protected void initializeFromPD(RegisterMap map) {} ++ protected Address getLocationPD(VMReg reg) { return null; } ++} +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java 2025-05-09 10:05:57.676290595 +0800 +@@ -40,6 +40,7 @@ + import sun.jvm.hotspot.runtime.linux_aarch64.LinuxAARCH64JavaThreadPDAccess; + import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess; + import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess; ++import sun.jvm.hotspot.runtime.linux_sw64.LinuxSW64JavaThreadPDAccess; + import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess; + import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess; + import sun.jvm.hotspot.runtime.bsd_aarch64.BsdAARCH64JavaThreadPDAccess; +@@ -99,6 +100,8 @@ + access = new LinuxPPC64JavaThreadPDAccess(); + } else if (cpu.equals("aarch64")) { + access = new LinuxAARCH64JavaThreadPDAccess(); ++ } else if (cpu.equals("sw64")) { ++ access = new LinuxSW64JavaThreadPDAccess(); + } else { + try { + access = (JavaThreadPDAccess) +diff -uNr openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java +--- openjdk/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java 2025-05-09 10:05:57.692290595 +0800 +@@ -54,8 +54,7 @@ + + public static boolean knownCPU(String cpu) { + final String[] KNOWN = +- new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "ppc64le", "aarch64"}; +- ++ new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "ppc64le", "aarch64", "sw_64", "sw64"}; + for(String s : KNOWN) { + if(s.equals(cpu)) + return true; +@@ -101,6 +100,9 @@ + if (cpu.equals("ppc64le")) + return "ppc64"; + ++ if (cpu.equals("sw_64")) ++ return "sw64"; ++ + return cpu; + + } +diff -uNr openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotJVMCIBackendFactory.java afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotJVMCIBackendFactory.java +--- openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotJVMCIBackendFactory.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotJVMCIBackendFactory.java 2025-05-09 10:05:57.728290597 +0800 +@@ -0,0 +1,191 @@ ++/* ++ * Copyright (c) 2015, 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. ++ */ ++package jdk.vm.ci.hotspot.sw64; ++ ++import static jdk.vm.ci.common.InitTimer.timer; ++ ++import java.util.EnumSet; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.code.Architecture; ++import jdk.vm.ci.code.RegisterConfig; ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.code.stack.StackIntrospection; ++import jdk.vm.ci.common.InitTimer; ++import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; ++import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; ++import jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; ++import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; ++import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; ++import jdk.vm.ci.hotspot.HotSpotStackIntrospection; ++import jdk.vm.ci.meta.ConstantReflectionProvider; ++import jdk.vm.ci.runtime.JVMCIBackend; ++ ++public class SW64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { ++ ++ protected EnumSet computeFeatures(@SuppressWarnings("unused") SW64HotSpotVMConfig config) { ++ // Configure the feature set using the HotSpot flag settings. ++ EnumSet features = EnumSet.noneOf(SW64.CPUFeature.class); ++ ++ if ((config.vmVersionFeatures & config.sw64FP) != 0) { ++ features.add(SW64.CPUFeature.FP); ++ } ++ if ((config.vmVersionFeatures & config.sw64ASIMD) != 0) { ++ features.add(SW64.CPUFeature.ASIMD); ++ } ++ if ((config.vmVersionFeatures & config.sw64EVTSTRM) != 0) { ++ features.add(SW64.CPUFeature.EVTSTRM); ++ } ++ if ((config.vmVersionFeatures & config.sw64AES) != 0) { ++ features.add(SW64.CPUFeature.AES); ++ } ++ if ((config.vmVersionFeatures & config.sw64PMULL) != 0) { ++ features.add(SW64.CPUFeature.PMULL); ++ } ++ if ((config.vmVersionFeatures & config.sw64SHA1) != 0) { ++ features.add(SW64.CPUFeature.SHA1); ++ } ++ if ((config.vmVersionFeatures & config.sw64SHA2) != 0) { ++ features.add(SW64.CPUFeature.SHA2); ++ } ++ if ((config.vmVersionFeatures & config.sw64CRC32) != 0) { ++ features.add(SW64.CPUFeature.CRC32); ++ } ++ if ((config.vmVersionFeatures & config.sw64LSE) != 0) { ++ features.add(SW64.CPUFeature.LSE); ++ } ++ if ((config.vmVersionFeatures & config.sw64STXR_PREFETCH) != 0) { ++ features.add(SW64.CPUFeature.STXR_PREFETCH); ++ } ++ if ((config.vmVersionFeatures & config.sw64A53MAC) != 0) { ++ features.add(SW64.CPUFeature.A53MAC); ++ } ++ if ((config.vmVersionFeatures & config.sw64DMB_ATOMICS) != 0) { ++ features.add(SW64.CPUFeature.DMB_ATOMICS); ++ } ++ ++ return features; ++ } ++ ++ protected EnumSet computeFlags(@SuppressWarnings("unused") SW64HotSpotVMConfig config) { ++ EnumSet flags = EnumSet.noneOf(SW64.Flag.class); ++ ++ if (config.useBarriersForVolatile) { ++ flags.add(SW64.Flag.UseBarriersForVolatile); ++ } ++ if (config.useCRC32) { ++ flags.add(SW64.Flag.UseCRC32); ++ } ++ if (config.useNeon) { ++ flags.add(SW64.Flag.UseNeon); ++ } ++ if (config.useSIMDForMemoryOps) { ++ flags.add(SW64.Flag.UseSIMDForMemoryOps); ++ } ++ if (config.avoidUnalignedAccesses) { ++ flags.add(SW64.Flag.AvoidUnalignedAccesses); ++ } ++ if (config.useLSE) { ++ flags.add(SW64.Flag.UseLSE); ++ } ++ if (config.useBlockZeroing) { ++ flags.add(SW64.Flag.UseBlockZeroing); ++ } ++ ++ return flags; ++ } ++ ++ protected TargetDescription createTarget(SW64HotSpotVMConfig config) { ++ final int stackFrameAlignment = 16; ++ final int implicitNullCheckLimit = 4096; ++ final boolean inlineObjects = true; ++ Architecture arch = new SW64(computeFeatures(config), computeFlags(config)); ++ return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); ++ } ++ ++ protected HotSpotConstantReflectionProvider createConstantReflection(HotSpotJVMCIRuntime runtime) { ++ return new HotSpotConstantReflectionProvider(runtime); ++ } ++ ++ protected RegisterConfig createRegisterConfig(SW64HotSpotVMConfig config, TargetDescription target) { ++ return new SW64HotSpotRegisterConfig(target, config.useCompressedOops); ++ } ++ ++ protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntime runtime, TargetDescription target, RegisterConfig regConfig) { ++ return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); ++ } ++ ++ protected HotSpotMetaAccessProvider createMetaAccess(HotSpotJVMCIRuntime runtime) { ++ return new HotSpotMetaAccessProvider(runtime); ++ } ++ ++ @Override ++ public String getArchitecture() { ++ return "sw64"; ++ } ++ ++ @Override ++ public String toString() { ++ return "JVMCIBackend:" + getArchitecture(); ++ } ++ ++ @Override ++ @SuppressWarnings("try") ++ public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntime runtime, JVMCIBackend host) { ++ ++ assert host == null; ++ SW64HotSpotVMConfig config = new SW64HotSpotVMConfig(runtime.getConfigStore()); ++ TargetDescription target = createTarget(config); ++ ++ RegisterConfig regConfig; ++ HotSpotCodeCacheProvider codeCache; ++ ConstantReflectionProvider constantReflection; ++ HotSpotMetaAccessProvider metaAccess; ++ StackIntrospection stackIntrospection; ++ try (InitTimer t = timer("create providers")) { ++ try (InitTimer rt = timer("create MetaAccess provider")) { ++ metaAccess = createMetaAccess(runtime); ++ } ++ try (InitTimer rt = timer("create RegisterConfig")) { ++ regConfig = createRegisterConfig(config, target); ++ } ++ try (InitTimer rt = timer("create CodeCache provider")) { ++ codeCache = createCodeCache(runtime, target, regConfig); ++ } ++ try (InitTimer rt = timer("create ConstantReflection provider")) { ++ constantReflection = createConstantReflection(runtime); ++ } ++ try (InitTimer rt = timer("create StackIntrospection provider")) { ++ stackIntrospection = new HotSpotStackIntrospection(runtime); ++ } ++ } ++ try (InitTimer rt = timer("instantiate backend")) { ++ return createBackend(metaAccess, codeCache, constantReflection, stackIntrospection); ++ } ++ } ++ ++ protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ++ StackIntrospection stackIntrospection) { ++ return new JVMCIBackend(metaAccess, codeCache, constantReflection, stackIntrospection); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotRegisterConfig.java afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotRegisterConfig.java +--- openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotRegisterConfig.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotRegisterConfig.java 2025-05-09 10:05:57.728290597 +0800 +@@ -0,0 +1,300 @@ ++/* ++ * Copyright (c) 2015, 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. ++ */ ++package jdk.vm.ci.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.lr; ++import static jdk.vm.ci.sw64.SW64.r0; ++import static jdk.vm.ci.sw64.SW64.r1; ++import static jdk.vm.ci.sw64.SW64.r2; ++import static jdk.vm.ci.sw64.SW64.r3; ++import static jdk.vm.ci.sw64.SW64.r4; ++import static jdk.vm.ci.sw64.SW64.r5; ++import static jdk.vm.ci.sw64.SW64.r6; ++import static jdk.vm.ci.sw64.SW64.r7; ++import static jdk.vm.ci.sw64.SW64.rscratch1; ++import static jdk.vm.ci.sw64.SW64.rscratch2; ++import static jdk.vm.ci.sw64.SW64.r12; ++import static jdk.vm.ci.sw64.SW64.r27; ++import static jdk.vm.ci.sw64.SW64.r28; ++import static jdk.vm.ci.sw64.SW64.r29; ++import static jdk.vm.ci.sw64.SW64.r31; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64.v0; ++import static jdk.vm.ci.sw64.SW64.v1; ++import static jdk.vm.ci.sw64.SW64.v2; ++import static jdk.vm.ci.sw64.SW64.v3; ++import static jdk.vm.ci.sw64.SW64.v4; ++import static jdk.vm.ci.sw64.SW64.v5; ++import static jdk.vm.ci.sw64.SW64.v6; ++import static jdk.vm.ci.sw64.SW64.v7; ++import static jdk.vm.ci.sw64.SW64.zr; ++ ++import java.util.ArrayList; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Set; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.code.Architecture; ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.CallingConvention.Type; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterArray; ++import jdk.vm.ci.code.RegisterAttributes; ++import jdk.vm.ci.code.RegisterConfig; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.code.ValueKindFactory; ++import jdk.vm.ci.common.JVMCIError; ++import jdk.vm.ci.hotspot.HotSpotCallingConventionType; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.JavaType; ++import jdk.vm.ci.meta.PlatformKind; ++import jdk.vm.ci.meta.Value; ++import jdk.vm.ci.meta.ValueKind; ++ ++public class SW64HotSpotRegisterConfig implements RegisterConfig { ++ ++ private final TargetDescription target; ++ ++ private final RegisterArray allocatable; ++ ++ /** ++ * The caller saved registers always include all parameter registers. ++ */ ++ private final RegisterArray callerSaved; ++ ++ private final boolean allAllocatableAreCallerSaved; ++ ++ private final RegisterAttributes[] attributesMap; ++ ++ @Override ++ public RegisterArray getAllocatableRegisters() { ++ return allocatable; ++ } ++ ++ @Override ++ public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) { ++ ArrayList list = new ArrayList<>(); ++ for (Register reg : registers) { ++ if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) { ++ list.add(reg); ++ } ++ } ++ ++ return new RegisterArray(list); ++ } ++ ++ @Override ++ public RegisterAttributes[] getAttributesMap() { ++ return attributesMap.clone(); ++ } ++ ++ private final RegisterArray javaGeneralParameterRegisters = new RegisterArray(r1, r2, r3, r4, r5, r6, r7, r0); ++ private final RegisterArray nativeGeneralParameterRegisters = new RegisterArray(r0, r1, r2, r3, r4, r5, r6, r7); ++ private final RegisterArray simdParameterRegisters = new RegisterArray(v0, v1, v2, v3, v4, v5, v6, v7); ++ ++ public static final Register inlineCacheRegister = rscratch2; ++ ++ /** ++ * Vtable stubs expect the metaspace Method in r12. ++ */ ++ public static final Register metaspaceMethodRegister = r12; ++ ++ public static final Register heapBaseRegister = r27; ++ public static final Register threadRegister = r28; ++ public static final Register fp = r29; ++ ++ private static final RegisterArray reservedRegisters ++ = new RegisterArray(rscratch1, rscratch2, threadRegister, fp, lr, r31, zr, sp); ++ ++ private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) { ++ RegisterArray allRegisters = arch.getAvailableValueRegisters(); ++ Register[] registers = new Register[allRegisters.size() - reservedRegisters.size() - (reserveForHeapBase ? 1 : 0)]; ++ List reservedRegistersList = reservedRegisters.asList(); ++ ++ int idx = 0; ++ for (Register reg : allRegisters) { ++ if (reservedRegistersList.contains(reg)) { ++ // skip reserved registers ++ continue; ++ } ++ assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp)); ++ if (reserveForHeapBase && reg.equals(heapBaseRegister)) { ++ // skip heap base register ++ continue; ++ } ++ ++ registers[idx++] = reg; ++ } ++ ++ assert idx == registers.length; ++ return new RegisterArray(registers); ++ } ++ ++ public SW64HotSpotRegisterConfig(TargetDescription target, boolean useCompressedOops) { ++ this(target, initAllocatable(target.arch, useCompressedOops)); ++ assert callerSaved.size() >= allocatable.size(); ++ } ++ ++ public SW64HotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable) { ++ this.target = target; ++ ++ this.allocatable = allocatable; ++ Set callerSaveSet = new HashSet<>(); ++ allocatable.addTo(callerSaveSet); ++ simdParameterRegisters.addTo(callerSaveSet); ++ javaGeneralParameterRegisters.addTo(callerSaveSet); ++ nativeGeneralParameterRegisters.addTo(callerSaveSet); ++ callerSaved = new RegisterArray(callerSaveSet); ++ ++ allAllocatableAreCallerSaved = true; ++ attributesMap = RegisterAttributes.createMap(this, SW64.allRegisters); ++ } ++ ++ @Override ++ public RegisterArray getCallerSaveRegisters() { ++ return callerSaved; ++ } ++ ++ @Override ++ public RegisterArray getCalleeSaveRegisters() { ++ return null; ++ } ++ ++ @Override ++ public boolean areAllAllocatableRegistersCallerSaved() { ++ return allAllocatableAreCallerSaved; ++ } ++ ++ @Override ++ public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory valueKindFactory) { ++ HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; ++ if (type == HotSpotCallingConventionType.NativeCall) { ++ return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory); ++ } ++ // On x64, parameter locations are the same whether viewed ++ // from the caller or callee perspective ++ return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory); ++ } ++ ++ @Override ++ public RegisterArray getCallingConventionRegisters(Type type, JavaKind kind) { ++ HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; ++ switch (kind) { ++ case Boolean: ++ case Byte: ++ case Short: ++ case Char: ++ case Int: ++ case Long: ++ case Object: ++ return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; ++ case Float: ++ case Double: ++ return simdParameterRegisters; ++ default: ++ throw JVMCIError.shouldNotReachHere(); ++ } ++ } ++ ++ private CallingConvention callingConvention(RegisterArray generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, HotSpotCallingConventionType type, ++ ValueKindFactory valueKindFactory) { ++ AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; ++ ++ int currentGeneral = 0; ++ int currentSIMD = 0; ++ int currentStackOffset = 0; ++ ++ for (int i = 0; i < parameterTypes.length; i++) { ++ final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); ++ ++ switch (kind) { ++ case Byte: ++ case Boolean: ++ case Short: ++ case Char: ++ case Int: ++ case Long: ++ case Object: ++ if (currentGeneral < generalParameterRegisters.size()) { ++ Register register = generalParameterRegisters.get(currentGeneral++); ++ locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); ++ } ++ break; ++ case Float: ++ case Double: ++ if (currentSIMD < simdParameterRegisters.size()) { ++ Register register = simdParameterRegisters.get(currentSIMD++); ++ locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); ++ } ++ break; ++ default: ++ throw JVMCIError.shouldNotReachHere(); ++ } ++ ++ if (locations[i] == null) { ++ ValueKind valueKind = valueKindFactory.getValueKind(kind); ++ locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.out); ++ currentStackOffset += Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize); ++ } ++ } ++ ++ JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); ++ AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind())); ++ return new CallingConvention(currentStackOffset, returnLocation, locations); ++ } ++ ++ @Override ++ public Register getReturnRegister(JavaKind kind) { ++ switch (kind) { ++ case Boolean: ++ case Byte: ++ case Char: ++ case Short: ++ case Int: ++ case Long: ++ case Object: ++ return r0; ++ case Float: ++ case Double: ++ return v0; ++ case Void: ++ case Illegal: ++ return null; ++ default: ++ throw new UnsupportedOperationException("no return register for type " + kind); ++ } ++ } ++ ++ @Override ++ public Register getFrameRegister() { ++ return sp; ++ } ++ ++ @Override ++ public String toString() { ++ return String.format("Allocatable: " + getAllocatableRegisters() + "%n" + "CallerSave: " + getCallerSaveRegisters() + "%n"); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotVMConfig.java afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotVMConfig.java +--- openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotVMConfig.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sw64/src/jdk/vm/ci/hotspot/sw64/SW64HotSpotVMConfig.java 2025-05-09 10:05:57.728290597 +0800 +@@ -0,0 +1,73 @@ ++/* ++ * 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. ++ */ ++package jdk.vm.ci.hotspot.sw64; ++ ++import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; ++import jdk.vm.ci.hotspot.HotSpotVMConfigStore; ++ ++/** ++ * Used to access native configuration details. ++ * ++ * All non-static, public fields in this class are so that they can be compiled as constants. ++ */ ++class SW64HotSpotVMConfig extends HotSpotVMConfigAccess { ++ ++ SW64HotSpotVMConfig(HotSpotVMConfigStore config) { ++ super(config); ++ } ++ ++ final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux"); ++ ++ final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); ++ ++ // CPU Capabilities ++ ++ /* ++ * These flags are set based on the corresponding command line flags. ++ */ ++ final boolean useBarriersForVolatile = getFlag("UseBarriersForVolatile", Boolean.class); ++ final boolean useCRC32 = getFlag("UseCRC32", Boolean.class); ++ final boolean useNeon = getFlag("UseNeon", Boolean.class); ++ final boolean useSIMDForMemoryOps = getFlag("UseSIMDForMemoryOps", Boolean.class); ++ final boolean avoidUnalignedAccesses = getFlag("AvoidUnalignedAccesses", Boolean.class); ++ final boolean useLSE = getFlag("UseLSE", Boolean.class); ++ final boolean useBlockZeroing = getFlag("UseBlockZeroing", Boolean.class); ++ ++ final long vmVersionFeatures = getFieldValue("Abstract_VM_Version::_features", Long.class, "uint64_t"); ++ ++ /* ++ * These flags are set if the corresponding support is in the hardware. ++ */ ++ final long sw64FP = getConstant("VM_Version::CPU_FP", Long.class); ++ final long sw64ASIMD = getConstant("VM_Version::CPU_ASIMD", Long.class); ++ final long sw64EVTSTRM = getConstant("VM_Version::CPU_EVTSTRM", Long.class); ++ final long sw64AES = getConstant("VM_Version::CPU_AES", Long.class); ++ final long sw64PMULL = getConstant("VM_Version::CPU_PMULL", Long.class); ++ final long sw64SHA1 = getConstant("VM_Version::CPU_SHA1", Long.class); ++ final long sw64SHA2 = getConstant("VM_Version::CPU_SHA2", Long.class); ++ final long sw64CRC32 = getConstant("VM_Version::CPU_CRC32", Long.class); ++ final long sw64LSE = getConstant("VM_Version::CPU_LSE", Long.class); ++ final long sw64STXR_PREFETCH = getConstant("VM_Version::CPU_STXR_PREFETCH", Long.class); ++ final long sw64A53MAC = getConstant("VM_Version::CPU_A53MAC", Long.class); ++ final long sw64DMB_ATOMICS = getConstant("VM_Version::CPU_DMB_ATOMICS", Long.class); ++} +diff -uNr openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64.java afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64.java +--- openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64.java 2025-05-09 10:05:57.736290597 +0800 +@@ -0,0 +1,255 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++package jdk.vm.ci.sw64; ++ ++import java.nio.ByteOrder; ++import java.util.EnumSet; ++ ++import jdk.vm.ci.code.Architecture; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.Register.RegisterCategory; ++import jdk.vm.ci.code.RegisterArray; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.PlatformKind; ++ ++/** ++ * Represents the SW64 architecture. ++ */ ++public class SW64 extends Architecture { ++ ++ public static final RegisterCategory CPU = new RegisterCategory("CPU"); ++ ++ // General purpose CPU registers ++ public static final Register r0 = new Register(0, 0, "r0", CPU); ++ public static final Register r1 = new Register(1, 1, "r1", CPU); ++ public static final Register r2 = new Register(2, 2, "r2", CPU); ++ public static final Register r3 = new Register(3, 3, "r3", CPU); ++ public static final Register r4 = new Register(4, 4, "r4", CPU); ++ public static final Register r5 = new Register(5, 5, "r5", CPU); ++ public static final Register r6 = new Register(6, 6, "r6", CPU); ++ public static final Register r7 = new Register(7, 7, "r7", CPU); ++ public static final Register r8 = new Register(8, 8, "r8", CPU); ++ public static final Register r9 = new Register(9, 9, "r9", CPU); ++ public static final Register r10 = new Register(10, 10, "r10", CPU); ++ public static final Register r11 = new Register(11, 11, "r11", CPU); ++ public static final Register r12 = new Register(12, 12, "r12", CPU); ++ public static final Register r13 = new Register(13, 13, "r13", CPU); ++ public static final Register r14 = new Register(14, 14, "r14", CPU); ++ public static final Register r15 = new Register(15, 15, "r15", CPU); ++ public static final Register r16 = new Register(16, 16, "r16", CPU); ++ public static final Register r17 = new Register(17, 17, "r17", CPU); ++ public static final Register r18 = new Register(18, 18, "r18", CPU); ++ public static final Register r19 = new Register(19, 19, "r19", CPU); ++ public static final Register r20 = new Register(20, 20, "r20", CPU); ++ public static final Register r21 = new Register(21, 21, "r21", CPU); ++ public static final Register r22 = new Register(22, 22, "r22", CPU); ++ public static final Register r23 = new Register(23, 23, "r23", CPU); ++ public static final Register r24 = new Register(24, 24, "r24", CPU); ++ public static final Register r25 = new Register(25, 25, "r25", CPU); ++ public static final Register r26 = new Register(26, 26, "r26", CPU); ++ public static final Register r27 = new Register(27, 27, "r27", CPU); ++ public static final Register r28 = new Register(28, 28, "r28", CPU); ++ public static final Register r29 = new Register(29, 29, "r29", CPU); ++ public static final Register r30 = new Register(30, 30, "r30", CPU); ++ ++ /* ++ * r31 is not a general purpose register, but represents either the stackpointer or the ++ * zero/discard register depending on the instruction. So we represent those two uses as two ++ * different registers. The register numbers are kept in sync with register_sw64.hpp and have ++ * to be sequential, hence we also need a general r31 register here, which is never used. ++ */ ++ public static final Register r31 = new Register(31, 31, "r31", CPU); ++ public static final Register zr = new Register(32, 31, "zr", CPU); ++ public static final Register sp = new Register(33, 31, "sp", CPU); ++ ++ public static final Register lr = r30; ++ ++ // Used by runtime code: cannot be compiler-allocated. ++ public static final Register rscratch1 = r8; ++ public static final Register rscratch2 = r9; ++ ++ // @formatter:off ++ public static final RegisterArray cpuRegisters = new RegisterArray( ++ r0, r1, r2, r3, r4, r5, r6, r7, ++ r8, r9, r10, r11, r12, r13, r14, r15, ++ r16, r17, r18, r19, r20, r21, r22, r23, ++ r24, r25, r26, r27, r28, r29, r30, r31, ++ zr, sp ++ ); ++ // @formatter:on ++ ++ public static final RegisterCategory SIMD = new RegisterCategory("SIMD"); ++ ++ // Simd registers ++ public static final Register v0 = new Register(34, 0, "v0", SIMD); ++ public static final Register v1 = new Register(35, 1, "v1", SIMD); ++ public static final Register v2 = new Register(36, 2, "v2", SIMD); ++ public static final Register v3 = new Register(37, 3, "v3", SIMD); ++ public static final Register v4 = new Register(38, 4, "v4", SIMD); ++ public static final Register v5 = new Register(39, 5, "v5", SIMD); ++ public static final Register v6 = new Register(40, 6, "v6", SIMD); ++ public static final Register v7 = new Register(41, 7, "v7", SIMD); ++ public static final Register v8 = new Register(42, 8, "v8", SIMD); ++ public static final Register v9 = new Register(43, 9, "v9", SIMD); ++ public static final Register v10 = new Register(44, 10, "v10", SIMD); ++ public static final Register v11 = new Register(45, 11, "v11", SIMD); ++ public static final Register v12 = new Register(46, 12, "v12", SIMD); ++ public static final Register v13 = new Register(47, 13, "v13", SIMD); ++ public static final Register v14 = new Register(48, 14, "v14", SIMD); ++ public static final Register v15 = new Register(49, 15, "v15", SIMD); ++ public static final Register v16 = new Register(50, 16, "v16", SIMD); ++ public static final Register v17 = new Register(51, 17, "v17", SIMD); ++ public static final Register v18 = new Register(52, 18, "v18", SIMD); ++ public static final Register v19 = new Register(53, 19, "v19", SIMD); ++ public static final Register v20 = new Register(54, 20, "v20", SIMD); ++ public static final Register v21 = new Register(55, 21, "v21", SIMD); ++ public static final Register v22 = new Register(56, 22, "v22", SIMD); ++ public static final Register v23 = new Register(57, 23, "v23", SIMD); ++ public static final Register v24 = new Register(58, 24, "v24", SIMD); ++ public static final Register v25 = new Register(59, 25, "v25", SIMD); ++ public static final Register v26 = new Register(60, 26, "v26", SIMD); ++ public static final Register v27 = new Register(61, 27, "v27", SIMD); ++ public static final Register v28 = new Register(62, 28, "v28", SIMD); ++ public static final Register v29 = new Register(63, 29, "v29", SIMD); ++ public static final Register v30 = new Register(64, 30, "v30", SIMD); ++ public static final Register v31 = new Register(65, 31, "v31", SIMD); ++ ++ // @formatter:off ++ public static final RegisterArray simdRegisters = new RegisterArray( ++ v0, v1, v2, v3, v4, v5, v6, v7, ++ v8, v9, v10, v11, v12, v13, v14, v15, ++ v16, v17, v18, v19, v20, v21, v22, v23, ++ v24, v25, v26, v27, v28, v29, v30, v31 ++ ); ++ // @formatter:on ++ ++ // @formatter:off ++ public static final RegisterArray allRegisters = new RegisterArray( ++ r0, r1, r2, r3, r4, r5, r6, r7, ++ r8, r9, r10, r11, r12, r13, r14, r15, ++ r16, r17, r18, r19, r20, r21, r22, r23, ++ r24, r25, r26, r27, r28, r29, r30, r31, ++ zr, sp, ++ ++ v0, v1, v2, v3, v4, v5, v6, v7, ++ v8, v9, v10, v11, v12, v13, v14, v15, ++ v16, v17, v18, v19, v20, v21, v22, v23, ++ v24, v25, v26, v27, v28, v29, v30, v31 ++ ); ++ // @formatter:on ++ ++ /** ++ * Basic set of CPU features mirroring what is returned from the cpuid instruction. See: ++ * {@code VM_Version::cpuFeatureFlags}. ++ */ ++ public enum CPUFeature { ++ FP, ++ ASIMD, ++ EVTSTRM, ++ AES, ++ PMULL, ++ SHA1, ++ SHA2, ++ CRC32, ++ LSE, ++ STXR_PREFETCH, ++ A53MAC, ++ DMB_ATOMICS ++ } ++ ++ private final EnumSet features; ++ ++ /** ++ * Set of flags to control code emission. ++ */ ++ public enum Flag { ++ UseBarriersForVolatile, ++ UseCRC32, ++ UseNeon, ++ UseSIMDForMemoryOps, ++ AvoidUnalignedAccesses, ++ UseLSE, ++ UseBlockZeroing ++ } ++ ++ private final EnumSet flags; ++ ++ public SW64(EnumSet features, EnumSet flags) { ++ super("sw64", SW64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, 0, 0, 0); ++ this.features = features; ++ this.flags = flags; ++ } ++ ++ public EnumSet getFeatures() { ++ return features; ++ } ++ ++ public EnumSet getFlags() { ++ return flags; ++ } ++ ++ @Override ++ public PlatformKind getPlatformKind(JavaKind javaKind) { ++ switch (javaKind) { ++ case Boolean: ++ case Byte: ++ return SW64Kind.BYTE; ++ case Short: ++ case Char: ++ return SW64Kind.WORD; ++ case Int: ++ return SW64Kind.DWORD; ++ case Long: ++ case Object: ++ return SW64Kind.QWORD; ++ case Float: ++ return SW64Kind.SINGLE; ++ case Double: ++ return SW64Kind.DOUBLE; ++ default: ++ return null; ++ } ++ } ++ ++ @Override ++ public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { ++ SW64Kind kind = (SW64Kind) platformKind; ++ if (kind.isInteger()) { ++ return category.equals(CPU); ++ } else if (kind.isSIMD()) { ++ return category.equals(SIMD); ++ } ++ return false; ++ } ++ ++ @Override ++ public SW64Kind getLargestStorableKind(RegisterCategory category) { ++ if (category.equals(CPU)) { ++ return SW64Kind.QWORD; ++ } else if (category.equals(SIMD)) { ++ return SW64Kind.V128_QWORD; ++ } else { ++ return null; ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64Kind.java afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64Kind.java +--- openjdk/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64Kind.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sw64/src/jdk/vm/ci/sw64/SW64Kind.java 2025-05-09 10:05:57.736290597 +0800 +@@ -0,0 +1,153 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++package jdk.vm.ci.sw64; ++ ++import jdk.vm.ci.meta.PlatformKind; ++ ++public enum SW64Kind implements PlatformKind { ++ ++ // scalar ++ BYTE(1), ++ WORD(2), ++ DWORD(4), ++ QWORD(8), ++ SINGLE(4), ++ DOUBLE(8), ++ ++ // SIMD ++ V32_BYTE(4, BYTE), ++ V32_WORD(4, WORD), ++ V64_BYTE(8, BYTE), ++ V64_WORD(8, WORD), ++ V64_DWORD(8, DWORD), ++ V128_BYTE(16, BYTE), ++ V128_WORD(16, WORD), ++ V128_DWORD(16, DWORD), ++ V128_QWORD(16, QWORD), ++ V128_SINGLE(16, SINGLE), ++ V128_DOUBLE(16, DOUBLE); ++ ++ private final int size; ++ private final int vectorLength; ++ ++ private final SW64Kind scalar; ++ private final EnumKey key = new EnumKey<>(this); ++ ++ SW64Kind(int size) { ++ this.size = size; ++ this.scalar = this; ++ this.vectorLength = 1; ++ } ++ ++ SW64Kind(int size, SW64Kind scalar) { ++ this.size = size; ++ this.scalar = scalar; ++ ++ assert size % scalar.size == 0; ++ this.vectorLength = size / scalar.size; ++ } ++ ++ public SW64Kind getScalar() { ++ return scalar; ++ } ++ ++ @Override ++ public int getSizeInBytes() { ++ return size; ++ } ++ ++ @Override ++ public int getVectorLength() { ++ return vectorLength; ++ } ++ ++ @Override ++ public Key getKey() { ++ return key; ++ } ++ ++ public boolean isInteger() { ++ switch (this) { ++ case BYTE: ++ case WORD: ++ case DWORD: ++ case QWORD: ++ return true; ++ default: ++ return false; ++ } ++ } ++ ++ public boolean isSIMD() { ++ switch (this) { ++ case SINGLE: ++ case DOUBLE: ++ case V32_BYTE: ++ case V32_WORD: ++ case V64_BYTE: ++ case V64_WORD: ++ case V64_DWORD: ++ case V128_BYTE: ++ case V128_WORD: ++ case V128_DWORD: ++ case V128_QWORD: ++ case V128_SINGLE: ++ case V128_DOUBLE: ++ return true; ++ default: ++ return false; ++ } ++ } ++ ++ @Override ++ public char getTypeChar() { ++ switch (this) { ++ case BYTE: ++ return 'b'; ++ case WORD: ++ return 'w'; ++ case DWORD: ++ return 'd'; ++ case QWORD: ++ return 'q'; ++ case SINGLE: ++ return 'S'; ++ case DOUBLE: ++ return 'D'; ++ case V32_BYTE: ++ case V32_WORD: ++ case V64_BYTE: ++ case V64_WORD: ++ case V64_DWORD: ++ case V128_BYTE: ++ case V128_WORD: ++ case V128_DWORD: ++ case V128_QWORD: ++ case V128_SINGLE: ++ case V128_DOUBLE: ++ return 'v'; ++ default: ++ return '-'; ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.ci/share/classes/module-info.java afu11u/src/jdk.internal.vm.ci/share/classes/module-info.java +--- openjdk/src/jdk.internal.vm.ci/share/classes/module-info.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.ci/share/classes/module-info.java 2025-05-09 10:05:57.736290597 +0800 +@@ -37,6 +37,7 @@ + + provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory, ++ jdk.vm.ci.hotspot.sw64.SW64HotSpotJVMCIBackendFactory, + jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory, + jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory; + } +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/module-info.java afu11u/src/jdk.internal.vm.compiler/share/classes/module-info.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/module-info.java 2022-10-12 23:00:03.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/module-info.java 2025-05-09 10:05:57.740290597 +0800 +@@ -47,6 +47,7 @@ + exports org.graalvm.compiler.api.replacements to jdk.aot; + exports org.graalvm.compiler.asm.amd64 to jdk.aot; + exports org.graalvm.compiler.asm.aarch64 to jdk.aot; ++ exports org.graalvm.compiler.asm.sw64 to jdk.aot; + exports org.graalvm.compiler.bytecode to jdk.aot; + exports org.graalvm.compiler.code to jdk.aot; + exports org.graalvm.compiler.core to jdk.aot; +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Address.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Address.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Address.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Address.java 2025-05-09 10:05:57.748290597 +0800 +@@ -0,0 +1,389 @@ ++/* ++ * Copyright (c) 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. ++ */ ++ ++ ++package org.graalvm.compiler.asm.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.zr; ++ ++import org.graalvm.compiler.asm.AbstractAddress; ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.debug.GraalError; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.code.Register; ++ ++/** ++ * Represents an address in target machine memory, specified using one of the different addressing ++ * modes of the SW64 ISA. - Base register only - Base register + immediate or register with ++ * shifted offset - Pre-indexed: base + immediate offset are written back to base register, value ++ * used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are ++ * written back to base register, value used in instruction is base only - Literal: PC + 19-bit ++ * signed word aligned offset ++ *

++ * Not all addressing modes are supported for all instructions. ++ */ ++public final class SW64Address extends AbstractAddress { ++ // Placeholder for addresses that get patched later. ++ public static final SW64Address PLACEHOLDER = createPcLiteralAddress(0); ++ ++ public enum AddressingMode { ++ /** ++ * base + uimm12 << log2(memory_transfer_size). ++ */ ++ IMMEDIATE_SCALED, ++ /** ++ * base + imm9. ++ */ ++ IMMEDIATE_UNSCALED, ++ /** ++ * base. ++ */ ++ BASE_REGISTER_ONLY, ++ /** ++ * base + offset [<< log2(memory_transfer_size)]. ++ */ ++ REGISTER_OFFSET, ++ /** ++ * base + extend(offset) [<< log2(memory_transfer_size)]. ++ */ ++ EXTENDED_REGISTER_OFFSET, ++ /** ++ * PC + imm21 (word aligned). ++ */ ++ PC_LITERAL, ++ /** ++ * address = base. base is updated to base + imm9 ++ */ ++ IMMEDIATE_POST_INDEXED, ++ /** ++ * address = base + imm9. base is updated to base + imm9 ++ */ ++ IMMEDIATE_PRE_INDEXED, ++ AddressingMode, ++ } ++ ++ private final Register base; ++ private final Register offset; ++ private final int immediate; ++ /** ++ * Should register offset be scaled or not. ++ */ ++ private final boolean scaled; ++ private final SW64Assembler.ExtendType extendType; ++ private final AddressingMode addressingMode; ++ ++ /** ++ * General address generation mechanism. Accepted values for all parameters depend on the ++ * addressingMode. Null is never accepted for a register, if an addressMode doesn't use a ++ * register the register has to be the zero-register. extendType has to be null for every ++ * addressingMode except EXTENDED_REGISTER_OFFSET. ++ */ ++ public static SW64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, SW64Assembler.ExtendType extendType) { ++ return new SW64Address(base, offset, immediate, isScaled, extendType, addressingMode); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param imm9 Signed 9-bit immediate value. ++ * @return an address specifying a post-indexed immediate address pointing to base. After ++ * ldr/str instruction, base is updated to point to base + imm9 ++ */ ++ public static SW64Address createPostIndexedImmediateAddress(Register base, int imm9) { ++ return new SW64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param imm9 Signed 9-bit immediate value. ++ * @return an address specifying a pre-indexed immediate address pointing to base + imm9. After ++ * ldr/str instruction, base is updated to point to base + imm9 ++ */ ++ public static SW64Address createPreIndexedImmediateAddress(Register base, int imm9) { ++ return new SW64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param imm12 Unsigned 12-bit immediate value. This is scaled by the word access size. This ++ * means if this address is used to load/store a word, the immediate is shifted by 2 ++ * (log2Ceil(4)). ++ * @return an address specifying a signed address of the form base + imm12 << ++ * log2(memory_transfer_size). ++ */ ++ public static SW64Address createScaledImmediateAddress(Register base, int imm12) { ++ return new SW64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param imm9 Signed 9-bit immediate value. ++ * @return an address specifying an unscaled immediate address of the form base + imm9 ++ */ ++ public static SW64Address createUnscaledImmediateAddress(Register base, int imm9) { ++ return new SW64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED); ++ } ++ ++ /** ++ * @param base May not be null or the zero register. ++ * @return an address specifying the address pointed to by base. ++ */ ++ public static SW64Address createBaseRegisterOnlyAddress(Register base) { ++ return createRegisterOffsetAddress(base, zr, false); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param offset Register specifying some offset, optionally scaled by the memory_transfer_size. ++ * May not be null or the stackpointer. ++ * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not. ++ * @return an address specifying a register offset address of the form base + offset [<< log2 ++ * (memory_transfer_size)] ++ */ ++ public static SW64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) { ++ return new SW64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param imm7 Signed 7-bit immediate value. ++ * @return an address specifying an unscaled immediate address of the form base + imm7 ++ */ ++ public static SW64Address createPairUnscaledImmediateAddress(Register base, int imm7) { ++ return new SW64Address(base, zr, imm7, false, null, AddressingMode.IMMEDIATE_UNSCALED); ++ } ++ ++ /** ++ * @param base may not be null or the zero-register. ++ * @param offset Word register specifying some offset, optionally scaled by the ++ * memory_transfer_size. May not be null or the stackpointer. ++ * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not. ++ * @param extendType Describes whether register is zero- or sign-extended. May not be null. ++ * @return an address specifying an extended register offset of the form base + ++ * extendType(offset) [<< log2(memory_transfer_size)] ++ */ ++ public static SW64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, SW64Assembler.ExtendType extendType) { ++ return new SW64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET); ++ } ++ ++ /** ++ * @param imm21 Signed 21-bit offset, word aligned. ++ * @return SW64Address specifying a PC-literal address of the form PC + offset ++ */ ++ public static SW64Address createPcLiteralAddress(int imm21) { ++ return new SW64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL); ++ } ++ ++ private SW64Address(Register base, Register offset, int immediate, boolean scaled, SW64Assembler.ExtendType extendType, AddressingMode addressingMode) { ++ this.base = base; ++ this.offset = offset; ++ if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) { ++ this.addressingMode = AddressingMode.BASE_REGISTER_ONLY; ++ } else { ++ this.addressingMode = addressingMode; ++ } ++ this.immediate = immediate; ++ this.scaled = scaled; ++ this.extendType = extendType; ++ assert verify(); ++ } ++ ++ private boolean verify() { ++ assert addressingMode != null; ++ assert base.getRegisterCategory().equals(SW64.CPU); ++ assert offset.getRegisterCategory().equals(SW64.CPU); ++ ++ switch (addressingMode) { ++ case IMMEDIATE_SCALED: ++ assert !base.equals(zr); ++ assert offset.equals(zr); ++ assert extendType == null; ++ assert NumUtil.isUnsignedNbit(12, immediate); ++ break; ++ case IMMEDIATE_UNSCALED: ++ assert !base.equals(zr); ++ assert offset.equals(zr); ++ assert extendType == null; ++ assert NumUtil.isSignedNbit(9, immediate); ++ break; ++ case BASE_REGISTER_ONLY: ++ assert !base.equals(zr); ++ assert offset.equals(zr); ++ assert extendType == null; ++ assert immediate == 0; ++ break; ++ case REGISTER_OFFSET: ++ assert !base.equals(zr); ++ assert offset.getRegisterCategory().equals(SW64.CPU); ++ assert extendType == null; ++ assert immediate == 0; ++ break; ++ case EXTENDED_REGISTER_OFFSET: ++ assert !base.equals(zr); ++ assert offset.getRegisterCategory().equals(SW64.CPU); ++ assert (extendType == SW64Assembler.ExtendType.SXTW || extendType == SW64Assembler.ExtendType.UXTW); ++ assert immediate == 0; ++ break; ++ case PC_LITERAL: ++ assert base.equals(zr); ++ assert offset.equals(zr); ++ assert extendType == null; ++ assert NumUtil.isSignedNbit(21, immediate); ++ assert ((immediate & 0x3) == 0); ++ break; ++ case IMMEDIATE_POST_INDEXED: ++ case IMMEDIATE_PRE_INDEXED: ++ assert !base.equals(zr); ++ assert offset.equals(zr); ++ assert extendType == null; ++ assert NumUtil.isSignedNbit(9, immediate); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ ++ return true; ++ } ++ ++ public Register getBase() { ++ return base; ++ } ++ ++ public Register getOffset() { ++ return offset; ++ } ++ ++ /** ++ * @return immediate in correct representation for the given addressing mode. For example in ++ * case of addressingMode ==IMMEDIATE_UNSCALED the value will be returned ++ * as the 9-bit signed representation. ++ */ ++ public int getImmediate() { ++ switch (addressingMode) { ++ case IMMEDIATE_UNSCALED: ++ case IMMEDIATE_POST_INDEXED: ++ case IMMEDIATE_PRE_INDEXED: ++ // 9-bit signed value ++ assert NumUtil.isSignedNbit(9, immediate); ++ return immediate & NumUtil.getNbitNumberInt(9); ++ case IMMEDIATE_SCALED: ++ // Unsigned value can be returned as-is. ++ assert NumUtil.isUnsignedNbit(12, immediate); ++ return immediate; ++ case PC_LITERAL: ++ // 21-bit signed value, but lower 2 bits are always 0 and are shifted out. ++ assert NumUtil.isSignedNbit(19, immediate >> 2); ++ return (immediate >> 2) & NumUtil.getNbitNumberInt(19); ++ default: ++ throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values."); ++ } ++ } ++ ++ /** ++ * @return Raw immediate as a 32-bit signed value. ++ */ ++ public int getImmediateRaw() { ++ switch (addressingMode) { ++ case IMMEDIATE_UNSCALED: ++ case IMMEDIATE_SCALED: ++ case IMMEDIATE_POST_INDEXED: ++ case IMMEDIATE_PRE_INDEXED: ++ case PC_LITERAL: ++ return immediate; ++ default: ++ throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values."); ++ } ++ } ++ ++ public boolean isScaled() { ++ return scaled; ++ } ++ ++ public SW64Assembler.ExtendType getExtendType() { ++ return extendType; ++ } ++ ++ public AddressingMode getAddressingMode() { ++ return addressingMode; ++ } ++ ++ public String toString(int log2TransferSize) { ++ int shiftVal = scaled ? log2TransferSize : 0; ++ switch (addressingMode) { ++ case IMMEDIATE_SCALED: ++ return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize); ++ case IMMEDIATE_UNSCALED: ++ return String.format("[X%d, %d]", base.encoding, immediate); ++ case BASE_REGISTER_ONLY: ++ return String.format("[X%d]", base.encoding); ++ case EXTENDED_REGISTER_OFFSET: ++ if (shiftVal != 0) { ++ return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal); ++ } else { ++ return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name()); ++ } ++ case REGISTER_OFFSET: ++ if (shiftVal != 0) { ++ return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal); ++ } else { ++ // LSL 0 may be optional, but still encoded differently so we always leave it ++ // off ++ return String.format("[X%d, X%d]", base.encoding, offset.encoding); ++ } ++ case PC_LITERAL: ++ return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate); ++ case IMMEDIATE_POST_INDEXED: ++ return String.format("[X%d],%d", base.encoding, immediate); ++ case IMMEDIATE_PRE_INDEXED: ++ return String.format("[X%d,%d]!", base.encoding, immediate); ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ /** ++ * Loads an address into Register r. ++ * ++ * @param masm the macro assembler. ++ * @param r general purpose register. May not be null. ++ */ ++ public void lea(SW64MacroAssembler masm, Register r) { ++ switch (addressingMode) { ++ case IMMEDIATE_UNSCALED: ++ if (immediate == 0 && base.equals(r)) { // it's a nop ++ break; ++ } ++ masm.add(64, r, base, immediate); ++ break; ++ case REGISTER_OFFSET: ++ masm.add(64, r, base, offset); ++ break; ++ case PC_LITERAL: { ++ masm.mov(r, getImmediate()); ++ break; ++ } ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Assembler.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Assembler.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Assembler.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64Assembler.java 2025-05-09 10:05:57.748290597 +0800 +@@ -0,0 +1,2835 @@ ++/* ++ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++package org.graalvm.compiler.asm.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.cpuRegisters; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ADD; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ADDS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ADR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ADRP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.AND; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ANDS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ASRV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.BFM; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.BIC; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.BICS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.BLR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.BR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.BRK; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CAS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CLREX; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CLS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CLZ; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CSEL; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CSINC; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.CSNEG; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.DMB; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.EON; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.EOR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.EXTR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FABS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FADD; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCCMP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCMP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCMPZERO; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCSEL; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCVTDS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCVTSD; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FCVTZS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FDIV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FMADD; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FMOV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FMSUB; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FMUL; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FNEG; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FRINTM; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FRINTN; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FRINTP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FRINTZ; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FSQRT; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.FSUB; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.HINT; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.HLT; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDADD; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDAR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDAXR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDRS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LDXR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LSLV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.LSRV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.MADD; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.MOVK; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.MOVN; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.MOVZ; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.MSUB; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ORN; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.ORR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.RBIT; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.RET; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.REVW; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.REVX; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.RORV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.SBFM; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.SCVTF; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.SDIV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.STLR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.STLXR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.STP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.STR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.STXR; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.SUB; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.SUBS; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.SWP; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.TBZ; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.TBNZ; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.UBFM; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.Instruction.UDIV; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.InstructionType.FP32; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.InstructionType.FP64; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.InstructionType.General32; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.InstructionType.General64; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.InstructionType.floatFromSize; ++import static org.graalvm.compiler.asm.sw64.SW64Assembler.InstructionType.generalFromSize; ++import static jdk.vm.ci.sw64.SW64.CPU; ++import static jdk.vm.ci.sw64.SW64.SIMD; ++import static jdk.vm.ci.sw64.SW64.r0; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64.zr; ++ ++import java.util.Arrays; ++ ++import org.graalvm.compiler.asm.Assembler; ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode; ++import org.graalvm.compiler.debug.GraalError; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.sw64.SW64.CPUFeature; ++import jdk.vm.ci.sw64.SW64.Flag; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.TargetDescription; ++ ++public abstract class SW64Assembler extends Assembler { ++ ++ public static class LogicalImmediateTable { ++ ++ private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable(); ++ ++ private static final int ImmediateOffset = 10; ++ private static final int ImmediateRotateOffset = 16; ++ private static final int ImmediateSizeOffset = 22; ++ ++ /** ++ * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction ++ * (SIXTY_FOUR_BIT_ONLY) or not at all (NO). ++ */ ++ enum Representable { ++ YES, ++ SIXTY_FOUR_BIT_ONLY, ++ NO ++ } ++ ++ /** ++ * Tests whether an immediate can be encoded for logical instructions. ++ * ++ * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a ++ * 64-bit instruction to load the 32-bit pattern into a register. ++ * @return enum specifying whether immediate can be used for 32- and 64-bit logical ++ * instructions ({@code #Representable.YES}), for 64-bit instructions only ( ++ * {@link Representable#SIXTY_FOUR_BIT_ONLY}) or not at all ( ++ * {@link Representable#NO}). ++ */ ++ public static Representable isRepresentable(boolean is64bit, long immediate) { ++ int pos = getLogicalImmTablePos(is64bit, immediate); ++ if (pos < 0) { ++ // if 32bit instruction we can try again as 64bit immediate which may succeed. ++ // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one. ++ if (!is64bit) { ++ assert NumUtil.isUnsignedNbit(32, immediate); ++ pos = getLogicalImmTablePos(true, immediate); ++ return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO; ++ } ++ return Representable.NO; ++ } ++ Immediate imm = IMMEDIATE_TABLE[pos]; ++ return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES; ++ } ++ ++ public static Representable isRepresentable(int immediate) { ++ return isRepresentable(false, immediate & 0xFFFF_FFFFL); ++ } ++ ++ public static int getLogicalImmEncoding(boolean is64bit, long value) { ++ int pos = getLogicalImmTablePos(is64bit, value); ++ assert pos >= 0 : "Value cannot be represented as logical immediate: " + value + ", is64bit=" + is64bit; ++ Immediate imm = IMMEDIATE_TABLE[pos]; ++ assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified"; ++ return IMMEDIATE_TABLE[pos].encoding; ++ } ++ ++ /** ++ * @param is64bit if true also allow 64-bit only encodings to be returned. ++ * @return If positive the return value is the position into the IMMEDIATE_TABLE for the ++ * given immediate, if negative the immediate cannot be encoded. ++ */ ++ private static int getLogicalImmTablePos(boolean is64bit, long value) { ++ Immediate imm; ++ if (!is64bit) { ++ // 32bit instructions can only have 32bit immediates. ++ if (!NumUtil.isUnsignedNbit(32, value)) { ++ return -1; ++ } ++ // If we have a 32bit instruction (and therefore immediate) we have to duplicate it ++ // across 64bit to find it in the table. ++ imm = new Immediate(value << 32 | value); ++ } else { ++ imm = new Immediate(value); ++ } ++ int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm); ++ if (pos < 0) { ++ return -1; ++ } ++ if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) { ++ return -1; ++ } ++ return pos; ++ } ++ ++ /** ++ * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of ++ * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each ++ * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by ++ * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting ++ * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the ++ * number of set bits and the pattern size. The pattern size is encoded as follows (x is ++ * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32 ++ * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern? ++ */ ++ private static final class Immediate implements Comparable { ++ public final long imm; ++ public final int encoding; ++ ++ Immediate(long imm, boolean is64, int s, int r) { ++ this.imm = imm; ++ this.encoding = computeEncoding(is64, s, r); ++ } ++ ++ // Used to be able to binary search for an immediate in the table. ++ Immediate(long imm) { ++ this(imm, false, 0, 0); ++ } ++ ++ /** ++ * Returns true if this pattern is only representable as 64bit. ++ */ ++ public boolean only64bit() { ++ return (encoding & (1 << ImmediateSizeOffset)) != 0; ++ } ++ ++ private static int computeEncoding(boolean is64, int s, int r) { ++ int sf = is64 ? 1 : 0; ++ return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset; ++ } ++ ++ @Override ++ public int compareTo(Immediate o) { ++ return Long.compare(imm, o.imm); ++ } ++ } ++ ++ private static Immediate[] buildImmediateTable() { ++ final int nrImmediates = 5334; ++ final Immediate[] table = new Immediate[nrImmediates]; ++ int nrImms = 0; ++ for (int logE = 1; logE <= 6; logE++) { ++ int e = 1 << logE; ++ long mask = NumUtil.getNbitNumberLong(e); ++ for (int nrOnes = 1; nrOnes < e; nrOnes++) { ++ long val = (1L << nrOnes) - 1; ++ // r specifies how much we rotate the value ++ for (int r = 0; r < e; r++) { ++ long immediate = (val >>> r | val << (e - r)) & mask; ++ // Duplicate pattern to fill whole 64bit range. ++ switch (logE) { ++ case 1: ++ immediate |= immediate << 2; ++ immediate |= immediate << 4; ++ immediate |= immediate << 8; ++ immediate |= immediate << 16; ++ immediate |= immediate << 32; ++ break; ++ case 2: ++ immediate |= immediate << 4; ++ immediate |= immediate << 8; ++ immediate |= immediate << 16; ++ immediate |= immediate << 32; ++ break; ++ case 3: ++ immediate |= immediate << 8; ++ immediate |= immediate << 16; ++ immediate |= immediate << 32; ++ break; ++ case 4: ++ immediate |= immediate << 16; ++ immediate |= immediate << 32; ++ break; ++ case 5: ++ immediate |= immediate << 32; ++ break; ++ } ++ // 5 - logE can underflow to -1, but we shift this bogus result ++ // out of the masked area. ++ int sizeEncoding = (1 << (5 - logE)) - 1; ++ int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1); ++ table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r); ++ } ++ } ++ } ++ Arrays.sort(table); ++ assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table."; ++ assert checkDuplicates(table) : "Duplicate values in table."; ++ return table; ++ } ++ ++ private static boolean checkDuplicates(Immediate[] table) { ++ for (int i = 0; i < table.length - 1; i++) { ++ if (table[i].imm >= table[i + 1].imm) { ++ return false; ++ } ++ } ++ return true; ++ } ++ } ++ ++ private static final int RdOffset = 0; ++ private static final int Rs1Offset = 5; ++ private static final int Rs2Offset = 16; ++ private static final int Rs3Offset = 10; ++ private static final int RtOffset = 0; ++ private static final int RnOffset = 5; ++ private static final int Rt2Offset = 10; ++ ++ /* Helper functions */ ++ private static int rd(Register reg) { ++ return reg.encoding << RdOffset; ++ } ++ ++ private static int rs1(Register reg) { ++ return reg.encoding << Rs1Offset; ++ } ++ ++ private static int rs2(Register reg) { ++ return reg.encoding << Rs2Offset; ++ } ++ ++ private static int rs3(Register reg) { ++ return reg.encoding << Rs3Offset; ++ } ++ ++ private static int rt(Register reg) { ++ return reg.encoding << RtOffset; ++ } ++ ++ private static int rt2(Register reg) { ++ return reg.encoding << Rt2Offset; ++ } ++ ++ private static int rn(Register reg) { ++ return reg.encoding << RnOffset; ++ } ++ ++ private static int maskField(int sizeInBits, int n) { ++ assert NumUtil.isSignedNbit(sizeInBits, n); ++ return n & NumUtil.getNbitNumberInt(sizeInBits); ++ } ++ ++ /** ++ * Enumeration of all different instruction kinds: General32/64 are the general instructions ++ * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for ++ * the 32/64bit float operations ++ */ ++ protected enum InstructionType { ++ General32(0b00 << 30, 32, true), ++ General64(0b10 << 30, 64, true), ++ FP32(0x00000000, 32, false), ++ FP64(0x00400000, 64, false); ++ ++ public final int encoding; ++ public final int width; ++ public final boolean isGeneral; ++ ++ InstructionType(int encoding, int width, boolean isGeneral) { ++ this.encoding = encoding; ++ this.width = width; ++ this.isGeneral = isGeneral; ++ } ++ ++ public static InstructionType generalFromSize(int size) { ++ assert size == 32 || size == 64; ++ return size == 32 ? General32 : General64; ++ } ++ ++ public static InstructionType floatFromSize(int size) { ++ assert size == 32 || size == 64; ++ return size == 32 ? FP32 : FP64; ++ } ++ ++ } ++ ++ private static final int ImmediateOffset = 10; ++ private static final int ImmediateRotateOffset = 16; ++ private static final int ImmediateSizeOffset = 22; ++ private static final int ExtendTypeOffset = 13; ++ ++ private static final int AddSubImmOp = 0x11000000; ++ private static final int AddSubShift12 = 0b01 << 22; ++ private static final int AddSubSetFlag = 0x20000000; ++ ++ private static final int LogicalImmOp = 0x12000000; ++ ++ private static final int MoveWideImmOp = 0x12800000; ++ private static final int MoveWideImmOffset = 5; ++ private static final int MoveWideShiftOffset = 21; ++ ++ private static final int BitfieldImmOp = 0x13000000; ++ ++ private static final int AddSubShiftedOp = 0x0B000000; ++ private static final int ShiftTypeOffset = 22; ++ ++ private static final int AddSubExtendedOp = 0x0B200000; ++ ++ private static final int MulOp = 0x1B000000; ++ private static final int DataProcessing1SourceOp = 0x5AC00000; ++ private static final int DataProcessing2SourceOp = 0x1AC00000; ++ ++ private static final int Fp1SourceOp = 0x1E204000; ++ private static final int Fp2SourceOp = 0x1E200800; ++ private static final int Fp3SourceOp = 0x1F000000; ++ ++ private static final int FpConvertOp = 0x1E200000; ++ private static final int FpImmOp = 0x1E201000; ++ private static final int FpImmOffset = 13; ++ ++ private static final int FpCmpOp = 0x1E202000; ++ ++ private static final int PcRelImmHiOffset = 5; ++ private static final int PcRelImmLoOffset = 29; ++ ++ private static final int PcRelImmOp = 0x10000000; ++ ++ private static final int UnconditionalBranchImmOp = 0x14000000; ++ private static final int UnconditionalBranchRegOp = 0xD6000000; ++ private static final int CompareBranchOp = 0x34000000; ++ ++ private static final int ConditionalBranchImmOffset = 5; ++ ++ private static final int ConditionalSelectOp = 0x1A800000; ++ private static final int ConditionalConditionOffset = 12; ++ ++ private static final int LoadStoreScaledOp = 0b111_0_01_00 << 22; ++ private static final int LoadStoreUnscaledOp = 0b111_0_00_00 << 22; ++ ++ private static final int LoadStoreRegisterOp = 0b111_0_00_00_1 << 21 | 0b10 << 10; ++ ++ private static final int LoadLiteralOp = 0x18000000; ++ ++ private static final int LoadStorePostIndexedOp = 0b111_0_00_00_0 << 21 | 0b01 << 10; ++ private static final int LoadStorePreIndexedOp = 0b111_0_00_00_0 << 21 | 0b11 << 10; ++ ++ private static final int LoadStoreUnscaledImmOffset = 12; ++ private static final int LoadStoreScaledImmOffset = 10; ++ private static final int LoadStoreScaledRegOffset = 12; ++ private static final int LoadStoreIndexedImmOffset = 12; ++ private static final int LoadStoreTransferSizeOffset = 30; ++ private static final int LoadStoreFpFlagOffset = 26; ++ private static final int LoadLiteralImmeOffset = 5; ++ ++ private static final int LoadStorePairOp = 0b101_0 << 26; ++ @SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23; ++ @SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23; ++ private static final int LoadStorePairImm7Offset = 15; ++ ++ private static final int LogicalShiftOp = 0x0A000000; ++ ++ private static final int ExceptionOp = 0xD4000000; ++ private static final int SystemImmediateOffset = 5; ++ ++ @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16; ++ ++ private static final int BarrierOp = 0xD503301F; ++ private static final int BarrierKindOffset = 8; ++ ++ private static final int CASAcquireOffset = 22; ++ private static final int CASReleaseOffset = 15; ++ ++ private static final int LDADDAcquireOffset = 23; ++ private static final int LDADDReleaseOffset = 22; ++ ++ /** ++ * Encoding for all instructions. ++ */ ++ public enum Instruction { ++ BCOND(0x54000000), ++ CBNZ(0x01000000), ++ CBZ(0x00000000), ++ TBZ(0x36000000), ++ TBNZ(0x37000000), ++ ++ B(0x00000000), ++ BL(0x80000000), ++ BR(0x001F0000), ++ BLR(0x003F0000), ++ RET(0x005F0000), ++ ++ LDR(0x00000000), ++ LDRS(0x00800000), ++ LDXR(0x081f7c00), ++ LDAR(0x8dffc00), ++ LDAXR(0x85ffc00), ++ ++ STR(0x00000000), ++ STXR(0x08007c00), ++ STLR(0x089ffc00), ++ STLXR(0x0800fc00), ++ ++ LDP(0b1 << 22), ++ STP(0b0 << 22), ++ ++ CAS(0x08A07C00), ++ LDADD(0x38200000), ++ SWP(0x38208000), ++ ++ ADR(0x00000000), ++ ADRP(0x80000000), ++ ++ ADD(0x00000000), ++ ADDS(ADD.encoding | AddSubSetFlag), ++ SUB(0x40000000), ++ SUBS(SUB.encoding | AddSubSetFlag), ++ ++ NOT(0x00200000), ++ AND(0x00000000), ++ BIC(AND.encoding | NOT.encoding), ++ ORR(0x20000000), ++ ORN(ORR.encoding | NOT.encoding), ++ EOR(0x40000000), ++ EON(EOR.encoding | NOT.encoding), ++ ANDS(0x60000000), ++ BICS(ANDS.encoding | NOT.encoding), ++ ++ ASRV(0x00002800), ++ RORV(0x00002C00), ++ LSRV(0x00002400), ++ LSLV(0x00002000), ++ ++ CLS(0x00001400), ++ CLZ(0x00001000), ++ RBIT(0x00000000), ++ REVX(0x00000C00), ++ REVW(0x00000800), ++ ++ MOVN(0x00000000), ++ MOVZ(0x40000000), ++ MOVK(0x60000000), ++ ++ CSEL(0x00000000), ++ CSNEG(0x40000400), ++ CSINC(0x00000400), ++ ++ BFM(0x20000000), ++ SBFM(0x00000000), ++ UBFM(0x40000000), ++ EXTR(0x13800000), ++ ++ MADD(0x00000000), ++ MSUB(0x00008000), ++ SDIV(0x00000C00), ++ UDIV(0x00000800), ++ ++ FMOV(0x00000000), ++ FMOVCPU2FPU(0x00070000), ++ FMOVFPU2CPU(0x00060000), ++ ++ FCVTDS(0x00028000), ++ FCVTSD(0x00020000), ++ ++ FCVTZS(0x00180000), ++ SCVTF(0x00020000), ++ ++ FABS(0x00008000), ++ FSQRT(0x00018000), ++ FNEG(0x00010000), ++ ++ FRINTM(0x00050000), ++ FRINTN(0x00040000), ++ FRINTP(0x00048000), ++ FRINTZ(0x00058000), ++ ++ FADD(0x00002000), ++ FSUB(0x00003000), ++ FMUL(0x00000000), ++ FDIV(0x00001000), ++ FMAX(0x00004000), ++ FMIN(0x00005000), ++ ++ FMADD(0x00000000), ++ FMSUB(0x00008000), ++ ++ FCMP(0x00000000), ++ FCMPZERO(0x00000008), ++ FCCMP(0x1E200400), ++ FCSEL(0x1E200C00), ++ ++ INS(0x4e081c00), ++ UMOV(0x4e083c00), ++ ++ CNT(0xe205800), ++ USRA(0x6f001400), ++ ++ HLT(0x00400000), ++ BRK(0x00200000), ++ ++ CLREX(0xd5033f5f), ++ HINT(0xD503201F), ++ DMB(0x000000A0), ++ ++ BLR_NATIVE(0xc0000000); ++ ++ public final int encoding; ++ ++ Instruction(int encoding) { ++ this.encoding = encoding; ++ } ++ ++ } ++ ++ public enum ShiftType { ++ LSL(0), ++ LSR(1), ++ ASR(2), ++ ROR(3); ++ ++ public final int encoding; ++ ++ ShiftType(int encoding) { ++ this.encoding = encoding; ++ } ++ } ++ ++ public enum ExtendType { ++ UXTB(0), ++ UXTH(1), ++ UXTW(2), ++ UXTX(3), ++ SXTB(4), ++ SXTH(5), ++ SXTW(6), ++ SXTX(7); ++ ++ public final int encoding; ++ ++ ExtendType(int encoding) { ++ this.encoding = encoding; ++ } ++ } ++ ++ /** ++ * Condition Flags for branches. See 4.3 ++ */ ++ public enum ConditionFlag { ++ // Integer | Floating-point meanings ++ /** Equal | Equal. */ ++ EQ(0x0), ++ ++ /** Not Equal | Not equal or unordered. */ ++ NE(0x1), ++ ++ /** Unsigned Higher or Same | Greater than, equal or unordered. */ ++ HS(0x2), ++ ++ /** Unsigned lower | less than. */ ++ LO(0x3), ++ ++ /** Minus (negative) | less than. */ ++ MI(0x4), ++ ++ /** Plus (positive or zero) | greater than, equal or unordered. */ ++ PL(0x5), ++ ++ /** Overflow set | unordered. */ ++ VS(0x6), ++ ++ /** Overflow clear | ordered. */ ++ VC(0x7), ++ ++ /** Unsigned higher | greater than or unordered. */ ++ HI(0x8), ++ ++ /** Unsigned lower or same | less than or equal. */ ++ LS(0x9), ++ ++ /** Signed greater than or equal | greater than or equal. */ ++ GE(0xA), ++ ++ /** Signed less than | less than or unordered. */ ++ LT(0xB), ++ ++ /** Signed greater than | greater than. */ ++ GT(0xC), ++ ++ /** Signed less than or equal | less than, equal or unordered. */ ++ LE(0xD), ++ ++ /** Always | always. */ ++ AL(0xE), ++ ++ /** Always | always (identical to AL, just to have valid 0b1111 encoding). */ ++ NV(0xF); ++ ++ public final int encoding; ++ ++ ConditionFlag(int encoding) { ++ this.encoding = encoding; ++ } ++ ++ /** ++ * @return ConditionFlag specified by decoding. ++ */ ++ public static ConditionFlag fromEncoding(int encoding) { ++ return values()[encoding]; ++ } ++ ++ public ConditionFlag negate() { ++ switch (this) { ++ case EQ: ++ return NE; ++ case NE: ++ return EQ; ++ case HS: ++ return LO; ++ case LO: ++ return HS; ++ case MI: ++ return PL; ++ case PL: ++ return MI; ++ case VS: ++ return VC; ++ case VC: ++ return VS; ++ case HI: ++ return LS; ++ case LS: ++ return HI; ++ case GE: ++ return LT; ++ case LT: ++ return GE; ++ case GT: ++ return LE; ++ case LE: ++ return GT; ++ case AL: ++ case NV: ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ } ++ ++ public SW64Assembler(TargetDescription target) { ++ super(target); ++ } ++ ++ public boolean supports(CPUFeature feature) { ++ return ((SW64) target.arch).getFeatures().contains(feature); ++ } ++ ++ public boolean isFlagSet(Flag flag) { ++ return ((SW64) target.arch).getFlags().contains(flag); ++ } ++ ++ /* Conditional Branch (5.2.1) */ ++ ++ /** ++ * Branch conditionally. ++ * ++ * @param condition may not be null. ++ * @param imm21 Signed 21-bit offset, has to be word aligned. ++ */ ++ protected void b(ConditionFlag condition, int imm21) { ++ b(condition, imm21, -1); ++ } ++ ++ /** ++ * Branch conditionally. Inserts instruction into code buffer at pos. ++ * ++ * @param condition may not be null. ++ * @param imm21 Signed 21-bit offset, has to be word aligned. ++ * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. ++ */ ++ protected void b(ConditionFlag condition, int imm21, int pos) { ++ if (pos == -1) { ++ emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding); ++ } else { ++ emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos); ++ } ++ } ++ ++ /** ++ * Compare register and branch if non-zero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param size Instruction size in bits. Should be either 32 or 64. ++ * @param imm21 Signed 21-bit offset, has to be word aligned. ++ */ ++ protected void cbnz(int size, Register reg, int imm21) { ++ conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1); ++ } ++ ++ /** ++ * Compare register and branch if non-zero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param size Instruction size in bits. Should be either 32 or 64. ++ * @param imm21 Signed 21-bit offset, has to be word aligned. ++ * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. ++ */ ++ protected void cbnz(int size, Register reg, int imm21, int pos) { ++ conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos); ++ } ++ ++ /** ++ * Compare and branch if zero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param size Instruction size in bits. Should be either 32 or 64. ++ * @param imm21 Signed 21-bit offset, has to be word aligned. ++ */ ++ protected void cbz(int size, Register reg, int imm21) { ++ conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1); ++ } ++ ++ /** ++ * Compare register and branch if zero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param size Instruction size in bits. Should be either 32 or 64. ++ * @param imm21 Signed 21-bit offset, has to be word aligned. ++ * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. ++ */ ++ protected void cbz(int size, Register reg, int imm21, int pos) { ++ conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos); ++ } ++ ++ /** ++ * Test a single bit and branch if the bit is nonzero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param uimm6 Unsigned 6-bit bit index. ++ * @param imm16 signed 16 bit offset ++ */ ++ protected void tbnz(Register reg, int uimm6, int imm16) { ++ tbnz(reg, uimm6, imm16, -1); ++ } ++ ++ /** ++ * Test a single bit and branch if the bit is zero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param uimm6 Unsigned 6-bit bit index. ++ * @param imm16 signed 16 bit offset ++ */ ++ protected void tbz(Register reg, int uimm6, int imm16) { ++ tbz(reg, uimm6, imm16, -1); ++ } ++ ++ /** ++ * Test a single bit and branch if the bit is nonzero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param uimm6 Unsigned 6-bit bit index. ++ * @param imm16 signed 16 bit offset ++ * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. ++ */ ++ protected void tbnz(Register reg, int uimm6, int imm16, int pos) { ++ assert reg.getRegisterCategory().equals(CPU); ++ assert NumUtil.isUnsignedNbit(6, uimm6); ++ assert NumUtil.isSignedNbit(18, imm16); ++ assert (imm16 & 3) == 0; ++ // size bit is overloaded as top bit of uimm6 bit index ++ int size = (((uimm6 >> 5) & 1) == 0 ? 32 : 64); ++ // remaining 5 bits are encoded lower down ++ int uimm5 = uimm6 >> 1; ++ int offset = (imm16 & NumUtil.getNbitNumberInt(16)) >> 2; ++ InstructionType type = generalFromSize(size); ++ int encoding = type.encoding | TBNZ.encoding | (uimm5 << 19) | (offset << 5) | rd(reg); ++ if (pos == -1) { ++ emitInt(encoding); ++ } else { ++ emitInt(encoding, pos); ++ } ++ } ++ ++ /** ++ * Test a single bit and branch if the bit is zero. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ * @param uimm6 Unsigned 6-bit bit index. ++ * @param imm16 signed 16 bit offset ++ * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. ++ */ ++ protected void tbz(Register reg, int uimm6, int imm16, int pos) { ++ assert reg.getRegisterCategory().equals(CPU); ++ assert NumUtil.isUnsignedNbit(6, uimm6); ++ assert NumUtil.isSignedNbit(18, imm16); ++ assert (imm16 & 3) == 0; ++ // size bit is overloaded as top bit of uimm6 bit index ++ int size = (((uimm6 >> 5) & 1) == 0 ? 32 : 64); ++ // remaining 5 bits are encoded lower down ++ int uimm5 = uimm6 >> 1; ++ int offset = (imm16 & NumUtil.getNbitNumberInt(16)) >> 2; ++ InstructionType type = generalFromSize(size); ++ int encoding = type.encoding | TBZ.encoding | (uimm5 << 19) | (offset << 5) | rd(reg); ++ if (pos == -1) { ++ emitInt(encoding); ++ } else { ++ emitInt(encoding, pos); ++ } ++ } ++ ++ private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) { ++ assert reg.getRegisterCategory().equals(CPU); ++ int instrEncoding = instr.encoding | CompareBranchOp; ++ if (pos == -1) { ++ emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg)); ++ } else { ++ emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos); ++ } ++ } ++ ++ private static int getConditionalBranchImm(int imm21) { ++ assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned"; ++ int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2; ++ return imm << ConditionalBranchImmOffset; ++ } ++ ++ /* Unconditional Branch (immediate) (5.2.2) */ ++ ++ /** ++ * @param imm28 Signed 28-bit offset, has to be word aligned. ++ */ ++ protected void b(int imm28) { ++ unconditionalBranchImmInstruction(imm28, Instruction.B, -1); ++ } ++ ++ /** ++ * ++ * @param imm28 Signed 28-bit offset, has to be word aligned. ++ * @param pos Position where instruction is inserted into code buffer. ++ */ ++ protected void b(int imm28, int pos) { ++ unconditionalBranchImmInstruction(imm28, Instruction.B, pos); ++ } ++ ++ /** ++ * Branch and link return address to register X30. ++ * ++ * @param imm28 Signed 28-bit offset, has to be word aligned. ++ */ ++ public void bl(int imm28) { ++ unconditionalBranchImmInstruction(imm28, Instruction.BL, -1); ++ } ++ ++ private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) { ++ assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned"; ++ int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2; ++ int instrEncoding = instr.encoding | UnconditionalBranchImmOp; ++ if (pos == -1) { ++ emitInt(instrEncoding | imm); ++ } else { ++ emitInt(instrEncoding | imm, pos); ++ } ++ } ++ ++ /* Unconditional Branch (register) (5.2.3) */ ++ ++ /** ++ * Branches to address in register and writes return address into register X30. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ */ ++ public void blr(Register reg) { ++ unconditionalBranchRegInstruction(BLR, reg); ++ } ++ ++ /** ++ * Branches to address in register. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ */ ++ protected void br(Register reg) { ++ unconditionalBranchRegInstruction(BR, reg); ++ } ++ ++ /** ++ * Return to address in register. ++ * ++ * @param reg general purpose register. May not be null, zero-register or stackpointer. ++ */ ++ public void ret(Register reg) { ++ unconditionalBranchRegInstruction(RET, reg); ++ } ++ ++ private void unconditionalBranchRegInstruction(Instruction instr, Register reg) { ++ assert reg.getRegisterCategory().equals(CPU); ++ assert !reg.equals(zr); ++ assert !reg.equals(sp); ++ emitInt(instr.encoding | UnconditionalBranchRegOp | rs1(reg)); ++ } ++ ++ /* Load-Store Single Register (5.3.1) */ ++ ++ /** ++ * Loads a srcSize value from address into rt zero-extending it. ++ * ++ * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ public void ldr(int srcSize, Register rt, SW64Address address) { ++ assert rt.getRegisterCategory().equals(CPU); ++ assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64; ++ int transferSize = NumUtil.log2Ceil(srcSize / 8); ++ loadStoreInstruction(LDR, rt, address, General32, transferSize); ++ } ++ ++ /** ++ * Loads a srcSize value from address into rt sign-extending it. ++ * ++ * @param targetSize size of target register in bits. Must be 32 or 64. ++ * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to ++ * targetSize. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ protected void ldrs(int targetSize, int srcSize, Register rt, SW64Address address) { ++ assert rt.getRegisterCategory().equals(CPU); ++ assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize; ++ int transferSize = NumUtil.log2Ceil(srcSize / 8); ++ loadStoreInstruction(LDRS, rt, address, generalFromSize(targetSize), transferSize); ++ } ++ ++ public enum PrefetchMode { ++ PLDL1KEEP(0b00000), ++ PLDL1STRM(0b00001), ++ PLDL2KEEP(0b00010), ++ PLDL2STRM(0b00011), ++ PLDL3KEEP(0b00100), ++ PLDL3STRM(0b00101), ++ ++ PLIL1KEEP(0b01000), ++ PLIL1STRM(0b01001), ++ PLIL2KEEP(0b01010), ++ PLIL2STRM(0b01011), ++ PLIL3KEEP(0b01100), ++ PLIL3STRM(0b01101), ++ ++ PSTL1KEEP(0b10000), ++ PSTL1STRM(0b10001), ++ PSTL2KEEP(0b10010), ++ PSTL2STRM(0b10011), ++ PSTL3KEEP(0b10100), ++ PSTL3STRM(0b10101); ++ ++ private final int encoding; ++ ++ PrefetchMode(int encoding) { ++ this.encoding = encoding; ++ } ++ ++ private static PrefetchMode[] modes = { ++ PLDL1KEEP, ++ PLDL1STRM, ++ PLDL2KEEP, ++ PLDL2STRM, ++ PLDL3KEEP, ++ PLDL3STRM, ++ ++ null, ++ null, ++ ++ PLIL1KEEP, ++ PLIL1STRM, ++ PLIL2KEEP, ++ PLIL2STRM, ++ PLIL3KEEP, ++ PLIL3STRM, ++ ++ null, ++ null, ++ ++ PSTL1KEEP, ++ PSTL1STRM, ++ PSTL2KEEP, ++ PSTL2STRM, ++ PSTL3KEEP, ++ PSTL3STRM ++ }; ++ ++ public static PrefetchMode lookup(int enc) { ++ assert enc >= 00 && enc < modes.length; ++ return modes[enc]; ++ } ++ ++ public Register toRegister() { ++ return cpuRegisters.get(encoding); ++ } ++ } ++ ++ /* ++ * implements a prefetch at a 64-bit aligned address using a scaled 12 bit or unscaled 9 bit ++ * displacement addressing mode ++ * ++ * @param rt general purpose register. May not be null, zr or stackpointer. ++ * ++ * @param address only displacement addressing modes allowed. May not be null. ++ */ ++ public void prfm(SW64Address address, PrefetchMode mode) { ++ assert (address.getAddressingMode() == AddressingMode.IMMEDIATE_SCALED || ++ address.getAddressingMode() == AddressingMode.IMMEDIATE_UNSCALED || ++ address.getAddressingMode() == AddressingMode.REGISTER_OFFSET); ++ assert mode != null; ++ final int srcSize = 64; ++ final int transferSize = NumUtil.log2Ceil(srcSize / 8); ++ final Register rt = mode.toRegister(); ++ // this looks weird but that's because loadStoreInstruction is weird ++ // instruction select fields are size [31:30], v [26] and opc [25:24] ++ // prfm requires size == 0b11, v == 0b0 and opc == 0b11 ++ // passing LDRS ensures opc[1] == 0b1 ++ // (n.b. passing LDR/STR makes no difference to opc[1:0]!!) ++ // passing General64 ensures opc[0] == 0b1 and v = 0b0 ++ // (n.b. passing General32 ensures opc[0] == 0b0 and v = 0b0) ++ // srcSize 64 ensures size == 0b11 ++ loadStoreInstruction(LDRS, rt, address, General64, transferSize); ++ } ++ ++ /** ++ * Stores register rt into memory pointed by address. ++ * ++ * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ public void str(int destSize, Register rt, SW64Address address) { ++ assert rt.getRegisterCategory().equals(CPU); ++ assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64; ++ int transferSize = NumUtil.log2Ceil(destSize / 8); ++ loadStoreInstruction(STR, rt, address, General64, transferSize); ++ } ++ ++ private void loadStoreInstruction(Instruction instr, Register reg, SW64Address address, InstructionType type, int log2TransferSize) { ++ assert log2TransferSize >= 0 && log2TransferSize < 4; ++ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; ++ int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0; ++ int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0; ++ int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg); ++ switch (address.getAddressingMode()) { ++ case IMMEDIATE_SCALED: ++ emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase())); ++ break; ++ case IMMEDIATE_UNSCALED: ++ emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase())); ++ break; ++ case BASE_REGISTER_ONLY: ++ emitInt(memop | LoadStoreScaledOp | rs1(address.getBase())); ++ break; ++ case EXTENDED_REGISTER_OFFSET: ++ case REGISTER_OFFSET: ++ ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX; ++ boolean shouldScale = address.isScaled() && log2TransferSize != 0; ++ emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase())); ++ break; ++ case PC_LITERAL: ++ assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger"; ++ transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset; ++ emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset); ++ break; ++ case IMMEDIATE_POST_INDEXED: ++ emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); ++ break; ++ case IMMEDIATE_PRE_INDEXED: ++ emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); ++ } ++ } ++ ++ /** ++ * Load Pair of Registers calculates an address from a base register value and an immediate ++ * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from ++ * two registers. ++ */ ++ public void ldp(int size, Register rt, Register rt2, SW64Address address) { ++ assert size == 32 || size == 64; ++ loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size)); ++ } ++ ++ /** ++ * Store Pair of Registers calculates an address from a base register value and an immediate ++ * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from ++ * two registers. ++ */ ++ public void stp(int size, Register rt, Register rt2, SW64Address address) { ++ assert size == 32 || size == 64; ++ loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size)); ++ } ++ ++ private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, SW64Address address, InstructionType type) { ++ int scaledOffset = maskField(7, address.getImmediateRaw()); // LDP/STP use a 7-bit scaled ++ // offset ++ int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt); ++ switch (address.getAddressingMode()) { ++ case IMMEDIATE_SCALED: ++ emitInt(memop | LoadStorePairOp | (0b010 << 23)); ++ break; ++ case IMMEDIATE_POST_INDEXED: ++ emitInt(memop | LoadStorePairOp | (0b001 << 23)); ++ break; ++ case IMMEDIATE_PRE_INDEXED: ++ emitInt(memop | LoadStorePairOp | (0b011 << 23)); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); ++ } ++ } ++ ++ /* Load-Store Exclusive (5.3.6) */ ++ ++ /** ++ * Load address exclusive. Natural alignment of address is required. ++ * ++ * @param size size of memory read in bits. Must be 8, 16, 32 or 64. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param rn general purpose register. ++ */ ++ protected void ldxr(int size, Register rt, Register rn) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ exclusiveLoadInstruction(LDXR, rt, rn, transferSize); ++ } ++ ++ /** ++ * Store address exclusive. Natural alignment of address is required. rs and rt may not point to ++ * the same register. ++ * ++ * @param size size of bits written to memory. Must be 8, 16, 32 or 64. ++ * @param rs general purpose register. Set to exclusive access status. 0 means success, ++ * everything else failure. May not be null, or stackpointer. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param rn general purpose register. ++ */ ++ protected void stxr(int size, Register rs, Register rt, Register rn) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ exclusiveStoreInstruction(STXR, rs, rt, rn, transferSize); ++ } ++ ++ /* Load-Acquire/Store-Release (5.3.7) */ ++ ++ /* non exclusive access */ ++ /** ++ * Load acquire. Natural alignment of address is required. ++ * ++ * @param size size of memory read in bits. Must be 8, 16, 32 or 64. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param rn general purpose register. ++ */ ++ protected void ldar(int size, Register rt, Register rn) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ exclusiveLoadInstruction(LDAR, rt, rn, transferSize); ++ } ++ ++ /** ++ * Store-release. Natural alignment of address is required. ++ * ++ * @param size size of bits written to memory. Must be 8, 16, 32 or 64. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param rn general purpose register. ++ */ ++ protected void stlr(int size, Register rt, Register rn) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ // Hack: Passing the zero-register means it is ignored when building the encoding. ++ exclusiveStoreInstruction(STLR, r0, rt, rn, transferSize); ++ } ++ ++ /* exclusive access */ ++ /** ++ * Load acquire exclusive. Natural alignment of address is required. ++ * ++ * @param size size of memory read in bits. Must be 8, 16, 32 or 64. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param rn general purpose register. ++ */ ++ public void ldaxr(int size, Register rt, Register rn) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ exclusiveLoadInstruction(LDAXR, rt, rn, transferSize); ++ } ++ ++ /** ++ * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to ++ * the same register. ++ * ++ * @param size size of bits written to memory. Must be 8, 16, 32 or 64. ++ * @param rs general purpose register. Set to exclusive access status. 0 means success, ++ * everything else failure. May not be null, or stackpointer. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param rn general purpose register. ++ */ ++ public void stlxr(int size, Register rs, Register rt, Register rn) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ exclusiveStoreInstruction(STLXR, rs, rt, rn, transferSize); ++ } ++ ++ private void exclusiveLoadInstruction(Instruction instr, Register reg, Register rn, int log2TransferSize) { ++ assert log2TransferSize >= 0 && log2TransferSize < 4; ++ assert reg.getRegisterCategory().equals(CPU); ++ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; ++ emitInt(transferSizeEncoding | instr.encoding | 1 << ImmediateSizeOffset | rn(rn) | rt(reg)); ++ } ++ ++ /** ++ * Stores data from rt into address and sets rs to the returned exclusive access status. ++ * ++ * @param rs general purpose register into which the exclusive access status is written. May not ++ * be null. ++ * @param rt general purpose register containing data to be written to memory at address. May ++ * not be null ++ * @param rn general purpose register containing the address specifying where rt is written to. ++ * @param log2TransferSize log2Ceil of memory transfer size. ++ */ ++ private void exclusiveStoreInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize) { ++ assert log2TransferSize >= 0 && log2TransferSize < 4; ++ assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); ++ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; ++ emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt)); ++ } ++ ++ /** ++ * Compare And Swap word or doubleword in memory. This reads a value from an address rn, ++ * compares it against a given value rs, and, if equal, stores the value rt to memory. The value ++ * read from address rn is stored in register rs. ++ * ++ * @param size size of bits read from memory. Must be 32 or 64. ++ * @param rs general purpose register to be compared and loaded. May not be null. ++ * @param rt general purpose register to be conditionally stored. May not be null. ++ * @param rn general purpose register containing the address from which to read. ++ * @param acquire boolean value signifying if the load should use acquire semantics. ++ * @param release boolean value signifying if the store should use release semantics. ++ */ ++ public void cas(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) { ++ assert size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ compareAndSwapInstruction(CAS, rs, rt, rn, transferSize, acquire, release); ++ } ++ ++ private void compareAndSwapInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize, boolean acquire, boolean release) { ++ assert log2TransferSize >= 0 && log2TransferSize < 4; ++ assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); ++ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; ++ emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << CASAcquireOffset | (release ? 1 : 0) << CASReleaseOffset); ++ } ++ ++ /** ++ * Atomic add. This reads a value from an address rn, stores the value in rt, and adds the value ++ * in rs to it, and stores the result back at address rn. The initial value read from memory is ++ * stored in rt. ++ * ++ * @param size size of operand to read from memory. Must be 8, 16, 32, or 64. ++ * @param rs general purpose register to be added to contents. May not be null. ++ * @param rt general purpose register to be loaded. May not be null. ++ * @param rn general purpose register or stack pointer holding an address from which to load. ++ * @param acquire boolean value signifying if the load should use acquire semantics. ++ * @param release boolean value signifying if the store should use release semantics. ++ */ ++ public void ldadd(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ loadAndAddInstruction(LDADD, rs, rt, rn, transferSize, acquire, release); ++ } ++ ++ private void loadAndAddInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize, boolean acquire, boolean release) { ++ assert log2TransferSize >= 0 && log2TransferSize < 4; ++ assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); ++ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; ++ emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << LDADDAcquireOffset | (release ? 1 : 0) << LDADDReleaseOffset); ++ } ++ ++ /** ++ * Atomic swap. This reads a value from an address rn, stores the value in rt, and then stores ++ * the value in rs back at address rn. ++ * ++ * @param size size of operand to read from memory. Must be 8, 16, 32, or 64. ++ * @param rs general purpose register to be stored. May not be null. ++ * @param rt general purpose register to be loaded. May not be null. ++ * @param rn general purpose register or stack pointer holding an address from which to load. ++ * @param acquire boolean value signifying if the load should use acquire semantics. ++ * @param release boolean value signifying if the store should use release semantics. ++ */ ++ public void swp(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) { ++ assert size == 8 || size == 16 || size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ swapInstruction(SWP, rs, rt, rn, transferSize, acquire, release); ++ } ++ ++ private void swapInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize, boolean acquire, boolean release) { ++ assert log2TransferSize >= 0 && log2TransferSize < 4; ++ assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); ++ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; ++ emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << LDADDAcquireOffset | (release ? 1 : 0) << LDADDReleaseOffset); ++ } ++ ++ /* PC-relative Address Calculation (5.4.4) */ ++ ++ /** ++ * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of ++ * the PC with its bottom 12-bits cleared, writing the result to dst. No offset is emitted; the ++ * instruction will be patched later. ++ * ++ * @param dst general purpose register. May not be null, zero-register or stackpointer. ++ */ ++ public void adrp(Register dst) { ++ emitInt(ADRP.encoding | PcRelImmOp | rd(dst)); ++ } ++ ++ /** ++ * Adds a 21-bit signed offset to the program counter and writes the result to dst. ++ * ++ * @param dst general purpose register. May not be null, zero-register or stackpointer. ++ * @param imm21 Signed 21-bit offset. ++ */ ++ public void adr(Register dst, int imm21) { ++ emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21)); ++ } ++ ++ /** ++ * Adds a 21-bit signed offset to the program counter and writes the result to dst. ++ * ++ * @param dst general purpose register. May not be null, zero-register or stackpointer. ++ * @param imm21 Signed 21-bit offset. ++ * @param pos the position in the code that the instruction is emitted. ++ */ ++ public void adr(Register dst, int imm21, int pos) { ++ emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos); ++ } ++ ++ private static int getPcRelativeImmEncoding(int imm21) { ++ assert NumUtil.isSignedNbit(21, imm21); ++ int imm = imm21 & NumUtil.getNbitNumberInt(21); ++ // higher 19 bit ++ int immHi = (imm >> 2) << PcRelImmHiOffset; ++ // lower 2 bit ++ int immLo = (imm & 0x3) << PcRelImmLoOffset; ++ return immHi | immLo; ++ } ++ ++ /* Arithmetic (Immediate) (5.4.1) */ ++ ++ /** ++ * dst = src + aimm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with ++ * the lower 12-bit cleared. ++ */ ++ protected void add(int size, Register dst, Register src, int aimm) { ++ assert !dst.equals(zr); ++ assert !src.equals(zr); ++ addSubImmInstruction(ADD, dst, src, aimm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src + aimm and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with ++ * the lower 12-bit cleared. ++ */ ++ protected void adds(int size, Register dst, Register src, int aimm) { ++ assert !dst.equals(sp); ++ assert !src.equals(zr); ++ addSubImmInstruction(ADDS, dst, src, aimm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src - aimm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with ++ * the lower 12-bit cleared. ++ */ ++ protected void sub(int size, Register dst, Register src, int aimm) { ++ assert !dst.equals(zr); ++ assert !src.equals(zr); ++ addSubImmInstruction(SUB, dst, src, aimm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src - aimm and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with ++ * the lower 12-bit cleared. ++ */ ++ protected void subs(int size, Register dst, Register src, int aimm) { ++ assert !dst.equals(sp); ++ assert !src.equals(zr); ++ addSubImmInstruction(SUBS, dst, src, aimm, generalFromSize(size)); ++ } ++ ++ private void addSubImmInstruction(Instruction instr, Register dst, Register src, int aimm, InstructionType type) { ++ emitInt(type.encoding | instr.encoding | AddSubImmOp | encodeAimm(aimm) | rd(dst) | rs1(src)); ++ } ++ ++ /** ++ * Encodes arithmetic immediate. ++ * ++ * @param imm Immediate has to be either an unsigned 12-bit value or an unsigned 24-bit value ++ * with the lower 12 bits zero. ++ * @return Representation of immediate for use with arithmetic instructions. ++ */ ++ private static int encodeAimm(int imm) { ++ assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm; ++ if (NumUtil.isUnsignedNbit(12, imm)) { ++ return imm << ImmediateOffset; ++ } else { ++ // First 12-bit are zero, so shift immediate 12-bit and set flag to indicate ++ // shifted immediate value. ++ return (imm >>> 12 << ImmediateOffset) | AddSubShift12; ++ } ++ } ++ ++ /** ++ * Checks whether immediate can be encoded as an arithmetic immediate. ++ * ++ * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with ++ * the lower 12 bits 0. ++ * @return true if valid arithmetic immediate, false otherwise. ++ */ ++ protected static boolean isAimm(int imm) { ++ return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0; ++ } ++ ++ /* Logical (immediate) (5.4.2) */ ++ ++ /** ++ * dst = src & bimm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or stack-pointer. ++ * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. ++ */ ++ public void and(int size, Register dst, Register src, long bimm) { ++ assert !dst.equals(zr); ++ assert !src.equals(sp); ++ logicalImmInstruction(AND, dst, src, bimm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src & bimm and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stack-pointer. ++ * @param src general purpose register. May not be null or stack-pointer. ++ * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. ++ */ ++ public void ands(int size, Register dst, Register src, long bimm) { ++ assert !dst.equals(sp); ++ assert !src.equals(sp); ++ logicalImmInstruction(ANDS, dst, src, bimm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src ^ bimm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or stack-pointer. ++ * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. ++ */ ++ public void eor(int size, Register dst, Register src, long bimm) { ++ assert !dst.equals(zr); ++ assert !src.equals(sp); ++ logicalImmInstruction(EOR, dst, src, bimm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src | bimm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or stack-pointer. ++ * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. ++ */ ++ protected void orr(int size, Register dst, Register src, long bimm) { ++ assert !dst.equals(zr); ++ assert !src.equals(sp); ++ logicalImmInstruction(ORR, dst, src, bimm, generalFromSize(size)); ++ } ++ ++ private void logicalImmInstruction(Instruction instr, Register dst, Register src, long bimm, InstructionType type) { ++ // Mask higher bits off, since we always pass longs around even for the 32-bit instruction. ++ long bimmValue; ++ if (type == General32) { ++ assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1."; ++ bimmValue = bimm & NumUtil.getNbitNumberLong(32); ++ } else { ++ bimmValue = bimm; ++ } ++ int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == General64, bimmValue); ++ emitInt(type.encoding | instr.encoding | LogicalImmOp | immEncoding | rd(dst) | rs1(src)); ++ } ++ ++ /* Move (wide immediate) (5.4.3) */ ++ ++ /** ++ * dst = uimm16 << shiftAmt. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param uimm16 16-bit unsigned immediate ++ * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller ++ * than size. ++ */ ++ protected void movz(int size, Register dst, int uimm16, int shiftAmt) { ++ moveWideImmInstruction(MOVZ, dst, uimm16, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = ~(uimm16 << shiftAmt). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param uimm16 16-bit unsigned immediate ++ * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller ++ * than size. ++ */ ++ protected void movn(int size, Register dst, int uimm16, int shiftAmt) { ++ moveWideImmInstruction(MOVN, dst, uimm16, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = uimm16. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param uimm16 16-bit unsigned immediate ++ * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than ++ * size. ++ */ ++ protected void movk(int size, Register dst, int uimm16, int pos) { ++ moveWideImmInstruction(MOVK, dst, uimm16, pos, generalFromSize(size)); ++ } ++ ++ private void moveWideImmInstruction(Instruction instr, Register dst, int uimm16, int shiftAmt, InstructionType type) { ++ assert dst.getRegisterCategory().equals(CPU); ++ assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit"; ++ assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt; ++ int shiftValue = shiftAmt >> 4; ++ emitInt(type.encoding | instr.encoding | MoveWideImmOp | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset); ++ } ++ ++ /* Bitfield Operations (5.4.5) */ ++ ++ /** ++ * Bitfield move. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ * @param r must be in the range 0 to size - 1 ++ * @param s must be in the range 0 to size - 1 ++ */ ++ public void bfm(int size, Register dst, Register src, int r, int s) { ++ bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size)); ++ } ++ ++ /** ++ * Unsigned bitfield move. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ * @param r must be in the range 0 to size - 1 ++ * @param s must be in the range 0 to size - 1 ++ */ ++ public void ubfm(int size, Register dst, Register src, int r, int s) { ++ bitfieldInstruction(UBFM, dst, src, r, s, generalFromSize(size)); ++ } ++ ++ /** ++ * Signed bitfield move. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ * @param r must be in the range 0 to size - 1 ++ * @param s must be in the range 0 to size - 1 ++ */ ++ protected void sbfm(int size, Register dst, Register src, int r, int s) { ++ bitfieldInstruction(SBFM, dst, src, r, s, generalFromSize(size)); ++ } ++ ++ private void bitfieldInstruction(Instruction instr, Register dst, Register src, int r, int s, InstructionType type) { ++ assert !dst.equals(sp) && !dst.equals(zr); ++ assert !src.equals(sp) && !src.equals(zr); ++ assert s >= 0 && s < type.width && r >= 0 && r < type.width; ++ int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; ++ emitInt(type.encoding | instr.encoding | BitfieldImmOp | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src)); ++ } ++ ++ /* Extract (Immediate) (5.4.6) */ ++ ++ /** ++ * Extract. dst = src1:src2 ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param lsb must be in range 0 to size - 1. ++ */ ++ protected void extr(int size, Register dst, Register src1, Register src2, int lsb) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ InstructionType type = generalFromSize(size); ++ assert lsb >= 0 && lsb < type.width; ++ int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; ++ emitInt(type.encoding | EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2)); ++ } ++ ++ /* Arithmetic (shifted register) (5.5.1) */ ++ ++ /** ++ * dst = src1 + shiftType(src2, imm). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType any type but ROR. ++ * @param imm must be in range 0 to size - 1. ++ */ ++ protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ addSubShiftedInstruction(ADD, dst, src1, src2, shiftType, imm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 + shiftType(src2, imm) and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType any type but ROR. ++ * @param imm must be in range 0 to size - 1. ++ */ ++ public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 - shiftType(src2, imm). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType any type but ROR. ++ * @param imm must be in range 0 to size - 1. ++ */ ++ protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ addSubShiftedInstruction(SUB, dst, src1, src2, shiftType, imm, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 - shiftType(src2, imm) and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType any type but ROR. ++ * @param imm must be in range 0 to size - 1. ++ */ ++ public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size)); ++ } ++ ++ private void addSubShiftedInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type) { ++ assert shiftType != ShiftType.ROR; ++ assert imm >= 0 && imm < type.width; ++ emitInt(type.encoding | instr.encoding | AddSubShiftedOp | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); ++ } ++ ++ /* Arithmetic (extended register) (5.5.2) */ ++ /** ++ * dst = src1 + extendType(src2) << imm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register.. ++ * @param src1 general purpose register. May not be null or zero-register. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param extendType defines how src2 is extended to the same size as src1. ++ * @param shiftAmt must be in range 0 to 4. ++ */ ++ public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ assert !dst.equals(zr); ++ assert !src1.equals(zr); ++ assert !src2.equals(sp); ++ addSubExtendedInstruction(ADD, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 + extendType(src2) << imm and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer.. ++ * @param src1 general purpose register. May not be null or zero-register. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param extendType defines how src2 is extended to the same size as src1. ++ * @param shiftAmt must be in range 0 to 4. ++ */ ++ protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ assert !dst.equals(sp); ++ assert !src1.equals(zr); ++ assert !src2.equals(sp); ++ addSubExtendedInstruction(ADDS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 - extendType(src2) << imm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register.. ++ * @param src1 general purpose register. May not be null or zero-register. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param extendType defines how src2 is extended to the same size as src1. ++ * @param shiftAmt must be in range 0 to 4. ++ */ ++ protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ assert !dst.equals(zr); ++ assert !src1.equals(zr); ++ assert !src2.equals(sp); ++ addSubExtendedInstruction(SUB, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 - extendType(src2) << imm and sets flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer.. ++ * @param src1 general purpose register. May not be null or zero-register. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param extendType defines how src2 is extended to the same size as src1. ++ * @param shiftAmt must be in range 0 to 4. ++ */ ++ public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ assert !dst.equals(sp); ++ assert !src1.equals(zr); ++ assert !src2.equals(sp); ++ addSubExtendedInstruction(SUBS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); ++ } ++ ++ private void addSubExtendedInstruction(Instruction instr, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type) { ++ assert shiftAmt >= 0 && shiftAmt <= 4; ++ emitInt(type.encoding | instr.encoding | AddSubExtendedOp | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); ++ } ++ ++ /* Logical (shifted register) (5.5.3) */ ++ /** ++ * dst = src1 & shiftType(src2, imm). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(AND, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 & shiftType(src2, imm) and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(ANDS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 & ~(shiftType(src2, imm)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(BIC, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(BICS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 ^ ~(shiftType(src2, imm)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(EON, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 ^ shiftType(src2, imm). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(EOR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 | shiftType(src2, imm). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(ORR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 | ~(shiftType(src2, imm)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType all types allowed, may not be null. ++ * @param shiftAmt must be in range 0 to size - 1. ++ */ ++ protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ logicalRegInstruction(ORN, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); ++ } ++ ++ private void logicalRegInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ assert shiftAmt >= 0 && shiftAmt < type.width; ++ emitInt(type.encoding | instr.encoding | LogicalShiftOp | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); ++ } ++ ++ /* Variable Shift (5.5.4) */ ++ /** ++ * dst = src1 >> (src2 & log2(size)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ protected void asr(int size, Register dst, Register src1, Register src2) { ++ dataProcessing2SourceOp(ASRV, dst, src1, src2, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 << (src2 & log2(size)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ protected void lsl(int size, Register dst, Register src1, Register src2) { ++ dataProcessing2SourceOp(LSLV, dst, src1, src2, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 >>> (src2 & log2(size)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ protected void lsr(int size, Register dst, Register src1, Register src2) { ++ dataProcessing2SourceOp(LSRV, dst, src1, src2, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = rotateRight(src1, (src2 & log2(size))). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ protected void ror(int size, Register dst, Register src1, Register src2) { ++ dataProcessing2SourceOp(RORV, dst, src1, src2, generalFromSize(size)); ++ } ++ ++ /* Bit Operations (5.5.5) */ ++ ++ /** ++ * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit ++ * in dst, that are the same as the topmost bit. The count does not include the topmost bit ++ * itself , so the result will be in the range 0 to size-1 inclusive. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, zero-register or the stackpointer. ++ * @param src source register. May not be null, zero-register or the stackpointer. ++ */ ++ protected void cls(int size, Register dst, Register src) { ++ dataProcessing1SourceOp(CLS, dst, src, generalFromSize(size)); ++ } ++ ++ /** ++ * Counts leading zeros. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, zero-register or the stackpointer. ++ * @param src source register. May not be null, zero-register or the stackpointer. ++ */ ++ public void clz(int size, Register dst, Register src) { ++ dataProcessing1SourceOp(CLZ, dst, src, generalFromSize(size)); ++ } ++ ++ /** ++ * Reverses bits. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, zero-register or the stackpointer. ++ * @param src source register. May not be null, zero-register or the stackpointer. ++ */ ++ public void rbit(int size, Register dst, Register src) { ++ dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size)); ++ } ++ ++ /** ++ * Reverses bytes. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src source register. May not be null or the stackpointer. ++ */ ++ public void rev(int size, Register dst, Register src) { ++ if (size == 64) { ++ dataProcessing1SourceOp(REVX, dst, src, generalFromSize(size)); ++ } else { ++ assert size == 32; ++ dataProcessing1SourceOp(REVW, dst, src, generalFromSize(size)); ++ } ++ } ++ ++ /* Conditional Data Processing (5.5.6) */ ++ ++ /** ++ * Conditional select. dst = src1 if condition else src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param condition any condition flag. May not be null. ++ */ ++ protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ conditionalSelectInstruction(CSEL, dst, src1, src2, condition, generalFromSize(size)); ++ } ++ ++ /** ++ * Conditional select negate. dst = src1 if condition else -src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param condition any condition flag. May not be null. ++ */ ++ protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ conditionalSelectInstruction(CSNEG, dst, src1, src2, condition, generalFromSize(size)); ++ } ++ ++ /** ++ * Conditional increase. dst = src1 if condition else src2 + 1. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param condition any condition flag. May not be null. ++ */ ++ protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ conditionalSelectInstruction(CSINC, dst, src1, src2, condition, generalFromSize(size)); ++ } ++ ++ private void conditionalSelectInstruction(Instruction instr, Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ emitInt(type.encoding | instr.encoding | ConditionalSelectOp | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); ++ } ++ ++ /* Integer Multiply/Divide (5.6) */ ++ ++ /** ++ * dst = src1 * src2 + src3. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param src3 general purpose register. May not be null or the stackpointer. ++ */ ++ protected void madd(int size, Register dst, Register src1, Register src2, Register src3) { ++ mulInstruction(MADD, dst, src1, src2, src3, generalFromSize(size)); ++ } ++ ++ /** ++ * dst = src3 - src1 * src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param src3 general purpose register. May not be null or the stackpointer. ++ */ ++ protected void msub(int size, Register dst, Register src1, Register src2, Register src3) { ++ mulInstruction(MSUB, dst, src1, src2, src3, generalFromSize(size)); ++ } ++ ++ /** ++ * Signed multiply high. dst = (src1 * src2)[127:64] ++ * ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ protected void smulh(Register dst, Register src1, Register src2) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ emitInt(0b10011011010 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); ++ } ++ ++ /** ++ * unsigned multiply high. dst = (src1 * src2)[127:64] ++ * ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ protected void umulh(Register dst, Register src1, Register src2) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ emitInt(0b10011011110 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); ++ } ++ ++ /** ++ * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) ++ * ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param src3 general purpose register. May not be null or the stackpointer. ++ */ ++ protected void umaddl(Register dst, Register src1, Register src2, Register src3) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ assert !src3.equals(sp); ++ emitInt(0b10011011101 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); ++ } ++ ++ /** ++ * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) ++ * ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ * @param src3 general purpose register. May not be null or the stackpointer. ++ */ ++ public void smaddl(Register dst, Register src1, Register src2, Register src3) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ assert !src3.equals(sp); ++ emitInt(0b10011011001 << 21 | dst.encoding | rs1(src1) | rs2(src2) | rs3(src3)); ++ } ++ ++ private void mulInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ assert !src3.equals(sp); ++ emitInt(type.encoding | instr.encoding | MulOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); ++ } ++ ++ /** ++ * Signed divide. dst = src1 / src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ public void sdiv(int size, Register dst, Register src1, Register src2) { ++ dataProcessing2SourceOp(SDIV, dst, src1, src2, generalFromSize(size)); ++ } ++ ++ /** ++ * Unsigned divide. dst = src1 / src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ public void udiv(int size, Register dst, Register src1, Register src2) { ++ dataProcessing2SourceOp(UDIV, dst, src1, src2, generalFromSize(size)); ++ } ++ ++ private void dataProcessing1SourceOp(Instruction instr, Register dst, Register src, InstructionType type) { ++ emitInt(type.encoding | instr.encoding | DataProcessing1SourceOp | rd(dst) | rs1(src)); ++ } ++ ++ private void dataProcessing2SourceOp(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { ++ assert !dst.equals(sp); ++ assert !src1.equals(sp); ++ assert !src2.equals(sp); ++ emitInt(type.encoding | instr.encoding | DataProcessing2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); ++ } ++ ++ /* Floating point operations */ ++ ++ /* Load-Store Single FP register (5.7.1.1) */ ++ /** ++ * Floating point load. ++ * ++ * @param size number of bits read from memory into rt. Must be 32 or 64. ++ * @param rt floating point register. May not be null. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ public void fldr(int size, Register rt, SW64Address address) { ++ assert rt.getRegisterCategory().equals(SIMD); ++ assert size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ loadStoreInstruction(LDR, rt, address, InstructionType.FP32, transferSize); ++ } ++ ++ /** ++ * Floating point store. ++ * ++ * @param size number of bits read from memory into rt. Must be 32 or 64. ++ * @param rt floating point register. May not be null. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ public void fstr(int size, Register rt, SW64Address address) { ++ assert rt.getRegisterCategory().equals(SIMD); ++ assert size == 32 || size == 64; ++ int transferSize = NumUtil.log2Ceil(size / 8); ++ loadStoreInstruction(STR, rt, address, InstructionType.FP64, transferSize); ++ } ++ ++ /* Floating-point Move (register) (5.7.2) */ ++ ++ /** ++ * Floating point move. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ protected void fmov(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FMOV, dst, src, floatFromSize(size)); ++ } ++ ++ /** ++ * Move size bits from floating point register unchanged to general purpose register. ++ * ++ * @param size number of bits read from memory into rt. Must be 32 or 64. ++ * @param dst general purpose register. May not be null, stack-pointer or zero-register ++ * @param src floating point register. May not be null. ++ */ ++ protected void fmovFpu2Cpu(int size, Register dst, Register src) { ++ assert dst.getRegisterCategory().equals(CPU); ++ assert src.getRegisterCategory().equals(SIMD); ++ fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU); ++ } ++ ++ /** ++ * Move size bits from general purpose register unchanged to floating point register. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst floating point register. May not be null. ++ * @param src general purpose register. May not be null or stack-pointer. ++ */ ++ protected void fmovCpu2Fpu(int size, Register dst, Register src) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ assert src.getRegisterCategory().equals(CPU); ++ fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU); ++ } ++ ++ private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) { ++ int sf = is64bit ? FP64.encoding | General64.encoding : FP32.encoding | General32.encoding; ++ emitInt(sf | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); ++ } ++ ++ /* Floating-point Move (immediate) (5.7.3) */ ++ ++ /** ++ * Move immediate into register. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst floating point register. May not be null. ++ * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be ++ * loaded, i.e. (float) imm == imm must be true. In all cases ++ * {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true ++ * depending on size. ++ */ ++ protected void fmov(int size, Register dst, double imm) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ InstructionType type = floatFromSize(size); ++ int immEncoding; ++ if (type == FP64) { ++ immEncoding = getDoubleImmediate(imm); ++ } else { ++ assert imm == (float) imm : "float mov must use an immediate that can be represented using a float."; ++ immEncoding = getFloatImmediate((float) imm); ++ } ++ emitInt(type.encoding | FMOV.encoding | FpImmOp | immEncoding | rd(dst)); ++ } ++ ++ private static int getDoubleImmediate(double imm) { ++ assert isDoubleImmediate(imm); ++ // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 ++ // 0000.0000.0000.0000.0000.0000.0000.0000 ++ long repr = Double.doubleToRawLongBits(imm); ++ int a = (int) (repr >>> 63) << 7; ++ int b = (int) ((repr >>> 61) & 0x1) << 6; ++ int cToH = (int) (repr >>> 48) & 0x3f; ++ return (a | b | cToH) << FpImmOffset; ++ } ++ ++ protected static boolean isDoubleImmediate(double imm) { ++ // Valid values will have the form: ++ // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 ++ // 0000.0000.0000.0000.0000.0000.0000.0000 ++ long bits = Double.doubleToRawLongBits(imm); ++ // lower 48 bits are cleared ++ if ((bits & NumUtil.getNbitNumberLong(48)) != 0) { ++ return false; ++ } ++ // bits[61..54] are all set or all cleared. ++ long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7); ++ if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) { ++ return false; ++ } ++ // bits[62] and bits[61] are opposites. ++ return ((bits ^ (bits << 1)) & (1L << 62)) != 0; ++ } ++ ++ private static int getFloatImmediate(float imm) { ++ assert isFloatImmediate(imm); ++ // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000 ++ int repr = Float.floatToRawIntBits(imm); ++ int a = (repr >>> 31) << 7; ++ int b = ((repr >>> 29) & 0x1) << 6; ++ int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6); ++ return (a | b | cToH) << FpImmOffset; ++ } ++ ++ protected static boolean isFloatImmediate(float imm) { ++ // Valid values will have the form: ++ // aBbb.bbbc.defg.h000.0000.0000.0000.0000 ++ int bits = Float.floatToRawIntBits(imm); ++ // lower 20 bits are cleared. ++ if ((bits & NumUtil.getNbitNumberInt(19)) != 0) { ++ return false; ++ } ++ // bits[29..25] are all set or all cleared ++ int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5); ++ if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) { ++ return false; ++ } ++ // bits[29] and bits[30] have to be opposite ++ return ((bits ^ (bits << 1)) & (1 << 30)) != 0; ++ } ++ ++ /* Convert Floating-point Precision (5.7.4.1) */ ++ /* Converts float to double and vice-versa */ ++ ++ /** ++ * Convert float to double and vice-versa. ++ * ++ * @param srcSize size of source register in bits. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void fcvt(int srcSize, Register dst, Register src) { ++ if (srcSize == 32) { ++ fpDataProcessing1Source(FCVTDS, dst, src, floatFromSize(srcSize)); ++ } else { ++ fpDataProcessing1Source(FCVTSD, dst, src, floatFromSize(srcSize)); ++ } ++ } ++ ++ /* Convert to Integer (5.7.4.2) */ ++ ++ /** ++ * Convert floating point to integer. Rounds towards zero. ++ * ++ * @param targetSize size of integer register. 32 or 64. ++ * @param srcSize size of floating point register. 32 or 64. ++ * @param dst general purpose register. May not be null, the zero-register or the stackpointer. ++ * @param src floating point register. May not be null. ++ */ ++ public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) { ++ assert !dst.equals(zr) && !dst.equals(sp); ++ assert src.getRegisterCategory().equals(SIMD); ++ fcvtCpuFpuInstruction(FCVTZS, dst, src, generalFromSize(targetSize), floatFromSize(srcSize)); ++ } ++ ++ /* Convert from Integer (5.7.4.2) */ ++ /** ++ * Converts integer to floating point. Uses rounding mode defined by FCPR. ++ * ++ * @param targetSize size of floating point register. 32 or 64. ++ * @param srcSize size of integer register. 32 or 64. ++ * @param dst floating point register. May not be null. ++ * @param src general purpose register. May not be null or the stackpointer. ++ */ ++ public void scvtf(int targetSize, int srcSize, Register dst, Register src) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ assert !src.equals(sp); ++ fcvtCpuFpuInstruction(SCVTF, dst, src, floatFromSize(targetSize), generalFromSize(srcSize)); ++ } ++ ++ private void fcvtCpuFpuInstruction(Instruction instr, Register dst, Register src, InstructionType type1, InstructionType type2) { ++ emitInt(type1.encoding | type2.encoding | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); ++ } ++ ++ /* Floating-point Round to Integral (5.7.5) */ ++ ++ /** ++ * Rounds floating-point to integral. Rounds towards zero. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ protected void frintz(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size)); ++ } ++ ++ /** ++ * Rounds floating-point to integral. Rounds towards nearest with ties to even. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void frintn(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FRINTN, dst, src, floatFromSize(size)); ++ } ++ ++ /** ++ * Rounds floating-point to integral. Rounds towards minus infinity. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void frintm(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FRINTM, dst, src, floatFromSize(size)); ++ } ++ ++ /** ++ * Rounds floating-point to integral. Rounds towards plus infinity. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void frintp(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FRINTP, dst, src, floatFromSize(size)); ++ } ++ ++ /* Floating-point Arithmetic (1 source) (5.7.6) */ ++ ++ /** ++ * dst = |src|. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void fabs(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FABS, dst, src, floatFromSize(size)); ++ } ++ ++ /** ++ * dst = -neg. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void fneg(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FNEG, dst, src, floatFromSize(size)); ++ } ++ ++ /** ++ * dst = Sqrt(src). ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src floating point register. May not be null. ++ */ ++ public void fsqrt(int size, Register dst, Register src) { ++ fpDataProcessing1Source(FSQRT, dst, src, floatFromSize(size)); ++ } ++ ++ private void fpDataProcessing1Source(Instruction instr, Register dst, Register src, InstructionType type) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ assert src.getRegisterCategory().equals(SIMD); ++ emitInt(type.encoding | instr.encoding | Fp1SourceOp | rd(dst) | rs1(src)); ++ } ++ ++ /* Floating-point Arithmetic (2 source) (5.7.7) */ ++ ++ /** ++ * dst = src1 + src2. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ */ ++ public void fadd(int size, Register dst, Register src1, Register src2) { ++ fpDataProcessing2Source(FADD, dst, src1, src2, floatFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 - src2. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ */ ++ public void fsub(int size, Register dst, Register src1, Register src2) { ++ fpDataProcessing2Source(FSUB, dst, src1, src2, floatFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 * src2. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ */ ++ public void fmul(int size, Register dst, Register src1, Register src2) { ++ fpDataProcessing2Source(FMUL, dst, src1, src2, floatFromSize(size)); ++ } ++ ++ /** ++ * dst = src1 / src2. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ */ ++ public void fdiv(int size, Register dst, Register src1, Register src2) { ++ fpDataProcessing2Source(FDIV, dst, src1, src2, floatFromSize(size)); ++ } ++ ++ private void fpDataProcessing2Source(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ assert src1.getRegisterCategory().equals(SIMD); ++ assert src2.getRegisterCategory().equals(SIMD); ++ emitInt(type.encoding | instr.encoding | Fp2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); ++ } ++ ++ /* Floating-point Multiply-Add (5.7.9) */ ++ ++ /** ++ * dst = src1 * src2 + src3. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ * @param src3 floating point register. May not be null. ++ */ ++ protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) { ++ fpDataProcessing3Source(FMADD, dst, src1, src2, src3, floatFromSize(size)); ++ } ++ ++ /** ++ * dst = src3 - src1 * src2. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ * @param src3 floating point register. May not be null. ++ */ ++ protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) { ++ fpDataProcessing3Source(FMSUB, dst, src1, src2, src3, floatFromSize(size)); ++ } ++ ++ private void fpDataProcessing3Source(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ assert src1.getRegisterCategory().equals(SIMD); ++ assert src2.getRegisterCategory().equals(SIMD); ++ assert src3.getRegisterCategory().equals(SIMD); ++ emitInt(type.encoding | instr.encoding | Fp3SourceOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); ++ } ++ ++ /* Floating-point Comparison (5.7.10) */ ++ ++ /** ++ * Compares src1 to src2. ++ * ++ * @param size register size. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ */ ++ public void fcmp(int size, Register src1, Register src2) { ++ assert src1.getRegisterCategory().equals(SIMD); ++ assert src2.getRegisterCategory().equals(SIMD); ++ InstructionType type = floatFromSize(size); ++ emitInt(type.encoding | FCMP.encoding | FpCmpOp | rs1(src1) | rs2(src2)); ++ } ++ ++ /** ++ * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4. ++ * ++ * @param size register size. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ * @param uimm4 condition flags that are used if condition is false. ++ * @param condition every condition allowed. May not be null. ++ */ ++ public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) { ++ assert NumUtil.isUnsignedNbit(4, uimm4); ++ assert src1.getRegisterCategory().equals(SIMD); ++ assert src2.getRegisterCategory().equals(SIMD); ++ InstructionType type = floatFromSize(size); ++ emitInt(type.encoding | FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2)); ++ } ++ ++ /** ++ * Compare register to 0.0 . ++ * ++ * @param size register size. ++ * @param src floating point register. May not be null. ++ */ ++ public void fcmpZero(int size, Register src) { ++ assert src.getRegisterCategory().equals(SIMD); ++ InstructionType type = floatFromSize(size); ++ emitInt(type.encoding | FCMPZERO.encoding | FpCmpOp | rs1(src)); ++ } ++ ++ /* Floating-point Conditional Select (5.7.11) */ ++ ++ /** ++ * Conditional select. dst = src1 if condition else src2. ++ * ++ * @param size register size. ++ * @param dst floating point register. May not be null. ++ * @param src1 floating point register. May not be null. ++ * @param src2 floating point register. May not be null. ++ * @param condition every condition allowed. May not be null. ++ */ ++ protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ assert dst.getRegisterCategory().equals(SIMD); ++ assert src1.getRegisterCategory().equals(SIMD); ++ assert src2.getRegisterCategory().equals(SIMD); ++ InstructionType type = floatFromSize(size); ++ emitInt(type.encoding | FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); ++ } ++ ++ /* Debug exceptions (5.9.1.2) */ ++ ++ /** ++ * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as ++ * UNALLOCATED instruction. ++ * ++ * @param uimm16 Arbitrary 16-bit unsigned payload. ++ */ ++ protected void hlt(int uimm16) { ++ exceptionInstruction(HLT, uimm16); ++ } ++ ++ /** ++ * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher ++ * exception level. ++ * ++ * @param uimm16 Arbitrary 16-bit unsigned payload. ++ */ ++ protected void brk(int uimm16) { ++ exceptionInstruction(BRK, uimm16); ++ } ++ ++ private void exceptionInstruction(Instruction instr, int uimm16) { ++ assert NumUtil.isUnsignedNbit(16, uimm16); ++ emitInt(instr.encoding | ExceptionOp | uimm16 << SystemImmediateOffset); ++ } ++ ++ /* Architectural hints (5.9.4) */ ++ public enum SystemHint { ++ NOP(0x0), ++ YIELD(0x1), ++ WFE(0x2), ++ WFI(0x3), ++ SEV(0x4), ++ SEVL(0x5); ++ ++ private final int encoding; ++ ++ SystemHint(int encoding) { ++ this.encoding = encoding; ++ } ++ } ++ ++ /** ++ * Architectural hints. ++ * ++ * @param hint Can be any of the defined hints. May not be null. ++ */ ++ protected void hint(SystemHint hint) { ++ emitInt(HINT.encoding | hint.encoding << SystemImmediateOffset); ++ } ++ ++ /** ++ * Clear Exclusive: clears the local record of the executing processor that an address has had a ++ * request for an exclusive access. ++ */ ++ protected void clrex() { ++ emitInt(CLREX.encoding); ++ } ++ ++ /** ++ * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying ++ * barrier. ++ * ++ * We only need synchronization across the inner shareable domain (see B2-90 in the Reference ++ * documentation). ++ */ ++ public enum BarrierKind { ++ LOAD_LOAD(0x9, "ISHLD"), ++ LOAD_STORE(0x9, "ISHLD"), ++ STORE_STORE(0xA, "ISHST"), ++ ANY_ANY(0xB, "ISH"); ++ ++ public final int encoding; ++ public final String optionName; ++ ++ BarrierKind(int encoding, String optionName) { ++ this.encoding = encoding; ++ this.optionName = optionName; ++ } ++ } ++ ++ /** ++ * Data Memory Barrier. ++ * ++ * @param barrierKind barrier that is issued. May not be null. ++ */ ++ public void dmb(BarrierKind barrierKind) { ++ emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64MacroAssembler.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64MacroAssembler.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64MacroAssembler.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64/src/org/graalvm/compiler/asm/sw64/SW64MacroAssembler.java 2025-05-09 10:05:57.748290597 +0800 +@@ -0,0 +1,1604 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.asm.sw64; ++ ++import static org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode.BASE_REGISTER_ONLY; ++import static org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode.EXTENDED_REGISTER_OFFSET; ++import static org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode.IMMEDIATE_SCALED; ++import static org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode.IMMEDIATE_UNSCALED; ++import static org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode.REGISTER_OFFSET; ++import static org.graalvm.compiler.asm.sw64.SW64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE; ++import static org.graalvm.compiler.asm.sw64.SW64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX; ++import static org.graalvm.compiler.asm.sw64.SW64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK; ++import static jdk.vm.ci.sw64.SW64.CPU; ++import static jdk.vm.ci.sw64.SW64.r8; ++import static jdk.vm.ci.sw64.SW64.r9; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64.zr; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.debug.GraalError; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.TargetDescription; ++ ++public class SW64MacroAssembler extends SW64Assembler { ++ ++ private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(r8), new ScratchRegister(r9)}; ++ ++ // Points to the next free scratch register ++ private int nextFreeScratchRegister = 0; ++ ++ public SW64MacroAssembler(TargetDescription target) { ++ super(target); ++ } ++ ++ public class ScratchRegister implements AutoCloseable { ++ private final Register register; ++ ++ public ScratchRegister(Register register) { ++ this.register = register; ++ } ++ ++ public Register getRegister() { ++ return register; ++ } ++ ++ @Override ++ public void close() { ++ assert nextFreeScratchRegister > 0 : "Close called too often"; ++ nextFreeScratchRegister--; ++ } ++ } ++ ++ public ScratchRegister getScratchRegister() { ++ return scratchRegister[nextFreeScratchRegister++]; ++ } ++ ++ /** ++ * Specifies what actions have to be taken to turn an arbitrary address of the form ++ * {@code base + displacement [+ index [<< scale]]} into a valid SW64Address. ++ */ ++ public static class AddressGenerationPlan { ++ public final WorkPlan workPlan; ++ public final SW64Address.AddressingMode addressingMode; ++ public final boolean needsScratch; ++ ++ public enum WorkPlan { ++ /** ++ * Can be used as-is without extra work. ++ */ ++ NO_WORK, ++ /** ++ * Add scaled displacement to index register. ++ */ ++ ADD_TO_INDEX, ++ /** ++ * Add unscaled displacement to base register. ++ */ ++ ADD_TO_BASE, ++ } ++ ++ /** ++ * @param workPlan Work necessary to generate a valid address. ++ * @param addressingMode Addressing mode of generated address. ++ * @param needsScratch True if generating address needs a scatch register, false otherwise. ++ */ ++ public AddressGenerationPlan(WorkPlan workPlan, SW64Address.AddressingMode addressingMode, boolean needsScratch) { ++ this.workPlan = workPlan; ++ this.addressingMode = addressingMode; ++ this.needsScratch = needsScratch; ++ } ++ } ++ ++ /** ++ * Generates an addressplan for an address of the form ++ * {@code base + displacement [+ index [<< log2(transferSize)]]} with the index register and ++ * scaling being optional. ++ * ++ * @param displacement an arbitrary displacement. ++ * @param hasIndexRegister true if the address uses an index register, false otherwise. non null ++ * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much ++ * the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8. ++ * @return AddressGenerationPlan that specifies the actions necessary to generate a valid ++ * SW64Address for the given parameters. ++ */ ++ public static AddressGenerationPlan generateAddressPlan(long displacement, boolean hasIndexRegister, int transferSize) { ++ assert transferSize == 0 || transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8; ++ boolean indexScaled = transferSize != 0; ++ int log2Scale = NumUtil.log2Ceil(transferSize); ++ long scaledDisplacement = displacement >> log2Scale; ++ boolean displacementScalable = indexScaled && (displacement & (transferSize - 1)) == 0; ++ if (displacement == 0) { ++ // register offset without any work beforehand. ++ return new AddressGenerationPlan(NO_WORK, REGISTER_OFFSET, false); ++ } else { ++ if (hasIndexRegister) { ++ if (displacementScalable) { ++ boolean needsScratch = !isArithmeticImmediate(scaledDisplacement); ++ return new AddressGenerationPlan(ADD_TO_INDEX, REGISTER_OFFSET, needsScratch); ++ } else { ++ boolean needsScratch = !isArithmeticImmediate(displacement); ++ return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch); ++ } ++ } else { ++ if (displacementScalable && NumUtil.isUnsignedNbit(12, scaledDisplacement)) { ++ return new AddressGenerationPlan(NO_WORK, IMMEDIATE_SCALED, false); ++ } else if (NumUtil.isSignedNbit(9, displacement)) { ++ return new AddressGenerationPlan(NO_WORK, IMMEDIATE_UNSCALED, false); ++ } else { ++ boolean needsScratch = !isArithmeticImmediate(displacement); ++ return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch); ++ } ++ } ++ } ++ } ++ ++ /** ++ * Returns an SW64Address pointing to ++ * {@code base + displacement + index << log2(transferSize)}. ++ * ++ * @param base general purpose register. May not be null or the zero register. ++ * @param displacement arbitrary displacement added to base. ++ * @param index general purpose register. May not be null or the stack pointer. ++ * @param signExtendIndex if true consider index register a word register that should be ++ * sign-extended before being added. ++ * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much ++ * the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8. ++ * @param additionalReg additional register used either as a scratch register or as part of the ++ * final address, depending on whether allowOverwrite is true or not. May not be null ++ * or stackpointer. ++ * @param allowOverwrite if true allows to change value of base or index register to generate ++ * address. ++ * @return SW64Address pointing to memory at ++ * {@code base + displacement + index << log2(transferSize)}. ++ */ ++ public SW64Address makeAddress(Register base, long displacement, Register index, boolean signExtendIndex, int transferSize, Register additionalReg, boolean allowOverwrite) { ++ AddressGenerationPlan plan = generateAddressPlan(displacement, !index.equals(zr), transferSize); ++ assert allowOverwrite || !zr.equals(additionalReg) || plan.workPlan == NO_WORK; ++ assert !plan.needsScratch || !zr.equals(additionalReg); ++ int log2Scale = NumUtil.log2Ceil(transferSize); ++ long scaledDisplacement = displacement >> log2Scale; ++ Register newIndex = index; ++ Register newBase = base; ++ int immediate; ++ switch (plan.workPlan) { ++ case NO_WORK: ++ if (plan.addressingMode == IMMEDIATE_SCALED) { ++ immediate = (int) scaledDisplacement; ++ } else { ++ immediate = (int) displacement; ++ } ++ break; ++ case ADD_TO_INDEX: ++ newIndex = allowOverwrite ? index : additionalReg; ++ assert !newIndex.equals(sp) && !newIndex.equals(zr); ++ if (plan.needsScratch) { ++ mov(additionalReg, scaledDisplacement); ++ add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg); ++ } else { ++ add(signExtendIndex ? 32 : 64, newIndex, index, (int) scaledDisplacement); ++ } ++ immediate = 0; ++ break; ++ case ADD_TO_BASE: ++ newBase = allowOverwrite ? base : additionalReg; ++ assert !newBase.equals(sp) && !newBase.equals(zr); ++ if (plan.needsScratch) { ++ mov(additionalReg, displacement); ++ add(64, newBase, base, additionalReg); ++ } else { ++ add(64, newBase, base, (int) displacement); ++ } ++ immediate = 0; ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ SW64Address.AddressingMode addressingMode = plan.addressingMode; ++ ExtendType extendType = null; ++ if (addressingMode == REGISTER_OFFSET) { ++ if (newIndex.equals(zr)) { ++ addressingMode = BASE_REGISTER_ONLY; ++ } else if (signExtendIndex) { ++ addressingMode = EXTENDED_REGISTER_OFFSET; ++ extendType = ExtendType.SXTW; ++ } ++ } ++ return SW64Address.createAddress(addressingMode, newBase, newIndex, immediate, transferSize != 0, extendType); ++ } ++ ++ /** ++ * Returns an SW64Address pointing to {@code base + displacement}. Specifies the memory ++ * transfer size to allow some optimizations when building the address. ++ * ++ * @param base general purpose register. May not be null or the zero register. ++ * @param displacement arbitrary displacement added to base. ++ * @param transferSize the memory transfer size in bytes. ++ * @param additionalReg additional register used either as a scratch register or as part of the ++ * final address, depending on whether allowOverwrite is true or not. May not be ++ * null, zero register or stackpointer. ++ * @param allowOverwrite if true allows to change value of base or index register to generate ++ * address. ++ * @return SW64Address pointing to memory at {@code base + displacement}. ++ */ ++ public SW64Address makeAddress(Register base, long displacement, Register additionalReg, int transferSize, boolean allowOverwrite) { ++ assert additionalReg.getRegisterCategory().equals(CPU); ++ return makeAddress(base, displacement, zr, /* sign-extend */false, transferSize, additionalReg, allowOverwrite); ++ } ++ ++ /** ++ * Returns an SW64Address pointing to {@code base + displacement}. Fails if address cannot be ++ * represented without overwriting base register or using a scratch register. ++ * ++ * @param base general purpose register. May not be null or the zero register. ++ * @param displacement arbitrary displacement added to base. ++ * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much ++ * the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8. ++ * @return SW64Address pointing to memory at {@code base + displacement}. ++ */ ++ public SW64Address makeAddress(Register base, long displacement, int transferSize) { ++ return makeAddress(base, displacement, zr, /* signExtend */false, transferSize, zr, /* allowOverwrite */false); ++ } ++ ++ /** ++ * Loads memory address into register. ++ * ++ * @param dst general purpose register. May not be null, zero-register or stackpointer. ++ * @param address address whose value is loaded into dst. May not be null, ++ * {@link org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode#IMMEDIATE_POST_INDEXED ++ * POST_INDEXED} or ++ * {@link org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode#IMMEDIATE_PRE_INDEXED ++ * IMMEDIATE_PRE_INDEXED} ++ * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much ++ * the index register is scaled. Can be 1, 2, 4 or 8. ++ */ ++ public void loadAddress(Register dst, SW64Address address, int transferSize) { ++ assert transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8; ++ assert dst.getRegisterCategory().equals(CPU); ++ int shiftAmt = NumUtil.log2Ceil(transferSize); ++ switch (address.getAddressingMode()) { ++ case IMMEDIATE_SCALED: ++ int scaledImmediate = address.getImmediateRaw() << shiftAmt; ++ int lowerBits = scaledImmediate & NumUtil.getNbitNumberInt(12); ++ int higherBits = scaledImmediate & ~NumUtil.getNbitNumberInt(12); ++ boolean firstAdd = true; ++ if (lowerBits != 0) { ++ add(64, dst, address.getBase(), lowerBits); ++ firstAdd = false; ++ } ++ if (higherBits != 0) { ++ Register src = firstAdd ? address.getBase() : dst; ++ add(64, dst, src, higherBits); ++ } ++ break; ++ case IMMEDIATE_UNSCALED: ++ int immediate = address.getImmediateRaw(); ++ add(64, dst, address.getBase(), immediate); ++ break; ++ case REGISTER_OFFSET: ++ add(64, dst, address.getBase(), address.getOffset(), ShiftType.LSL, address.isScaled() ? shiftAmt : 0); ++ break; ++ case EXTENDED_REGISTER_OFFSET: ++ add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0); ++ break; ++ case PC_LITERAL: { ++ addressOf(dst); ++ break; ++ } ++ case BASE_REGISTER_ONLY: ++ movx(dst, address.getBase()); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ public void movx(Register dst, Register src) { ++ mov(64, dst, src); ++ } ++ ++ public void mov(int size, Register dst, Register src) { ++ if (dst.equals(sp) || src.equals(sp)) { ++ add(size, dst, src, 0); ++ } else { ++ or(size, dst, zr, src); ++ } ++ } ++ ++ /** ++ * Generates a 64-bit immediate move code sequence. ++ * ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param imm ++ */ ++ private void mov64(Register dst, long imm) { ++ // We have to move all non zero parts of the immediate in 16-bit chunks ++ boolean firstMove = true; ++ for (int offset = 0; offset < 64; offset += 16) { ++ int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16); ++ if (chunk == 0) { ++ continue; ++ } ++ if (firstMove) { ++ movz(64, dst, chunk, offset); ++ firstMove = false; ++ } else { ++ movk(64, dst, chunk, offset); ++ } ++ } ++ assert !firstMove; ++ } ++ ++ /** ++ * Loads immediate into register. ++ * ++ * @param dst general purpose register. May not be null, zero-register or stackpointer. ++ * @param imm immediate loaded into register. ++ */ ++ public void mov(Register dst, long imm) { ++ assert dst.getRegisterCategory().equals(CPU); ++ if (imm == 0L) { ++ movx(dst, zr); ++ } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) { ++ or(64, dst, zr, imm); ++ } else if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) { ++ // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can ++ // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and ++ // then sign extend ++ // them. This allows us to cover immediates like ~1L with 2 instructions. ++ mov(dst, (int) imm); ++ sxt(64, 32, dst, dst); ++ } else { ++ mov64(dst, imm); ++ } ++ } ++ ++ /** ++ * Loads immediate into register. ++ * ++ * @param dst general purpose register. May not be null, zero-register or stackpointer. ++ * @param imm immediate loaded into register. ++ */ ++ public void mov(Register dst, int imm) { ++ mov(dst, imm & 0xFFFF_FFFFL); ++ } ++ ++ /** ++ * Generates a 48-bit immediate move code sequence. The immediate may later be updated by ++ * HotSpot. ++ * ++ * In SW64 mode the virtual address space is 48-bits in size, so we only need three ++ * instructions to create a patchable instruction sequence that can reach anywhere. ++ * ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param imm ++ */ ++ public void movNativeAddress(Register dst, long imm) { ++ assert (imm & 0xFFFF_0000_0000_0000L) == 0; ++ // We have to move all non zero parts of the immediate in 16-bit chunks ++ boolean firstMove = true; ++ for (int offset = 0; offset < 48; offset += 16) { ++ int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16); ++ if (firstMove) { ++ movz(64, dst, chunk, offset); ++ firstMove = false; ++ } else { ++ movk(64, dst, chunk, offset); ++ } ++ } ++ assert !firstMove; ++ } ++ ++ /** ++ * Generates a 32-bit immediate move code sequence. The immediate may later be updated by ++ * HotSpot. ++ * ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param imm ++ */ ++ public void movNarrowAddress(Register dst, long imm) { ++ assert (imm & 0xFFFF_FFFF_0000_0000L) == 0; ++ movz(64, dst, (int) (imm >>> 16), 16); ++ movk(64, dst, (int) (imm & 0xffff), 0); ++ } ++ ++ /** ++ * @return Number of instructions necessary to load immediate into register. ++ */ ++ public static int nrInstructionsToMoveImmediate(long imm) { ++ if (imm == 0L || LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) { ++ return 1; ++ } ++ if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) { ++ // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can ++ // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and ++ // then sign extend ++ // them. This allows us to cover immediates like ~1L with 2 instructions. ++ return 2; ++ } ++ int nrInstructions = 0; ++ for (int offset = 0; offset < 64; offset += 16) { ++ int part = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16); ++ if (part != 0) { ++ nrInstructions++; ++ } ++ } ++ return nrInstructions; ++ } ++ ++ /** ++ * Loads a srcSize value from address into rt sign-extending it if necessary. ++ * ++ * @param targetSize size of target register in bits. Must be 32 or 64. ++ * @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to ++ * targetSize. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ @Override ++ public void ldrs(int targetSize, int srcSize, Register rt, SW64Address address) { ++ assert targetSize == 32 || targetSize == 64; ++ assert srcSize <= targetSize; ++ if (targetSize == srcSize) { ++ super.ldr(srcSize, rt, address); ++ } else { ++ super.ldrs(targetSize, srcSize, rt, address); ++ } ++ } ++ ++ /** ++ * Loads a srcSize value from address into rt zero-extending it if necessary. ++ * ++ * @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to ++ * targetSize. ++ * @param rt general purpose register. May not be null or stackpointer. ++ * @param address all addressing modes allowed. May not be null. ++ */ ++ @Override ++ public void ldr(int srcSize, Register rt, SW64Address address) { ++ super.ldr(srcSize, rt, address); ++ } ++ ++ /** ++ * Conditional move. dst = src1 if condition else src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param result general purpose register. May not be null or the stackpointer. ++ * @param trueValue general purpose register. May not be null or the stackpointer. ++ * @param falseValue general purpose register. May not be null or the stackpointer. ++ * @param cond any condition flag. May not be null. ++ */ ++ public void cmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag cond) { ++ super.csel(size, result, trueValue, falseValue, cond); ++ } ++ ++ /** ++ * Conditional set. dst = 1 if condition else 0. ++ * ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param condition any condition. May not be null. ++ */ ++ public void cset(Register dst, ConditionFlag condition) { ++ super.csinc(32, dst, zr, zr, condition.negate()); ++ } ++ ++ /** ++ * dst = src1 + src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null. ++ * @param src1 general purpose register. May not be null. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void add(int size, Register dst, Register src1, Register src2) { ++ if (dst.equals(sp) || src1.equals(sp)) { ++ super.add(size, dst, src1, src2, ExtendType.UXTX, 0); ++ } else { ++ super.add(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ } ++ ++ /** ++ * dst = src1 + src2 and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null. ++ * @param src1 general purpose register. May not be null. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void adds(int size, Register dst, Register src1, Register src2) { ++ if (dst.equals(sp) || src1.equals(sp)) { ++ super.adds(size, dst, src1, src2, ExtendType.UXTX, 0); ++ } else { ++ super.adds(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ } ++ ++ /** ++ * dst = src1 - src2 and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null. ++ * @param src1 general purpose register. May not be null. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void subs(int size, Register dst, Register src1, Register src2) { ++ if (dst.equals(sp) || src1.equals(sp)) { ++ super.subs(size, dst, src1, src2, ExtendType.UXTX, 0); ++ } else { ++ super.subs(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ } ++ ++ /** ++ * dst = src1 - src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null. ++ * @param src1 general purpose register. May not be null. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void sub(int size, Register dst, Register src1, Register src2) { ++ if (dst.equals(sp) || src1.equals(sp)) { ++ super.sub(size, dst, src1, src2, ExtendType.UXTX, 0); ++ } else { ++ super.sub(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ } ++ ++ /** ++ * dst = src1 + shiftType(src2, shiftAmt & (size - 1)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType any type but ROR. ++ * @param shiftAmt arbitrary shift amount. ++ */ ++ @Override ++ public void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ int shift = clampShiftAmt(size, shiftAmt); ++ super.add(size, dst, src1, src2, shiftType, shift); ++ } ++ ++ /** ++ * dst = src1 + shiftType(src2, shiftAmt & (size-1)) and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ * @param shiftType any type but ROR. ++ * @param shiftAmt arbitrary shift amount. ++ */ ++ @Override ++ public void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ int shift = clampShiftAmt(size, shiftAmt); ++ super.sub(size, dst, src1, src2, shiftType, shift); ++ } ++ ++ /** ++ * dst = -src1. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or stackpointer. ++ */ ++ public void neg(int size, Register dst, Register src) { ++ sub(size, dst, zr, src); ++ } ++ ++ /** ++ * dst = src + immediate. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param immediate 32-bit signed int ++ */ ++ @Override ++ public void add(int size, Register dst, Register src, int immediate) { ++ assert (!dst.equals(zr) && !src.equals(zr)); ++ if (immediate < 0) { ++ sub(size, dst, src, -immediate); ++ } else if (isAimm(immediate)) { ++ if (!(dst.equals(src) && immediate == 0)) { ++ super.add(size, dst, src, immediate); ++ } ++ } else if (immediate >= -(1 << 24) && immediate < (1 << 24)) { ++ super.add(size, dst, src, immediate & -(1 << 12)); ++ super.add(size, dst, dst, immediate & ((1 << 12) - 1)); ++ } else { ++ assert !dst.equals(src); ++ mov(dst, immediate); ++ add(size, src, dst, dst); ++ } ++ } ++ ++ /** ++ * dst = src + immediate. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param immediate 64-bit signed int ++ */ ++ public void add(int size, Register dst, Register src, long immediate) { ++ if (NumUtil.isInt(immediate)) { ++ add(size, dst, src, (int) immediate); ++ } else { ++ assert (!dst.equals(zr) && !src.equals(zr)); ++ assert !dst.equals(src); ++ assert size == 64; ++ mov(dst, immediate); ++ add(size, src, dst, dst); ++ } ++ } ++ ++ /** ++ * dst = src + aimm and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param immediate arithmetic immediate. ++ */ ++ @Override ++ public void adds(int size, Register dst, Register src, int immediate) { ++ assert (!dst.equals(sp) && !src.equals(zr)); ++ if (immediate < 0) { ++ subs(size, dst, src, -immediate); ++ } else if (!(dst.equals(src) && immediate == 0)) { ++ super.adds(size, dst, src, immediate); ++ } ++ } ++ ++ /** ++ * dst = src - immediate. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param immediate 32-bit signed int ++ */ ++ @Override ++ public void sub(int size, Register dst, Register src, int immediate) { ++ assert (!dst.equals(zr) && !src.equals(zr)); ++ if (immediate < 0) { ++ add(size, dst, src, -immediate); ++ } else if (isAimm(immediate)) { ++ if (!(dst.equals(src) && immediate == 0)) { ++ super.sub(size, dst, src, immediate); ++ } ++ } else if (immediate >= -(1 << 24) && immediate < (1 << 24)) { ++ super.sub(size, dst, src, immediate & -(1 << 12)); ++ super.sub(size, dst, dst, immediate & ((1 << 12) - 1)); ++ } else { ++ assert !dst.equals(src); ++ mov(dst, immediate); ++ sub(size, src, dst, dst); ++ } ++ } ++ ++ /** ++ * dst = src - aimm and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or zero-register. ++ * @param immediate arithmetic immediate. ++ */ ++ @Override ++ public void subs(int size, Register dst, Register src, int immediate) { ++ assert (!dst.equals(sp) && !src.equals(zr)); ++ if (immediate < 0) { ++ adds(size, dst, src, -immediate); ++ } else if (!dst.equals(src) || immediate != 0) { ++ super.subs(size, dst, src, immediate); ++ } ++ } ++ ++ /** ++ * dst = src1 * src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ public void mul(int size, Register dst, Register src1, Register src2) { ++ super.madd(size, dst, src1, src2, zr); ++ } ++ ++ /** ++ * unsigned multiply high. dst = (src1 * src2) >> size ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ public void umulh(int size, Register dst, Register src1, Register src2) { ++ assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp)); ++ assert size == 32 || size == 64; ++ if (size == 64) { ++ super.umulh(dst, src1, src2); ++ } else { ++ // xDst = wSrc1 * wSrc2 ++ super.umaddl(dst, src1, src2, zr); ++ // xDst = xDst >> 32 ++ lshr(64, dst, dst, 32); ++ } ++ } ++ ++ /** ++ * signed multiply high. dst = (src1 * src2) >> size ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src1 general purpose register. May not be null or the stackpointer. ++ * @param src2 general purpose register. May not be null or the stackpointer. ++ */ ++ public void smulh(int size, Register dst, Register src1, Register src2) { ++ assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp)); ++ assert size == 32 || size == 64; ++ if (size == 64) { ++ super.smulh(dst, src1, src2); ++ } else { ++ // xDst = wSrc1 * wSrc2 ++ super.smaddl(dst, src1, src2, zr); ++ // xDst = xDst >> 32 ++ lshr(64, dst, dst, 32); ++ } ++ } ++ ++ /** ++ * dst = src1 % src2. Signed. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param n numerator. General purpose register. May not be null or the stackpointer. ++ * @param d denominator. General purpose register. Divisor May not be null or the stackpointer. ++ */ ++ public void rem(int size, Register dst, Register n, Register d) { ++ assert (!dst.equals(sp) && !n.equals(sp) && !d.equals(sp)); ++ // There is no irem or similar instruction. Instead we use the relation: ++ // n % d = n - Floor(n / d) * d if nd >= 0 ++ // n % d = n - Ceil(n / d) * d else ++ // Which is equivalent to n - TruncatingDivision(n, d) * d ++ super.sdiv(size, dst, n, d); ++ super.msub(size, dst, dst, d, n); ++ } ++ ++ /** ++ * dst = src1 % src2. Unsigned. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param n numerator. General purpose register. May not be null or the stackpointer. ++ * @param d denominator. General purpose register. Divisor May not be null or the stackpointer. ++ */ ++ public void urem(int size, Register dst, Register n, Register d) { ++ // There is no irem or similar instruction. Instead we use the relation: ++ // n % d = n - Floor(n / d) * d ++ // Which is equivalent to n - TruncatingDivision(n, d) * d ++ super.udiv(size, dst, n, d); ++ super.msub(size, dst, dst, d, n); ++ } ++ ++ /** ++ * Add/subtract instruction encoding supports 12-bit immediate values. ++ * ++ * @param imm immediate value to be tested. ++ * @return true if immediate can be used directly for arithmetic instructions (add/sub), false ++ * otherwise. ++ */ ++ public static boolean isArithmeticImmediate(long imm) { ++ // If we have a negative immediate we just use the opposite operator. I.e.: x - (-5) == x + ++ // 5. ++ return NumUtil.isInt(Math.abs(imm)) && isAimm((int) Math.abs(imm)); ++ } ++ ++ /** ++ * Compare instructions are add/subtract instructions and so support 12-bit immediate values. ++ * ++ * @param imm immediate value to be tested. ++ * @return true if immediate can be used directly with comparison instructions, false otherwise. ++ */ ++ public static boolean isComparisonImmediate(long imm) { ++ return isArithmeticImmediate(imm); ++ } ++ ++ /** ++ * Move wide immediate instruction encoding supports 16-bit immediate values which can be ++ * optionally-shifted by multiples of 16 (i.e. 0, 16, 32, 48). ++ * ++ * @return true if immediate can be moved directly into a register, false otherwise. ++ */ ++ public static boolean isMovableImmediate(long imm) { ++ // // Positions of first, respectively last set bit. ++ // int start = Long.numberOfTrailingZeros(imm); ++ // int end = 64 - Long.numberOfLeadingZeros(imm); ++ // int length = end - start; ++ // if (length > 16) { ++ // return false; ++ // } ++ // // We can shift the necessary part of the immediate (i.e. everything between the first ++ // and ++ // // last set bit) by as much as 16 - length around to arrive at a valid shift amount ++ // int tolerance = 16 - length; ++ // int prevMultiple = NumUtil.roundDown(start, 16); ++ // int nextMultiple = NumUtil.roundUp(start, 16); ++ // return start - prevMultiple <= tolerance || nextMultiple - start <= tolerance; ++ /* ++ * This is a bit optimistic because the constant could also be for an arithmetic instruction ++ * which only supports 12-bits. That case needs to be handled in the backend. ++ */ ++ return NumUtil.isInt(Math.abs(imm)) && NumUtil.isUnsignedNbit(16, (int) Math.abs(imm)); ++ } ++ ++ /** ++ * dst = src << (shiftAmt & (size - 1)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ * @param shiftAmt amount by which src is shifted. ++ */ ++ public void shl(int size, Register dst, Register src, long shiftAmt) { ++ int shift = clampShiftAmt(size, shiftAmt); ++ super.ubfm(size, dst, src, (size - shift) & (size - 1), size - 1 - shift); ++ } ++ ++ /** ++ * dst = src1 << (src2 & (size - 1)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or stackpointer. ++ * @param shift general purpose register. May not be null or stackpointer. ++ */ ++ public void shl(int size, Register dst, Register src, Register shift) { ++ super.lsl(size, dst, src, shift); ++ } ++ ++ /** ++ * dst = src >>> (shiftAmt & (size - 1)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ * @param shiftAmt amount by which src is shifted. ++ */ ++ public void lshr(int size, Register dst, Register src, long shiftAmt) { ++ int shift = clampShiftAmt(size, shiftAmt); ++ super.ubfm(size, dst, src, shift, size - 1); ++ } ++ ++ /** ++ * dst = src1 >>> (src2 & (size - 1)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or stackpointer. ++ * @param shift general purpose register. May not be null or stackpointer. ++ */ ++ public void lshr(int size, Register dst, Register src, Register shift) { ++ super.lsr(size, dst, src, shift); ++ } ++ ++ /** ++ * dst = src >> (shiftAmt & log2(size)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ * @param shiftAmt amount by which src is shifted. ++ */ ++ public void ashr(int size, Register dst, Register src, long shiftAmt) { ++ int shift = clampShiftAmt(size, shiftAmt); ++ super.sbfm(size, dst, src, shift, size - 1); ++ } ++ ++ /** ++ * dst = src1 >> (src2 & log2(size)). ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or stackpointer. ++ * @param shift general purpose register. May not be null or stackpointer. ++ */ ++ public void ashr(int size, Register dst, Register src, Register shift) { ++ super.asr(size, dst, src, shift); ++ } ++ ++ /** ++ * Clamps shiftAmt into range 0 <= shiftamt < size according to JLS. ++ * ++ * @param size size of operation. ++ * @param shiftAmt arbitrary shift amount. ++ * @return value between 0 and size - 1 inclusive that is equivalent to shiftAmt according to ++ * JLS. ++ */ ++ private static int clampShiftAmt(int size, long shiftAmt) { ++ return (int) (shiftAmt & (size - 1)); ++ } ++ ++ /** ++ * dst = src1 & src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void and(int size, Register dst, Register src1, Register src2) { ++ super.and(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ ++ /** ++ * dst = src1 ^ src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void eor(int size, Register dst, Register src1, Register src2) { ++ super.eor(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ ++ /** ++ * dst = src1 | src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src1 general purpose register. May not be null or stackpointer. ++ * @param src2 general purpose register. May not be null or stackpointer. ++ */ ++ public void or(int size, Register dst, Register src1, Register src2) { ++ super.orr(size, dst, src1, src2, ShiftType.LSL, 0); ++ } ++ ++ /** ++ * dst = src | bimm. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or zero-register. ++ * @param src general purpose register. May not be null or stack-pointer. ++ * @param bimm logical immediate. See {@link SW64Assembler.LogicalImmediateTable} for exact ++ * definition. ++ */ ++ public void or(int size, Register dst, Register src, long bimm) { ++ super.orr(size, dst, src, bimm); ++ } ++ ++ /** ++ * dst = ~src. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stackpointer. ++ * @param src general purpose register. May not be null or stackpointer. ++ */ ++ public void not(int size, Register dst, Register src) { ++ super.orn(size, dst, zr, src, ShiftType.LSL, 0); ++ } ++ ++ /** ++ * Sign-extend value from src into dst. ++ * ++ * @param destSize destination register size. Must be 32 or 64. ++ * @param srcSize source register size. Must be smaller than destSize. ++ * @param dst general purpose register. May not be null, stackpointer or zero-register. ++ * @param src general purpose register. May not be null, stackpointer or zero-register. ++ */ ++ public void sxt(int destSize, int srcSize, Register dst, Register src) { ++ assert (srcSize < destSize && srcSize > 0); ++ super.sbfm(destSize, dst, src, 0, srcSize - 1); ++ } ++ ++ /** ++ * dst = src if condition else -src. ++ * ++ * @param size register size. Must be 32 or 64. ++ * @param dst general purpose register. May not be null or the stackpointer. ++ * @param src general purpose register. May not be null or the stackpointer. ++ * @param condition any condition except AV or NV. May not be null. ++ */ ++ public void csneg(int size, Register dst, Register src, ConditionFlag condition) { ++ super.csneg(size, dst, src, src, condition.negate()); ++ } ++ ++ /** ++ * @return True if the immediate can be used directly for logical 64-bit instructions. ++ */ ++ public static boolean isLogicalImmediate(long imm) { ++ return LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO; ++ } ++ ++ /** ++ * @return True if the immediate can be used directly for logical 32-bit instructions. ++ */ ++ public static boolean isLogicalImmediate(int imm) { ++ return LogicalImmediateTable.isRepresentable(imm) == LogicalImmediateTable.Representable.YES; ++ } ++ ++ /* Float instructions */ ++ ++ /** ++ * Moves integer to float, float to integer, or float to float. Does not support integer to ++ * integer moves. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst Either floating-point or general-purpose register. If general-purpose register may ++ * not be stackpointer or zero register. Cannot be null in any case. ++ * @param src Either floating-point or general-purpose register. If general-purpose register may ++ * not be stackpointer. Cannot be null in any case. ++ */ ++ @Override ++ public void fmov(int size, Register dst, Register src) { ++ assert !(dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)) : "src and dst cannot both be integer registers."; ++ if (dst.getRegisterCategory().equals(CPU)) { ++ super.fmovFpu2Cpu(size, dst, src); ++ } else if (src.getRegisterCategory().equals(CPU)) { ++ super.fmovCpu2Fpu(size, dst, src); ++ } else { ++ super.fmov(size, dst, src); ++ } ++ } ++ ++ /** ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst floating point register. May not be null. ++ * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be ++ * loaded, i.e. (float) imm == imm must be true. In all cases ++ * {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true ++ * depending on size. ++ */ ++ @Override ++ public void fmov(int size, Register dst, double imm) { ++ if (imm == 0.0) { ++ assert Double.doubleToRawLongBits(imm) == 0L : "-0.0 is no valid immediate."; ++ super.fmovCpu2Fpu(size, dst, zr); ++ } else { ++ super.fmov(size, dst, imm); ++ } ++ } ++ ++ /** ++ * ++ * @return true if immediate can be loaded directly into floating-point register, false ++ * otherwise. ++ */ ++ public static boolean isDoubleImmediate(double imm) { ++ return Double.doubleToRawLongBits(imm) == 0L || SW64Assembler.isDoubleImmediate(imm); ++ } ++ ++ /** ++ * ++ * @return true if immediate can be loaded directly into floating-point register, false ++ * otherwise. ++ */ ++ public static boolean isFloatImmediate(float imm) { ++ return Float.floatToRawIntBits(imm) == 0 || SW64Assembler.isFloatImmediate(imm); ++ } ++ ++ /** ++ * Conditional move. dst = src1 if condition else src2. ++ * ++ * @param size register size. ++ * @param result floating point register. May not be null. ++ * @param trueValue floating point register. May not be null. ++ * @param falseValue floating point register. May not be null. ++ * @param condition every condition allowed. May not be null. ++ */ ++ public void fcmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag condition) { ++ super.fcsel(size, result, trueValue, falseValue, condition); ++ } ++ ++ /** ++ * dst = src1 % src2. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst floating-point register. May not be null. ++ * @param n numerator. Floating-point register. May not be null. ++ * @param d denominator. Floating-point register. May not be null. ++ */ ++ public void frem(int size, Register dst, Register n, Register d) { ++ // There is no frem instruction, instead we compute the remainder using the relation: ++ // rem = n - Truncating(n / d) * d ++ super.fdiv(size, dst, n, d); ++ super.frintz(size, dst, dst); ++ super.fmsub(size, dst, dst, d, n); ++ } ++ ++ /* Branches */ ++ ++ /** ++ * Compares x and y and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param x general purpose register. May not be null or stackpointer. ++ * @param y general purpose register. May not be null or stackpointer. ++ */ ++ public void cmp(int size, Register x, Register y) { ++ assert size == 32 || size == 64; ++ super.subs(size, zr, x, y, ShiftType.LSL, 0); ++ } ++ ++ /** ++ * Compares x to y and sets condition flags. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param x general purpose register. May not be null or stackpointer. ++ * @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it. ++ */ ++ public void cmp(int size, Register x, int y) { ++ assert size == 32 || size == 64; ++ if (y < 0) { ++ super.adds(size, zr, x, -y); ++ } else { ++ super.subs(size, zr, x, y); ++ } ++ } ++ ++ /** ++ * Sets condition flags according to result of x & y. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stack-pointer. ++ * @param x general purpose register. May not be null or stackpointer. ++ * @param y general purpose register. May not be null or stackpointer. ++ */ ++ public void ands(int size, Register dst, Register x, Register y) { ++ super.ands(size, dst, x, y, ShiftType.LSL, 0); ++ } ++ ++ /** ++ * Sets overflow flag according to result of x * y. ++ * ++ * @param size register size. Has to be 32 or 64. ++ * @param dst general purpose register. May not be null or stack-pointer. ++ * @param x general purpose register. May not be null or stackpointer. ++ * @param y general purpose register. May not be null or stackpointer. ++ */ ++ public void mulvs(int size, Register dst, Register x, Register y) { ++ try (ScratchRegister sc1 = getScratchRegister(); ++ ScratchRegister sc2 = getScratchRegister()) { ++ switch (size) { ++ case 64: { ++ // Be careful with registers: it's possible that x, y, and dst are the same ++ // register. ++ Register rscratch1 = sc1.getRegister(); ++ Register rscratch2 = sc2.getRegister(); ++ mul(64, rscratch1, x, y); // Result bits 0..63 ++ smulh(64, rscratch2, x, y); // Result bits 64..127 ++ // Top is pure sign ext ++ subs(64, zr, rscratch2, rscratch1, ShiftType.ASR, 63); ++ // Copy all 64 bits of the result into dst ++ mov(64, dst, rscratch1); ++ mov(rscratch1, 0x80000000); ++ // Develop 0 (EQ), or 0x80000000 (NE) ++ cmov(32, rscratch1, rscratch1, zr, ConditionFlag.NE); ++ cmp(32, rscratch1, 1); ++ // 0x80000000 - 1 => VS ++ break; ++ } ++ case 32: { ++ Register rscratch1 = sc1.getRegister(); ++ smaddl(rscratch1, x, y, zr); ++ // Copy the low 32 bits of the result into dst ++ mov(32, dst, rscratch1); ++ subs(64, zr, rscratch1, rscratch1, ExtendType.SXTW, 0); ++ // NE => overflow ++ mov(rscratch1, 0x80000000); ++ // Develop 0 (EQ), or 0x80000000 (NE) ++ cmov(32, rscratch1, rscratch1, zr, ConditionFlag.NE); ++ cmp(32, rscratch1, 1); ++ // 0x80000000 - 1 => VS ++ break; ++ } ++ } ++ } ++ } ++ ++ /** ++ * When patching up Labels we have to know what kind of code to generate. ++ */ ++ public enum PatchLabelKind { ++ BRANCH_CONDITIONALLY(0x0), ++ BRANCH_UNCONDITIONALLY(0x1), ++ BRANCH_NONZERO(0x2), ++ BRANCH_ZERO(0x3), ++ BRANCH_BIT_NONZERO(0x4), ++ BRANCH_BIT_ZERO(0x5), ++ JUMP_ADDRESS(0x6), ++ ADR(0x7); ++ ++ /** ++ * Offset by which additional information for branch conditionally, branch zero and branch ++ * non zero has to be shifted. ++ */ ++ public static final int INFORMATION_OFFSET = 5; ++ ++ public final int encoding; ++ ++ PatchLabelKind(int encoding) { ++ this.encoding = encoding; ++ } ++ ++ /** ++ * @return PatchLabelKind with given encoding. ++ */ ++ private static PatchLabelKind fromEncoding(int encoding) { ++ return values()[encoding & NumUtil.getNbitNumberInt(INFORMATION_OFFSET)]; ++ } ++ ++ } ++ ++ public void adr(Register dst, Label label) { ++ // TODO Handle case where offset is too large for a single jump instruction ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.adr(dst, offset); ++ } else { ++ label.addPatchAt(position()); ++ // Encode condition flag so that we know how to patch the instruction later ++ emitInt(PatchLabelKind.ADR.encoding | dst.encoding << PatchLabelKind.INFORMATION_OFFSET); ++ } ++ } ++ ++ /** ++ * Compare register and branch if non-zero. ++ * ++ * @param size Instruction size in bits. Should be either 32 or 64. ++ * @param cmp general purpose register. May not be null, zero-register or stackpointer. ++ * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. ++ */ ++ public void cbnz(int size, Register cmp, Label label) { ++ // TODO Handle case where offset is too large for a single jump instruction ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.cbnz(size, cmp, offset); ++ } else { ++ label.addPatchAt(position()); ++ int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1); ++ int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET; ++ // Encode condition flag so that we know how to patch the instruction later ++ emitInt(PatchLabelKind.BRANCH_NONZERO.encoding | regEncoding | sizeEncoding); ++ } ++ } ++ ++ /** ++ * Compare register and branch if zero. ++ * ++ * @param size Instruction size in bits. Should be either 32 or 64. ++ * @param cmp general purpose register. May not be null, zero-register or stackpointer. ++ * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. ++ */ ++ public void cbz(int size, Register cmp, Label label) { ++ // TODO Handle case where offset is too large for a single jump instruction ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.cbz(size, cmp, offset); ++ } else { ++ label.addPatchAt(position()); ++ int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1); ++ int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET; ++ // Encode condition flag so that we know how to patch the instruction later ++ emitInt(PatchLabelKind.BRANCH_ZERO.encoding | regEncoding | sizeEncoding); ++ } ++ } ++ ++ /** ++ * Test a single bit and branch if the bit is nonzero. ++ * ++ * @param cmp general purpose register. May not be null, zero-register or stackpointer. ++ * @param uimm6 Unsigned 6-bit bit index. ++ * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. ++ */ ++ public void tbnz(Register cmp, int uimm6, Label label) { ++ assert NumUtil.isUnsignedNbit(6, uimm6); ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.tbnz(cmp, uimm6, offset); ++ } else { ++ label.addPatchAt(position()); ++ int indexEncoding = uimm6 << PatchLabelKind.INFORMATION_OFFSET; ++ int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 6); ++ emitInt(PatchLabelKind.BRANCH_BIT_NONZERO.encoding | indexEncoding | regEncoding); ++ } ++ } ++ ++ /** ++ * Test a single bit and branch if the bit is zero. ++ * ++ * @param cmp general purpose register. May not be null, zero-register or stackpointer. ++ * @param uimm6 Unsigned 6-bit bit index. ++ * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. ++ */ ++ public void tbz(Register cmp, int uimm6, Label label) { ++ assert NumUtil.isUnsignedNbit(6, uimm6); ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.tbz(cmp, uimm6, offset); ++ } else { ++ label.addPatchAt(position()); ++ int indexEncoding = uimm6 << PatchLabelKind.INFORMATION_OFFSET; ++ int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 6); ++ emitInt(PatchLabelKind.BRANCH_BIT_ZERO.encoding | indexEncoding | regEncoding); ++ } ++ } ++ ++ /** ++ * Branches to label if condition is true. ++ * ++ * @param condition any condition value allowed. Non null. ++ * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. ++ */ ++ public void branchConditionally(ConditionFlag condition, Label label) { ++ // TODO Handle case where offset is too large for a single jump instruction ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.b(condition, offset); ++ } else { ++ label.addPatchAt(position()); ++ // Encode condition flag so that we know how to patch the instruction later ++ emitInt(PatchLabelKind.BRANCH_CONDITIONALLY.encoding | condition.encoding << PatchLabelKind.INFORMATION_OFFSET); ++ } ++ } ++ ++ /** ++ * Branches if condition is true. Address of jump is patched up by HotSpot c++ code. ++ * ++ * @param condition any condition value allowed. Non null. ++ */ ++ public void branchConditionally(ConditionFlag condition) { ++ // Correct offset is fixed up by HotSpot later. ++ super.b(condition, 0); ++ } ++ ++ /** ++ * Jumps to label. ++ * ++ * param label Can only handle signed 28-bit offsets. May be unbound. Non null. ++ */ ++ @Override ++ public void jmp(Label label) { ++ // TODO Handle case where offset is too large for a single jump instruction ++ if (label.isBound()) { ++ int offset = label.position() - position(); ++ super.b(offset); ++ } else { ++ label.addPatchAt(position()); ++ emitInt(PatchLabelKind.BRANCH_UNCONDITIONALLY.encoding); ++ } ++ } ++ ++ /** ++ * Jump to address in dest. ++ * ++ * @param dest General purpose register. May not be null, zero-register or stackpointer. ++ */ ++ public void jmp(Register dest) { ++ super.br(dest); ++ } ++ ++ /** ++ * Immediate jump instruction fixed up by HotSpot c++ code. ++ */ ++ public void jmp() { ++ // Offset has to be fixed up by c++ code. ++ super.b(0); ++ } ++ ++ /** ++ * ++ * @return true if immediate offset can be used in a single branch instruction. ++ */ ++ public static boolean isBranchImmediateOffset(long imm) { ++ return NumUtil.isSignedNbit(28, imm); ++ } ++ ++ /* system instructions */ ++ ++ /** ++ * Exception codes used when calling hlt instruction. ++ */ ++ public enum SW64ExceptionCode { ++ NO_SWITCH_TARGET(0x0), ++ BREAKPOINT(0x1); ++ ++ public final int encoding; ++ ++ SW64ExceptionCode(int encoding) { ++ this.encoding = encoding; ++ } ++ } ++ ++ /** ++ * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as ++ * UNALLOCATED instruction. ++ * ++ * @param exceptionCode exception code specifying why halt was called. Non null. ++ */ ++ public void hlt(SW64ExceptionCode exceptionCode) { ++ super.hlt(exceptionCode.encoding); ++ } ++ ++ /** ++ * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher ++ * exception level. ++ * ++ * @param exceptionCode exception code specifying why break was called. Non null. ++ */ ++ public void brk(SW64ExceptionCode exceptionCode) { ++ super.brk(exceptionCode.encoding); ++ } ++ ++ public void pause() { ++ throw GraalError.unimplemented(); ++ } ++ ++ /** ++ * Executes no-op instruction. No registers or flags are updated, except for PC. ++ */ ++ public void nop() { ++ super.hint(SystemHint.NOP); ++ } ++ ++ /** ++ * Same as {@link #nop()}. ++ */ ++ @Override ++ public void ensureUniquePC() { ++ nop(); ++ } ++ ++ /** ++ * Aligns PC. ++ * ++ * @param modulus Has to be positive multiple of 4. ++ */ ++ @Override ++ public void align(int modulus) { ++ assert modulus > 0 && (modulus & 0x3) == 0 : "Modulus has to be a positive multiple of 4."; ++ if (position() % modulus == 0) { ++ return; ++ } ++ int offset = modulus - position() % modulus; ++ for (int i = 0; i < offset; i += 4) { ++ nop(); ++ } ++ } ++ ++ /** ++ * Patches jump targets when label gets bound. ++ */ ++ @Override ++ protected void patchJumpTarget(int branch, int jumpTarget) { ++ int instruction = getInt(branch); ++ int branchOffset = jumpTarget - branch; ++ PatchLabelKind type = PatchLabelKind.fromEncoding(instruction); ++ switch (type) { ++ case BRANCH_CONDITIONALLY: ++ ConditionFlag cf = ConditionFlag.fromEncoding(instruction >>> PatchLabelKind.INFORMATION_OFFSET); ++ super.b(cf, branchOffset, branch); ++ break; ++ case BRANCH_UNCONDITIONALLY: ++ super.b(branchOffset, branch); ++ break; ++ case JUMP_ADDRESS: ++ int offset = instruction >>> PatchLabelKind.INFORMATION_OFFSET; ++ emitInt(jumpTarget - offset, branch); ++ break; ++ case BRANCH_NONZERO: ++ case BRANCH_ZERO: { ++ int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET; ++ int sizeEncoding = information & 1; ++ int regEncoding = information >>> 1; ++ Register reg = SW64.cpuRegisters.get(regEncoding); ++ // 1 => 64; 0 => 32 ++ int size = sizeEncoding * 32 + 32; ++ switch (type) { ++ case BRANCH_NONZERO: ++ super.cbnz(size, reg, branchOffset, branch); ++ break; ++ case BRANCH_ZERO: ++ super.cbz(size, reg, branchOffset, branch); ++ break; ++ } ++ break; ++ } ++ case BRANCH_BIT_NONZERO: ++ case BRANCH_BIT_ZERO: { ++ int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET; ++ int sizeEncoding = information & NumUtil.getNbitNumberInt(6); ++ int regEncoding = information >>> 6; ++ Register reg = SW64.cpuRegisters.get(regEncoding); ++ switch (type) { ++ case BRANCH_BIT_NONZERO: ++ super.tbnz(reg, sizeEncoding, branchOffset, branch); ++ break; ++ case BRANCH_BIT_ZERO: ++ super.tbz(reg, sizeEncoding, branchOffset, branch); ++ break; ++ } ++ break; ++ } ++ case ADR: { ++ int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET; ++ int regEncoding = information; ++ Register reg = SW64.cpuRegisters.get(regEncoding); ++ super.adr(reg, branchOffset, branch); ++ break; ++ } ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ /** ++ * Generates an address of the form {@code base + displacement}. ++ * ++ * Does not change base register to fulfill this requirement. Will fail if displacement cannot ++ * be represented directly as address. ++ * ++ * @param base general purpose register. May not be null or the zero register. ++ * @param displacement arbitrary displacement added to base. ++ * @return SW64Address referencing memory at {@code base + displacement}. ++ */ ++ @Override ++ public SW64Address makeAddress(Register base, int displacement) { ++ return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, zr, /* allowOverwrite */false); ++ } ++ ++ @Override ++ public SW64Address getPlaceholder(int instructionStartPosition) { ++ return SW64Address.PLACEHOLDER; ++ } ++ ++ public void addressOf(Register dst) { ++ // This will be fixed up later. ++ super.adrp(dst); ++ super.add(64, dst, dst, 0); ++ } ++ ++ /** ++ * Loads an address into Register d. ++ * ++ * @param d general purpose register. May not be null. ++ * @param a SW64Address the address of an operand. ++ */ ++ public void lea(Register d, SW64Address a) { ++ a.lea(this, d); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/SW64MacroAssemblerTest.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/SW64MacroAssemblerTest.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/SW64MacroAssemblerTest.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/SW64MacroAssemblerTest.java 2025-05-09 10:05:57.748290597 +0800 +@@ -0,0 +1,286 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.asm.sw64.test; ++ ++import static org.junit.Assert.assertArrayEquals; ++ ++import java.util.EnumSet; ++ ++import org.junit.Assert; ++import org.junit.Before; ++import org.junit.Test; ++ ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.AddressGenerationPlan; ++import org.graalvm.compiler.test.GraalTest; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.sw64.SW64.CPUFeature; ++import jdk.vm.ci.code.Architecture; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.TargetDescription; ++ ++public class SW64MacroAssemblerTest extends GraalTest { ++ ++ private SW64MacroAssembler masm; ++ private TestProtectedAssembler asm; ++ private Register base; ++ private Register index; ++ private Register scratch; ++ ++ private static EnumSet computeFeatures() { ++ EnumSet features = EnumSet.noneOf(SW64.CPUFeature.class); ++ features.add(CPUFeature.FP); ++ return features; ++ } ++ ++ private static EnumSet computeFlags() { ++ EnumSet flags = EnumSet.noneOf(SW64.Flag.class); ++ return flags; ++ } ++ ++ private static TargetDescription createTarget() { ++ final int stackFrameAlignment = 16; ++ final int implicitNullCheckLimit = 4096; ++ final boolean inlineObjects = true; ++ Architecture arch = new SW64(computeFeatures(), computeFlags()); ++ return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); ++ } ++ ++ @Before ++ public void setupEnvironment() { ++ TargetDescription target = createTarget(); ++ masm = new SW64MacroAssembler(target); ++ asm = new TestProtectedAssembler(target); ++ base = SW64.r10; ++ index = SW64.r13; ++ scratch = SW64.r15; ++ } ++ ++ @Test ++ public void testGenerateAddressPlan() { ++ AddressGenerationPlan plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 0); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && ++ (plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_UNSCALED)); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 1); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && ++ (plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_UNSCALED)); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(8) - 1, false, 0); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_UNSCALED); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 1); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_SCALED); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 2, false, 4); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.IMMEDIATE_SCALED); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(0, false, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(0, false, 0); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(9), false, 0); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13), false, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(12), false, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(-(NumUtil.getNbitNumberInt(12) << 12), false, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), true, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 3, true, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && !plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ ++ plan = SW64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13) << 3, true, 8); ++ Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && plan.needsScratch && plan.addressingMode == SW64Address.AddressingMode.REGISTER_OFFSET); ++ } ++ ++ @Test ++ public void testMakeAddressNoAction() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12) << 3, SW64.zr, false, 8, null, false); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.IMMEDIATE_SCALED && address.getBase().equals(base) && ++ address.getOffset().equals(SW64.zr) && address.getImmediateRaw() == NumUtil.getNbitNumberInt(12)); ++ // No code generated. ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testMakeAddressAddIndex() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, null, true); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index)); ++ asm.add(64, index, index, NumUtil.getNbitNumberInt(8) << 2); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testMakeAddressAddIndexNoOverwrite() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, scratch, false); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(scratch)); ++ asm.add(64, scratch, index, NumUtil.getNbitNumberInt(8) << 2); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testMakeAddressAddBaseNoOverwrite() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, scratch, false); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(scratch) && address.getOffset().equals(index)); ++ asm.add(64, scratch, base, NumUtil.getNbitNumberInt(12)); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testMakeAddressAddBase() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, null, true); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index)); ++ asm.add(64, base, base, NumUtil.getNbitNumberInt(12)); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testMakeAddressAddIndexNoOverwriteExtend() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, false); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) && ++ address.getOffset().equals(scratch) && address.getExtendType() == SW64Assembler.ExtendType.SXTW); ++ asm.add(32, scratch, index, NumUtil.getNbitNumberInt(8) << 2); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testMakeAddressAddIndexExtend() { ++ SW64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, true); ++ Assert.assertTrue(address.isScaled() && address.getAddressingMode() == SW64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) && ++ address.getOffset().equals(index) && address.getExtendType() == SW64Assembler.ExtendType.SXTW); ++ asm.add(32, index, index, NumUtil.getNbitNumberInt(8) << 2); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressUnscaled() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createUnscaledImmediateAddress(base, NumUtil.getNbitNumberInt(8)); ++ masm.loadAddress(dst, address, 8); ++ asm.add(64, dst, base, NumUtil.getNbitNumberInt(8)); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressUnscaled2() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createUnscaledImmediateAddress(base, -NumUtil.getNbitNumberInt(8)); ++ masm.loadAddress(dst, address, 8); ++ asm.sub(64, dst, base, NumUtil.getNbitNumberInt(8)); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressScaled() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(12)); ++ masm.loadAddress(dst, address, 8); ++ asm.add(64, dst, base, NumUtil.getNbitNumberInt(9) << 3); ++ asm.add(64, dst, dst, NumUtil.getNbitNumberInt(3) << 12); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressScaledLowerOnly() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(5)); ++ masm.loadAddress(dst, address, 8); ++ asm.add(64, dst, base, NumUtil.getNbitNumberInt(5) << 3); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressScaledHigherOnly() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createScaledImmediateAddress(base, 1 << 11); ++ masm.loadAddress(dst, address, 8); ++ asm.add(64, dst, base, 1 << 11 << 3); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressRegisterOffsetUnscaled() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createRegisterOffsetAddress(base, index, false); ++ masm.loadAddress(dst, address, 4); ++ asm.add(64, dst, base, index, SW64Assembler.ShiftType.LSL, 0); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressRegisterOffsetScaled() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createRegisterOffsetAddress(base, index, true); ++ masm.loadAddress(dst, address, 4); ++ asm.add(64, dst, base, index, SW64Assembler.ShiftType.LSL, 2); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressExtendedRegisterOffsetUnscaled() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createExtendedRegisterOffsetAddress(base, index, false, SW64Assembler.ExtendType.SXTW); ++ masm.loadAddress(dst, address, 4); ++ asm.add(64, dst, base, index, SW64Assembler.ExtendType.SXTW, 0); ++ compareAssembly(); ++ } ++ ++ @Test ++ public void testLoadAddressExtendedRegisterOffsetScaled() { ++ Register dst = SW64.r26; ++ SW64Address address = SW64Address.createExtendedRegisterOffsetAddress(base, index, true, SW64Assembler.ExtendType.SXTW); ++ masm.loadAddress(dst, address, 4); ++ asm.add(64, dst, base, index, SW64Assembler.ExtendType.SXTW, 2); ++ compareAssembly(); ++ } ++ ++ /** ++ * Compares assembly generated by the macro assembler to the hand-generated assembly. ++ */ ++ private void compareAssembly() { ++ byte[] expected = asm.close(true); ++ byte[] actual = masm.close(true); ++ assertArrayEquals(expected, actual); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/TestProtectedAssembler.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/TestProtectedAssembler.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/TestProtectedAssembler.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sw64.test/src/org/graalvm/compiler/asm/sw64/test/TestProtectedAssembler.java 2025-05-09 10:05:57.748290597 +0800 +@@ -0,0 +1,552 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.asm.sw64.test; ++ ++import org.graalvm.compiler.asm.AbstractAddress; ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.TargetDescription; ++ ++/** ++ * Cheat so that we can test protected functions of assembler. ++ */ ++class TestProtectedAssembler extends SW64Assembler { ++ ++ TestProtectedAssembler(TargetDescription target) { ++ super(target); ++ } ++ ++ @Override ++ protected void cbnz(int size, Register reg, int imm21, int pos) { ++ super.cbnz(size, reg, imm21, pos); ++ } ++ ++ @Override ++ protected void cbz(int size, Register reg, int imm21, int pos) { ++ super.cbz(size, reg, imm21, pos); ++ } ++ ++ @Override ++ public void ands(int size, Register dst, Register src, long bimm) { ++ super.ands(size, dst, src, bimm); ++ } ++ ++ @Override ++ protected void b(ConditionFlag condition, int imm21) { ++ super.b(condition, imm21); ++ } ++ ++ @Override ++ protected void b(ConditionFlag condition, int imm21, int pos) { ++ super.b(condition, imm21, pos); ++ } ++ ++ @Override ++ protected void cbnz(int size, Register reg, int imm21) { ++ super.cbnz(size, reg, imm21); ++ } ++ ++ @Override ++ protected void cbz(int size, Register reg, int imm21) { ++ super.cbz(size, reg, imm21); ++ } ++ ++ @Override ++ protected void b(int imm28) { ++ super.b(imm28); ++ } ++ ++ @Override ++ protected void b(int imm28, int pos) { ++ super.b(imm28, pos); ++ } ++ ++ @Override ++ public void bl(int imm28) { ++ super.bl(imm28); ++ } ++ ++ @Override ++ public void blr(Register reg) { ++ super.blr(reg); ++ } ++ ++ @Override ++ protected void br(Register reg) { ++ super.br(reg); ++ } ++ ++ @Override ++ public void ret(Register reg) { ++ super.ret(reg); ++ } ++ ++ @Override ++ public void ldr(int srcSize, Register rt, SW64Address address) { ++ super.ldr(srcSize, rt, address); ++ } ++ ++ @Override ++ public void ldrs(int targetSize, int srcSize, Register rt, SW64Address address) { ++ super.ldrs(targetSize, srcSize, rt, address); ++ } ++ ++ @Override ++ public void str(int destSize, Register rt, SW64Address address) { ++ super.str(destSize, rt, address); ++ } ++ ++ @Override ++ protected void ldxr(int size, Register rt, Register rn) { ++ super.ldxr(size, rt, rn); ++ } ++ ++ @Override ++ protected void stxr(int size, Register rs, Register rt, Register rn) { ++ super.stxr(size, rs, rt, rn); ++ } ++ ++ @Override ++ protected void ldar(int size, Register rt, Register rn) { ++ super.ldar(size, rt, rn); ++ } ++ ++ @Override ++ protected void stlr(int size, Register rt, Register rn) { ++ super.stlr(size, rt, rn); ++ } ++ ++ @Override ++ public void ldaxr(int size, Register rt, Register rn) { ++ super.ldaxr(size, rt, rn); ++ } ++ ++ @Override ++ public void stlxr(int size, Register rs, Register rt, Register rn) { ++ super.stlxr(size, rs, rt, rn); ++ } ++ ++ @Override ++ public void adr(Register dst, int imm21) { ++ super.adr(dst, imm21); ++ } ++ ++ @Override ++ protected void add(int size, Register dst, Register src, int aimm) { ++ super.add(size, dst, src, aimm); ++ } ++ ++ @Override ++ protected void adds(int size, Register dst, Register src, int aimm) { ++ super.adds(size, dst, src, aimm); ++ } ++ ++ @Override ++ protected void sub(int size, Register dst, Register src, int aimm) { ++ super.sub(size, dst, src, aimm); ++ } ++ ++ @Override ++ protected void subs(int size, Register dst, Register src, int aimm) { ++ super.subs(size, dst, src, aimm); ++ } ++ ++ @Override ++ public void and(int size, Register dst, Register src, long bimm) { ++ super.and(size, dst, src, bimm); ++ } ++ ++ @Override ++ public void eor(int size, Register dst, Register src, long bimm) { ++ super.eor(size, dst, src, bimm); ++ } ++ ++ @Override ++ protected void orr(int size, Register dst, Register src, long bimm) { ++ super.orr(size, dst, src, bimm); ++ } ++ ++ @Override ++ protected void movz(int size, Register dst, int uimm16, int shiftAmt) { ++ super.movz(size, dst, uimm16, shiftAmt); ++ } ++ ++ @Override ++ protected void movn(int size, Register dst, int uimm16, int shiftAmt) { ++ super.movn(size, dst, uimm16, shiftAmt); ++ } ++ ++ @Override ++ protected void movk(int size, Register dst, int uimm16, int pos) { ++ super.movk(size, dst, uimm16, pos); ++ } ++ ++ @Override ++ public void bfm(int size, Register dst, Register src, int r, int s) { ++ super.bfm(size, dst, src, r, s); ++ } ++ ++ @Override ++ public void ubfm(int size, Register dst, Register src, int r, int s) { ++ super.ubfm(size, dst, src, r, s); ++ } ++ ++ @Override ++ protected void sbfm(int size, Register dst, Register src, int r, int s) { ++ super.sbfm(size, dst, src, r, s); ++ } ++ ++ @Override ++ protected void extr(int size, Register dst, Register src1, Register src2, int lsb) { ++ super.extr(size, dst, src1, src2, lsb); ++ } ++ ++ @Override ++ public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ super.adds(size, dst, src1, src2, shiftType, imm); ++ } ++ ++ @Override ++ public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ super.subs(size, dst, src1, src2, shiftType, imm); ++ } ++ ++ @Override ++ protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ super.add(size, dst, src1, src2, shiftType, imm); ++ } ++ ++ @Override ++ protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { ++ super.sub(size, dst, src1, src2, shiftType, imm); ++ } ++ ++ @Override ++ public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ super.add(size, dst, src1, src2, extendType, shiftAmt); ++ } ++ ++ @Override ++ protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ super.adds(size, dst, src1, src2, extendType, shiftAmt); ++ } ++ ++ @Override ++ protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ super.sub(size, dst, src1, src2, extendType, shiftAmt); ++ } ++ ++ @Override ++ public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { ++ super.subs(size, dst, src1, src2, extendType, shiftAmt); ++ } ++ ++ @Override ++ protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.and(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.ands(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.bic(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.bics(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.eon(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.eor(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.orr(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { ++ super.orn(size, dst, src1, src2, shiftType, shiftAmt); ++ } ++ ++ @Override ++ protected void asr(int size, Register dst, Register src1, Register src2) { ++ super.asr(size, dst, src1, src2); ++ } ++ ++ @Override ++ protected void lsl(int size, Register dst, Register src1, Register src2) { ++ super.lsl(size, dst, src1, src2); ++ } ++ ++ @Override ++ protected void lsr(int size, Register dst, Register src1, Register src2) { ++ super.lsr(size, dst, src1, src2); ++ } ++ ++ @Override ++ protected void ror(int size, Register dst, Register src1, Register src2) { ++ super.ror(size, dst, src1, src2); ++ } ++ ++ @Override ++ protected void cls(int size, Register dst, Register src) { ++ super.cls(size, dst, src); ++ } ++ ++ @Override ++ public void clz(int size, Register dst, Register src) { ++ super.clz(size, dst, src); ++ } ++ ++ @Override ++ public void rbit(int size, Register dst, Register src) { ++ super.rbit(size, dst, src); ++ } ++ ++ @Override ++ public void rev(int size, Register dst, Register src) { ++ super.rev(size, dst, src); ++ } ++ ++ @Override ++ protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ super.csel(size, dst, src1, src2, condition); ++ } ++ ++ @Override ++ protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ super.csneg(size, dst, src1, src2, condition); ++ } ++ ++ @Override ++ protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ super.csinc(size, dst, src1, src2, condition); ++ } ++ ++ @Override ++ protected void madd(int size, Register dst, Register src1, Register src2, Register src3) { ++ super.madd(size, dst, src1, src2, src3); ++ } ++ ++ @Override ++ protected void msub(int size, Register dst, Register src1, Register src2, Register src3) { ++ super.msub(size, dst, src1, src2, src3); ++ } ++ ++ @Override ++ public void sdiv(int size, Register dst, Register src1, Register src2) { ++ super.sdiv(size, dst, src1, src2); ++ } ++ ++ @Override ++ public void udiv(int size, Register dst, Register src1, Register src2) { ++ super.udiv(size, dst, src1, src2); ++ } ++ ++ @Override ++ public void fldr(int size, Register rt, SW64Address address) { ++ super.fldr(size, rt, address); ++ } ++ ++ @Override ++ public void fstr(int size, Register rt, SW64Address address) { ++ super.fstr(size, rt, address); ++ } ++ ++ @Override ++ protected void fmov(int size, Register dst, Register src) { ++ super.fmov(size, dst, src); ++ } ++ ++ @Override ++ protected void fmovFpu2Cpu(int size, Register dst, Register src) { ++ super.fmovFpu2Cpu(size, dst, src); ++ } ++ ++ @Override ++ protected void fmovCpu2Fpu(int size, Register dst, Register src) { ++ super.fmovCpu2Fpu(size, dst, src); ++ } ++ ++ @Override ++ protected void fmov(int size, Register dst, double imm) { ++ super.fmov(size, dst, imm); ++ } ++ ++ @Override ++ public void fcvt(int srcSize, Register dst, Register src) { ++ super.fcvt(srcSize, dst, src); ++ } ++ ++ @Override ++ public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) { ++ super.fcvtzs(targetSize, srcSize, dst, src); ++ } ++ ++ @Override ++ public void scvtf(int targetSize, int srcSize, Register dst, Register src) { ++ super.scvtf(targetSize, srcSize, dst, src); ++ } ++ ++ @Override ++ protected void frintz(int size, Register dst, Register src) { ++ super.frintz(size, dst, src); ++ } ++ ++ @Override ++ public void fabs(int size, Register dst, Register src) { ++ super.fabs(size, dst, src); ++ } ++ ++ @Override ++ public void fneg(int size, Register dst, Register src) { ++ super.fneg(size, dst, src); ++ } ++ ++ @Override ++ public void fsqrt(int size, Register dst, Register src) { ++ super.fsqrt(size, dst, src); ++ } ++ ++ @Override ++ public void fadd(int size, Register dst, Register src1, Register src2) { ++ super.fadd(size, dst, src1, src2); ++ } ++ ++ @Override ++ public void fsub(int size, Register dst, Register src1, Register src2) { ++ super.fsub(size, dst, src1, src2); ++ } ++ ++ @Override ++ public void fmul(int size, Register dst, Register src1, Register src2) { ++ super.fmul(size, dst, src1, src2); ++ } ++ ++ @Override ++ public void fdiv(int size, Register dst, Register src1, Register src2) { ++ super.fdiv(size, dst, src1, src2); ++ } ++ ++ @Override ++ protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) { ++ super.fmadd(size, dst, src1, src2, src3); ++ } ++ ++ @Override ++ protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) { ++ super.fmsub(size, dst, src1, src2, src3); ++ } ++ ++ @Override ++ public void fcmp(int size, Register src1, Register src2) { ++ super.fcmp(size, src1, src2); ++ } ++ ++ @Override ++ public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) { ++ super.fccmp(size, src1, src2, uimm4, condition); ++ } ++ ++ @Override ++ public void fcmpZero(int size, Register src) { ++ super.fcmpZero(size, src); ++ } ++ ++ @Override ++ protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { ++ super.fcsel(size, dst, src1, src2, condition); ++ } ++ ++ @Override ++ protected void hlt(int uimm16) { ++ super.hlt(uimm16); ++ } ++ ++ @Override ++ protected void brk(int uimm16) { ++ super.brk(uimm16); ++ } ++ ++ @Override ++ protected void hint(SystemHint hint) { ++ super.hint(hint); ++ } ++ ++ @Override ++ protected void clrex() { ++ super.clrex(); ++ } ++ ++ @Override ++ public void dmb(BarrierKind barrierKind) { ++ super.dmb(barrierKind); ++ } ++ ++ @Override ++ public void align(int modulus) { ++ } ++ ++ @Override ++ public void jmp(Label l) { ++ } ++ ++ @Override ++ protected void patchJumpTarget(int branch, int jumpTarget) { ++ ++ } ++ ++ @Override ++ public AbstractAddress makeAddress(Register base, int displacement) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public AbstractAddress getPlaceholder(int instructionStartPosition) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public void ensureUniquePC() { ++ throw new UnsupportedOperationException(); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressLoweringByUse.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressLoweringByUse.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressLoweringByUse.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressLoweringByUse.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,227 @@ ++/* ++ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2017, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.core.common.type.Stamp; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.AddNode; ++import org.graalvm.compiler.nodes.memory.address.AddressNode; ++import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; ++import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.meta.JavaConstant; ++ ++public class SW64AddressLoweringByUse extends AddressLoweringByUsePhase.AddressLoweringByUse { ++ private SW64LIRKindTool kindtool; ++ ++ public SW64AddressLoweringByUse(SW64LIRKindTool kindtool) { ++ this.kindtool = kindtool; ++ } ++ ++ @Override ++ public AddressNode lower(ValueNode use, Stamp stamp, AddressNode address) { ++ if (address instanceof OffsetAddressNode) { ++ OffsetAddressNode offsetAddress = (OffsetAddressNode) address; ++ return doLower(stamp, offsetAddress.getBase(), offsetAddress.getOffset()); ++ } else { ++ // must be an already transformed SW64AddressNode ++ return address; ++ } ++ } ++ ++ @Override ++ public AddressNode lower(AddressNode address) { ++ return lower(null, null, address); ++ } ++ ++ private AddressNode doLower(Stamp stamp, ValueNode base, ValueNode index) { ++ SW64AddressNode ret = new SW64AddressNode(base, index); ++ SW64Kind sw64Kind = (stamp == null ? null : getSW64Kind(stamp)); ++ ++ // improve the address as much as possible ++ boolean changed; ++ do { ++ changed = improve(sw64Kind, ret); ++ } while (changed); ++ ++ // avoid duplicates ++ return base.graph().unique(ret); ++ } ++ ++ protected boolean improve(SW64Kind kind, SW64AddressNode ret) { ++ SW64Address.AddressingMode mode = ret.getAddressingMode(); ++ // if we have already set a displacement or set to base only mode then we are done ++ if (isDisplacementMode(mode) || isBaseOnlyMode(mode)) { ++ return false; ++ } ++ ValueNode base = ret.getBase(); ++ ValueNode index = ret.getIndex(); ++ ++ // avoid a constant or null base if possible ++ if (base == null) { ++ ret.setBase(index); ++ ret.setIndex(base); ++ return true; ++ } ++ // make sure any integral JavaConstant ++ // is the index rather than the base ++ // strictly we don't need the conditions on index ++ // as we ought not to see two JavaConstant values ++ if (base.isJavaConstant() && base.asJavaConstant().getJavaKind().isNumericInteger() && ++ index != null && !index.isJavaConstant()) { ++ ret.setBase(index); ++ ret.setIndex(base); ++ return true; ++ } ++ ++ // if the base is an add then move it up ++ if (index == null && base instanceof AddNode) { ++ AddNode add = (AddNode) base; ++ ret.setBase(add.getX()); ++ ret.setIndex(add.getY()); ++ return true; ++ } ++ ++ // we can try to fold a JavaConstant index into a displacement ++ if (index != null && index.isJavaConstant()) { ++ JavaConstant javaConstant = index.asJavaConstant(); ++ if (javaConstant.getJavaKind().isNumericInteger()) { ++ long disp = javaConstant.asLong(); ++ mode = immediateMode(kind, disp); ++ if (isDisplacementMode(mode)) { ++ index = null; ++ // we can fold this in as a displacement ++ // but first see if we can pull up any additional ++ // constants added into the base ++ boolean tryNextBase = (base instanceof AddNode); ++ while (tryNextBase) { ++ AddNode add = (AddNode) base; ++ tryNextBase = false; ++ ValueNode child = add.getX(); ++ if (child.isJavaConstant() && child.asJavaConstant().getJavaKind().isNumericInteger()) { ++ long newDisp = disp + child.asJavaConstant().asLong(); ++ SW64Address.AddressingMode newMode = immediateMode(kind, newDisp); ++ if (newMode != SW64Address.AddressingMode.REGISTER_OFFSET) { ++ disp = newDisp; ++ mode = newMode; ++ base = add.getY(); ++ ret.setBase(base); ++ tryNextBase = (base instanceof AddNode); ++ } ++ } else { ++ child = add.getY(); ++ if (child.isJavaConstant() && child.asJavaConstant().getJavaKind().isNumericInteger()) { ++ long newDisp = disp + child.asJavaConstant().asLong(); ++ SW64Address.AddressingMode newMode = immediateMode(kind, newDisp); ++ if (newMode != SW64Address.AddressingMode.REGISTER_OFFSET) { ++ disp = newDisp; ++ mode = newMode; ++ base = add.getX(); ++ ret.setBase(base); ++ tryNextBase = (base instanceof AddNode); ++ } ++ } ++ } ++ } ++ if (disp != 0) { ++ // ok now set the displacement in place of an index ++ ret.setIndex(null); ++ int scaleFactor = computeScaleFactor(kind, mode); ++ ret.setDisplacement(disp, scaleFactor, mode); ++ } else { ++ // reset to base register only ++ ret.setIndex(null); ++ ret.setDisplacement(0, 1, SW64Address.AddressingMode.BASE_REGISTER_ONLY); ++ } ++ return true; ++ } ++ } ++ } ++ // nope cannot improve this any more ++ return false; ++ } ++ ++ private SW64Kind getSW64Kind(Stamp stamp) { ++ LIRKind lirKind = stamp.getLIRKind(kindtool); ++ if (!lirKind.isValue()) { ++ if (!lirKind.isReference(0) || lirKind.getReferenceCount() != 1) { ++ return null; ++ } ++ } ++ ++ return (SW64Kind) lirKind.getPlatformKind(); ++ } ++ ++ private static SW64Address.AddressingMode immediateMode(SW64Kind kind, long value) { ++ if (kind != null) { ++ int size = kind.getSizeInBytes(); ++ // this next test should never really fail ++ if ((value & (size - 1)) == 0) { ++ long encodedValue = value / size; ++ // assert value % size == 0 ++ // we can try for a 12 bit scaled offset ++ if (NumUtil.isUnsignedNbit(12, encodedValue)) { ++ return SW64Address.AddressingMode.IMMEDIATE_SCALED; ++ } ++ } ++ } ++ ++ // we can try for a 9 bit unscaled offset ++ if (NumUtil.isSignedNbit(9, value)) { ++ return SW64Address.AddressingMode.IMMEDIATE_UNSCALED; ++ } ++ ++ // nope this index needs to be passed via offset register ++ return SW64Address.AddressingMode.REGISTER_OFFSET; ++ } ++ ++ private static int computeScaleFactor(SW64Kind kind, SW64Address.AddressingMode mode) { ++ if (mode == SW64Address.AddressingMode.IMMEDIATE_SCALED) { ++ return kind.getSizeInBytes(); ++ } ++ return 1; ++ } ++ ++ boolean isBaseOnlyMode(SW64Address.AddressingMode addressingMode) { ++ return addressingMode == SW64Address.AddressingMode.BASE_REGISTER_ONLY; ++ } ++ ++ private static boolean isDisplacementMode(SW64Address.AddressingMode addressingMode) { ++ switch (addressingMode) { ++ case IMMEDIATE_POST_INDEXED: ++ case IMMEDIATE_PRE_INDEXED: ++ case IMMEDIATE_SCALED: ++ case IMMEDIATE_UNSCALED: ++ return true; ++ } ++ return false; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressNode.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressNode.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressNode.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64AddressNode.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,142 @@ ++/* ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.lir.sw64.SW64AddressValue; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.memory.address.AddressNode; ++import org.graalvm.compiler.nodes.spi.LIRLowerable; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++ ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * Represents an SW64 address in the graph. ++ */ ++@NodeInfo ++public class SW64AddressNode extends AddressNode implements LIRLowerable { ++ ++ public static final NodeClass TYPE = NodeClass.create(SW64AddressNode.class); ++ ++ @OptionalInput private ValueNode base; ++ ++ @OptionalInput private ValueNode index; ++ private SW64Address.AddressingMode addressingMode; ++ ++ private long displacement; ++ private int scaleFactor; ++ ++ public SW64AddressNode(ValueNode base) { ++ this(base, null); ++ } ++ ++ public SW64AddressNode(ValueNode base, ValueNode index) { ++ super(TYPE); ++ this.base = base; ++ this.index = index; ++ this.addressingMode = AddressingMode.REGISTER_OFFSET; ++ this.displacement = 0; ++ this.scaleFactor = 1; ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool gen) { ++ LIRGeneratorTool tool = gen.getLIRGeneratorTool(); ++ ++ AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base)); ++ AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index)); ++ ++ AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); ++ AllocatableValue indexReference; ++ if (index == null) { ++ indexReference = null; ++ } else if (addressingMode.equals(AddressingMode.IMMEDIATE_UNSCALED)) { ++ indexReference = LIRKind.derivedBaseFromValue(indexValue); ++ } else { ++ if (LIRKind.isValue(indexValue.getValueKind())) { ++ indexReference = null; ++ } else { ++ indexReference = Value.ILLEGAL; ++ } ++ } ++ ++ LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp(NodeView.DEFAULT)), baseReference, indexReference); ++ gen.setResult(this, new SW64AddressValue(kind, baseValue, indexValue, (int) displacement, scaleFactor, addressingMode)); ++ } ++ ++ @Override ++ public ValueNode getBase() { ++ return base; ++ } ++ ++ public void setBase(ValueNode base) { ++ // allow modification before inserting into the graph ++ if (isAlive()) { ++ updateUsages(this.base, base); ++ } ++ this.base = base; ++ } ++ ++ @Override ++ public ValueNode getIndex() { ++ return index; ++ } ++ ++ public void setIndex(ValueNode index) { ++ // allow modification before inserting into the graph ++ if (isAlive()) { ++ updateUsages(this.index, index); ++ } ++ this.index = index; ++ } ++ ++ public long getDisplacement() { ++ return displacement; ++ } ++ ++ public void setDisplacement(long displacement, int scaleFactor, SW64Address.AddressingMode addressingMode) { ++ this.displacement = displacement; ++ this.scaleFactor = scaleFactor; ++ this.addressingMode = addressingMode; ++ } ++ ++ @Override ++ public long getMaxConstantDisplacement() { ++ return displacement; ++ } ++ ++ public AddressingMode getAddressingMode() { ++ return addressingMode; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ArithmeticLIRGenerator.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ArithmeticLIRGenerator.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ArithmeticLIRGenerator.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ArithmeticLIRGenerator.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,515 @@ ++/* ++ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64Kind.DWORD; ++import static jdk.vm.ci.sw64.SW64Kind.QWORD; ++import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; ++import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; ++import static org.graalvm.compiler.lir.sw64.SW64BitManipulationOp.BitManipulationOpCode.BSR; ++import static org.graalvm.compiler.lir.sw64.SW64BitManipulationOp.BitManipulationOpCode.CLZ; ++import static org.graalvm.compiler.lir.sw64.SW64BitManipulationOp.BitManipulationOpCode.CTZ; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.core.common.calc.FloatConvert; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.ConstantValue; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.Variable; ++import org.graalvm.compiler.lir.sw64.SW64AddressValue; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticOp; ++import org.graalvm.compiler.lir.sw64.SW64BitManipulationOp; ++import org.graalvm.compiler.lir.sw64.SW64Move.LoadOp; ++import org.graalvm.compiler.lir.sw64.SW64Move.StoreConstantOp; ++import org.graalvm.compiler.lir.sw64.SW64Move.StoreOp; ++import org.graalvm.compiler.lir.sw64.SW64ReinterpretOp; ++import org.graalvm.compiler.lir.sw64.SW64SignExtendOp; ++import org.graalvm.compiler.lir.sw64.SW64Unary; ++import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.RegisterValue; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.PlatformKind; ++import jdk.vm.ci.meta.Value; ++import jdk.vm.ci.meta.ValueKind; ++ ++public class SW64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements SW64ArithmeticLIRGeneratorTool { ++ ++ @Override ++ public SW64LIRGenerator getLIRGen() { ++ return (SW64LIRGenerator) super.getLIRGen(); ++ } ++ ++ @Override ++ protected boolean isNumericInteger(PlatformKind kind) { ++ return ((SW64Kind) kind).isInteger(); ++ } ++ ++ @Override ++ protected Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { ++ if (isNumericInteger(a.getPlatformKind())) { ++ SW64ArithmeticOp op = setFlags ? SW64ArithmeticOp.ADDS : SW64ArithmeticOp.ADD; ++ return emitBinary(resultKind, op, true, a, b); ++ } else { ++ assert !setFlags : "Cannot set flags on floating point arithmetic"; ++ return emitBinary(resultKind, SW64ArithmeticOp.FADD, true, a, b); ++ } ++ } ++ ++ @Override ++ protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { ++ if (isNumericInteger(a.getPlatformKind())) { ++ SW64ArithmeticOp op = setFlags ? SW64ArithmeticOp.SUBS : SW64ArithmeticOp.SUB; ++ return emitBinary(resultKind, op, false, a, b); ++ } else { ++ assert !setFlags : "Cannot set flags on floating point arithmetic"; ++ return emitBinary(resultKind, SW64ArithmeticOp.FSUB, false, a, b); ++ } ++ } ++ ++ public Value emitExtendMemory(boolean isSigned, SW64Kind memoryKind, int resultBits, SW64AddressValue address, LIRFrameState state) { ++ // Issue a zero extending load of the proper bit size and set the result to ++ // the proper kind. ++ Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? SW64Kind.DWORD : SW64Kind.QWORD)); ++ ++ int targetSize = resultBits <= 32 ? 32 : 64; ++ switch (memoryKind) { ++ case BYTE: ++ case WORD: ++ case DWORD: ++ case QWORD: ++ getLIRGen().append(new SW64Unary.MemoryOp(isSigned, targetSize, ++ memoryKind.getSizeInBytes() * 8, result, address, state)); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ return result; ++ } ++ ++ @Override ++ public Value emitMul(Value a, Value b, boolean setFlags) { ++ SW64ArithmeticOp intOp = setFlags ? SW64ArithmeticOp.MULVS : SW64ArithmeticOp.MUL; ++ return emitBinary(LIRKind.combine(a, b), getOpCode(a, intOp, SW64ArithmeticOp.FMUL), true, a, b); ++ } ++ ++ @Override ++ public Value emitMulHigh(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.SMULH, true, a, b); ++ } ++ ++ @Override ++ public Value emitUMulHigh(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.UMULH, true, a, b); ++ } ++ ++ @Override ++ public Value emitDiv(Value a, Value b, LIRFrameState state) { ++ return emitBinary(LIRKind.combine(a, b), getOpCode(a, SW64ArithmeticOp.DIV, SW64ArithmeticOp.FDIV), false, asAllocatable(a), asAllocatable(b)); ++ } ++ ++ @Override ++ public Value emitRem(Value a, Value b, LIRFrameState state) { ++ return emitBinary(LIRKind.combine(a, b), getOpCode(a, SW64ArithmeticOp.REM, SW64ArithmeticOp.FREM), false, asAllocatable(a), asAllocatable(b)); ++ } ++ ++ @Override ++ public Value emitUDiv(Value a, Value b, LIRFrameState state) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.UDIV, false, asAllocatable(a), asAllocatable(b)); ++ } ++ ++ @Override ++ public Value emitURem(Value a, Value b, LIRFrameState state) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.UREM, false, asAllocatable(a), asAllocatable(b)); ++ } ++ ++ @Override ++ public Value emitAnd(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.AND, true, a, b); ++ } ++ ++ @Override ++ public Value emitOr(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.OR, true, a, b); ++ } ++ ++ @Override ++ public Value emitXor(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.XOR, true, a, b); ++ } ++ ++ @Override ++ public Value emitShl(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.SHL, false, a, b); ++ } ++ ++ @Override ++ public Value emitShr(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.ASHR, false, a, b); ++ } ++ ++ @Override ++ public Value emitUShr(Value a, Value b) { ++ assert isNumericInteger(a.getPlatformKind()); ++ return emitBinary(LIRKind.combine(a, b), SW64ArithmeticOp.LSHR, false, a, b); ++ } ++ ++ @Override ++ public Value emitFloatConvert(FloatConvert op, Value inputVal) { ++ PlatformKind resultPlatformKind = getFloatConvertResultKind(op); ++ LIRKind resultLirKind = LIRKind.combine(inputVal).changeType(resultPlatformKind); ++ Variable result = getLIRGen().newVariable(resultLirKind); ++ getLIRGen().append(new SW64FloatConvertOp(op, result, asAllocatable(inputVal))); ++ return result; ++ } ++ ++ private static PlatformKind getFloatConvertResultKind(FloatConvert op) { ++ switch (op) { ++ case F2I: ++ case D2I: ++ return SW64Kind.DWORD; ++ case F2L: ++ case D2L: ++ return SW64Kind.QWORD; ++ case I2F: ++ case L2F: ++ case D2F: ++ return SW64Kind.SINGLE; ++ case I2D: ++ case L2D: ++ case F2D: ++ return SW64Kind.DOUBLE; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ @Override ++ public Value emitReinterpret(LIRKind to, Value inputVal) { ++ ValueKind from = inputVal.getValueKind(); ++ if (to.equals(from)) { ++ return inputVal; ++ } ++ Variable result = getLIRGen().newVariable(to); ++ getLIRGen().append(new SW64ReinterpretOp(result, asAllocatable(inputVal))); ++ return result; ++ } ++ ++ @Override ++ public Value emitNarrow(Value inputVal, int bits) { ++ if (inputVal.getPlatformKind() == SW64Kind.QWORD && bits <= 32) { ++ LIRKind resultKind = getResultLirKind(bits, inputVal); ++ long mask = NumUtil.getNbitNumberLong(bits); ++ Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask)); ++ return emitBinary(resultKind, SW64ArithmeticOp.AND, true, inputVal, maskValue); ++ } else { ++ return inputVal; ++ } ++ } ++ ++ @Override ++ public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { ++ assert fromBits <= toBits && toBits <= 64; ++ if (fromBits == toBits) { ++ return inputVal; ++ } ++ LIRKind resultKind = getResultLirKind(toBits, inputVal); ++ long mask = NumUtil.getNbitNumberLong(fromBits); ++ Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask)); ++ return emitBinary(resultKind, SW64ArithmeticOp.AND, true, inputVal, maskValue); ++ } ++ ++ @Override ++ public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { ++ LIRKind resultKind = getResultLirKind(toBits, inputVal); ++ assert fromBits <= toBits && toBits <= 64; ++ if (fromBits == toBits) { ++ return inputVal; ++ } else if (isJavaConstant(inputVal)) { ++ JavaConstant javaConstant = asJavaConstant(inputVal); ++ long constant; ++ if (javaConstant.isNull()) { ++ constant = 0; ++ } else { ++ constant = javaConstant.asLong(); ++ } ++ int shiftCount = QWORD.getSizeInBytes() * 8 - fromBits; ++ return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount)); ++ } ++ Variable result = getLIRGen().newVariable(resultKind); ++ getLIRGen().append(new SW64SignExtendOp(result, asAllocatable(inputVal), fromBits, toBits)); ++ return result; ++ } ++ ++ private static LIRKind getResultLirKind(int resultBitSize, Value... inputValues) { ++ if (resultBitSize == 64) { ++ return LIRKind.combine(inputValues).changeType(QWORD); ++ } else { ++ // FIXME: I have no idea what this assert was ever for ++ // assert resultBitSize == 32; ++ return LIRKind.combine(inputValues).changeType(DWORD); ++ } ++ } ++ ++ protected Variable emitBinary(ValueKind resultKind, SW64ArithmeticOp op, boolean commutative, Value a, Value b) { ++ Variable result = getLIRGen().newVariable(resultKind); ++ if (isValidBinaryConstant(op, a, b)) { ++ emitBinaryConst(result, op, asAllocatable(a), asJavaConstant(b)); ++ } else if (commutative && isValidBinaryConstant(op, b, a)) { ++ emitBinaryConst(result, op, asAllocatable(b), asJavaConstant(a)); ++ } else { ++ emitBinaryVar(result, op, asAllocatable(a), asAllocatable(b)); ++ } ++ return result; ++ } ++ ++ private void emitBinaryVar(Variable result, SW64ArithmeticOp op, AllocatableValue a, AllocatableValue b) { ++ AllocatableValue x = moveSp(a); ++ AllocatableValue y = moveSp(b); ++ switch (op) { ++ case FREM: ++ case REM: ++ case UREM: ++ getLIRGen().append(new SW64ArithmeticOp.BinaryCompositeOp(op, result, x, y)); ++ break; ++ default: ++ getLIRGen().append(new SW64ArithmeticOp.BinaryOp(op, result, x, y)); ++ break; ++ } ++ } ++ ++ private void emitBinaryConst(Variable result, SW64ArithmeticOp op, AllocatableValue a, JavaConstant b) { ++ AllocatableValue x = moveSp(a); ++ getLIRGen().append(new SW64ArithmeticOp.BinaryConstOp(op, result, x, b)); ++ } ++ ++ private static boolean isValidBinaryConstant(SW64ArithmeticOp op, Value a, Value b) { ++ if (!isJavaConstant(b)) { ++ return false; ++ } ++ JavaConstant constValue = asJavaConstant(b); ++ switch (op.category) { ++ case LOGICAL: ++ return isLogicalConstant(constValue); ++ case ARITHMETIC: ++ return isArithmeticConstant(constValue); ++ case SHIFT: ++ assert constValue.asLong() >= 0 && constValue.asLong() < a.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ return true; ++ case NONE: ++ return false; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ private static boolean isLogicalConstant(JavaConstant constValue) { ++ switch (constValue.getJavaKind()) { ++ case Int: ++ return SW64MacroAssembler.isLogicalImmediate(constValue.asInt()); ++ case Long: ++ return SW64MacroAssembler.isLogicalImmediate(constValue.asLong()); ++ default: ++ return false; ++ } ++ } ++ ++ protected static boolean isArithmeticConstant(JavaConstant constValue) { ++ switch (constValue.getJavaKind()) { ++ case Int: ++ case Long: ++ return SW64MacroAssembler.isArithmeticImmediate(constValue.asLong()); ++ case Object: ++ return constValue.isNull(); ++ default: ++ return false; ++ } ++ } ++ ++ @Override ++ public Value emitNegate(Value inputVal) { ++ return emitUnary(getOpCode(inputVal, SW64ArithmeticOp.NEG, SW64ArithmeticOp.FNEG), inputVal); ++ } ++ ++ @Override ++ public Value emitNot(Value input) { ++ assert isNumericInteger(input.getPlatformKind()); ++ return emitUnary(SW64ArithmeticOp.NOT, input); ++ } ++ ++ @Override ++ public Value emitMathAbs(Value input) { ++ return emitUnary(getOpCode(input, SW64ArithmeticOp.ABS, SW64ArithmeticOp.FABS), input); ++ } ++ ++ @Override ++ public Value emitMathSqrt(Value input) { ++ assert input.getPlatformKind() == SW64Kind.DOUBLE; ++ return emitUnary(SW64ArithmeticOp.SQRT, input); ++ } ++ ++ @Override ++ public Variable emitBitScanForward(Value value) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public Value emitBitCount(Value operand) { ++ throw GraalError.unimplemented("SW64 ISA does not offer way to implement this more efficiently than a simple Java algorithm."); ++ } ++ ++ @Override ++ public Value emitBitScanReverse(Value value) { ++ Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(SW64Kind.DWORD)); ++ getLIRGen().append(new SW64BitManipulationOp(BSR, result, asAllocatable(value))); ++ return result; ++ } ++ ++ @Override ++ public Value emitCountLeadingZeros(Value value) { ++ Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(SW64Kind.DWORD)); ++ getLIRGen().append(new SW64BitManipulationOp(CLZ, result, asAllocatable(value))); ++ return result; ++ } ++ ++ @Override ++ public Value emitCountTrailingZeros(Value value) { ++ Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(SW64Kind.DWORD)); ++ getLIRGen().append(new SW64BitManipulationOp(CTZ, result, asAllocatable(value))); ++ return result; ++ } ++ ++ private Variable emitUnary(SW64ArithmeticOp op, Value inputVal) { ++ AllocatableValue input = asAllocatable(inputVal); ++ Variable result = getLIRGen().newVariable(LIRKind.combine(input)); ++ getLIRGen().append(new SW64ArithmeticOp.UnaryOp(op, result, input)); ++ return result; ++ } ++ ++ /** ++ * If val denotes the stackpointer, move it to another location. This is necessary since most ++ * ops cannot handle the stackpointer as input or output. ++ */ ++ private AllocatableValue moveSp(AllocatableValue val) { ++ if (val instanceof RegisterValue && ((RegisterValue) val).getRegister().equals(sp)) { ++ assert val.getPlatformKind() == SW64Kind.QWORD : "Stackpointer must be long"; ++ return getLIRGen().emitMove(val); ++ } ++ return val; ++ } ++ ++ /** ++ * Returns the opcode depending on the platform kind of val. ++ */ ++ private SW64ArithmeticOp getOpCode(Value val, SW64ArithmeticOp intOp, SW64ArithmeticOp floatOp) { ++ return isNumericInteger(val.getPlatformKind()) ? intOp : floatOp; ++ } ++ ++ @Override ++ public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { ++ SW64AddressValue loadAddress = getLIRGen().asAddressValue(address); ++ Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind)); ++ getLIRGen().append(new LoadOp((SW64Kind) kind.getPlatformKind(), result, loadAddress, state)); ++ return result; ++ } ++ ++ @Override ++ public void emitStore(ValueKind lirKind, Value address, Value inputVal, LIRFrameState state) { ++ SW64AddressValue storeAddress = getLIRGen().asAddressValue(address); ++ SW64Kind kind = (SW64Kind) lirKind.getPlatformKind(); ++ ++ if (isJavaConstant(inputVal) && kind.isInteger()) { ++ JavaConstant c = asJavaConstant(inputVal); ++ if (c.isDefaultForKind()) { ++ // We can load 0 directly into integer registers ++ getLIRGen().append(new StoreConstantOp(kind, storeAddress, c, state)); ++ return; ++ } ++ } ++ AllocatableValue input = asAllocatable(inputVal); ++ getLIRGen().append(new StoreOp(kind, storeAddress, input, state)); ++ } ++ ++ @Override ++ public Value emitMathLog(Value input, boolean base10) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public Value emitMathCos(Value input) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public Value emitMathSin(Value input) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public Value emitMathTan(Value input) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public void emitCompareOp(SW64Kind cmpKind, Variable left, Value right) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public Value emitRound(Value value, RoundingMode mode) { ++ SW64ArithmeticOp op; ++ switch (mode) { ++ case NEAREST: ++ op = SW64ArithmeticOp.FRINTN; ++ break; ++ case UP: ++ op = SW64ArithmeticOp.FRINTP; ++ break; ++ case DOWN: ++ op = SW64ArithmeticOp.FRINTM; ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ ++ return emitUnary(op, value); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64FloatConvertOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64FloatConvertOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64FloatConvertOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64FloatConvertOp.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.calc.FloatConvert; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++public final class SW64FloatConvertOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64FloatConvertOp.class); ++ ++ private final FloatConvert op; ++ @Def protected AllocatableValue resultValue; ++ @Use protected AllocatableValue inputValue; ++ ++ protected SW64FloatConvertOp(FloatConvert op, AllocatableValue resultValue, AllocatableValue inputValue) { ++ super(TYPE); ++ this.op = op; ++ this.resultValue = resultValue; ++ this.inputValue = inputValue; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ int fromSize = inputValue.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ int toSize = resultValue.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ ++ Register result = asRegister(resultValue); ++ Register input = asRegister(inputValue); ++ switch (op) { ++ case F2I: ++ case D2I: ++ case F2L: ++ case D2L: ++ masm.fcvtzs(toSize, fromSize, result, input); ++ break; ++ case I2F: ++ case I2D: ++ case L2F: ++ case L2D: ++ masm.scvtf(toSize, fromSize, result, input); ++ break; ++ case D2F: ++ case F2D: ++ masm.fcvt(fromSize, result, input); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRGenerator.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRGenerator.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRGenerator.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRGenerator.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,516 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; ++import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; ++ ++import java.util.function.Function; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ConditionFlag; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.calc.Condition; ++import org.graalvm.compiler.core.common.spi.LIRKindTool; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRValueUtil; ++import org.graalvm.compiler.lir.LabelRef; ++import org.graalvm.compiler.lir.StandardOp; ++import org.graalvm.compiler.lir.SwitchStrategy; ++import org.graalvm.compiler.lir.Variable; ++import org.graalvm.compiler.lir.sw64.SW64AddressValue; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticOp; ++import org.graalvm.compiler.lir.sw64.SW64ArrayCompareToOp; ++import org.graalvm.compiler.lir.sw64.SW64ArrayEqualsOp; ++import org.graalvm.compiler.lir.sw64.SW64ByteSwapOp; ++import org.graalvm.compiler.lir.sw64.SW64Compare; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow.BranchOp; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow.CondMoveOp; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow.StrategySwitchOp; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow.TableSwitchOp; ++import org.graalvm.compiler.lir.sw64.SW64LIRFlagsVersioned; ++import org.graalvm.compiler.lir.sw64.SW64Move; ++import org.graalvm.compiler.lir.sw64.SW64AtomicMove.AtomicReadAndAddOp; ++import org.graalvm.compiler.lir.sw64.SW64AtomicMove.AtomicReadAndAddLSEOp; ++import org.graalvm.compiler.lir.sw64.SW64AtomicMove.CompareAndSwapOp; ++import org.graalvm.compiler.lir.sw64.SW64AtomicMove.AtomicReadAndWriteOp; ++import org.graalvm.compiler.lir.sw64.SW64Move.MembarOp; ++import org.graalvm.compiler.lir.sw64.SW64PauseOp; ++import org.graalvm.compiler.lir.gen.LIRGenerationResult; ++import org.graalvm.compiler.lir.gen.LIRGenerator; ++import org.graalvm.compiler.phases.util.Providers; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.RegisterValue; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.PlatformKind; ++import jdk.vm.ci.meta.PrimitiveConstant; ++import jdk.vm.ci.meta.Value; ++import jdk.vm.ci.meta.ValueKind; ++ ++public abstract class SW64LIRGenerator extends LIRGenerator { ++ ++ public SW64LIRGenerator(LIRKindTool lirKindTool, SW64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) { ++ super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); ++ } ++ ++ /** ++ * Checks whether the supplied constant can be used without loading it into a register for store ++ * operations, i.e., on the right hand side of a memory access. ++ * ++ * @param c The constant to check. ++ * @return True if the constant can be used directly, false if the constant needs to be in a ++ * register. ++ */ ++ protected static final boolean canStoreConstant(JavaConstant c) { ++ // Our own code never calls this since we can't make a definite statement about whether or ++ // not we can inline a constant without knowing what kind of operation we execute. Let's be ++ // optimistic here and fix up mistakes later. ++ return true; ++ } ++ ++ /** ++ * SW64 cannot use anything smaller than a word in any instruction other than load and store. ++ */ ++ @Override ++ public > K toRegisterKind(K kind) { ++ switch ((SW64Kind) kind.getPlatformKind()) { ++ case BYTE: ++ case WORD: ++ return kind.changeType(SW64Kind.DWORD); ++ default: ++ return kind; ++ } ++ } ++ ++ @Override ++ public void emitNullCheck(Value address, LIRFrameState state) { ++ append(new SW64Move.NullCheckOp(asAddressValue(address), state)); ++ } ++ ++ @Override ++ public Variable emitAddress(AllocatableValue stackslot) { ++ Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); ++ append(new SW64Move.StackLoadAddressOp(result, stackslot)); ++ return result; ++ } ++ ++ public SW64AddressValue asAddressValue(Value address) { ++ if (address instanceof SW64AddressValue) { ++ return (SW64AddressValue) address; ++ } else { ++ return new SW64AddressValue(address.getValueKind(), asAllocatable(address), Value.ILLEGAL, 0, 1, AddressingMode.BASE_REGISTER_ONLY); ++ } ++ } ++ ++ @Override ++ public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { ++ Variable prevValue = newVariable(expectedValue.getValueKind()); ++ Variable scratch = newVariable(LIRKind.value(SW64Kind.DWORD)); ++ append(new CompareAndSwapOp(prevValue, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch)); ++ assert trueValue.getValueKind().equals(falseValue.getValueKind()); ++ Variable result = newVariable(trueValue.getValueKind()); ++ append(new CondMoveOp(result, ConditionFlag.EQ, asAllocatable(trueValue), asAllocatable(falseValue))); ++ return result; ++ } ++ ++ @Override ++ public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) { ++ Variable result = newVariable(newValue.getValueKind()); ++ Variable scratch = newVariable(LIRKind.value(SW64Kind.WORD)); ++ append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch)); ++ return result; ++ } ++ ++ @Override ++ public Value emitAtomicReadAndWrite(Value address, ValueKind kind, Value newValue) { ++ Variable result = newVariable(kind); ++ Variable scratch = newVariable(kind); ++ append(new AtomicReadAndWriteOp((SW64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), asAllocatable(newValue), asAllocatable(scratch))); ++ return result; ++ } ++ ++ @Override ++ public Value emitAtomicReadAndAdd(Value address, ValueKind kind, Value delta) { ++ Variable result = newVariable(kind); ++ if (SW64LIRFlagsVersioned.useLSE(target().arch)) { ++ append(new AtomicReadAndAddLSEOp((SW64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), asAllocatable(delta))); ++ } else { ++ append(new AtomicReadAndAddOp((SW64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), delta)); ++ } ++ return result; ++ } ++ ++ @Override ++ public void emitMembar(int barriers) { ++ int necessaryBarriers = target().arch.requiredBarriers(barriers); ++ if (target().isMP && necessaryBarriers != 0) { ++ append(new MembarOp(necessaryBarriers)); ++ } ++ } ++ ++ @Override ++ public void emitJump(LabelRef label) { ++ assert label != null; ++ append(new StandardOp.JumpOp(label)); ++ } ++ ++ @Override ++ public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability) { ++ append(new SW64ControlFlow.BranchOp(ConditionFlag.VS, overflow, noOverflow, overflowProbability)); ++ } ++ ++ /** ++ * Branches to label if (left & right) == 0. If negated is true branchse on non-zero instead. ++ * ++ * @param left Integer kind. Non null. ++ * @param right Integer kind. Non null. ++ * @param trueDestination destination if left & right == 0. Non null. ++ * @param falseDestination destination if left & right != 0. Non null ++ * @param trueSuccessorProbability hoistoric probability that comparison is true ++ */ ++ @Override ++ public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability) { ++ assert ((SW64Kind) left.getPlatformKind()).isInteger() && left.getPlatformKind() == right.getPlatformKind(); ++ ((SW64ArithmeticLIRGenerator) getArithmetic()).emitBinary(LIRKind.combine(left, right), SW64ArithmeticOp.ANDS, true, left, right); ++ append(new SW64ControlFlow.BranchOp(ConditionFlag.EQ, trueDestination, falseDestination, trueSuccessorProbability)); ++ } ++ ++ /** ++ * Conditionally move trueValue into new variable if cond + unorderedIsTrue is true, else ++ * falseValue. ++ * ++ * @param left Arbitrary value. Has to have same type as right. Non null. ++ * @param right Arbitrary value. Has to have same type as left. Non null. ++ * @param cond condition that decides whether to move trueValue or falseValue into result. Non ++ * null. ++ * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or ++ * not. Ignored for integer comparisons. ++ * @param trueValue arbitrary value same type as falseValue. Non null. ++ * @param falseValue arbitrary value same type as trueValue. Non null. ++ * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non ++ * null. ++ */ ++ @Override ++ public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { ++ boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue); ++ Condition finalCondition = mirrored ? cond.mirror() : cond; ++ boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue; ++ ConditionFlag cmpCondition = toConditionFlag(((SW64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue); ++ Variable result = newVariable(trueValue.getValueKind()); ++ append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue))); ++ return result; ++ } ++ ++ @Override ++ public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, ++ double trueDestinationProbability) { ++ boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue); ++ Condition finalCondition = mirrored ? cond.mirror() : cond; ++ boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue; ++ ConditionFlag cmpCondition = toConditionFlag(((SW64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue); ++ append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability)); ++ } ++ ++ private static ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) { ++ return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue); ++ } ++ ++ /** ++ * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific ++ * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly ++ * handled the case of 'EQ && unorderedIsTrue', respectively 'NE && !unorderedIsTrue'! ++ */ ++ private static ConditionFlag toFloatConditionFlag(Condition cond, boolean unorderedIsTrue) { ++ switch (cond) { ++ case LT: ++ return unorderedIsTrue ? ConditionFlag.LT : ConditionFlag.LO; ++ case LE: ++ return unorderedIsTrue ? ConditionFlag.LE : ConditionFlag.LS; ++ case GE: ++ return unorderedIsTrue ? ConditionFlag.PL : ConditionFlag.GE; ++ case GT: ++ return unorderedIsTrue ? ConditionFlag.HI : ConditionFlag.GT; ++ case EQ: ++ return ConditionFlag.EQ; ++ case NE: ++ return ConditionFlag.NE; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ /** ++ * Takes a Condition and returns the correct Aarch64 specific ConditionFlag. ++ */ ++ private static ConditionFlag toIntConditionFlag(Condition cond) { ++ switch (cond) { ++ case EQ: ++ return ConditionFlag.EQ; ++ case NE: ++ return ConditionFlag.NE; ++ case LT: ++ return ConditionFlag.LT; ++ case LE: ++ return ConditionFlag.LE; ++ case GT: ++ return ConditionFlag.GT; ++ case GE: ++ return ConditionFlag.GE; ++ case AE: ++ return ConditionFlag.HS; ++ case BE: ++ return ConditionFlag.LS; ++ case AT: ++ return ConditionFlag.HI; ++ case BT: ++ return ConditionFlag.LO; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ /** ++ * This method emits the compare instruction, and may reorder the operands. It returns true if ++ * it did so. ++ * ++ * @param a the left operand of the comparison. Has to have same type as b. Non null. ++ * @param b the right operand of the comparison. Has to have same type as a. Non null. ++ * @return true if mirrored (i.e. "b cmp a" instead of "a cmp b" was done). ++ */ ++ protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) { ++ Value left; ++ Value right; ++ boolean mirrored; ++ SW64Kind kind = (SW64Kind) cmpKind; ++ if (kind.isInteger()) { ++ Value aExt = a; ++ Value bExt = b; ++ ++ int compareBytes = cmpKind.getSizeInBytes(); ++ // SW64 compares 32 or 64 bits: sign extend a and b as required. ++ if (compareBytes < a.getPlatformKind().getSizeInBytes()) { ++ aExt = arithmeticLIRGen.emitSignExtend(a, compareBytes * 8, 64); ++ } ++ if (compareBytes < b.getPlatformKind().getSizeInBytes()) { ++ bExt = arithmeticLIRGen.emitSignExtend(b, compareBytes * 8, 64); ++ } ++ ++ if (LIRValueUtil.isVariable(bExt)) { ++ left = load(bExt); ++ right = loadNonConst(aExt); ++ mirrored = true; ++ } else { ++ left = load(aExt); ++ right = loadNonConst(bExt); ++ mirrored = false; ++ } ++ append(new SW64Compare.CompareOp(left, loadNonCompareConst(right))); ++ } else if (kind.isSIMD()) { ++ if (SW64Compare.FloatCompareOp.isFloatCmpConstant(a, condition, unorderedIsTrue)) { ++ left = load(b); ++ right = a; ++ mirrored = true; ++ } else if (SW64Compare.FloatCompareOp.isFloatCmpConstant(b, condition, unorderedIsTrue)) { ++ left = load(a); ++ right = b; ++ mirrored = false; ++ } else { ++ left = load(a); ++ right = loadReg(b); ++ mirrored = false; ++ } ++ append(new SW64Compare.FloatCompareOp(left, asAllocatable(right), condition, unorderedIsTrue)); ++ } else { ++ throw GraalError.shouldNotReachHere(); ++ } ++ return mirrored; ++ } ++ ++ /** ++ * If value is a constant that cannot be used directly with a gpCompare instruction load it into ++ * a register and return the register, otherwise return constant value unchanged. ++ */ ++ protected Value loadNonCompareConst(Value value) { ++ if (!isCompareConstant(value)) { ++ return loadReg(value); ++ } ++ return value; ++ } ++ ++ /** ++ * Checks whether value can be used directly with a gpCompare instruction. This is not ++ * the same as {@link SW64ArithmeticLIRGenerator#isArithmeticConstant(JavaConstant)}, because ++ * 0.0 is a valid compare constant for floats, while there are no arithmetic constants for ++ * floats. ++ * ++ * @param value any type. Non null. ++ * @return true if value can be used directly in comparison instruction, false otherwise. ++ */ ++ public boolean isCompareConstant(Value value) { ++ if (isJavaConstant(value)) { ++ JavaConstant constant = asJavaConstant(value); ++ if (constant instanceof PrimitiveConstant) { ++ final long longValue = constant.asLong(); ++ long maskedValue; ++ switch (constant.getJavaKind()) { ++ case Boolean: ++ case Byte: ++ maskedValue = longValue & 0xFF; ++ break; ++ case Char: ++ case Short: ++ maskedValue = longValue & 0xFFFF; ++ break; ++ case Int: ++ maskedValue = longValue & 0xFFFF_FFFF; ++ break; ++ case Long: ++ maskedValue = longValue; ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ return SW64MacroAssembler.isArithmeticImmediate(maskedValue); ++ } else { ++ return constant.isDefaultForKind(); ++ } ++ } ++ return false; ++ } ++ ++ /** ++ * Moves trueValue into result if (left & right) == 0, else falseValue. ++ * ++ * @param left Integer kind. Non null. ++ * @param right Integer kind. Non null. ++ * @param trueValue Integer kind. Non null. ++ * @param falseValue Integer kind. Non null. ++ * @return virtual register containing trueValue if (left & right) == 0, else falseValue. ++ */ ++ @Override ++ public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { ++ assert ((SW64Kind) left.getPlatformKind()).isInteger() && ((SW64Kind) right.getPlatformKind()).isInteger(); ++ assert ((SW64Kind) trueValue.getPlatformKind()).isInteger() && ((SW64Kind) falseValue.getPlatformKind()).isInteger(); ++ ((SW64ArithmeticLIRGenerator) getArithmetic()).emitBinary(left.getValueKind(), SW64ArithmeticOp.ANDS, true, left, right); ++ Variable result = newVariable(trueValue.getValueKind()); ++ append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue))); ++ return result; ++ } ++ ++ @Override ++ public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { ++ append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getValueKind()), SW64LIRGenerator::toIntConditionFlag)); ++ } ++ ++ protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, ++ Function converter) { ++ return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter); ++ } ++ ++ @Override ++ protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { ++ append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind()))); ++ } ++ ++ @Override ++ public Variable emitByteSwap(Value input) { ++ Variable result = newVariable(LIRKind.combine(input)); ++ append(new SW64ByteSwapOp(result, input)); ++ return result; ++ } ++ ++ @Override ++ public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) { ++ LIRKind resultKind = LIRKind.value(SW64Kind.DWORD); ++ // DMS TODO: check calling conversion and registers used ++ RegisterValue res = SW64.r0.asValue(resultKind); ++ RegisterValue cnt1 = SW64.r1.asValue(length1.getValueKind()); ++ RegisterValue cnt2 = SW64.r2.asValue(length2.getValueKind()); ++ emitMove(cnt1, length1); ++ emitMove(cnt2, length2); ++ append(new SW64ArrayCompareToOp(this, kind1, kind2, res, array1, array2, cnt1, cnt2)); ++ Variable result = newVariable(resultKind); ++ emitMove(result, res); ++ return result; ++ } ++ ++ @Override ++ public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { ++ Variable result = newVariable(LIRKind.value(SW64Kind.DWORD)); ++ append(new SW64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); ++ return result; ++ } ++ ++ @Override ++ protected JavaConstant zapValueForKind(PlatformKind kind) { ++ long dead = 0xDEADDEADDEADDEADL; ++ switch ((SW64Kind) kind) { ++ case BYTE: ++ return JavaConstant.forByte((byte) dead); ++ case WORD: ++ return JavaConstant.forShort((short) dead); ++ case DWORD: ++ return JavaConstant.forInt((int) dead); ++ case QWORD: ++ return JavaConstant.forLong(dead); ++ case SINGLE: ++ return JavaConstant.forFloat(Float.intBitsToFloat((int) dead)); ++ case DOUBLE: ++ return JavaConstant.forDouble(Double.longBitsToDouble(dead)); ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ /** ++ * Loads value into virtual register. Contrary to {@link #load(Value)} this handles ++ * RegisterValues (i.e. values corresponding to fixed physical registers) correctly, by not ++ * creating an unnecessary move into a virtual register. ++ * ++ * This avoids generating the following code: mov x0, x19 # x19 is fixed thread register ldr x0, ++ * [x0] instead of: ldr x0, [x19]. ++ */ ++ protected AllocatableValue loadReg(Value val) { ++ if (!(val instanceof Variable || val instanceof RegisterValue)) { ++ return emitMove(val); ++ } ++ return (AllocatableValue) val; ++ } ++ ++ @Override ++ public void emitPause() { ++ append(new SW64PauseOp()); ++ } ++ ++ public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args); ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRKindTool.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRKindTool.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRKindTool.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64LIRKindTool.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.spi.LIRKindTool; ++import org.graalvm.compiler.debug.GraalError; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++ ++public class SW64LIRKindTool implements LIRKindTool { ++ ++ @Override ++ public LIRKind getIntegerKind(int bits) { ++ if (bits <= 8) { ++ return LIRKind.value(SW64Kind.BYTE); ++ } else if (bits <= 16) { ++ return LIRKind.value(SW64Kind.WORD); ++ } else if (bits <= 32) { ++ return LIRKind.value(SW64Kind.DWORD); ++ } else { ++ assert bits <= 64; ++ return LIRKind.value(SW64Kind.QWORD); ++ } ++ } ++ ++ @Override ++ public LIRKind getFloatingKind(int bits) { ++ switch (bits) { ++ case 32: ++ return LIRKind.value(SW64Kind.SINGLE); ++ case 64: ++ return LIRKind.value(SW64Kind.DOUBLE); ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ @Override ++ public LIRKind getObjectKind() { ++ return LIRKind.reference(SW64Kind.QWORD); ++ } ++ ++ @Override ++ public LIRKind getWordKind() { ++ return LIRKind.value(SW64Kind.QWORD); ++ } ++ ++ @Override ++ public LIRKind getNarrowOopKind() { ++ return LIRKind.compressedReference(SW64Kind.DWORD); ++ } ++ ++ @Override ++ public LIRKind getNarrowPointerKind() { ++ return LIRKind.value(SW64Kind.DWORD); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64MoveFactory.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64MoveFactory.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64MoveFactory.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64MoveFactory.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (c) 2015, 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; ++import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; ++import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.type.DataPointerConstant; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstruction; ++import org.graalvm.compiler.lir.sw64.SW64AddressValue; ++import org.graalvm.compiler.lir.sw64.SW64Move; ++import org.graalvm.compiler.lir.sw64.SW64Move.LoadAddressOp; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; ++ ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64MoveFactory implements MoveFactory { ++ ++ @Override ++ public LIRInstruction createMove(AllocatableValue dst, Value src) { ++ boolean srcIsSlot = isStackSlotValue(src); ++ boolean dstIsSlot = isStackSlotValue(dst); ++ if (isConstantValue(src)) { ++ return createLoad(dst, asConstant(src)); ++ } else if (src instanceof SW64AddressValue) { ++ return new LoadAddressOp(dst, (SW64AddressValue) src); ++ } else { ++ assert src instanceof AllocatableValue; ++ if (srcIsSlot && dstIsSlot) { ++ throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass()); ++ } else { ++ return new SW64Move.Move(dst, (AllocatableValue) src); ++ } ++ } ++ } ++ ++ @Override ++ public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { ++ return new SW64Move.Move(result, input); ++ } ++ ++ @Override ++ public LIRInstruction createLoad(AllocatableValue dst, Constant src) { ++ if (src instanceof JavaConstant) { ++ JavaConstant javaConstant = (JavaConstant) src; ++ if (canInlineConstant(javaConstant)) { ++ return new SW64Move.LoadInlineConstant(javaConstant, dst); ++ } else { ++ // return new SW64Move.LoadConstantFromTable(javaConstant, ++ // constantTableBaseProvider.getConstantTableBase(), dst); ++ return new SW64Move.LoadInlineConstant(javaConstant, dst); ++ } ++ } else if (src instanceof DataPointerConstant) { ++ return new SW64Move.LoadDataOp(dst, (DataPointerConstant) src); ++ } else { ++ // throw GraalError.shouldNotReachHere(src.getClass().toString()); ++ throw GraalError.unimplemented(); ++ } ++ } ++ ++ @Override ++ public LIRInstruction createStackLoad(AllocatableValue result, Constant input) { ++ return createLoad(result, input); ++ } ++ ++ @Override ++ public boolean canInlineConstant(Constant con) { ++ if (con instanceof JavaConstant) { ++ JavaConstant c = (JavaConstant) con; ++ switch (c.getJavaKind()) { ++ case Boolean: ++ case Byte: ++ case Char: ++ case Short: ++ case Int: ++ return SW64MacroAssembler.isMovableImmediate(c.asInt()); ++ case Long: ++ return SW64MacroAssembler.isMovableImmediate(c.asLong()); ++ case Object: ++ return c.isNull(); ++ default: ++ return false; ++ } ++ } ++ return false; ++ } ++ ++ @Override ++ public boolean allowConstantToStackMove(Constant value) { ++ return false; ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeLIRBuilder.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeLIRBuilder.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeLIRBuilder.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeLIRBuilder.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import org.graalvm.compiler.core.gen.NodeLIRBuilder; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.ValueNode; ++ ++/** ++ * This class implements the SW64 specific portion of the LIR generator. ++ */ ++public abstract class SW64NodeLIRBuilder extends NodeLIRBuilder { ++ ++ public SW64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SW64NodeMatchRules nodeMatchRules) { ++ super(graph, lirGen, nodeMatchRules); ++ } ++ ++ @Override ++ protected boolean peephole(ValueNode valueNode) { ++ // No peephole optimizations for now ++ return false; ++ } ++ ++ @Override ++ public SW64LIRGenerator getLIRGeneratorTool() { ++ return (SW64LIRGenerator) super.getLIRGeneratorTool(); ++ } ++ ++ @Override ++ protected void emitPrologue(StructuredGraph graph) { ++ // XXX Maybe we need something like this. ++ // getLIRGeneratorTool().emitLoadConstantTableBase(); ++ super.emitPrologue(graph); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeMatchRules.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeMatchRules.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeMatchRules.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64NodeMatchRules.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import org.graalvm.compiler.core.gen.NodeMatchRules; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++import org.graalvm.compiler.nodes.DeoptimizingNode; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.memory.Access; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++ ++public class SW64NodeMatchRules extends NodeMatchRules { ++ ++ public SW64NodeMatchRules(LIRGeneratorTool gen) { ++ super(gen); ++ } ++ ++ protected LIRFrameState getState(Access access) { ++ if (access instanceof DeoptimizingNode) { ++ return state((DeoptimizingNode) access); ++ } ++ return null; ++ } ++ ++ protected SW64Kind getMemoryKind(Access access) { ++ return (SW64Kind) gen.getLIRKind(access.asNode().stamp(NodeView.DEFAULT)).getPlatformKind(); ++ } ++ ++ @Override ++ public SW64LIRGenerator getLIRGeneratorTool() { ++ return (SW64LIRGenerator) gen; ++ } ++ ++ protected SW64ArithmeticLIRGenerator getArithmeticLIRGenerator() { ++ return (SW64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadNode.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadNode.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadNode.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadNode.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2017, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++ ++import org.graalvm.compiler.core.common.type.IntegerStamp; ++import org.graalvm.compiler.core.common.type.Stamp; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.lir.sw64.SW64AddressValue; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.FrameState; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.SignExtendNode; ++import org.graalvm.compiler.nodes.calc.ZeroExtendNode; ++import org.graalvm.compiler.nodes.extended.GuardingNode; ++import org.graalvm.compiler.nodes.memory.ReadNode; ++import org.graalvm.compiler.nodes.memory.address.AddressNode; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++import jdk.internal.vm.compiler.word.LocationIdentity; ++ ++/** ++ * SW64-specific subclass of ReadNode that knows how to merge ZeroExtend and SignExtend into the ++ * read. ++ */ ++ ++@NodeInfo ++public class SW64ReadNode extends ReadNode { ++ public static final NodeClass TYPE = NodeClass.create(SW64ReadNode.class); ++ private final IntegerStamp accessStamp; ++ private final boolean isSigned; ++ ++ public SW64ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, ++ FrameState stateBefore, IntegerStamp accessStamp, boolean isSigned) { ++ super(TYPE, address, location, stamp, guard, barrierType, nullCheck, stateBefore); ++ this.accessStamp = accessStamp; ++ this.isSigned = isSigned; ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool gen) { ++ SW64LIRGenerator lirgen = (SW64LIRGenerator) gen.getLIRGeneratorTool(); ++ SW64ArithmeticLIRGenerator arithgen = (SW64ArithmeticLIRGenerator) lirgen.getArithmetic(); ++ SW64Kind readKind = (SW64Kind) lirgen.getLIRKind(accessStamp).getPlatformKind(); ++ int resultBits = ((IntegerStamp) stamp(NodeView.DEFAULT)).getBits(); ++ gen.setResult(this, arithgen.emitExtendMemory(isSigned, readKind, resultBits, (SW64AddressValue) gen.operand(getAddress()), gen.state(this))); ++ } ++ ++ /** ++ * replace a ReadNode with an SW64-specific variant which knows how to merge a downstream ++ * zero or sign extend into the read operation. ++ * ++ * @param readNode ++ */ ++ public static void replace(ReadNode readNode) { ++ assert readNode.getUsageCount() == 1; ++ assert readNode.getUsageAt(0) instanceof ZeroExtendNode || readNode.getUsageAt(0) instanceof SignExtendNode; ++ ++ ValueNode usage = (ValueNode) readNode.getUsageAt(0); ++ boolean isSigned = usage instanceof SignExtendNode; ++ IntegerStamp accessStamp = ((IntegerStamp) readNode.getAccessStamp()); ++ ++ AddressNode address = readNode.getAddress(); ++ LocationIdentity location = readNode.getLocationIdentity(); ++ Stamp stamp = usage.stamp(NodeView.DEFAULT); ++ GuardingNode guard = readNode.getGuard(); ++ BarrierType barrierType = readNode.getBarrierType(); ++ boolean nullCheck = readNode.getNullCheck(); ++ FrameState stateBefore = readNode.stateBefore(); ++ SW64ReadNode clone = new SW64ReadNode(address, location, stamp, guard, barrierType, nullCheck, stateBefore, accessStamp, isSigned); ++ StructuredGraph graph = readNode.graph(); ++ graph.add(clone); ++ // splice out the extend node ++ usage.replaceAtUsagesAndDelete(readNode); ++ // swap the clone for the read ++ graph.replaceFixedWithFixed(readNode, clone); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadReplacementPhase.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadReplacementPhase.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadReplacementPhase.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64ReadReplacementPhase.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2017, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import org.graalvm.compiler.graph.Node; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.calc.SignExtendNode; ++import org.graalvm.compiler.nodes.calc.ZeroExtendNode; ++import org.graalvm.compiler.nodes.memory.ReadNode; ++import org.graalvm.compiler.phases.Phase; ++ ++/** ++ * SW64-specific phase which substitutes certain read nodes with arch-specific variants in order ++ * to allow merging of zero and sign extension into the read operation. ++ */ ++ ++public class SW64ReadReplacementPhase extends Phase { ++ @Override ++ protected void run(StructuredGraph graph) { ++ for (Node node : graph.getNodes()) { ++ // don't process nodes we just added ++ if (node instanceof SW64ReadNode) { ++ continue; ++ } ++ if (node instanceof ReadNode) { ++ ReadNode readNode = (ReadNode) node; ++ if (readNode.hasExactlyOneUsage()) { ++ Node usage = readNode.getUsageAt(0); ++ if (usage instanceof ZeroExtendNode || usage instanceof SignExtendNode) { ++ SW64ReadNode.replace(readNode); ++ } ++ } ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64SuitesCreator.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64SuitesCreator.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64SuitesCreator.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sw64/src/org/graalvm/compiler/core/sw64/SW64SuitesCreator.java 2025-05-09 10:05:57.760290598 +0800 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.core.sw64; ++ ++import java.util.ListIterator; ++ ++import org.graalvm.compiler.java.DefaultSuitesCreator; ++import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; ++import org.graalvm.compiler.options.OptionValues; ++import org.graalvm.compiler.phases.BasePhase; ++import org.graalvm.compiler.phases.Phase; ++import org.graalvm.compiler.phases.PhaseSuite; ++import org.graalvm.compiler.phases.tiers.CompilerConfiguration; ++import org.graalvm.compiler.phases.tiers.LowTierContext; ++import org.graalvm.compiler.phases.tiers.Suites; ++ ++public class SW64SuitesCreator extends DefaultSuitesCreator { ++ private final Class insertReadReplacementBefore; ++ ++ public SW64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins, Class insertReadReplacementBefore) { ++ super(compilerConfiguration, plugins); ++ this.insertReadReplacementBefore = insertReadReplacementBefore; ++ } ++ ++ @Override ++ public Suites createSuites(OptionValues options) { ++ Suites suites = super.createSuites(options); ++ ++ ListIterator> findPhase = suites.getLowTier().findPhase(insertReadReplacementBefore); ++ // Put SW64ReadReplacementPhase right before the SchedulePhase ++ while (PhaseSuite.findNextPhase(findPhase, insertReadReplacementBefore)) { ++ // Search for last occurrence of SchedulePhase ++ } ++ findPhase.previous(); ++ findPhase.add(new SW64ReadReplacementPhase()); ++ return suites; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackendFactory.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackendFactory.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackendFactory.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackendFactory.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,231 @@ ++/* ++ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.common.InitTimer.timer; ++ ++import java.util.ArrayList; ++import java.util.List; ++ ++import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; ++import org.graalvm.compiler.bytecode.BytecodeProvider; ++import org.graalvm.compiler.core.sw64.SW64AddressLoweringByUse; ++import org.graalvm.compiler.core.sw64.SW64LIRKindTool; ++import org.graalvm.compiler.core.sw64.SW64SuitesCreator; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.HotSpotBackend; ++import org.graalvm.compiler.hotspot.HotSpotBackendFactory; ++import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; ++import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl; ++import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins; ++import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotProviders; ++import org.graalvm.compiler.hotspot.meta.HotSpotRegisters; ++import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; ++import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; ++import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; ++import org.graalvm.compiler.nodes.spi.LoweringProvider; ++import org.graalvm.compiler.nodes.spi.Replacements; ++import org.graalvm.compiler.options.OptionValues; ++import org.graalvm.compiler.phases.Phase; ++import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase; ++import org.graalvm.compiler.phases.schedule.SchedulePhase; ++import org.graalvm.compiler.phases.tiers.CompilerConfiguration; ++import org.graalvm.compiler.phases.util.Providers; ++import org.graalvm.compiler.replacements.sw64.SW64GraphBuilderPlugins; ++import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; ++import org.graalvm.compiler.serviceprovider.ServiceProvider; ++import org.graalvm.compiler.word.WordTypes; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.code.Architecture; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterConfig; ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.common.InitTimer; ++import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; ++import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; ++import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; ++import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; ++import jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig; ++import jdk.vm.ci.meta.Value; ++import jdk.vm.ci.runtime.JVMCIBackend; ++ ++@ServiceProvider(HotSpotBackendFactory.class) ++public class SW64HotSpotBackendFactory implements HotSpotBackendFactory { ++ ++ @Override ++ public String getName() { ++ return "community"; ++ } ++ ++ @Override ++ public Class getArchitecture() { ++ return SW64.class; ++ } ++ ++ @Override ++ @SuppressWarnings("try") ++ public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntime jvmciRuntime, HotSpotBackend host) { ++ assert host == null; ++ ++ JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend(); ++ GraalHotSpotVMConfig config = graalRuntime.getVMConfig(); ++ HotSpotProviders providers; ++ HotSpotRegistersProvider registers; ++ HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache(); ++ TargetDescription target = codeCache.getTarget(); ++ HotSpotHostForeignCallsProvider foreignCalls; ++ Value[] nativeABICallerSaveRegisters; ++ HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess(); ++ HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection(); ++ HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess); ++ HotSpotLoweringProvider lowerer; ++ HotSpotSnippetReflectionProvider snippetReflection; ++ HotSpotReplacementsImpl replacements; ++ HotSpotSuitesProvider suites; ++ HotSpotWordTypes wordTypes; ++ Plugins plugins; ++ BytecodeProvider bytecodeProvider; ++ try (InitTimer t = timer("create providers")) { ++ try (InitTimer rt = timer("create HotSpotRegisters provider")) { ++ registers = createRegisters(); ++ } ++ try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) { ++ nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig()); ++ } ++ try (InitTimer rt = timer("create WordTypes")) { ++ wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind); ++ } ++ try (InitTimer rt = timer("create ForeignCalls provider")) { ++ foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); ++ } ++ try (InitTimer rt = timer("create Lowerer provider")) { ++ lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target); ++ } ++ HotSpotStampProvider stampProvider = new HotSpotStampProvider(); ++ Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider); ++ ++ try (InitTimer rt = timer("create SnippetReflection provider")) { ++ snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes); ++ } ++ try (InitTimer rt = timer("create Bytecode provider")) { ++ bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection); ++ } ++ try (InitTimer rt = timer("create Replacements provider")) { ++ replacements = createReplacements(graalRuntime.getOptions(), p, snippetReflection, bytecodeProvider); ++ } ++ try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { ++ plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); ++ replacements.setGraphBuilderPlugins(plugins); ++ } ++ try (InitTimer rt = timer("create Suites provider")) { ++ suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, replacements); ++ } ++ providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers, ++ snippetReflection, wordTypes, ++ plugins); ++ } ++ try (InitTimer rt = timer("instantiate backend")) { ++ return createBackend(config, graalRuntime, providers); ++ } ++ } ++ ++ protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, ++ HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, ++ HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) { ++ Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, ++ replacements); ++ SW64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false); ++ return plugins; ++ } ++ ++ protected SW64HotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { ++ return new SW64HotSpotBackend(config, runtime, providers); ++ } ++ ++ protected HotSpotRegistersProvider createRegisters() { ++ return new HotSpotRegisters(SW64HotSpotRegisterConfig.threadRegister, SW64HotSpotRegisterConfig.heapBaseRegister, sp); ++ } ++ ++ protected HotSpotReplacementsImpl createReplacements(OptionValues options, Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) { ++ return new HotSpotReplacementsImpl(options, p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget()); ++ } ++ ++ protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, ++ HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { ++ return new SW64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); ++ } ++ ++ protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, ++ @SuppressWarnings("unused") Replacements replacements) { ++ SW64SuitesCreator suitesCreator = new SW64SuitesCreator(compilerConfiguration, plugins, SchedulePhase.class); ++ Phase addressLoweringPhase = new AddressLoweringByUsePhase(new SW64AddressLoweringByUse(new SW64LIRKindTool())); ++ return new AddressLoweringHotSpotSuitesProvider(suitesCreator, config, runtime, addressLoweringPhase); ++ } ++ ++ protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { ++ return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes); ++ } ++ ++ protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, ++ HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { ++ return new SW64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target); ++ } ++ ++ protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) { ++ List callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList()); ++ callerSave.remove(SW64.r19); ++ callerSave.remove(SW64.r20); ++ callerSave.remove(SW64.r21); ++ callerSave.remove(SW64.r22); ++ callerSave.remove(SW64.r23); ++ callerSave.remove(SW64.r24); ++ callerSave.remove(SW64.r25); ++ callerSave.remove(SW64.r26); ++ callerSave.remove(SW64.r27); ++ callerSave.remove(SW64.r28); ++ Value[] nativeABICallerSaveRegisters = new Value[callerSave.size()]; ++ for (int i = 0; i < callerSave.size(); i++) { ++ nativeABICallerSaveRegisters[i] = callerSave.get(i).asValue(); ++ } ++ return nativeABICallerSaveRegisters; ++ } ++ ++ @Override ++ public String toString() { ++ return "SW64"; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackend.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackend.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackend.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotBackend.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,367 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static java.lang.reflect.Modifier.isStatic; ++import static jdk.vm.ci.sw64.SW64.lr; ++import static jdk.vm.ci.sw64.SW64.r10; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.fp; ++import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; ++import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; ++ ++import jdk.internal.vm.compiler.collections.EconomicSet; ++import org.graalvm.compiler.asm.Assembler; ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.ScratchRegister; ++import org.graalvm.compiler.code.CompilationResult; ++import org.graalvm.compiler.core.sw64.SW64NodeMatchRules; ++import org.graalvm.compiler.core.common.CompilationIdentifier; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.HotSpotDataBuilder; ++import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; ++import org.graalvm.compiler.hotspot.HotSpotHostBackend; ++import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; ++import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; ++import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotProviders; ++import org.graalvm.compiler.hotspot.stubs.Stub; ++import org.graalvm.compiler.lir.LIR; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.sw64.SW64FrameMap; ++import org.graalvm.compiler.lir.sw64.SW64FrameMapBuilder; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; ++import org.graalvm.compiler.lir.asm.DataBuilder; ++import org.graalvm.compiler.lir.asm.FrameContext; ++import org.graalvm.compiler.lir.framemap.FrameMap; ++import org.graalvm.compiler.lir.framemap.FrameMapBuilder; ++import org.graalvm.compiler.lir.gen.LIRGenerationResult; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterConfig; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.hotspot.HotSpotCallingConventionType; ++import jdk.vm.ci.hotspot.HotSpotSentinelConstant; ++import jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.JavaType; ++import jdk.vm.ci.meta.ResolvedJavaMethod; ++ ++/** ++ * HotSpot SW64 specific backend. ++ */ ++public class SW64HotSpotBackend extends HotSpotHostBackend { ++ ++ public SW64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { ++ super(config, runtime, providers); ++ } ++ ++ @Override ++ public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { ++ RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; ++ return new SW64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull); ++ } ++ ++ @Override ++ public FrameMap newFrameMap(RegisterConfig registerConfig) { ++ return new SW64FrameMap(getCodeCache(), registerConfig, this); ++ } ++ ++ @Override ++ public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) { ++ return new SW64HotSpotLIRGenerator(getProviders(), config, lirGenRes); ++ } ++ ++ @Override ++ public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) { ++ return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub, config.requiresReservedStackCheck(graph.getMethods())); ++ } ++ ++ @Override ++ public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { ++ return new SW64HotSpotNodeLIRBuilder(graph, lirGen, new SW64NodeMatchRules(lirGen)); ++ } ++ ++ @Override ++ protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) { ++ SW64MacroAssembler masm = (SW64MacroAssembler) crb.asm; ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ SW64Address address = masm.makeAddress(sp, -bangOffset, scratch, 8, /* allowOverwrite */false); ++ masm.str(64, zr, address); ++ } ++ } ++ ++ private class HotSpotFrameContext implements FrameContext { ++ final boolean isStub; ++ ++ HotSpotFrameContext(boolean isStub) { ++ this.isStub = isStub; ++ } ++ ++ @Override ++ public void enter(CompilationResultBuilder crb) { ++ FrameMap frameMap = crb.frameMap; ++ final int frameSize = frameMap.frameSize(); ++ final int totalFrameSize = frameMap.totalFrameSize(); ++ assert frameSize + 2 * crb.target.arch.getWordSize() == totalFrameSize : "total framesize should be framesize + 2 words"; ++ SW64MacroAssembler masm = (SW64MacroAssembler) crb.asm; ++ if (!isStub) { ++ emitStackOverflowCheck(crb); ++ } ++ crb.blockComment("[method prologue]"); ++ ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ int wordSize = crb.target.arch.getWordSize(); ++ Register rscratch1 = sc.getRegister(); ++ assert totalFrameSize > 0; ++ if (frameSize < 1 << 9) { ++ masm.sub(64, sp, sp, totalFrameSize); ++ masm.stp(64, fp, lr, SW64Address.createScaledImmediateAddress(sp, frameSize / wordSize)); ++ } else { ++ masm.stp(64, fp, lr, SW64Address.createPreIndexedImmediateAddress(sp, -2)); ++ if (frameSize < 1 << 12) { ++ masm.sub(64, sp, sp, totalFrameSize - 2 * wordSize); ++ } else { ++ masm.mov(rscratch1, totalFrameSize - 2 * wordSize); ++ masm.sub(64, sp, sp, rscratch1); ++ } ++ } ++ } ++ if (ZapStackOnMethodEntry.getValue(crb.getOptions())) { ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ int longSize = 8; ++ masm.mov(64, scratch, sp); ++ SW64Address address = SW64Address.createPostIndexedImmediateAddress(scratch, longSize); ++ try (ScratchRegister sc2 = masm.getScratchRegister()) { ++ Register value = sc2.getRegister(); ++ masm.mov(value, 0xBADDECAFFC0FFEEL); ++ for (int i = 0; i < frameSize; i += longSize) { ++ masm.str(64, value, address); ++ } ++ } ++ ++ } ++ } ++ crb.blockComment("[code body]"); ++ } ++ ++ @Override ++ public void leave(CompilationResultBuilder crb) { ++ SW64MacroAssembler masm = (SW64MacroAssembler) crb.asm; ++ FrameMap frameMap = crb.frameMap; ++ final int totalFrameSize = frameMap.totalFrameSize(); ++ ++ crb.blockComment("[method epilogue]"); ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ int wordSize = crb.target.arch.getWordSize(); ++ Register rscratch1 = sc.getRegister(); ++ final int frameSize = frameMap.frameSize(); ++ assert totalFrameSize > 0; ++ if (frameSize < 1 << 9) { ++ masm.ldp(64, fp, lr, SW64Address.createScaledImmediateAddress(sp, frameSize / wordSize)); ++ masm.add(64, sp, sp, totalFrameSize); ++ } else { ++ if (frameSize < 1 << 12) { ++ masm.add(64, sp, sp, totalFrameSize - 2 * wordSize); ++ } else { ++ masm.mov(rscratch1, totalFrameSize - 2 * wordSize); ++ masm.add(64, sp, sp, rscratch1); ++ } ++ masm.ldp(64, fp, lr, SW64Address.createPostIndexedImmediateAddress(sp, 2)); ++ } ++ } ++ ++ } ++ ++ @Override ++ public boolean hasFrame() { ++ return true; ++ } ++ ++ } ++ ++ @Override ++ protected Assembler createAssembler(FrameMap frameMap) { ++ return new SW64MacroAssembler(getTarget()); ++ } ++ ++ @Override ++ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { ++ HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRen; ++ LIR lir = gen.getLIR(); ++ assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; ++ ++ Stub stub = gen.getStub(); ++ Assembler masm = createAssembler(frameMap); ++ HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); ++ ++ DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); ++ CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, dataBuilder, frameContext, lir.getOptions(), lir.getDebug(), compilationResult, ++ Register.None); ++ crb.setTotalFrameSize(frameMap.totalFrameSize()); ++ crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); ++ StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); ++ if (deoptimizationRescueSlot != null && stub == null) { ++ crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); ++ } ++ ++ if (stub != null) { ++ EconomicSet destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir); ++ updateStub(stub, destroyedCallerRegisters, gen.getCalleeSaveInfo(), frameMap); ++ } ++ return crb; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { ++ SW64MacroAssembler masm = (SW64MacroAssembler) crb.asm; ++ FrameMap frameMap = crb.frameMap; ++ RegisterConfig regConfig = frameMap.getRegisterConfig(); ++ Label verifiedStub = new Label(); ++ ++ emitCodePrefix(crb, installedCodeOwner, masm, regConfig, verifiedStub); ++ emitCodeBody(crb, lir, masm); ++ emitCodeSuffix(crb, masm, frameMap); ++ } ++ ++ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, SW64MacroAssembler masm, RegisterConfig regConfig, Label verifiedStub) { ++ HotSpotProviders providers = getProviders(); ++ if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) { ++ crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); ++ CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this); ++ // See definition of IC_Klass in c1_LIRAssembler_sw64.cpp ++ // equal to scratch(1) careful! ++ Register inlineCacheKlass = SW64HotSpotRegisterConfig.inlineCacheRegister; ++ Register receiver = asRegister(cc.getArgument(0)); ++ int transferSize = config.useCompressedClassPointers ? 4 : 8; ++ SW64Address klassAddress = masm.makeAddress(receiver, config.hubOffset, transferSize); ++ ++ // Are r10 and r11 available scratch registers here? One would hope so. ++ Register klass = r10; ++ if (config.useCompressedClassPointers) { ++ masm.ldr(32, klass, klassAddress); ++ SW64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding(), config); ++ } else { ++ masm.ldr(64, klass, klassAddress); ++ } ++ masm.cmp(64, inlineCacheKlass, klass); ++ /* ++ * Conditional jumps have a much lower range than unconditional ones, which can be a ++ * problem because the miss handler could be out of range. ++ */ ++ masm.branchConditionally(SW64Assembler.ConditionFlag.EQ, verifiedStub); ++ SW64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER)); ++ } ++ masm.align(config.codeEntryAlignment); ++ crb.recordMark(config.MARKID_OSR_ENTRY); ++ masm.bind(verifiedStub); ++ crb.recordMark(config.MARKID_VERIFIED_ENTRY); ++ ++ if (GeneratePIC.getValue(crb.getOptions())) { ++ // Check for method state ++ HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; ++ if (!frameContext.isStub) { ++ crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(SW64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT); ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ masm.addressOf(scratch); ++ masm.ldr(64, scratch, SW64Address.createBaseRegisterOnlyAddress(scratch)); ++ Label noCall = new Label(); ++ masm.cbz(64, scratch, noCall); ++ SW64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER)); ++ masm.bind(noCall); ++ } ++ } ++ } ++ } ++ ++ private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, SW64MacroAssembler masm) { ++ emitInvalidatePlaceholder(crb, masm); ++ crb.emit(lir); ++ } ++ ++ /** ++ * Insert a nop at the start of the prolog so we can patch in a branch if we need to invalidate ++ * the method later. ++ * ++ * @see "http://mail.openjdk.java.net/pipermail/sw64-port-dev/2013-September/000273.html" ++ */ ++ public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ if (!GeneratePIC.getValue(crb.getOptions())) { ++ crb.blockComment("[nop for method invalidation]"); ++ masm.nop(); ++ } ++ } ++ ++ private void emitCodeSuffix(CompilationResultBuilder crb, SW64MacroAssembler masm, FrameMap frameMap) { ++ HotSpotProviders providers = getProviders(); ++ HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; ++ if (!frameContext.isStub) { ++ HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); ++ ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER); ++ Register helper = SW64Call.isNearCall(linkage) ? null : scratch; ++ SW64Call.directCall(crb, masm, linkage, helper, null); ++ } ++ crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); ++ ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER); ++ masm.adr(lr, 0); // Warning: the argument is an offset from the instruction! ++ SW64Call.directJmp(crb, masm, linkage); ++ } else { ++ // No need to emit the stubs for entries back into the method since ++ // it has no calls that can cause such "return" entries ++ assert !frameMap.accessesCallerFrame(); ++ } ++ } ++ ++ @Override ++ public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { ++ RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; ++ return new SW64HotSpotRegisterAllocationConfig(registerConfigNonNull, allocationRestrictedTo); ++ } ++ ++ @Override ++ public EconomicSet translateToCallerRegisters(EconomicSet calleeRegisters) { ++ return calleeRegisters; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotConstantRetrievalOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotConstantRetrievalOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotConstantRetrievalOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotConstantRetrievalOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import java.util.ArrayList; ++import java.util.EnumSet; ++ ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++import jdk.vm.ci.meta.Value; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.LIRValueUtil; ++import org.graalvm.compiler.lir.ValueProcedure; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++public final class SW64HotSpotConstantRetrievalOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotConstantRetrievalOp.class); ++ ++ @Def protected AllocatableValue result; ++ protected final Constant[] constants; ++ @Alive protected AllocatableValue[] constantDescriptions; ++ @Temp protected AllocatableValue[] gotSlotOffsetParameters; ++ @Temp protected AllocatableValue[] descriptionParameters; ++ @Temp protected Value[] callTemps; ++ @State protected LIRFrameState frameState; ++ private final ForeignCallLinkage callLinkage; ++ private final Object[] notes; ++ ++ private class CollectTemporaries implements ValueProcedure { ++ ArrayList values = new ArrayList<>(); ++ ++ CollectTemporaries() { ++ forEachTemp(this); ++ } ++ ++ public Value[] asArray() { ++ Value[] copy = new Value[values.size()]; ++ return values.toArray(copy); ++ } ++ ++ @Override ++ public Value doValue(Value value, OperandMode mode, EnumSet flags) { ++ values.add(value); ++ return value; ++ } ++ } ++ ++ public SW64HotSpotConstantRetrievalOp(Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState, ForeignCallLinkage callLinkage, Object[] notes) { ++ super(TYPE); ++ this.constantDescriptions = constantDescriptions; ++ this.constants = constants; ++ this.frameState = frameState; ++ this.notes = notes; ++ assert constants.length == notes.length; ++ ++ // call arguments ++ CallingConvention callingConvention = callLinkage.getOutgoingCallingConvention(); ++ this.gotSlotOffsetParameters = new AllocatableValue[constants.length]; ++ int argIndex = 0; ++ for (int i = 0; i < constants.length; i++, argIndex++) { ++ this.gotSlotOffsetParameters[i] = callingConvention.getArgument(argIndex); ++ } ++ this.descriptionParameters = new AllocatableValue[constantDescriptions.length]; ++ for (int i = 0; i < constantDescriptions.length; i++, argIndex++) { ++ this.descriptionParameters[i] = callingConvention.getArgument(argIndex); ++ } ++ this.result = callingConvention.getReturn(); ++ ++ this.callLinkage = callLinkage; ++ ++ // compute registers that are killed by the stub, but are not used as other temps. ++ this.callTemps = new Value[0]; ++ this.callTemps = LIRValueUtil.subtractRegisters(callLinkage.getTemporaries(), new CollectTemporaries().asArray()); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // metadata_adr ++ for (int i = 0; i < constants.length; i++) { ++ crb.recordInlineDataInCodeWithNote(constants[i], notes[i]); ++ masm.addressOf(asRegister(gotSlotOffsetParameters[i])); ++ } ++ ++ for (int i = 0; i < constantDescriptions.length; i++) { ++ masm.mov(64, asRegister(descriptionParameters[i]), asRegister(constantDescriptions[i])); ++ } ++ ++ final int before = masm.position(); ++ masm.bl(before); ++ final int after = masm.position(); ++ crb.recordDirectCall(before, after, callLinkage, frameState); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallEpilogueOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallEpilogueOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallEpilogueOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallEpilogueOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.zr; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++ ++@Opcode("CRUNTIME_CALL_EPILOGUE") ++public class SW64HotSpotCRuntimeCallEpilogueOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotCRuntimeCallEpilogueOp.class); ++ ++ private final int threadLastJavaSpOffset; ++ private final int threadLastJavaPcOffset; ++ private final Register thread; ++ @SuppressWarnings("unused") private final Label label; ++ ++ public SW64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, Register thread, Label label) { ++ super(TYPE); ++ this.threadLastJavaSpOffset = threadLastJavaSpOffset; ++ this.threadLastJavaPcOffset = threadLastJavaPcOffset; ++ this.thread = thread; ++ this.label = label; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // Reset last Java frame: ++ masm.str(64, zr, masm.makeAddress(thread, threadLastJavaSpOffset, 8)); ++ masm.str(64, zr, masm.makeAddress(thread, threadLastJavaPcOffset, 8)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallPrologueOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallPrologueOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallPrologueOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotCRuntimeCallPrologueOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++@Opcode("CRUNTIME_CALL_PROLOGUE") ++public class SW64HotSpotCRuntimeCallPrologueOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotCRuntimeCallPrologueOp.class); ++ ++ private final int threadLastJavaSpOffset; ++ private final int threadLastJavaPcOffset; ++ private final Register thread; ++ @Temp({REG}) protected AllocatableValue scratch; ++ private final Label label; ++ ++ public SW64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, Register thread, AllocatableValue scratch, Label label) { ++ super(TYPE); ++ this.threadLastJavaSpOffset = threadLastJavaSpOffset; ++ this.threadLastJavaPcOffset = threadLastJavaPcOffset; ++ this.thread = thread; ++ this.scratch = scratch; ++ this.label = label; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // Save last Java frame. ++ // We cannot save the SP directly so use a temporary register. ++ Register scratchRegister = asRegister(scratch); ++ masm.movx(scratchRegister, sp); ++ masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaSpOffset, 8)); ++ ++ // Get the current PC. Use a label to patch the return address. ++ masm.adr(scratchRegister, label); ++ masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaPcOffset, 8)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeCallerOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeCallerOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeCallerOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeCallerOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,52 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++/** ++ * Removes the current frame and tail calls the uncommon trap routine. ++ */ ++@Opcode("DEOPT_CALLER") ++public class SW64HotSpotDeoptimizeCallerOp extends SW64HotSpotEpilogueOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotDeoptimizeCallerOp.class); ++ ++ public SW64HotSpotDeoptimizeCallerOp(GraalHotSpotVMConfig config) { ++ super(TYPE, config); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ leaveFrame(crb, masm, /* emitSafepoint */false, false); ++ SW64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDeoptimizeOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.StandardOp.BlockEndOp; ++import org.graalvm.compiler.lir.sw64.SW64BlockEndOp; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++@Opcode("DEOPT") ++public class SW64HotSpotDeoptimizeOp extends SW64BlockEndOp implements BlockEndOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotDeoptimizeOp.class); ++ ++ @State private LIRFrameState info; ++ ++ public SW64HotSpotDeoptimizeOp(LIRFrameState info) { ++ super(TYPE); ++ this.info = info; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ try (SW64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) { ++ SW64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), scratch.getRegister(), info, null); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectStaticCallOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectStaticCallOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectStaticCallOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectStaticCallOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.inlineCacheRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64Call.DirectCallOp; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; ++ ++import jdk.vm.ci.meta.ResolvedJavaMethod; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for ++ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. ++ */ ++@Opcode("CALL_DIRECT") ++final class SW64HotSpotDirectStaticCallOp extends DirectCallOp { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotDirectStaticCallOp.class); ++ ++ private final InvokeKind invokeKind; ++ private final GraalHotSpotVMConfig config; ++ ++ SW64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { ++ super(TYPE, target, result, parameters, temps, state); ++ assert invokeKind.isDirect(); ++ this.invokeKind = invokeKind; ++ this.config = config; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // The mark for an invocation that uses an inline cache must be placed at the ++ // instruction that loads the Klass from the inline cache. ++ // For the first invocation this is set to a bitpattern that is guaranteed to never be a ++ // valid object which causes the called function to call a handler that installs the ++ // correct inline cache value here. ++ crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); ++ masm.movNativeAddress(inlineCacheRegister, config.nonOopBits); ++ super.emitCode(crb, masm); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectVirtualCallOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectVirtualCallOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectVirtualCallOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotDirectVirtualCallOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.inlineCacheRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64Call.DirectCallOp; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; ++ ++import jdk.vm.ci.meta.ResolvedJavaMethod; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for ++ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. ++ */ ++@Opcode("CALL_DIRECT") ++final class SW64HotSpotDirectVirtualCallOp extends DirectCallOp { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotDirectVirtualCallOp.class); ++ ++ private final InvokeKind invokeKind; ++ private final GraalHotSpotVMConfig config; ++ ++ SW64HotSpotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { ++ super(TYPE, target, result, parameters, temps, state); ++ assert invokeKind.isIndirect(); ++ this.invokeKind = invokeKind; ++ this.config = config; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // The mark for an invocation that uses an inline cache must be placed at the ++ // instruction that loads the Klass from the inline cache. ++ // For the first invocation this is set to a bitpattern that is guaranteed to never be a ++ // valid object which causes the called function to call a handler that installs the ++ // correct inline cache value here. ++ crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); ++ masm.movNativeAddress(inlineCacheRegister, config.nonOopBits); ++ super.emitCode(crb, masm); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotEpilogueOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotEpilogueOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotEpilogueOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotEpilogueOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,103 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.lr; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.fp; ++import static org.graalvm.compiler.hotspot.HotSpotHostBackend.ENABLE_STACK_RESERVED_ZONE; ++import static org.graalvm.compiler.hotspot.HotSpotHostBackend.THROW_DELAYED_STACKOVERFLOW_ERROR; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.ScratchRegister; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.sw64.SW64BlockEndOp; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterValue; ++ ++/** ++ * Superclass for operations that leave a method's frame. ++ */ ++abstract class SW64HotSpotEpilogueOp extends SW64BlockEndOp { ++ ++ private final GraalHotSpotVMConfig config; ++ private final Register thread; ++ ++ protected SW64HotSpotEpilogueOp(LIRInstructionClass c, GraalHotSpotVMConfig config, Register thread) { ++ super(c); ++ this.config = config; ++ this.thread = thread; ++ } ++ ++ protected SW64HotSpotEpilogueOp(LIRInstructionClass c, GraalHotSpotVMConfig config) { ++ super(c); ++ this.config = config; ++ this.thread = null; // no safepoint ++ } ++ ++ protected void leaveFrame(CompilationResultBuilder crb, SW64MacroAssembler masm, boolean emitSafepoint, boolean requiresReservedStackAccessCheck) { ++ assert crb.frameContext != null : "We never elide frames in sw64"; ++ crb.frameContext.leave(crb); ++ if (requiresReservedStackAccessCheck) { ++ HotSpotForeignCallsProvider foreignCalls = (HotSpotForeignCallsProvider) crb.foreignCalls; ++ Label noReserved = new Label(); ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ masm.ldr(64, scratch, masm.makeAddress(thread, config.javaThreadReservedStackActivationOffset, 8)); ++ masm.subs(64, zr, sp, scratch); ++ } ++ masm.branchConditionally(SW64Assembler.ConditionFlag.LO, noReserved); ++ ForeignCallLinkage enableStackReservedZone = foreignCalls.lookupForeignCall(ENABLE_STACK_RESERVED_ZONE); ++ CallingConvention cc = enableStackReservedZone.getOutgoingCallingConvention(); ++ assert cc.getArgumentCount() == 1; ++ Register arg0 = ((RegisterValue) cc.getArgument(0)).getRegister(); ++ masm.mov(64, arg0, thread); ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ masm.stp(64, fp, lr, SW64Address.createPreIndexedImmediateAddress(sp, -2)); ++ SW64Call.directCall(crb, masm, enableStackReservedZone, sc.getRegister(), null); ++ masm.ldp(64, fp, lr, SW64Address.createPostIndexedImmediateAddress(sp, 2)); ++ } ++ SW64Call.directJmp(crb, masm, foreignCalls.lookupForeignCall(THROW_DELAYED_STACKOVERFLOW_ERROR)); ++ masm.bind(noReserved); ++ } ++ if (emitSafepoint) { ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ SW64HotSpotSafepointOp.emitCode(crb, masm, config, true, thread, scratch, null); ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotForeignCallsProvider.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotForeignCallsProvider.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotForeignCallsProvider.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotForeignCallsProvider.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.r0; ++import static jdk.vm.ci.sw64.SW64.r3; ++import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; ++import static jdk.vm.ci.meta.Value.ILLEGAL; ++import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS; ++import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; ++import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF; ++import static org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions.UPDATE_BYTES_CRC32C; ++import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; ++import static jdk.internal.vm.compiler.word.LocationIdentity.any; ++ ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.HotSpotBackend; ++import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; ++import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotProviders; ++import org.graalvm.compiler.options.OptionValues; ++import org.graalvm.compiler.word.WordTypes; ++ ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.CodeCacheProvider; ++import jdk.vm.ci.code.RegisterValue; ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; ++import jdk.vm.ci.meta.MetaAccessProvider; ++import jdk.vm.ci.meta.PlatformKind; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider { ++ ++ private final Value[] nativeABICallerSaveRegisters; ++ ++ public SW64HotSpotForeignCallsProvider(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ++ WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { ++ super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); ++ this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters; ++ } ++ ++ @Override ++ public void initialize(HotSpotProviders providers, OptionValues options) { ++ GraalHotSpotVMConfig config = runtime.getVMConfig(); ++ TargetDescription target = providers.getCodeCache().getTarget(); ++ PlatformKind word = target.arch.getWordKind(); ++ ++ // The calling convention for the exception handler stub is (only?) defined in ++ // TemplateInterpreterGenerator::generate_throw_exception() ++ RegisterValue exception = r0.asValue(LIRKind.reference(word)); ++ RegisterValue exceptionPc = r3.asValue(LIRKind.value(word)); ++ CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc); ++ register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any())); ++ register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any())); ++ ++ // These stubs do callee saving ++ if (config.useCRC32Intrinsics) { ++ registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, any()); ++ } ++ if (config.useCRC32CIntrinsics) { ++ registerForeignCall(UPDATE_BYTES_CRC32C, config.updateBytesCRC32C, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, any()); ++ } ++ ++ super.initialize(providers, options); ++ } ++ ++ @Override ++ public Value[] getNativeABICallerSaveRegisters() { ++ return nativeABICallerSaveRegisters; ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotJumpToExceptionHandlerInCallerOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotJumpToExceptionHandlerInCallerOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotJumpToExceptionHandlerInCallerOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotJumpToExceptionHandlerInCallerOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,90 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.fp; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.ScratchRegister; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.serviceprovider.GraalServices; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Sets up the arguments for an exception handler in the callers frame, removes the current frame ++ * and jumps to the handler. ++ */ ++@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") ++public class SW64HotSpotJumpToExceptionHandlerInCallerOp extends SW64HotSpotEpilogueOp { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotJumpToExceptionHandlerInCallerOp.class); ++ ++ @Use(REG) private AllocatableValue handlerInCallerPc; ++ @Use(REG) private AllocatableValue exception; ++ @Use(REG) private AllocatableValue exceptionPc; ++ private final Register thread; ++ private final int isMethodHandleReturnOffset; ++ ++ public SW64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, ++ Register thread, GraalHotSpotVMConfig config) { ++ super(TYPE, config); ++ this.handlerInCallerPc = handlerInCallerPc; ++ this.exception = exception; ++ this.exceptionPc = exceptionPc; ++ this.isMethodHandleReturnOffset = isMethodHandleReturnOffset; ++ this.thread = thread; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ leaveFrame(crb, masm, /* emitSafepoint */false, false); ++ ++ if (GraalServices.JAVA_SPECIFICATION_VERSION < 8) { ++ // Restore sp from fp if the exception PC is a method handle call site. ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ final boolean allowOverwrite = false; ++ SW64Address address = masm.makeAddress(thread, isMethodHandleReturnOffset, scratch, 4, allowOverwrite); ++ masm.ldr(32, scratch, address); ++ Label noRestore = new Label(); ++ masm.cbz(32, scratch, noRestore); ++ masm.mov(64, sp, fp); ++ masm.bind(noRestore); ++ } ++ } ++ ++ masm.jmp(asRegister(handlerInCallerPc)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLIRGenerator.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLIRGenerator.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLIRGenerator.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLIRGenerator.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,550 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; ++import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE; ++import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; ++import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; ++import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; ++import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; ++ ++import java.util.function.Function; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ConditionFlag; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.PrefetchMode; ++import org.graalvm.compiler.core.sw64.SW64ArithmeticLIRGenerator; ++import org.graalvm.compiler.core.sw64.SW64LIRGenerator; ++import org.graalvm.compiler.core.sw64.SW64LIRKindTool; ++import org.graalvm.compiler.core.common.CompressEncoding; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.calc.Condition; ++import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.core.common.spi.LIRKindTool; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.HotSpotBackend; ++import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; ++import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; ++import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; ++import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; ++import org.graalvm.compiler.hotspot.HotSpotLockStack; ++import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; ++import org.graalvm.compiler.hotspot.meta.HotSpotProviders; ++import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; ++import org.graalvm.compiler.hotspot.stubs.Stub; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstruction; ++import org.graalvm.compiler.lir.LabelRef; ++import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; ++import org.graalvm.compiler.lir.SwitchStrategy; ++import org.graalvm.compiler.lir.Variable; ++import org.graalvm.compiler.lir.VirtualStackSlot; ++import org.graalvm.compiler.lir.sw64.SW64AddressValue; ++import org.graalvm.compiler.lir.sw64.SW64CCall; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow.StrategySwitchOp; ++import org.graalvm.compiler.lir.sw64.SW64FrameMapBuilder; ++import org.graalvm.compiler.lir.sw64.SW64Move; ++import org.graalvm.compiler.lir.sw64.SW64Move.StoreOp; ++import org.graalvm.compiler.lir.sw64.SW64PrefetchOp; ++import org.graalvm.compiler.lir.sw64.SW64RestoreRegistersOp; ++import org.graalvm.compiler.lir.sw64.SW64SaveRegistersOp; ++import org.graalvm.compiler.lir.gen.LIRGenerationResult; ++import org.graalvm.compiler.options.OptionValues; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterValue; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; ++import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; ++import jdk.vm.ci.hotspot.HotSpotObjectConstant; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++import jdk.vm.ci.meta.DeoptimizationAction; ++import jdk.vm.ci.meta.DeoptimizationReason; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.PlatformKind; ++import jdk.vm.ci.meta.SpeculationLog; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * LIR generator specialized for SW64 HotSpot. ++ */ ++public class SW64HotSpotLIRGenerator extends SW64LIRGenerator implements HotSpotLIRGenerator { ++ ++ final GraalHotSpotVMConfig config; ++ private HotSpotDebugInfoBuilder debugInfoBuilder; ++ ++ protected SW64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { ++ this(new SW64LIRKindTool(), new SW64ArithmeticLIRGenerator(), new SW64HotSpotMoveFactory(), providers, config, lirGenRes); ++ } ++ ++ protected SW64HotSpotLIRGenerator(LIRKindTool lirKindTool, SW64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, ++ LIRGenerationResult lirGenRes) { ++ super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); ++ this.config = config; ++ } ++ ++ @Override ++ public HotSpotProviders getProviders() { ++ return (HotSpotProviders) super.getProviders(); ++ } ++ ++ @Override ++ public boolean needOnlyOopMaps() { ++ // Stubs only need oop maps ++ return getResult().getStub() != null; ++ } ++ ++ private LIRFrameState currentRuntimeCallInfo; ++ ++ @Override ++ protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { ++ currentRuntimeCallInfo = info; ++ if (SW64Call.isNearCall(linkage)) { ++ append(new SW64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label)); ++ } else { ++ append(new SW64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label)); ++ } ++ } ++ ++ @Override ++ public void emitTailcall(Value[] args, Value address) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args) { ++ Value[] argLocations = new Value[args.length]; ++ getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention); ++ for (int i = 0; i < args.length; i++) { ++ Value arg = args[i]; ++ AllocatableValue loc = nativeCallingConvention.getArgument(i); ++ emitMove(loc, arg); ++ argLocations[i] = loc; ++ } ++ Value ptr = emitLoadConstant(LIRKind.value(SW64Kind.QWORD), JavaConstant.forLong(address)); ++ append(new SW64CCall(nativeCallingConvention.getReturn(), ptr, argLocations)); ++ } ++ ++ /** ++ * @param savedRegisters the registers saved by this operation which may be subject to pruning ++ * @param savedRegisterLocations the slots to which the registers are saved ++ * @param supportsRemove determines if registers can be pruned ++ */ ++ protected SW64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { ++ SW64SaveRegistersOp save = new SW64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove); ++ append(save); ++ return save; ++ } ++ ++ /** ++ * Allocate a stack slot for saving a register. ++ */ ++ protected VirtualStackSlot allocateSaveRegisterLocation(Register register) { ++ PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory()); ++ if (kind.getVectorLength() > 1) { ++ // we don't use vector registers, so there is no need to save them ++ kind = SW64Kind.QWORD; ++ } ++ return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind)); ++ } ++ ++ /** ++ * Adds a node to the graph that saves all allocatable registers to the stack. ++ * ++ * @param supportsRemove determines if registers can be pruned ++ * @return the register save node ++ */ ++ private SW64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) { ++ AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length]; ++ for (int i = 0; i < savedRegisters.length; i++) { ++ savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]); ++ } ++ return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove); ++ } ++ ++ protected void emitRestoreRegisters(SW64SaveRegistersOp save) { ++ append(new SW64RestoreRegistersOp(save.getSlots().clone(), save)); ++ } ++ ++ @Override ++ public VirtualStackSlot getLockSlot(int lockDepth) { ++ return getLockStack().makeLockSlot(lockDepth); ++ } ++ ++ private HotSpotLockStack getLockStack() { ++ assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; ++ return debugInfoBuilder.lockStack(); ++ } ++ ++ @Override ++ public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, ++ double trueDestinationProbability) { ++ Value localX = x; ++ Value localY = y; ++ if (localX instanceof HotSpotObjectConstant) { ++ localX = load(localX); ++ } ++ if (localY instanceof HotSpotObjectConstant) { ++ localY = load(localY); ++ } ++ super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); ++ } ++ ++ @Override ++ protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) { ++ Value localA = a; ++ Value localB = b; ++ if (isConstantValue(a)) { ++ Constant c = asConstant(a); ++ if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { ++ localA = SW64.zr.asValue(LIRKind.value(SW64Kind.DWORD)); ++ } else if (c instanceof HotSpotObjectConstant) { ++ localA = load(localA); ++ } ++ } ++ if (isConstantValue(b)) { ++ Constant c = asConstant(b); ++ if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { ++ localB = SW64.zr.asValue(LIRKind.value(SW64Kind.DWORD)); ++ } else if (c instanceof HotSpotObjectConstant) { ++ localB = load(localB); ++ } ++ } ++ return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue); ++ } ++ ++ @Override ++ public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { ++ LIRKind inputKind = pointer.getValueKind(LIRKind.class); ++ LIRKindTool lirKindTool = getLIRKindTool(); ++ assert inputKind.getPlatformKind() == SW64Kind.QWORD; ++ if (inputKind.isReference(0)) { ++ // oop ++ Variable result = newVariable(LIRKind.compressedReference(SW64Kind.DWORD)); ++ append(new SW64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); ++ return result; ++ } else { ++ // metaspace pointer ++ Variable result = newVariable(LIRKind.value(SW64Kind.DWORD)); ++ AllocatableValue base = Value.ILLEGAL; ++ OptionValues options = getResult().getLIR().getOptions(); ++ if (encoding.hasBase() || GeneratePIC.getValue(options)) { ++ if (GeneratePIC.getValue(options)) { ++ Variable baseAddress = newVariable(lirKindTool.getWordKind()); ++ SW64HotSpotMove.BaseMove move = new SW64HotSpotMove.BaseMove(baseAddress, config); ++ append(move); ++ base = baseAddress; ++ } else { ++ base = emitLoadConstant(LIRKind.value(SW64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); ++ } ++ } ++ append(new SW64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); ++ return result; ++ } ++ } ++ ++ @Override ++ public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { ++ LIRKind inputKind = pointer.getValueKind(LIRKind.class); ++ assert inputKind.getPlatformKind() == SW64Kind.DWORD; ++ if (inputKind.isReference(0)) { ++ // oop ++ Variable result = newVariable(LIRKind.reference(SW64Kind.QWORD)); ++ append(new SW64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); ++ return result; ++ } else { ++ // metaspace pointer ++ Variable result = newVariable(LIRKind.value(SW64Kind.QWORD)); ++ AllocatableValue base = Value.ILLEGAL; ++ OptionValues options = getResult().getLIR().getOptions(); ++ if (encoding.hasBase() || GeneratePIC.getValue(options)) { ++ if (GeneratePIC.getValue(options)) { ++ Variable baseAddress = newVariable(LIRKind.value(SW64Kind.QWORD)); ++ SW64HotSpotMove.BaseMove move = new SW64HotSpotMove.BaseMove(baseAddress, config); ++ append(move); ++ base = baseAddress; ++ } else { ++ base = emitLoadConstant(LIRKind.value(SW64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); ++ } ++ } ++ append(new SW64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); ++ return result; ++ } ++ } ++ ++ @Override ++ public void emitNullCheck(Value address, LIRFrameState state) { ++ if (address.getValueKind().getPlatformKind() == SW64Kind.DWORD) { ++ CompressEncoding encoding = config.getOopEncoding(); ++ Value uncompressed = emitUncompress(address, encoding, false); ++ append(new SW64Move.NullCheckOp(asAddressValue(uncompressed), state)); ++ } else { ++ super.emitNullCheck(address, state); ++ } ++ } ++ ++ @Override ++ public void emitPrefetchAllocate(Value address) { ++ append(new SW64PrefetchOp(asAddressValue(address), PrefetchMode.PSTL1KEEP)); ++ } ++ ++ @Override ++ public void beforeRegisterAllocation() { ++ super.beforeRegisterAllocation(); ++ boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); ++ if (hasDebugInfo) { ++ getResult().setDeoptimizationRescueSlot(((SW64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); ++ } ++ ++ getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); ++ } ++ ++ private Label label; ++ ++ @Override ++ public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { ++ HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; ++ boolean destroysRegisters = hotspotLinkage.destroysRegisters(); ++ ++ SW64SaveRegistersOp save = null; ++ Stub stub = getStub(); ++ if (destroysRegisters) { ++ if (stub != null && stub.preservesRegisters()) { ++ Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray(); ++ save = emitSaveAllRegisters(savedRegisters, true); ++ } ++ } ++ ++ Variable result; ++ LIRFrameState debugInfo = null; ++ if (hotspotLinkage.needsDebugInfo()) { ++ debugInfo = state; ++ assert debugInfo != null || getStub() != null; ++ } ++ ++ if (destroysRegisters || hotspotLinkage.needsJavaFrameAnchor()) { ++ HotSpotRegistersProvider registers = getProviders().getRegisters(); ++ Register thread = registers.getThreadRegister(); ++ Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind())); ++ ++ // We need a label for the return address. ++ label = new Label(); ++ ++ append(new SW64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, scratch, label)); ++ result = super.emitForeignCall(hotspotLinkage, debugInfo, args); ++ append(new SW64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, label)); ++ ++ // Clear it out so it's not being reused later. ++ label = null; ++ } else { ++ result = super.emitForeignCall(hotspotLinkage, debugInfo, args); ++ } ++ ++ if (destroysRegisters) { ++ if (stub != null) { ++ if (stub.preservesRegisters()) { ++ HotSpotLIRGenerationResult generationResult = getResult(); ++ LIRFrameState key = currentRuntimeCallInfo; ++ if (key == null) { ++ key = LIRFrameState.NO_STATE; ++ } ++ assert !generationResult.getCalleeSaveInfo().containsKey(key); ++ generationResult.getCalleeSaveInfo().put(key, save); ++ emitRestoreRegisters(save); ++ } ++ } ++ } ++ ++ return result; ++ } ++ ++ @Override ++ public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { ++ Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); ++ Value speculation = emitJavaConstant(getMetaAccess().encodeSpeculation(SpeculationLog.NO_SPECULATION)); ++ moveDeoptValuesToThread(actionAndReason, speculation); ++ append(new SW64HotSpotDeoptimizeCallerOp(config)); ++ } ++ ++ @Override ++ public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) { ++ moveDeoptValuesToThread(actionAndReason, failedSpeculation); ++ append(new SW64HotSpotDeoptimizeOp(state)); ++ } ++ ++ private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { ++ moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); ++ moveValueToThread(speculation, config.pendingFailedSpeculationOffset); ++ } ++ ++ private void moveValueToThread(Value value, int offset) { ++ LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); ++ RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); ++ final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes(); ++ SW64AddressValue address = new SW64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, offset, transferSize, AddressingMode.IMMEDIATE_SCALED); ++ append(new StoreOp((SW64Kind) value.getPlatformKind(), address, loadReg(value), null)); ++ } ++ ++ @Override ++ public void emitUnwind(Value exception) { ++ ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); ++ CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); ++ assert outgoingCc.getArgumentCount() == 2; ++ RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0); ++ emitMove(exceptionParameter, exception); ++ append(new SW64HotSpotUnwindOp(config, exceptionParameter)); ++ } ++ ++ @Override ++ public Value emitLoadObjectAddress(Constant constant) { ++ HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant; ++ LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind(); ++ Variable result = newVariable(kind); ++ append(new SW64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE)); ++ return result; ++ } ++ ++ @Override ++ public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { ++ HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant; ++ LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind(); ++ Variable result = newVariable(kind); ++ append(new SW64HotSpotLoadAddressOp(result, constant, action)); ++ return result; ++ } ++ ++ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { ++ ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall); ++ append(new SW64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); ++ AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); ++ return emitMove(result); ++ } ++ ++ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { ++ Constant[] constants = new Constant[]{constant}; ++ Object[] notes = new Object[]{action}; ++ return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState); ++ } ++ ++ @Override ++ public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) { ++ AllocatableValue[] constantDescriptions = new AllocatableValue[0]; ++ return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState); ++ } ++ ++ @Override ++ public Value emitLoadConfigValue(int markId, LIRKind kind) { ++ Variable result = newVariable(kind); ++ append(new SW64HotSpotLoadConfigValueOp(markId, result)); ++ return result; ++ } ++ ++ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) { ++ AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; ++ return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState); ++ } ++ ++ @Override ++ public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { ++ return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); ++ } ++ ++ @Override ++ public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { ++ return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); ++ } ++ ++ @Override ++ public void emitReturn(JavaKind kind, Value input) { ++ AllocatableValue operand = Value.ILLEGAL; ++ if (input != null) { ++ operand = resultOperandFor(kind, input.getValueKind()); ++ emitMove(operand, input); ++ } ++ Register thread = getProviders().getRegisters().getThreadRegister(); ++ append(new SW64HotSpotReturnOp(operand, getStub() != null, config, thread, getResult().requiresReservedStackAccessCheck())); ++ } ++ ++ @Override ++ public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { ++ return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState); ++ } ++ ++ @Override ++ public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { ++ AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; ++ return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState); ++ } ++ ++ /** ++ * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not ++ * being generated. ++ */ ++ public Stub getStub() { ++ return getResult().getStub(); ++ } ++ ++ @Override ++ public HotSpotLIRGenerationResult getResult() { ++ return ((HotSpotLIRGenerationResult) super.getResult()); ++ } ++ ++ @Override ++ protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, ++ Function converter) { ++ return new SW64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter); ++ } ++ ++ public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { ++ this.debugInfoBuilder = debugInfoBuilder; ++ } ++ ++ @Override ++ public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { ++ throw GraalError.unimplemented(); ++ } ++ ++ @Override ++ public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { ++ throw GraalError.unimplemented(); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadAddressOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadAddressOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadAddressOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadAddressOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++public final class SW64HotSpotLoadAddressOp extends SW64LIRInstruction { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotLoadAddressOp.class); ++ ++ @Def({OperandFlag.REG}) protected AllocatableValue result; ++ private final Constant constant; ++ private final Object note; ++ ++ public SW64HotSpotLoadAddressOp(AllocatableValue result, Constant constant, Object note) { ++ super(TYPE); ++ this.result = result; ++ this.constant = constant; ++ this.note = note; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ crb.recordInlineDataInCodeWithNote(constant, note); ++ SW64Kind kind = (SW64Kind) result.getPlatformKind(); ++ int size = 0; ++ switch (kind) { ++ case DWORD: ++ size = 32; ++ break; ++ case QWORD: ++ size = 64; ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("unexpected kind: " + kind); ++ } ++ if (crb.compilationResult.isImmutablePIC()) { ++ Register dst = asRegister(result); ++ masm.addressOf(dst); ++ masm.ldr(size, dst, SW64Address.createBaseRegisterOnlyAddress(dst)); ++ } else { ++ masm.ldr(size, asRegister(result), masm.getPlaceholder(-1)); ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadConfigValueOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadConfigValueOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadConfigValueOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoadConfigValueOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++public final class SW64HotSpotLoadConfigValueOp extends SW64LIRInstruction { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotLoadConfigValueOp.class); ++ ++ @Def({OperandFlag.REG}) protected AllocatableValue result; ++ private final int markId; ++ ++ public SW64HotSpotLoadConfigValueOp(int markId, AllocatableValue result) { ++ super(TYPE); ++ this.result = result; ++ this.markId = markId; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ if (GeneratePIC.getValue(crb.getOptions())) { ++ SW64Kind kind = (SW64Kind) result.getPlatformKind(); ++ Register reg = asRegister(result); ++ masm.adrp(reg); ++ masm.add(64, reg, reg, 1); ++ switch (kind) { ++ case BYTE: ++ masm.ldrs(8, 32, reg, SW64Address.createBaseRegisterOnlyAddress(reg)); ++ break; ++ case WORD: ++ masm.ldrs(16, 32, reg, SW64Address.createBaseRegisterOnlyAddress(reg)); ++ break; ++ case DWORD: ++ masm.ldr(32, reg, SW64Address.createBaseRegisterOnlyAddress(reg)); ++ break; ++ case QWORD: ++ masm.ldr(64, reg, SW64Address.createBaseRegisterOnlyAddress(reg)); ++ break; ++ default: ++ throw GraalError.unimplemented(); ++ } ++ masm.nop(); ++ } else { ++ throw GraalError.unimplemented(); ++ } ++ crb.recordMark(markId); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoweringProvider.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoweringProvider.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoweringProvider.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotLoweringProvider.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; ++import org.graalvm.compiler.debug.DebugHandlersFactory; ++import org.graalvm.compiler.graph.Node; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; ++import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; ++import org.graalvm.compiler.hotspot.meta.HotSpotProviders; ++import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; ++import org.graalvm.compiler.nodes.calc.FloatConvertNode; ++import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; ++import org.graalvm.compiler.nodes.calc.RemNode; ++import org.graalvm.compiler.nodes.spi.LoweringTool; ++import org.graalvm.compiler.options.OptionValues; ++import org.graalvm.compiler.replacements.sw64.SW64FloatArithmeticSnippets; ++import org.graalvm.compiler.replacements.sw64.SW64IntegerArithmeticSnippets; ++ ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; ++import jdk.vm.ci.meta.MetaAccessProvider; ++ ++public class SW64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider { ++ ++ private SW64IntegerArithmeticSnippets integerArithmeticSnippets; ++ private SW64FloatArithmeticSnippets floatArithmeticSnippets; ++ ++ public SW64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, ++ HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { ++ super(runtime, metaAccess, foreignCalls, registers, constantReflection, target); ++ } ++ ++ @Override ++ public void initialize(OptionValues options, Iterable factories, HotSpotProviders providers, GraalHotSpotVMConfig config) { ++ integerArithmeticSnippets = new SW64IntegerArithmeticSnippets(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); ++ floatArithmeticSnippets = new SW64FloatArithmeticSnippets(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); ++ super.initialize(options, factories, providers, config); ++ } ++ ++ @Override ++ public void lower(Node n, LoweringTool tool) { ++ if (n instanceof IntegerDivRemNode) { ++ integerArithmeticSnippets.lower((IntegerDivRemNode) n, tool); ++ } else if (n instanceof RemNode) { ++ floatArithmeticSnippets.lower((RemNode) n, tool); ++ } else if (n instanceof FloatConvertNode) { ++ // AMD64 has custom lowerings for ConvertNodes, HotSpotLoweringProvider does not expect ++ // to see a ConvertNode and throws an error, just do nothing here. ++ } else { ++ super.lower(n, tool); ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMoveFactory.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMoveFactory.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMoveFactory.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMoveFactory.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (c) 2015, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL; ++import static jdk.vm.ci.meta.JavaConstant.INT_0; ++import static jdk.vm.ci.meta.JavaConstant.LONG_0; ++ ++import org.graalvm.compiler.core.sw64.SW64MoveFactory; ++import org.graalvm.compiler.lir.LIRInstruction; ++ ++import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; ++import jdk.vm.ci.hotspot.HotSpotConstant; ++import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; ++import jdk.vm.ci.hotspot.HotSpotObjectConstant; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++ ++public class SW64HotSpotMoveFactory extends SW64MoveFactory { ++ ++ @Override ++ public boolean canInlineConstant(Constant c) { ++ if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { ++ return true; ++ } else if (c instanceof HotSpotObjectConstant || c instanceof HotSpotMetaspaceConstant) { ++ return false; ++ } else { ++ return super.canInlineConstant(c); ++ } ++ } ++ ++ @Override ++ public LIRInstruction createLoad(AllocatableValue dst, Constant src) { ++ Constant usedSource; ++ if (COMPRESSED_NULL.equals(src)) { ++ usedSource = INT_0; ++ } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) { ++ usedSource = LONG_0; ++ } else { ++ usedSource = src; ++ } ++ if (usedSource instanceof HotSpotConstant) { ++ HotSpotConstant constant = (HotSpotConstant) usedSource; ++ if (constant.isCompressed()) { ++ return new SW64HotSpotMove.LoadHotSpotObjectConstantInline(constant, dst); ++ } else { ++ // XXX Do we need the constant table? ++ // return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst, ++ // constantTableBaseProvider.getConstantTableBase()); ++ return new SW64HotSpotMove.LoadHotSpotObjectConstantInline(constant, dst); ++ } ++ } else { ++ return super.createLoad(dst, usedSource); ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMove.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMove.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMove.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotMove.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,244 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static jdk.vm.ci.code.ValueUtil.isRegister; ++import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.CompressEncoding; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRInstruction; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.hotspot.HotSpotConstant; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++ ++public class SW64HotSpotMove { ++ ++ public static class LoadHotSpotObjectConstantInline extends SW64LIRInstruction implements LoadConstantOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantInline.class); ++ ++ private HotSpotConstant constant; ++ @Def({REG, STACK}) AllocatableValue result; ++ ++ public LoadHotSpotObjectConstantInline(HotSpotConstant constant, AllocatableValue result) { ++ super(TYPE); ++ this.constant = constant; ++ this.result = result; ++ } ++ ++ @Override ++ protected void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ crb.recordInlineDataInCode(constant); ++ if (constant.isCompressed()) { ++ // masm.forceMov(asRegister(result), 0); ++ masm.movNarrowAddress(asRegister(result), 0); ++ } else { ++ masm.movNativeAddress(asRegister(result), 0); ++ } ++ } ++ ++ @Override ++ public AllocatableValue getResult() { ++ return result; ++ } ++ ++ @Override ++ public Constant getConstant() { ++ return constant; ++ } ++ } ++ ++ public static final class BaseMove extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BaseMove.class); ++ ++ @LIRInstruction.Def({REG, HINT}) protected AllocatableValue result; ++ private final GraalHotSpotVMConfig config; ++ ++ public BaseMove(AllocatableValue result, GraalHotSpotVMConfig config) { ++ super(TYPE); ++ this.result = result; ++ this.config = config; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ try (SW64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ masm.adrp(scratch); ++ masm.add(64, scratch, scratch, 1); ++ masm.ldr(64, asRegister(result), SW64Address.createBaseRegisterOnlyAddress(scratch)); ++ masm.nop(); ++ crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS); ++ } ++ } ++ ++ } ++ ++ /** ++ * Compresses a 8-byte pointer as a 4-byte int. ++ */ ++ public static class CompressPointer extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); ++ ++ private final CompressEncoding encoding; ++ private final boolean nonNull; ++ ++ @Def({REG, HINT}) protected AllocatableValue result; ++ @Use({REG}) protected AllocatableValue input; ++ @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; ++ ++ public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { ++ super(TYPE); ++ this.result = result; ++ this.input = input; ++ this.baseRegister = baseRegister; ++ this.encoding = encoding; ++ this.nonNull = nonNull; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register resultRegister = asRegister(result); ++ Register ptr = asRegister(input); ++ Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr); ++ // result = (ptr - base) >> shift ++ if (!encoding.hasBase()) { ++ if (encoding.hasShift()) { ++ masm.lshr(64, resultRegister, ptr, encoding.getShift()); ++ } else { ++ masm.movx(resultRegister, ptr); ++ } ++ } else if (nonNull) { ++ masm.sub(64, resultRegister, ptr, base); ++ if (encoding.hasShift()) { ++ masm.lshr(64, resultRegister, resultRegister, encoding.getShift()); ++ } ++ } else { ++ // if ptr is null it still has to be null after compression ++ masm.cmp(64, ptr, 0); ++ masm.cmov(64, resultRegister, ptr, base, SW64Assembler.ConditionFlag.NE); ++ masm.sub(64, resultRegister, resultRegister, base); ++ if (encoding.hasShift()) { ++ masm.lshr(64, resultRegister, resultRegister, encoding.getShift()); ++ } ++ } ++ } ++ } ++ ++ /** ++ * Decompresses a 4-byte offset into an actual pointer. ++ */ ++ public static class UncompressPointer extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); ++ ++ private final CompressEncoding encoding; ++ private final boolean nonNull; ++ ++ @Def({REG}) protected AllocatableValue result; ++ @Use({REG}) protected AllocatableValue input; ++ @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; ++ ++ public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { ++ super(TYPE); ++ this.result = result; ++ this.input = input; ++ this.baseRegister = baseRegister; ++ this.encoding = encoding; ++ this.nonNull = nonNull; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register inputRegister = asRegister(input); ++ Register resultRegister = asRegister(result); ++ Register base = encoding.hasBase() ? asRegister(baseRegister) : null; ++ emitUncompressCode(masm, inputRegister, resultRegister, base, encoding.getShift(), nonNull); ++ } ++ ++ public static void emitUncompressCode(SW64MacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) { ++ // result = base + (ptr << shift) ++ if (nonNull || baseReg == null) { ++ masm.add(64, resReg, baseReg == null ? zr : baseReg, inputRegister, SW64Assembler.ShiftType.LSL, shift); ++ } else { ++ // if ptr is null it has to be null after decompression ++ Label done = new Label(); ++ if (!resReg.equals(inputRegister)) { ++ masm.mov(32, resReg, inputRegister); ++ } ++ masm.cbz(32, resReg, done); ++ masm.add(64, resReg, baseReg, resReg, SW64Assembler.ShiftType.LSL, shift); ++ masm.bind(done); ++ } ++ } ++ } ++ ++ // ++ // private static void decompressPointer(CompilationResultBuilder crb, ARMv8MacroAssembler masm, ++ // Register result, ++ // Register ptr, long base, int shift, int alignment) { ++ // assert base != 0 || shift == 0 || alignment == shift; ++ // // result = heapBase + ptr << alignment ++ // Register heapBase = ARMv8.heapBaseRegister; ++ // // if result == 0, we make sure that it will still be 0 at the end, so that it traps when ++ // // loading storing a value. ++ // masm.cmp(32, ptr, 0); ++ // masm.add(64, result, heapBase, ptr, ARMv8Assembler.ExtendType.UXTX, alignment); ++ // masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE); ++ // } ++ ++ public static void decodeKlassPointer(CompilationResultBuilder crb, SW64MacroAssembler masm, Register result, Register ptr, CompressEncoding encoding, GraalHotSpotVMConfig config) { ++ try (SW64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) { ++ Register scratch = sc.getRegister(); ++ boolean pic = GeneratePIC.getValue(crb.getOptions()); ++ if (pic || encoding.hasBase() || encoding.getShift() != 0) { ++ if (pic) { ++ masm.addressOf(scratch); ++ masm.ldr(64, scratch, SW64Address.createBaseRegisterOnlyAddress(scratch)); ++ masm.add(64, result, scratch, ptr, SW64Assembler.ExtendType.UXTX, encoding.getShift()); ++ crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS); ++ } else { ++ masm.mov(scratch, encoding.getBase()); ++ masm.add(64, result, scratch, ptr, SW64Assembler.ExtendType.UXTX, encoding.getShift()); ++ } ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotNodeLIRBuilder.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotNodeLIRBuilder.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotNodeLIRBuilder.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotNodeLIRBuilder.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,193 @@ ++/* ++ * Copyright (c) 2015, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.lr; ++import static jdk.vm.ci.code.ValueUtil.isStackSlot; ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.fp; ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.inlineCacheRegister; ++import static jdk.vm.ci.hotspot.sw64.SW64HotSpotRegisterConfig.metaspaceMethodRegister; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; ++ ++import org.graalvm.compiler.core.sw64.SW64NodeLIRBuilder; ++import org.graalvm.compiler.core.sw64.SW64NodeMatchRules; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.core.gen.DebugInfoBuilder; ++import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; ++import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; ++import org.graalvm.compiler.hotspot.HotSpotLockStack; ++import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; ++import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; ++import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.Variable; ++import org.graalvm.compiler.lir.sw64.SW64BreakpointOp; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++import org.graalvm.compiler.nodes.BreakpointNode; ++import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; ++import org.graalvm.compiler.nodes.DirectCallTargetNode; ++import org.graalvm.compiler.nodes.FullInfopointNode; ++import org.graalvm.compiler.nodes.IndirectCallTargetNode; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.ParameterNode; ++import org.graalvm.compiler.nodes.SafepointNode; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.spi.NodeValueMap; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.BytecodeFrame; ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterValue; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.code.ValueUtil; ++import jdk.vm.ci.hotspot.HotSpotCallingConventionType; ++import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.JavaType; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * LIR generator specialized for SW64 HotSpot. ++ */ ++public class SW64HotSpotNodeLIRBuilder extends SW64NodeLIRBuilder implements HotSpotNodeLIRBuilder { ++ ++ public SW64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, SW64NodeMatchRules nodeMatchRules) { ++ super(graph, gen, nodeMatchRules); ++ assert gen instanceof SW64HotSpotLIRGenerator; ++ assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; ++ ((SW64HotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder())); ++ } ++ ++ @Override ++ protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { ++ HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(SW64Kind.QWORD)); ++ return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen); ++ } ++ ++ private SW64HotSpotLIRGenerator getGen() { ++ return (SW64HotSpotLIRGenerator) gen; ++ } ++ ++ @Override ++ protected void emitPrologue(StructuredGraph graph) { ++ CallingConvention incomingArguments = gen.getResult().getCallingConvention(); ++ Value[] params = new Value[incomingArguments.getArgumentCount() + 2]; ++ for (int i = 0; i < incomingArguments.getArgumentCount(); i++) { ++ params[i] = incomingArguments.getArgument(i); ++ if (isStackSlot(params[i])) { ++ StackSlot slot = ValueUtil.asStackSlot(params[i]); ++ if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { ++ gen.getResult().getLIR().setHasArgInCallerFrame(); ++ } ++ } ++ } ++ params[params.length - 2] = fp.asValue(LIRKind.value(SW64Kind.QWORD)); ++ params[params.length - 1] = lr.asValue(LIRKind.value(SW64Kind.QWORD)); ++ ++ gen.emitIncomingValues(params); ++ ++ for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { ++ Value paramValue = params[param.index()]; ++ assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp(NodeView.DEFAULT))) : paramValue.getValueKind() + " != " + param.stamp(NodeView.DEFAULT); ++ setResult(param, gen.emitMove(paramValue)); ++ } ++ } ++ ++ @Override ++ public void visitSafepointNode(SafepointNode i) { ++ LIRFrameState info = state(i); ++ Register thread = getGen().getProviders().getRegisters().getThreadRegister(); ++ Variable scratch = gen.newVariable(LIRKind.value(getGen().target().arch.getWordKind())); ++ append(new SW64HotSpotSafepointOp(info, getGen().config, thread, scratch)); ++ } ++ ++ @Override ++ protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { ++ InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); ++ if (invokeKind.isIndirect()) { ++ append(new SW64HotSpotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); ++ } else { ++ assert invokeKind.isDirect(); ++ HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); ++ assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; ++ append(new SW64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); ++ } ++ } ++ ++ @Override ++ protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { ++ Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()); ++ Value targetAddressSrc = operand(callTarget.computedAddress()); ++ AllocatableValue metaspaceMethodDst = metaspaceMethodRegister.asValue(metaspaceMethodSrc.getValueKind()); ++ AllocatableValue targetAddressDst = inlineCacheRegister.asValue(targetAddressSrc.getValueKind()); ++ gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc); ++ gen.emitMove(targetAddressDst, targetAddressSrc); ++ append(new SW64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, getGen().config)); ++ } ++ ++ @Override ++ public void emitPatchReturnAddress(ValueNode address) { ++ append(new SW64HotSpotPatchReturnAddressOp(gen.load(operand(address)))); ++ } ++ ++ @Override ++ public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { ++ Variable handler = gen.load(operand(handlerInCallerPc)); ++ ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); ++ CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); ++ assert outgoingCc.getArgumentCount() == 2; ++ RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0); ++ RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1); ++ gen.emitMove(exceptionFixed, operand(exception)); ++ gen.emitMove(exceptionPcFixed, operand(exceptionPc)); ++ Register thread = getGen().getProviders().getRegisters().getThreadRegister(); ++ SW64HotSpotJumpToExceptionHandlerInCallerOp op = new SW64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, ++ getGen().config.threadIsMethodHandleReturnOffset, thread, getGen().config); ++ append(op); ++ } ++ ++ @Override ++ public void visitFullInfopointNode(FullInfopointNode i) { ++ if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) { ++ i.getDebug().log("Ignoring InfopointNode for AFTER_BCI"); ++ } else { ++ super.visitFullInfopointNode(i); ++ } ++ } ++ ++ @Override ++ public void visitBreakpointNode(BreakpointNode node) { ++ JavaType[] sig = new JavaType[node.arguments().size()]; ++ for (int i = 0; i < sig.length; i++) { ++ sig[i] = node.arguments().get(i).stamp(NodeView.DEFAULT).javaType(gen.getMetaAccess()); ++ } ++ ++ Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments()); ++ append(new SW64BreakpointOp(parameters)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotPatchReturnAddressOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotPatchReturnAddressOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotPatchReturnAddressOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotPatchReturnAddressOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,63 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Patch the return address of the current frame. ++ */ ++@Opcode("PATCH_RETURN") ++final class SW64HotSpotPatchReturnAddressOp extends SW64LIRInstruction { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotPatchReturnAddressOp.class); ++ ++ @Use(REG) AllocatableValue address; ++ ++ SW64HotSpotPatchReturnAddressOp(AllocatableValue address) { ++ super(TYPE); ++ this.address = address; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ final int frameSize = crb.frameMap.frameSize(); ++ // LR is saved in the {fp, lr} pair above the frame ++ SW64Address lrAddress = SW64Address.createUnscaledImmediateAddress(sp, ++ frameSize + crb.target.wordSize); ++ masm.str(64, asRegister(address), lrAddress); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotRegisterAllocationConfig.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotRegisterAllocationConfig.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotRegisterAllocationConfig.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotRegisterAllocationConfig.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,133 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.r0; ++import static jdk.vm.ci.sw64.SW64.r1; ++import static jdk.vm.ci.sw64.SW64.r10; ++import static jdk.vm.ci.sw64.SW64.r11; ++import static jdk.vm.ci.sw64.SW64.r12; ++import static jdk.vm.ci.sw64.SW64.r13; ++import static jdk.vm.ci.sw64.SW64.r14; ++import static jdk.vm.ci.sw64.SW64.r15; ++import static jdk.vm.ci.sw64.SW64.r16; ++import static jdk.vm.ci.sw64.SW64.r17; ++import static jdk.vm.ci.sw64.SW64.r18; ++import static jdk.vm.ci.sw64.SW64.r19; ++import static jdk.vm.ci.sw64.SW64.r2; ++import static jdk.vm.ci.sw64.SW64.r20; ++import static jdk.vm.ci.sw64.SW64.r21; ++import static jdk.vm.ci.sw64.SW64.r22; ++import static jdk.vm.ci.sw64.SW64.r23; ++import static jdk.vm.ci.sw64.SW64.r24; ++import static jdk.vm.ci.sw64.SW64.r25; ++import static jdk.vm.ci.sw64.SW64.r26; ++import static jdk.vm.ci.sw64.SW64.r28; ++import static jdk.vm.ci.sw64.SW64.r3; ++import static jdk.vm.ci.sw64.SW64.r4; ++import static jdk.vm.ci.sw64.SW64.r5; ++import static jdk.vm.ci.sw64.SW64.r6; ++import static jdk.vm.ci.sw64.SW64.r7; ++import static jdk.vm.ci.sw64.SW64.r8; ++import static jdk.vm.ci.sw64.SW64.r9; ++import static jdk.vm.ci.sw64.SW64.v0; ++import static jdk.vm.ci.sw64.SW64.v1; ++import static jdk.vm.ci.sw64.SW64.v10; ++import static jdk.vm.ci.sw64.SW64.v11; ++import static jdk.vm.ci.sw64.SW64.v12; ++import static jdk.vm.ci.sw64.SW64.v13; ++import static jdk.vm.ci.sw64.SW64.v14; ++import static jdk.vm.ci.sw64.SW64.v15; ++import static jdk.vm.ci.sw64.SW64.v16; ++import static jdk.vm.ci.sw64.SW64.v17; ++import static jdk.vm.ci.sw64.SW64.v18; ++import static jdk.vm.ci.sw64.SW64.v19; ++import static jdk.vm.ci.sw64.SW64.v2; ++import static jdk.vm.ci.sw64.SW64.v20; ++import static jdk.vm.ci.sw64.SW64.v21; ++import static jdk.vm.ci.sw64.SW64.v22; ++import static jdk.vm.ci.sw64.SW64.v23; ++import static jdk.vm.ci.sw64.SW64.v24; ++import static jdk.vm.ci.sw64.SW64.v25; ++import static jdk.vm.ci.sw64.SW64.v26; ++import static jdk.vm.ci.sw64.SW64.v27; ++import static jdk.vm.ci.sw64.SW64.v28; ++import static jdk.vm.ci.sw64.SW64.v29; ++import static jdk.vm.ci.sw64.SW64.v3; ++import static jdk.vm.ci.sw64.SW64.v30; ++import static jdk.vm.ci.sw64.SW64.v31; ++import static jdk.vm.ci.sw64.SW64.v4; ++import static jdk.vm.ci.sw64.SW64.v5; ++import static jdk.vm.ci.sw64.SW64.v6; ++import static jdk.vm.ci.sw64.SW64.v7; ++import static jdk.vm.ci.sw64.SW64.v8; ++import static jdk.vm.ci.sw64.SW64.v9; ++ ++import java.util.ArrayList; ++import java.util.BitSet; ++ ++import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterArray; ++import jdk.vm.ci.code.RegisterConfig; ++ ++public class SW64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig { ++ ++ // @formatter:off ++ static final Register[] registerAllocationOrder = { ++ r0, r1, r2, r3, r4, r5, r6, r7, ++ r8, r9, r10, r11, r12, r13, r14, r15, ++ r16, r17, r18, r19, r20, r21, r22, r23, ++ r24, r25, r26, /* r27, */ r28, /* r29, r30, r31 */ ++ ++ v0, v1, v2, v3, v4, v5, v6, v7, ++ v8, v9, v10, v11, v12, v13, v14, v15, ++ v16, v17, v18, v19, v20, v21, v22, v23, ++ v24, v25, v26, v27, v28, v29, v30, v31 ++ }; ++ // @formatter:on ++ ++ public SW64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { ++ super(registerConfig, allocationRestrictedTo); ++ } ++ ++ @Override ++ protected RegisterArray initAllocatable(RegisterArray registers) { ++ BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size()); ++ for (Register reg : registers) { ++ regMap.set(reg.number); ++ } ++ ++ ArrayList allocatableRegisters = new ArrayList<>(registers.size()); ++ for (Register reg : registerAllocationOrder) { ++ if (regMap.get(reg.number)) { ++ allocatableRegisters.add(reg); ++ } ++ } ++ ++ return super.initAllocatable(new RegisterArray(allocatableRegisters)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotReturnOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotReturnOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotReturnOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotReturnOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,74 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.lr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * Returns from a function. ++ */ ++@Opcode("RETURN") ++public final class SW64HotSpotReturnOp extends SW64HotSpotEpilogueOp { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotReturnOp.class); ++ ++ @Use({REG, ILLEGAL}) private Value result; ++ private final boolean isStub; ++ private final boolean requiresReservedStackAccessCheck; ++ ++ public SW64HotSpotReturnOp(Value result, boolean isStub, GraalHotSpotVMConfig config, Register thread, boolean requiresReservedStackAccessCheck) { ++ super(TYPE, config, thread); ++ this.requiresReservedStackAccessCheck = requiresReservedStackAccessCheck; ++ assert validReturnValue(result); ++ this.result = result; ++ this.isStub = isStub; ++ } ++ ++ private static boolean validReturnValue(Value result) { ++ if (result.equals(Value.ILLEGAL)) { ++ return true; ++ } ++ return asRegister(result).encoding == 0; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ final boolean emitSafepoint = !isStub; ++ leaveFrame(crb, masm, emitSafepoint, requiresReservedStackAccessCheck); ++ masm.ret(lr); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotSafepointOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotSafepointOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotSafepointOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotSafepointOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64LIRInstruction; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.site.InfopointReason; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Emits a safepoint poll. ++ */ ++@Opcode("SAFEPOINT") ++public class SW64HotSpotSafepointOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotSafepointOp.class); ++ ++ @State protected LIRFrameState state; ++ @Temp protected AllocatableValue scratchValue; ++ ++ private final GraalHotSpotVMConfig config; ++ private final Register thread; ++ ++ public SW64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, Register thread, AllocatableValue scratch) { ++ super(TYPE); ++ this.state = state; ++ this.config = config; ++ this.thread = thread; ++ this.scratchValue = scratch; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register scratch = asRegister(scratchValue); ++ emitCode(crb, masm, config, false, thread, scratch, state); ++ } ++ ++ /** ++ * Conservatively checks whether we can load the safepoint polling address with a single ldr ++ * instruction or not. ++ * ++ * @return true if it is guaranteed that polling page offset will always fit into a 21-bit ++ * signed integer, false otherwise. ++ */ ++ private static boolean isPollingPageFar(GraalHotSpotVMConfig config) { ++ final long pollingPageAddress = config.safepointPollingAddress; ++ return !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheLowBound) || !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheHighBound); ++ } ++ ++ public static void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register thread, Register scratch, LIRFrameState state) { ++ if (config.threadLocalHandshakes) { ++ emitThreadLocalPoll(crb, masm, config, onReturn, thread, scratch, state); ++ } else { ++ emitGlobalPoll(crb, masm, config, onReturn, scratch, state); ++ } ++ } ++ ++ private static void emitGlobalPoll(CompilationResultBuilder crb, SW64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) { ++ if (isPollingPageFar(config)) { ++ crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); ++ masm.movNativeAddress(scratch, config.safepointPollingAddress); ++ crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); ++ if (state != null) { ++ crb.recordInfopoint(masm.position(), state, InfopointReason.SAFEPOINT); ++ } ++ masm.ldr(32, zr, SW64Address.createBaseRegisterOnlyAddress(scratch)); ++ } else { ++ crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR); ++ if (state != null) { ++ crb.recordInfopoint(masm.position(), state, InfopointReason.SAFEPOINT); ++ } ++ masm.ldr(32, zr, SW64Address.createPcLiteralAddress(0)); ++ } ++ } ++ ++ private static void emitThreadLocalPoll(CompilationResultBuilder crb, SW64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register thread, Register scratch, ++ LIRFrameState state) { ++ assert config.threadPollingPageOffset >= 0; ++ masm.ldr(64, scratch, masm.makeAddress(thread, config.threadPollingPageOffset, 8)); ++ crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); ++ if (state != null) { ++ crb.recordInfopoint(masm.position(), state, InfopointReason.SAFEPOINT); ++ } ++ masm.ldr(32, zr, SW64Address.createBaseRegisterOnlyAddress(scratch)); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotStrategySwitchOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotStrategySwitchOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotStrategySwitchOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotStrategySwitchOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,82 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import java.util.function.Function; ++ ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.calc.Condition; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.LabelRef; ++import org.graalvm.compiler.lir.SwitchStrategy; ++import org.graalvm.compiler.lir.sw64.SW64ControlFlow; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; ++import jdk.vm.ci.meta.Constant; ++import jdk.vm.ci.meta.Value; ++ ++final class SW64HotSpotStrategySwitchOp extends SW64ControlFlow.StrategySwitchOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotStrategySwitchOp.class); ++ ++ SW64HotSpotStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, Function converter) { ++ super(TYPE, strategy, keyTargets, defaultTarget, key, scratch, converter); ++ } ++ ++ @Override ++ public void emitCode(final CompilationResultBuilder crb, final SW64MacroAssembler masm) { ++ strategy.run(new HotSpotSwitchClosure(asRegister(key), crb, masm)); ++ } ++ ++ public class HotSpotSwitchClosure extends SwitchClosure { ++ ++ protected HotSpotSwitchClosure(Register keyRegister, CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ super(keyRegister, crb, masm); ++ } ++ ++ @Override ++ protected void emitComparison(Constant c) { ++ if (c instanceof HotSpotMetaspaceConstant) { ++ HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) c; ++ if (meta.isCompressed()) { ++ crb.recordInlineDataInCode(meta); ++ // masm.cmpl(keyRegister, 0xDEADDEAD); ++ throw GraalError.unimplemented(); ++ } else { ++ crb.recordInlineDataInCode(meta); ++ masm.movNativeAddress(asRegister(scratch), 0x0000_DEAD_DEAD_DEADL); ++ masm.cmp(64, keyRegister, asRegister(scratch)); ++ } ++ } else { ++ super.emitComparison(c); ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotUnwindOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotUnwindOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotUnwindOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64HotSpotUnwindOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,73 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.lr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.CallingConvention; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterValue; ++ ++/** ++ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. ++ */ ++@Opcode("UNWIND") ++public final class SW64HotSpotUnwindOp extends SW64HotSpotEpilogueOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64HotSpotUnwindOp.class); ++ ++ @Use protected RegisterValue exception; ++ ++ public SW64HotSpotUnwindOp(GraalHotSpotVMConfig config, RegisterValue exception) { ++ super(TYPE, config); ++ this.exception = exception; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ leaveFrame(crb, masm, /* emitSafepoint */false, false); ++ ++ ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER); ++ CallingConvention cc = linkage.getOutgoingCallingConvention(); ++ assert cc.getArgumentCount() == 2; ++ assert exception.equals(cc.getArgument(0)); ++ ++ // Get return address (is in lr after frame leave) ++ Register returnAddress = asRegister(cc.getArgument(1)); ++ masm.movx(returnAddress, lr); ++ ++ SW64Call.directJmp(crb, masm, linkage); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64IndirectCallOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64IndirectCallOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64IndirectCallOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sw64/src/org/graalvm/compiler/hotspot/sw64/SW64IndirectCallOp.java 2025-05-09 10:05:57.788290599 +0800 +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.hotspot.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static jdk.vm.ci.sw64.SW64.r12; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.sw64.SW64Call; ++import org.graalvm.compiler.lir.sw64.SW64Call.IndirectCallOp; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.ResolvedJavaMethod; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * A register indirect call that complies with the extra conventions for such calls in HotSpot. In ++ * particular, the metaspace Method of the callee must be in r12 for the case where a vtable entry's ++ * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to ++ * be in r12. ++ */ ++@Opcode("CALL_INDIRECT") ++final class SW64IndirectCallOp extends IndirectCallOp { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64IndirectCallOp.class); ++ ++ /** ++ * Vtable stubs expect the metaspace Method in r12. ++ */ ++ public static final Register METHOD = r12; ++ ++ @Use({REG}) private Value metaspaceMethod; ++ ++ private final GraalHotSpotVMConfig config; ++ ++ SW64IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, ++ GraalHotSpotVMConfig config) { ++ super(TYPE, callTarget, result, parameters, temps, targetAddress, state); ++ this.metaspaceMethod = metaspaceMethod; ++ this.config = config; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ crb.recordMark(config.MARKID_INLINE_INVOKE); ++ Register callReg = asRegister(targetAddress); ++ assert !callReg.equals(METHOD); ++ SW64Call.indirectCall(crb, masm, callReg, callTarget, state); ++ } ++ ++ @Override ++ public void verify() { ++ super.verify(); ++ assert asRegister(metaspaceMethod).equals(METHOD); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AddressValue.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AddressValue.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AddressValue.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AddressValue.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import java.util.EnumSet; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Address.AddressingMode; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ExtendType; ++import org.graalvm.compiler.lir.CompositeValue; ++import org.graalvm.compiler.lir.InstructionValueConsumer; ++import org.graalvm.compiler.lir.InstructionValueProcedure; ++import org.graalvm.compiler.lir.LIRInstruction; ++import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterValue; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Value; ++import jdk.vm.ci.meta.ValueKind; ++ ++public final class SW64AddressValue extends CompositeValue { ++ private static final EnumSet flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL); ++ ++ @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue base; ++ @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue offset; ++ private final int displacement; ++ ++ /** ++ * Whether register offset should be scaled or not. ++ */ ++ private final int scaleFactor; ++ private final AddressingMode addressingMode; ++ ++ public SW64AddressValue(ValueKind kind, AllocatableValue base, AllocatableValue offset, int displacement, int scaleFactor, AddressingMode addressingMode) { ++ super(kind); ++ this.base = base; ++ this.offset = offset; ++ this.displacement = displacement; ++ this.scaleFactor = scaleFactor; ++ this.addressingMode = addressingMode; ++ } ++ ++ private static Register toRegister(AllocatableValue value) { ++ if (value.equals(Value.ILLEGAL)) { ++ return SW64.zr; ++ } else { ++ return ((RegisterValue) value).getRegister(); ++ } ++ } ++ ++ public AllocatableValue getBase() { ++ return base; ++ } ++ ++ public AllocatableValue getOffset() { ++ return offset; ++ } ++ ++ public int getDisplacement() { ++ return displacement; ++ } ++ ++ public boolean isScaled() { ++ return scaleFactor != 1; ++ } ++ ++ public int getScaleFactor() { ++ return scaleFactor; ++ } ++ ++ public AddressingMode getAddressingMode() { ++ return addressingMode; ++ } ++ ++ public SW64Address toAddress() { ++ Register baseReg = toRegister(base); ++ Register offsetReg = toRegister(offset); ++ SW64Assembler.ExtendType extendType = addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET ? ExtendType.SXTW : null; ++ return SW64Address.createAddress(addressingMode, baseReg, offsetReg, displacement / scaleFactor, isScaled(), extendType); ++ } ++ ++ @Override ++ public CompositeValue forEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueProcedure proc) { ++ AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags); ++ AllocatableValue newOffset = (AllocatableValue) proc.doValue(inst, offset, mode, flags); ++ if (!base.identityEquals(newBase) || !offset.identityEquals(newOffset)) { ++ return new SW64AddressValue(getValueKind(), newBase, newOffset, displacement, scaleFactor, addressingMode); ++ } ++ return this; ++ } ++ ++ @Override ++ protected void visitEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueConsumer proc) { ++ proc.visitValue(inst, base, mode, flags); ++ proc.visitValue(inst, offset, mode, flags); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticLIRGeneratorTool.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticLIRGeneratorTool.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticLIRGeneratorTool.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticLIRGeneratorTool.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.lir.Variable; ++import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * This interface can be used to generate SW64 LIR for arithmetic operations. ++ */ ++public interface SW64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorTool { ++ ++ Value emitCountLeadingZeros(Value value); ++ ++ Value emitCountTrailingZeros(Value value); ++ ++ enum RoundingMode { ++ NEAREST(0), ++ DOWN(1), ++ UP(2), ++ TRUNCATE(3); ++ ++ public final int encoding; ++ ++ RoundingMode(int encoding) { ++ this.encoding = encoding; ++ } ++ } ++ ++ Value emitRound(Value value, RoundingMode mode); ++ ++ void emitCompareOp(SW64Kind cmpKind, Variable left, Value right); ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArithmeticOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,440 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.sw64.SW64ArithmeticOp.ARMv8ConstantCategory.ARITHMETIC; ++import static org.graalvm.compiler.lir.sw64.SW64ArithmeticOp.ARMv8ConstantCategory.LOGICAL; ++import static org.graalvm.compiler.lir.sw64.SW64ArithmeticOp.ARMv8ConstantCategory.NONE; ++import static org.graalvm.compiler.lir.sw64.SW64ArithmeticOp.ARMv8ConstantCategory.SHIFT; ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ConditionFlag; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.JavaConstant; ++ ++public enum SW64ArithmeticOp { ++ // TODO At least add and sub *can* be used with SP, so this should be supported ++ NEG, ++ NOT, ++ ADD(ARITHMETIC), ++ ADDS(ARITHMETIC), ++ SUB(ARITHMETIC), ++ SUBS(ARITHMETIC), ++ MUL, ++ MULVS, ++ DIV, ++ SMULH, ++ UMULH, ++ REM, ++ UDIV, ++ UREM, ++ AND(LOGICAL), ++ ANDS(LOGICAL), ++ OR(LOGICAL), ++ XOR(LOGICAL), ++ SHL(SHIFT), ++ LSHR(SHIFT), ++ ASHR(SHIFT), ++ ABS, ++ ++ FADD, ++ FSUB, ++ FMUL, ++ FDIV, ++ FREM, ++ FNEG, ++ FABS, ++ FRINTM, ++ FRINTN, ++ FRINTP, ++ SQRT; ++ ++ /** ++ * Specifies what constants can be used directly without having to be loaded into a register ++ * with the given instruction. ++ */ ++ public enum ARMv8ConstantCategory { ++ NONE, ++ LOGICAL, ++ ARITHMETIC, ++ SHIFT ++ } ++ ++ public final ARMv8ConstantCategory category; ++ ++ SW64ArithmeticOp(ARMv8ConstantCategory category) { ++ this.category = category; ++ } ++ ++ SW64ArithmeticOp() { ++ this(NONE); ++ } ++ ++ public static class UnaryOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(UnaryOp.class); ++ ++ @Opcode private final SW64ArithmeticOp opcode; ++ @Def({REG}) protected AllocatableValue result; ++ @Use({REG}) protected AllocatableValue x; ++ ++ public UnaryOp(SW64ArithmeticOp opcode, AllocatableValue result, AllocatableValue x) { ++ super(TYPE); ++ this.opcode = opcode; ++ this.result = result; ++ this.x = x; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register dst = asRegister(result); ++ Register src = asRegister(x); ++ int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ switch (opcode) { ++ case NEG: ++ masm.sub(size, dst, zr, src); ++ break; ++ case FNEG: ++ masm.fneg(size, dst, src); ++ break; ++ case NOT: ++ masm.not(size, dst, src); ++ break; ++ case ABS: ++ masm.cmp(size, src, 0); ++ masm.csneg(size, dst, src, ConditionFlag.LT); ++ break; ++ case FABS: ++ masm.fabs(size, dst, src); ++ break; ++ case FRINTM: ++ masm.frintm(size, dst, src); ++ break; ++ case FRINTN: ++ masm.frintn(size, dst, src); ++ break; ++ case FRINTP: ++ masm.frintp(size, dst, src); ++ break; ++ case SQRT: ++ masm.fsqrt(size, dst, src); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("op=" + opcode.name()); ++ } ++ } ++ } ++ ++ public static class BinaryConstOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryConstOp.class); ++ ++ @Opcode private final SW64ArithmeticOp op; ++ @Def({REG}) protected AllocatableValue result; ++ @Use({REG}) protected AllocatableValue a; ++ private final JavaConstant b; ++ ++ public BinaryConstOp(SW64ArithmeticOp op, AllocatableValue result, AllocatableValue a, JavaConstant b) { ++ super(TYPE); ++ this.op = op; ++ this.result = result; ++ this.a = a; ++ this.b = b; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ assert op.category != NONE; ++ Register dst = asRegister(result); ++ Register src = asRegister(a); ++ int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ switch (op) { ++ case ADD: ++ // Don't use asInt() here, since we can't use asInt on a long variable, even ++ // if the constant easily fits as an int. ++ assert SW64MacroAssembler.isArithmeticImmediate(b.asLong()); ++ masm.add(size, dst, src, (int) b.asLong()); ++ break; ++ case SUB: ++ // Don't use asInt() here, since we can't use asInt on a long variable, even ++ // if the constant easily fits as an int. ++ assert SW64MacroAssembler.isArithmeticImmediate(b.asLong()); ++ masm.sub(size, dst, src, (int) b.asLong()); ++ break; ++ case ADDS: ++ assert SW64MacroAssembler.isArithmeticImmediate(b.asLong()); ++ masm.adds(size, dst, src, (int) b.asLong()); ++ break; ++ case SUBS: ++ assert SW64MacroAssembler.isArithmeticImmediate(b.asLong()); ++ masm.subs(size, dst, src, (int) b.asLong()); ++ break; ++ case AND: ++ // XXX Should this be handled somewhere else? ++ if (size == 32 && b.asLong() == 0xFFFF_FFFFL) { ++ masm.mov(size, dst, src); ++ } else { ++ masm.and(size, dst, src, b.asLong()); ++ } ++ break; ++ case ANDS: ++ masm.ands(size, dst, src, b.asLong()); ++ break; ++ case OR: ++ masm.or(size, dst, src, b.asLong()); ++ break; ++ case XOR: ++ masm.eor(size, dst, src, b.asLong()); ++ break; ++ case SHL: ++ masm.shl(size, dst, src, b.asLong()); ++ break; ++ case LSHR: ++ masm.lshr(size, dst, src, b.asLong()); ++ break; ++ case ASHR: ++ masm.ashr(size, dst, src, b.asLong()); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("op=" + op.name()); ++ } ++ } ++ } ++ ++ public static class BinaryOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryOp.class); ++ ++ @Opcode private final SW64ArithmeticOp op; ++ @Def({REG}) protected AllocatableValue result; ++ @Use({REG}) protected AllocatableValue a; ++ @Use({REG}) protected AllocatableValue b; ++ ++ public BinaryOp(SW64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) { ++ super(TYPE); ++ this.op = op; ++ this.result = result; ++ this.a = a; ++ this.b = b; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register dst = asRegister(result); ++ Register src1 = asRegister(a); ++ Register src2 = asRegister(b); ++ int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ switch (op) { ++ case ADD: ++ masm.add(size, dst, src1, src2); ++ break; ++ case ADDS: ++ masm.adds(size, dst, src1, src2); ++ break; ++ case SUB: ++ masm.sub(size, dst, src1, src2); ++ break; ++ case SUBS: ++ masm.subs(size, dst, src1, src2); ++ break; ++ case MUL: ++ masm.mul(size, dst, src1, src2); ++ break; ++ case UMULH: ++ masm.umulh(size, dst, src1, src2); ++ break; ++ case SMULH: ++ masm.smulh(size, dst, src1, src2); ++ break; ++ case DIV: ++ masm.sdiv(size, dst, src1, src2); ++ break; ++ case UDIV: ++ masm.udiv(size, dst, src1, src2); ++ break; ++ case AND: ++ masm.and(size, dst, src1, src2); ++ break; ++ case ANDS: ++ masm.ands(size, dst, src1, src2); ++ break; ++ case OR: ++ masm.or(size, dst, src1, src2); ++ break; ++ case XOR: ++ masm.eor(size, dst, src1, src2); ++ break; ++ case SHL: ++ masm.shl(size, dst, src1, src2); ++ break; ++ case LSHR: ++ masm.lshr(size, dst, src1, src2); ++ break; ++ case ASHR: ++ masm.ashr(size, dst, src1, src2); ++ break; ++ case FADD: ++ masm.fadd(size, dst, src1, src2); ++ break; ++ case FSUB: ++ masm.fsub(size, dst, src1, src2); ++ break; ++ case FMUL: ++ masm.fmul(size, dst, src1, src2); ++ break; ++ case FDIV: ++ masm.fdiv(size, dst, src1, src2); ++ break; ++ case MULVS: ++ masm.mulvs(size, dst, src1, src2); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("op=" + op.name()); ++ } ++ } ++ } ++ ++ /** ++ * Class used for instructions that have to reuse one of their arguments. This only applies to ++ * the remainder instructions at the moment, since we have to compute n % d using rem = n - ++ * TruncatingDivision(n, d) * d ++ * ++ * TODO (das) Replace the remainder nodes in the LIR. ++ */ ++ public static class BinaryCompositeOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryCompositeOp.class); ++ @Opcode private final SW64ArithmeticOp op; ++ @Def({REG}) protected AllocatableValue result; ++ @Alive({REG}) protected AllocatableValue a; ++ @Alive({REG}) protected AllocatableValue b; ++ ++ public BinaryCompositeOp(SW64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) { ++ super(TYPE); ++ this.op = op; ++ this.result = result; ++ this.a = a; ++ this.b = b; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register dst = asRegister(result); ++ Register src1 = asRegister(a); ++ Register src2 = asRegister(b); ++ int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ switch (op) { ++ case REM: ++ masm.rem(size, dst, src1, src2); ++ break; ++ case UREM: ++ masm.urem(size, dst, src1, src2); ++ break; ++ case FREM: ++ masm.frem(size, dst, src1, src2); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ } ++ ++ public static class AddSubShiftOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AddSubShiftOp.class); ++ ++ @Opcode private final SW64ArithmeticOp op; ++ @Def(REG) protected AllocatableValue result; ++ @Use(REG) protected AllocatableValue src1; ++ @Use(REG) protected AllocatableValue src2; ++ private final SW64MacroAssembler.ShiftType shiftType; ++ private final int shiftAmt; ++ ++ /** ++ * Computes result = src1 src2 . ++ */ ++ public AddSubShiftOp(SW64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, SW64MacroAssembler.ShiftType shiftType, int shiftAmt) { ++ super(TYPE); ++ assert op == ADD || op == SUB; ++ this.op = op; ++ this.result = result; ++ this.src1 = src1; ++ this.src2 = src2; ++ this.shiftType = shiftType; ++ this.shiftAmt = shiftAmt; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ switch (op) { ++ case ADD: ++ masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt); ++ break; ++ case SUB: ++ masm.sub(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ } ++ ++ public static class ExtendedAddShiftOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(ExtendedAddShiftOp.class); ++ @Def(REG) protected AllocatableValue result; ++ @Use(REG) protected AllocatableValue src1; ++ @Use(REG) protected AllocatableValue src2; ++ private final SW64Assembler.ExtendType extendType; ++ private final int shiftAmt; ++ ++ /** ++ * Computes result = src1 + extendType(src2) << shiftAmt. ++ * ++ * @param extendType defines how src2 is extended to the same size as src1. ++ * @param shiftAmt must be in range 0 to 4. ++ */ ++ public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, AllocatableValue src2, SW64Assembler.ExtendType extendType, int shiftAmt) { ++ super(TYPE); ++ this.result = result; ++ this.src1 = src1; ++ this.src2 = src2; ++ this.extendType = extendType; ++ this.shiftAmt = shiftAmt; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayCompareToOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayCompareToOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayCompareToOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayCompareToOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,288 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import java.lang.reflect.Array; ++import java.lang.reflect.Field; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ConditionFlag; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.Value; ++import sun.misc.Unsafe; ++ ++/** ++ * Emits code which compares two arrays lexicographically. If the CPU supports any vector ++ * instructions specialized code is emitted to leverage these instructions. ++ */ ++@Opcode("ARRAY_COMPARE_TO") ++public final class SW64ArrayCompareToOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64ArrayCompareToOp.class); ++ ++ private final JavaKind kind1; ++ private final JavaKind kind2; ++ ++ private final int array1BaseOffset; ++ private final int array2BaseOffset; ++ ++ @Def({REG}) protected Value resultValue; ++ ++ @Alive({REG}) protected Value array1Value; ++ @Alive({REG}) protected Value array2Value; ++ @Use({REG}) protected Value length1Value; ++ @Use({REG}) protected Value length2Value; ++ @Temp({REG}) protected Value length1ValueTemp; ++ @Temp({REG}) protected Value length2ValueTemp; ++ ++ @Temp({REG}) protected Value temp1; ++ @Temp({REG}) protected Value temp2; ++ @Temp({REG}) protected Value temp3; ++ @Temp({REG}) protected Value temp4; ++ @Temp({REG}) protected Value temp5; ++ @Temp({REG}) protected Value temp6; ++ ++ public SW64ArrayCompareToOp(LIRGeneratorTool tool, JavaKind kind1, JavaKind kind2, Value result, Value array1, Value array2, Value length1, Value length2) { ++ super(TYPE); ++ this.kind1 = kind1; ++ this.kind2 = kind2; ++ ++ // Both offsets should be the same but better be safe than sorry. ++ Class array1Class = Array.newInstance(kind1.toJavaClass(), 0).getClass(); ++ Class array2Class = Array.newInstance(kind2.toJavaClass(), 0).getClass(); ++ this.array1BaseOffset = UNSAFE.arrayBaseOffset(array1Class); ++ this.array2BaseOffset = UNSAFE.arrayBaseOffset(array2Class); ++ ++ this.resultValue = result; ++ ++ this.array1Value = array1; ++ this.array2Value = array2; ++ ++ /* ++ * The length values are inputs but are also killed like temporaries so need both Use and ++ * Temp annotations, which will only work with fixed registers. ++ */ ++ ++ this.length1Value = length1; ++ this.length2Value = length2; ++ this.length1ValueTemp = length1; ++ this.length2ValueTemp = length2; ++ ++ // Allocate some temporaries. ++ this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp3 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp4 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp5 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp6 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ } ++ ++ private static final Unsafe UNSAFE = initUnsafe(); ++ ++ private static Unsafe initUnsafe() { ++ try { ++ return Unsafe.getUnsafe(); ++ } catch (SecurityException se) { ++ try { ++ Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); ++ theUnsafe.setAccessible(true); ++ return (Unsafe) theUnsafe.get(Unsafe.class); ++ } catch (Exception e) { ++ throw new RuntimeException("exception while trying to get Unsafe", e); ++ } ++ } ++ } ++ ++ @Override ++ protected void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ ++ Register result = asRegister(resultValue); ++ Register length1 = asRegister(length1Value); ++ Register length2 = asRegister(length2Value); ++ ++ Register array1 = asRegister(temp1); ++ Register array2 = asRegister(temp2); ++ Register length = asRegister(temp3); ++ Register temp = asRegister(temp4); ++ Register tailCount = asRegister(temp5); ++ Register vecCount = asRegister(temp6); ++ ++ // Checkstyle: stop ++ final Label BREAK_LABEL = new Label(); ++ final Label STRING_DIFFER_LABEL = new Label(); ++ final Label LENGTH_DIFFER_LABEL = new Label(); ++ final Label MAIN_LOOP_LABEL = new Label(); ++ final Label COMPARE_SHORT_LABEL = new Label(); ++ // Checkstyle: resume ++ ++ // Checkstyle: stop ++ int CHAR_SIZE_BYTES = 1; ++ int VECTOR_SIZE_BYTES = 8; ++ int VECTOR_COUNT_BYTES = 8; ++ // Checkstyle: resume ++ ++ // Byte is expanded to short if we compare strings with different encoding ++ if (kind1 != kind2 || kind1 == JavaKind.Char) { ++ CHAR_SIZE_BYTES = 2; ++ } ++ ++ if (kind1 != kind2) { ++ VECTOR_COUNT_BYTES = 4; ++ } ++ ++ // Load array base addresses. ++ masm.lea(array1, SW64Address.createUnscaledImmediateAddress(asRegister(array1Value), array1BaseOffset)); ++ masm.lea(array2, SW64Address.createUnscaledImmediateAddress(asRegister(array2Value), array2BaseOffset)); ++ ++ // Calculate minimal length in chars for different kind case ++ // Conditions could be squashed but lets keep it readable ++ if (kind1 != kind2) { ++ masm.lshr(64, length2, length2, 1); ++ } ++ ++ if (kind1 == kind2 && kind1 == JavaKind.Char) { ++ masm.lshr(64, length1, length1, 1); ++ masm.lshr(64, length2, length2, 1); ++ } ++ ++ masm.cmp(64, length1, length2); ++ masm.cmov(64, length, length1, length2, ConditionFlag.LT); ++ ++ // One of strings is empty ++ masm.cbz(64, length, LENGTH_DIFFER_LABEL); ++ ++ // Go back to bytes if necessary ++ if (kind1 != kind2 || kind1 == JavaKind.Char) { ++ masm.shl(64, length, length, 1); ++ } ++ ++ masm.mov(64, vecCount, zr); ++ masm.and(64, tailCount, length, VECTOR_SIZE_BYTES - 1); // tail count (in bytes) ++ masm.ands(64, length, length, ~(VECTOR_SIZE_BYTES - 1)); // vector count (in bytes) ++ ++ // Length of string is less than VECTOR_SIZE, go to simple compare ++ masm.branchConditionally(ConditionFlag.EQ, COMPARE_SHORT_LABEL); ++ ++ // MAIN_LOOP - read strings by 8 byte. ++ masm.bind(MAIN_LOOP_LABEL); ++ if (kind1 != kind2) { ++ // Load 32 bits ad unpack it to entire 64bit register ++ masm.ldr(32, result, SW64Address.createRegisterOffsetAddress(array1, vecCount, false)); ++ masm.ubfm(64, temp, result, 0, 7); ++ masm.lshr(64, result, result, 8); ++ masm.bfm(64, temp, result, 48, 7); ++ masm.lshr(64, result, result, 8); ++ masm.bfm(64, temp, result, 32, 7); ++ masm.lshr(64, result, result, 8); ++ masm.bfm(64, temp, result, 16, 7); ++ // Unpacked value placed in temp now ++ ++ masm.shl(64, result, vecCount, 1); ++ masm.ldr(64, result, SW64Address.createRegisterOffsetAddress(array2, result, false)); ++ } else { ++ masm.ldr(64, temp, SW64Address.createRegisterOffsetAddress(array1, vecCount, false)); ++ masm.ldr(64, result, SW64Address.createRegisterOffsetAddress(array2, vecCount, false)); ++ } ++ masm.eor(64, result, temp, result); ++ masm.cbnz(64, result, STRING_DIFFER_LABEL); ++ masm.add(64, vecCount, vecCount, VECTOR_COUNT_BYTES); ++ masm.cmp(64, vecCount, length); ++ masm.branchConditionally(ConditionFlag.LT, MAIN_LOOP_LABEL); ++ // End of MAIN_LOOP ++ ++ // Strings are equal and no TAIL go to END ++ masm.cbz(64, tailCount, LENGTH_DIFFER_LABEL); ++ ++ // Compaire tail of long string ... ++ masm.lea(array1, SW64Address.createRegisterOffsetAddress(array1, length, false)); ++ masm.lea(array2, SW64Address.createRegisterOffsetAddress(array2, length, false)); ++ ++ // ... or string less than vector length ++ masm.bind(COMPARE_SHORT_LABEL); ++ for (int i = 0; i < VECTOR_COUNT_BYTES; i += CHAR_SIZE_BYTES) { ++ if (kind1 != kind2) { ++ masm.ldr(8, temp, SW64Address.createUnscaledImmediateAddress(array1, i / 2)); ++ } else { ++ masm.ldr(8 * CHAR_SIZE_BYTES, temp, SW64Address.createUnscaledImmediateAddress(array1, i)); ++ } ++ ++ masm.ldr(8 * CHAR_SIZE_BYTES, result, SW64Address.createUnscaledImmediateAddress(array2, i)); ++ ++ if (kind1 != kind2 && kind1 == JavaKind.Char) { ++ // Weird swap of substraction order ++ masm.subs(64, result, result, temp); ++ } else { ++ masm.subs(64, result, temp, result); ++ } ++ ++ masm.branchConditionally(ConditionFlag.NE, BREAK_LABEL); ++ masm.subs(64, tailCount, tailCount, CHAR_SIZE_BYTES); ++ masm.branchConditionally(ConditionFlag.EQ, LENGTH_DIFFER_LABEL); ++ } ++ ++ // STRING_DIFFER extract exact value of a difference ++ masm.bind(STRING_DIFFER_LABEL); ++ masm.rbit(64, tailCount, result); ++ masm.clz(64, vecCount, tailCount); ++ masm.and(64, vecCount, vecCount, ~((8 * CHAR_SIZE_BYTES) - 1)); // Round to byte or short ++ ++ masm.eor(64, result, temp, result); ++ masm.ashr(64, result, result, vecCount); ++ masm.ashr(64, temp, temp, vecCount); ++ ++ masm.and(64, result, result, 0xFFFF >>> (16 - (8 * CHAR_SIZE_BYTES))); // 0xFF or 0xFFFF ++ masm.and(64, temp, temp, 0xFFFF >>> (16 - (8 * CHAR_SIZE_BYTES))); ++ ++ masm.sub(64, result, temp, result); ++ masm.branchConditionally(ConditionFlag.AL, BREAK_LABEL); ++ // End of STRING_DIFFER ++ ++ // Strings are equials up to length, ++ // return length difference in chars ++ masm.bind(LENGTH_DIFFER_LABEL); ++ if (kind1 != kind2 && kind1 == JavaKind.Char) { ++ // Weird swap of substraction order ++ masm.sub(64, result, length2, length1); ++ } else { ++ masm.sub(64, result, length1, length2); ++ } ++ ++ // We are done ++ masm.bind(BREAK_LABEL); ++ } ++ ++} // class +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayEqualsOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayEqualsOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayEqualsOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ArrayEqualsOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,218 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ConditionFlag; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.ScratchRegister; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.lir.gen.LIRGeneratorTool; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * Emits code which compares two arrays of the same length. If the CPU supports any vector ++ * instructions specialized code is emitted to leverage these instructions. ++ */ ++@Opcode("ARRAY_EQUALS") ++public final class SW64ArrayEqualsOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64ArrayEqualsOp.class); ++ ++ private final JavaKind kind; ++ private final int arrayBaseOffset; ++ private final int arrayIndexScale; ++ ++ @Def({REG}) protected Value resultValue; ++ @Alive({REG}) protected Value array1Value; ++ @Alive({REG}) protected Value array2Value; ++ @Alive({REG}) protected Value lengthValue; ++ @Temp({REG}) protected Value temp1; ++ @Temp({REG}) protected Value temp2; ++ @Temp({REG}) protected Value temp3; ++ @Temp({REG}) protected Value temp4; ++ ++ public SW64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) { ++ super(TYPE); ++ ++ assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; ++ this.kind = kind; ++ ++ this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); ++ this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); ++ ++ this.resultValue = result; ++ this.array1Value = array1; ++ this.array2Value = array2; ++ this.lengthValue = length; ++ ++ // Allocate some temporaries. ++ this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); ++ this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); ++ this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register result = asRegister(resultValue); ++ Register array1 = asRegister(temp1); ++ Register array2 = asRegister(temp2); ++ Register length = asRegister(temp3); ++ ++ Label breakLabel = new Label(); ++ ++ try (ScratchRegister sc1 = masm.getScratchRegister()) { ++ Register rscratch1 = sc1.getRegister(); ++ // Load array base addresses. ++ masm.lea(array1, SW64Address.createUnscaledImmediateAddress(asRegister(array1Value), arrayBaseOffset)); ++ masm.lea(array2, SW64Address.createUnscaledImmediateAddress(asRegister(array2Value), arrayBaseOffset)); ++ ++ // Get array length in bytes. ++ masm.mov(rscratch1, arrayIndexScale); ++ masm.smaddl(length, asRegister(lengthValue), rscratch1, zr); ++ masm.mov(64, result, length); // copy ++ ++ emit8ByteCompare(crb, masm, result, array1, array2, length, breakLabel, rscratch1); ++ emitTailCompares(masm, result, array1, array2, breakLabel, rscratch1); ++ ++ // Return: rscratch1 is non-zero iff the arrays differ ++ masm.bind(breakLabel); ++ masm.cmp(64, rscratch1, zr); ++ masm.cset(result, ConditionFlag.EQ); ++ } ++ } ++ ++ /** ++ * Vector size used in {@link #emit8ByteCompare}. ++ */ ++ private static final int VECTOR_SIZE = 8; ++ ++ /** ++ * Emits code that uses 8-byte vector compares. ++ * ++ */ ++ private void emit8ByteCompare(CompilationResultBuilder crb, SW64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label breakLabel, ++ Register rscratch1) { ++ Label loop = new Label(); ++ Label compareTail = new Label(); ++ ++ Register temp = asRegister(temp4); ++ ++ masm.and(64, result, result, VECTOR_SIZE - 1); // tail count (in bytes) ++ masm.ands(64, length, length, ~(VECTOR_SIZE - 1)); // vector count (in bytes) ++ masm.branchConditionally(ConditionFlag.EQ, compareTail); ++ ++ masm.lea(array1, SW64Address.createRegisterOffsetAddress(array1, length, false)); ++ masm.lea(array2, SW64Address.createRegisterOffsetAddress(array2, length, false)); ++ masm.sub(64, length, zr, length); ++ ++ // Align the main loop ++ masm.align(crb.target.wordSize * 2); ++ masm.bind(loop); ++ masm.ldr(64, temp, SW64Address.createRegisterOffsetAddress(array1, length, false)); ++ masm.ldr(64, rscratch1, SW64Address.createRegisterOffsetAddress(array2, length, false)); ++ masm.eor(64, rscratch1, temp, rscratch1); ++ masm.cbnz(64, rscratch1, breakLabel); ++ masm.add(64, length, length, VECTOR_SIZE); ++ masm.cbnz(64, length, loop); ++ ++ masm.cbz(64, result, breakLabel); ++ ++ /* ++ * Compare the remaining bytes with an unaligned memory load aligned to the end of the ++ * array. ++ */ ++ masm.lea(array1, SW64Address.createUnscaledImmediateAddress(array1, -VECTOR_SIZE)); ++ masm.lea(array2, SW64Address.createUnscaledImmediateAddress(array2, -VECTOR_SIZE)); ++ masm.ldr(64, temp, SW64Address.createRegisterOffsetAddress(array1, result, false)); ++ masm.ldr(64, rscratch1, SW64Address.createRegisterOffsetAddress(array2, result, false)); ++ masm.eor(64, rscratch1, temp, rscratch1); ++ masm.jmp(breakLabel); ++ ++ masm.bind(compareTail); ++ } ++ ++ /** ++ * Emits code to compare the remaining 1 to 4 bytes. ++ * ++ */ ++ private void emitTailCompares(SW64MacroAssembler masm, Register result, Register array1, Register array2, Label breakLabel, Register rscratch1) { ++ Label compare2Bytes = new Label(); ++ Label compare1Byte = new Label(); ++ Label end = new Label(); ++ ++ Register temp = asRegister(temp4); ++ ++ if (kind.getByteCount() <= 4) { ++ // Compare trailing 4 bytes, if any. ++ masm.ands(32, zr, result, 4); ++ masm.branchConditionally(ConditionFlag.EQ, compare2Bytes); ++ masm.ldr(32, temp, SW64Address.createPostIndexedImmediateAddress(array1, 4)); ++ masm.ldr(32, rscratch1, SW64Address.createPostIndexedImmediateAddress(array2, 4)); ++ masm.eor(32, rscratch1, temp, rscratch1); ++ masm.cbnz(32, rscratch1, breakLabel); ++ ++ if (kind.getByteCount() <= 2) { ++ // Compare trailing 2 bytes, if any. ++ masm.bind(compare2Bytes); ++ masm.ands(32, zr, result, 2); ++ masm.branchConditionally(ConditionFlag.EQ, compare1Byte); ++ masm.ldr(16, temp, SW64Address.createPostIndexedImmediateAddress(array1, 2)); ++ masm.ldr(16, rscratch1, SW64Address.createPostIndexedImmediateAddress(array2, 2)); ++ masm.eor(32, rscratch1, temp, rscratch1); ++ masm.cbnz(32, rscratch1, breakLabel); ++ ++ // The one-byte tail compare is only required for boolean and byte arrays. ++ if (kind.getByteCount() <= 1) { ++ // Compare trailing byte, if any. ++ masm.bind(compare1Byte); ++ masm.ands(32, zr, result, 1); ++ masm.branchConditionally(ConditionFlag.EQ, end); ++ masm.ldr(8, temp, SW64Address.createBaseRegisterOnlyAddress(array1)); ++ masm.ldr(8, rscratch1, SW64Address.createBaseRegisterOnlyAddress(array2)); ++ masm.eor(32, rscratch1, temp, rscratch1); ++ masm.cbnz(32, rscratch1, breakLabel); ++ } else { ++ masm.bind(compare1Byte); ++ } ++ } else { ++ masm.bind(compare2Bytes); ++ } ++ } ++ masm.bind(end); ++ masm.mov(64, rscratch1, zr); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AtomicMove.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AtomicMove.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AtomicMove.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64AtomicMove.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,258 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.ScratchRegister; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.LIRValueUtil; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64AtomicMove { ++ /** ++ * Compare and swap instruction. Does the following atomically: ++ * CAS(newVal, expected, address): ++ * oldVal = *address ++ * if oldVal == expected: ++ * *address = newVal ++ * return oldVal ++ * ++ */ ++ @Opcode("CAS") ++ public static class CompareAndSwapOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); ++ ++ @Def protected AllocatableValue resultValue; ++ @Alive protected Value expectedValue; ++ @Alive protected AllocatableValue newValue; ++ @Alive protected AllocatableValue addressValue; ++ @Temp protected AllocatableValue scratchValue; ++ ++ public CompareAndSwapOp(AllocatableValue result, Value expectedValue, AllocatableValue newValue, AllocatableValue addressValue, AllocatableValue scratch) { ++ super(TYPE); ++ this.resultValue = result; ++ this.expectedValue = expectedValue; ++ this.newValue = newValue; ++ this.addressValue = addressValue; ++ this.scratchValue = scratch; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ SW64Kind kind = (SW64Kind) expectedValue.getPlatformKind(); ++ assert kind.isInteger(); ++ final int size = kind.getSizeInBytes() * Byte.SIZE; ++ ++ Register address = asRegister(addressValue); ++ Register result = asRegister(resultValue); ++ Register newVal = asRegister(newValue); ++ if (SW64LIRFlagsVersioned.useLSE(masm.target.arch)) { ++ Register expected = asRegister(expectedValue); ++ masm.mov(size, result, expected); ++ masm.cas(size, result, newVal, address, true /* acquire */, true /* release */); ++ SW64Compare.gpCompare(masm, resultValue, expectedValue); ++ } else { ++ // We could avoid using a scratch register here, by reusing resultValue for the ++ // stlxr success flag and issue a mov resultValue, expectedValue in case of success ++ // before returning. ++ Register scratch = asRegister(scratchValue); ++ Label retry = new Label(); ++ Label fail = new Label(); ++ masm.bind(retry); ++ masm.ldaxr(size, result, address); ++ SW64Compare.gpCompare(masm, resultValue, expectedValue); ++ masm.branchConditionally(SW64Assembler.ConditionFlag.NE, fail); ++ masm.stlxr(size, scratch, newVal, address); ++ // if scratch == 0 then write successful, else retry. ++ masm.cbnz(32, scratch, retry); ++ masm.bind(fail); ++ } ++ } ++ } ++ ++ /** ++ * Load (Read) and Add instruction. Does the following atomically: ++ * ATOMIC_READ_AND_ADD(addend, result, address): ++ * result = *address ++ * *address = result + addend ++ * return result ++ * ++ */ ++ @Opcode("ATOMIC_READ_AND_ADD") ++ public static final class AtomicReadAndAddOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AtomicReadAndAddOp.class); ++ ++ private final SW64Kind accessKind; ++ ++ @Def({REG}) protected AllocatableValue resultValue; ++ @Alive({REG}) protected AllocatableValue addressValue; ++ @Alive({REG, CONST}) protected Value deltaValue; ++ ++ public AtomicReadAndAddOp(SW64Kind kind, AllocatableValue result, AllocatableValue address, Value delta) { ++ super(TYPE); ++ this.accessKind = kind; ++ this.resultValue = result; ++ this.addressValue = address; ++ this.deltaValue = delta; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ assert accessKind.isInteger(); ++ final int size = accessKind.getSizeInBytes() * Byte.SIZE; ++ ++ Register address = asRegister(addressValue); ++ Register result = asRegister(resultValue); ++ ++ Label retry = new Label(); ++ masm.bind(retry); ++ masm.ldaxr(size, result, address); ++ try (ScratchRegister scratchRegister1 = masm.getScratchRegister()) { ++ Register scratch1 = scratchRegister1.getRegister(); ++ if (LIRValueUtil.isConstantValue(deltaValue)) { ++ long delta = LIRValueUtil.asConstantValue(deltaValue).getJavaConstant().asLong(); ++ masm.add(size, scratch1, result, delta); ++ } else { // must be a register then ++ masm.add(size, scratch1, result, asRegister(deltaValue)); ++ } ++ try (ScratchRegister scratchRegister2 = masm.getScratchRegister()) { ++ Register scratch2 = scratchRegister2.getRegister(); ++ masm.stlxr(size, scratch2, scratch1, address); ++ // if scratch2 == 0 then write successful, else retry ++ masm.cbnz(32, scratch2, retry); ++ } ++ } ++ } ++ } ++ ++ /** ++ * Load (Read) and Add instruction. Does the following atomically: ++ * ATOMIC_READ_AND_ADD(addend, result, address): ++ * result = *address ++ * *address = result + addend ++ * return result ++ * ++ * ++ * The LSE version has different properties with regards to the register allocator. To define ++ * these differences, we have to create a separate LIR instruction class. ++ * ++ * The difference to {@linkplain AtomicReadAndAddOp} is: ++ *

  • {@linkplain #deltaValue} must be a register (@Use({REG}) instead @Alive({REG,CONST})) ++ *
  • {@linkplain #resultValue} may be an alias for the input registers (@Use instead ++ * of @Alive) ++ */ ++ @Opcode("ATOMIC_READ_AND_ADD") ++ public static final class AtomicReadAndAddLSEOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AtomicReadAndAddLSEOp.class); ++ ++ private final SW64Kind accessKind; ++ ++ @Def({REG}) protected AllocatableValue resultValue; ++ @Use({REG}) protected AllocatableValue addressValue; ++ @Use({REG}) protected AllocatableValue deltaValue; ++ ++ public AtomicReadAndAddLSEOp(SW64Kind kind, AllocatableValue result, AllocatableValue address, AllocatableValue delta) { ++ super(TYPE); ++ this.accessKind = kind; ++ this.resultValue = result; ++ this.addressValue = address; ++ this.deltaValue = delta; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ assert accessKind.isInteger(); ++ final int size = accessKind.getSizeInBytes() * Byte.SIZE; ++ ++ Register address = asRegister(addressValue); ++ Register delta = asRegister(deltaValue); ++ Register result = asRegister(resultValue); ++ masm.ldadd(size, delta, result, address, true, true); ++ } ++ } ++ ++ /** ++ * Load (Read) and Write instruction. Does the following atomically: ++ * ATOMIC_READ_AND_WRITE(newValue, result, address): ++ * result = *address ++ * *address = newValue ++ * return result ++ * ++ */ ++ @Opcode("ATOMIC_READ_AND_WRITE") ++ public static final class AtomicReadAndWriteOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AtomicReadAndWriteOp.class); ++ ++ private final SW64Kind accessKind; ++ ++ @Def protected AllocatableValue resultValue; ++ @Alive protected AllocatableValue addressValue; ++ @Alive protected AllocatableValue newValue; ++ @Temp protected AllocatableValue scratchValue; ++ ++ public AtomicReadAndWriteOp(SW64Kind kind, AllocatableValue result, AllocatableValue address, AllocatableValue newValue, AllocatableValue scratch) { ++ super(TYPE); ++ this.accessKind = kind; ++ this.resultValue = result; ++ this.addressValue = address; ++ this.newValue = newValue; ++ this.scratchValue = scratch; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ assert accessKind.isInteger(); ++ final int size = accessKind.getSizeInBytes() * Byte.SIZE; ++ ++ Register address = asRegister(addressValue); ++ Register value = asRegister(newValue); ++ Register result = asRegister(resultValue); ++ ++ if (SW64LIRFlagsVersioned.useLSE(masm.target.arch)) { ++ masm.swp(size, value, result, address, true, true); ++ } else { ++ Register scratch = asRegister(scratchValue); ++ Label retry = new Label(); ++ masm.bind(retry); ++ masm.ldaxr(size, result, address); ++ masm.stlxr(size, scratch, value, address); ++ // if scratch == 0 then write successful, else retry ++ masm.cbnz(32, scratch, retry); ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BitManipulationOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BitManipulationOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BitManipulationOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BitManipulationOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Bit manipulation ops for ARMv8 ISA. ++ */ ++public class SW64BitManipulationOp extends SW64LIRInstruction { ++ public enum BitManipulationOpCode { ++ CTZ, ++ BSR, ++ BSWP, ++ CLZ, ++ } ++ ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64BitManipulationOp.class); ++ ++ @Opcode private final BitManipulationOpCode opcode; ++ @Def protected AllocatableValue result; ++ @Use({REG}) protected AllocatableValue input; ++ ++ public SW64BitManipulationOp(BitManipulationOpCode opcode, AllocatableValue result, AllocatableValue input) { ++ super(TYPE); ++ this.opcode = opcode; ++ this.result = result; ++ this.input = input; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register dst = asRegister(result); ++ Register src = asRegister(input); ++ final int size = input.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ switch (opcode) { ++ case CLZ: ++ masm.clz(size, dst, src); ++ break; ++ case BSR: ++ // BSR == - 1 - CLZ(input) ++ masm.clz(size, dst, src); ++ masm.neg(size, dst, dst); ++ masm.add(size, dst, dst, size - 1); ++ break; ++ case CTZ: ++ // CTZ == CLZ(rbit(input)) ++ masm.rbit(size, dst, src); ++ masm.clz(size, dst, dst); ++ break; ++ case BSWP: ++ masm.rev(size, dst, src); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BlockEndOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BlockEndOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BlockEndOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BlockEndOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstruction; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.StandardOp.BlockEndOp; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++public abstract class SW64BlockEndOp extends LIRInstruction implements BlockEndOp { ++ ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64BlockEndOp.class); ++ ++ protected SW64BlockEndOp(LIRInstructionClass c) { ++ super(c); ++ } ++ ++ @Override ++ public final void emitCode(CompilationResultBuilder crb) { ++ emitCode(crb, (SW64MacroAssembler) crb.asm); ++ } ++ ++ protected abstract void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm); ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BreakpointOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BreakpointOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BreakpointOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64BreakpointOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.SW64ExceptionCode; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.meta.Value; ++ ++@Opcode("BREAKPOINT") ++public class SW64BreakpointOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64BreakpointOp.class); ++ ++ /** ++ * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger). ++ */ ++ @Use({REG, STACK}) private Value[] parameters; ++ ++ public SW64BreakpointOp(Value[] parameters) { ++ super(TYPE); ++ this.parameters = parameters; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ masm.brk(SW64ExceptionCode.BREAKPOINT); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ByteSwapOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ByteSwapOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ByteSwapOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ByteSwapOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.ValueUtil; ++import jdk.vm.ci.meta.Value; ++ ++@Opcode("BSWAP") ++public final class SW64ByteSwapOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64ByteSwapOp.class); ++ ++ @Def({OperandFlag.REG, OperandFlag.HINT}) protected Value result; ++ @Use protected Value input; ++ ++ public SW64ByteSwapOp(Value result, Value input) { ++ super(TYPE); ++ this.result = result; ++ this.input = input; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ switch ((SW64Kind) input.getPlatformKind()) { ++ case DWORD: ++ masm.rev(32, ValueUtil.asRegister(result), ValueUtil.asRegister(input)); ++ break; ++ case QWORD: ++ masm.rev(64, ValueUtil.asRegister(result), ValueUtil.asRegister(input)); ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Call.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Call.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Call.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Call.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,269 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++import static jdk.vm.ci.sw64.SW64.r8; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static jdk.vm.ci.code.ValueUtil.isRegister; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.InvokeTarget; ++import jdk.vm.ci.meta.ResolvedJavaMethod; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64Call { ++ ++ public abstract static class CallOp extends SW64LIRInstruction { ++ @Def({REG, ILLEGAL}) protected Value result; ++ @Use({REG, STACK}) protected Value[] parameters; ++ @Temp({REG, STACK}) protected Value[] temps; ++ @State protected LIRFrameState state; ++ ++ protected CallOp(LIRInstructionClass c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { ++ super(c); ++ this.result = result; ++ this.parameters = parameters; ++ this.state = state; ++ this.temps = addStackSlotsToTemporaries(parameters, temps); ++ assert temps != null; ++ } ++ ++ @Override ++ public boolean destroysCallerSavedRegisters() { ++ return true; ++ } ++ } ++ ++ public abstract static class MethodCallOp extends CallOp { ++ protected final ResolvedJavaMethod callTarget; ++ ++ protected MethodCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { ++ super(c, result, parameters, temps, state); ++ this.callTarget = callTarget; ++ } ++ } ++ ++ @Opcode("CALL_INDIRECT") ++ public static class IndirectCallOp extends MethodCallOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(IndirectCallOp.class); ++ ++ @Use({REG}) protected Value targetAddress; ++ ++ public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { ++ this(TYPE, callTarget, result, parameters, temps, targetAddress, state); ++ } ++ ++ protected IndirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, ++ LIRFrameState state) { ++ super(c, callTarget, result, parameters, temps, state); ++ this.targetAddress = targetAddress; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register target = asRegister(targetAddress); ++ indirectCall(crb, masm, target, callTarget, state); ++ } ++ ++ @Override ++ public void verify() { ++ super.verify(); ++ assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, " + "it must be in a fixed register for now"; ++ } ++ } ++ ++ @Opcode("CALL_DIRECT") ++ public abstract static class DirectCallOp extends MethodCallOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectCallOp.class); ++ ++ public DirectCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { ++ super(TYPE, target, result, parameters, temps, state); ++ } ++ ++ protected DirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { ++ super(c, callTarget, result, parameters, temps, state); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ directCall(crb, masm, callTarget, null, state); ++ } ++ } ++ ++ public abstract static class ForeignCallOp extends CallOp { ++ protected final ForeignCallLinkage callTarget; ++ protected final Label label; ++ ++ protected ForeignCallOp(LIRInstructionClass c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) { ++ super(c, result, parameters, temps, state); ++ this.callTarget = callTarget; ++ this.label = label; ++ } ++ ++ @Override ++ public boolean destroysCallerSavedRegisters() { ++ return callTarget.destroysRegisters(); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ emitCall(crb, masm); ++ } ++ ++ protected abstract void emitCall(CompilationResultBuilder crb, SW64MacroAssembler masm); ++ } ++ ++ @Opcode("NEAR_FOREIGN_CALL") ++ public static class DirectNearForeignCallOp extends ForeignCallOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); ++ ++ public DirectNearForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) { ++ super(TYPE, callTarget, result, parameters, temps, state, label); ++ } ++ ++ @Override ++ protected void emitCall(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ directCall(crb, masm, callTarget, null, state, label); ++ } ++ } ++ ++ @Opcode("FAR_FOREIGN_CALL") ++ public static class DirectFarForeignCallOp extends ForeignCallOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); ++ ++ public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) { ++ super(TYPE, callTarget, result, parameters, temps, state, label); ++ } ++ ++ @Override ++ protected void emitCall(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // We can use any scratch register we want, since we know that they have been saved ++ // before calling. ++ directCall(crb, masm, callTarget, r8, state, label); ++ } ++ } ++ ++ /** ++ * Tests whether linkage can be called directly under all circumstances without the need for a ++ * scratch register. ++ * ++ * Note this is a pessimistic assumption: This may return false despite a near call/jump being ++ * adequate. ++ * ++ * @param linkage Foreign call description ++ * @return true if foreign call can be called directly and does not need a scratch register to ++ * load the address into. ++ */ ++ public static boolean isNearCall(ForeignCallLinkage linkage) { ++ long maxOffset = linkage.getMaxCallTargetOffset(); ++ return maxOffset != -1 && SW64MacroAssembler.isBranchImmediateOffset(maxOffset); ++ } ++ ++ public static void directCall(CompilationResultBuilder crb, SW64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) { ++ directCall(crb, masm, callTarget, scratch, info, null); ++ } ++ ++ public static void directCall(CompilationResultBuilder crb, SW64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info, Label label) { ++ int before = masm.position(); ++ if (scratch != null) { ++ if (GeneratePIC.getValue(crb.getOptions())) { ++ masm.bl(0); ++ } else { ++ /* ++ * Offset might not fit into a 28-bit immediate, generate an indirect call with a ++ * 64-bit immediate address which is fixed up by HotSpot. ++ */ ++ masm.movNativeAddress(scratch, 0L); ++ masm.blr(scratch); ++ } ++ } else { ++ // Address is fixed up by HotSpot. ++ masm.bl(0); ++ } ++ if (label != null) { ++ // We need this label to be the return address. ++ masm.bind(label); ++ } ++ int after = masm.position(); ++ crb.recordDirectCall(before, after, callTarget, info); ++ crb.recordExceptionHandlers(after, info); ++ masm.ensureUniquePC(); ++ } ++ ++ public static void indirectCall(CompilationResultBuilder crb, SW64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { ++ int before = masm.position(); ++ masm.blr(dst); ++ int after = masm.position(); ++ crb.recordIndirectCall(before, after, callTarget, info); ++ crb.recordExceptionHandlers(after, info); ++ masm.ensureUniquePC(); ++ } ++ ++ public static void directJmp(CompilationResultBuilder crb, SW64MacroAssembler masm, InvokeTarget callTarget) { ++ try (SW64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) { ++ int before = masm.position(); ++ if (GeneratePIC.getValue(crb.getOptions())) { ++ masm.jmp(); ++ } else { ++ masm.movNativeAddress(scratch.getRegister(), 0L); ++ masm.jmp(scratch.getRegister()); ++ } ++ int after = masm.position(); ++ crb.recordDirectCall(before, after, callTarget, null); ++ masm.ensureUniquePC(); ++ } ++ } ++ ++ public static void indirectJmp(CompilationResultBuilder crb, SW64MacroAssembler masm, Register dst, InvokeTarget target) { ++ int before = masm.position(); ++ masm.jmp(dst); ++ int after = masm.position(); ++ crb.recordIndirectCall(before, after, target, null); ++ masm.ensureUniquePC(); ++ } ++ ++ public static void directConditionalJmp(CompilationResultBuilder crb, SW64MacroAssembler masm, InvokeTarget target, SW64Assembler.ConditionFlag cond) { ++ int before = masm.position(); ++ masm.branchConditionally(cond); ++ int after = masm.position(); ++ crb.recordDirectCall(before, after, target, null); ++ masm.ensureUniquePC(); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64CCall.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64CCall.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64CCall.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64CCall.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,69 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.ValueUtil; ++import jdk.vm.ci.meta.Value; ++ ++public final class SW64CCall extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64CCall.class); ++ ++ @Def({REG, ILLEGAL}) protected Value result; ++ @Use({REG, STACK}) protected Value[] parameters; ++ @Use({REG}) protected Value functionPtr; ++ ++ public SW64CCall(Value result, Value functionPtr, Value[] parameters) { ++ super(TYPE); ++ this.result = result; ++ this.functionPtr = functionPtr; ++ this.parameters = parameters; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ directCall(masm); ++ } ++ ++ private void directCall(SW64MacroAssembler masm) { ++ Register reg = ValueUtil.asRegister(functionPtr); ++ masm.blr(reg); ++ masm.ensureUniquePC(); ++ } ++ ++ @Override ++ public boolean destroysCallerSavedRegisters() { ++ return true; ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Compare.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Compare.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Compare.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Compare.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,176 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; ++import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static jdk.vm.ci.code.ValueUtil.isRegister; ++ ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.core.common.calc.Condition; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64Compare { ++ ++ public static class CompareOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareOp.class); ++ ++ @Use protected Value x; ++ @Use({REG, CONST}) protected Value y; ++ ++ public CompareOp(Value x, Value y) { ++ super(TYPE); ++ assert ((SW64Kind) x.getPlatformKind()).isInteger() && ((SW64Kind) y.getPlatformKind()).isInteger(); ++ assert x.getPlatformKind() == y.getPlatformKind(); ++ this.x = x; ++ this.y = y; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ gpCompare(masm, x, y); ++ } ++ } ++ ++ /** ++ * Compares integer values x and y. ++ * ++ * @param x integer value to compare. May not be null. ++ * @param y integer value to compare. May not be null. ++ */ ++ public static void gpCompare(SW64MacroAssembler masm, Value x, Value y) { ++ final int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ if (isRegister(y)) { ++ masm.cmp(size, asRegister(x), asRegister(y)); ++ } else { ++ JavaConstant constant = asJavaConstant(y); ++ if (constant.isDefaultForKind()) { ++ masm.cmp(size, asRegister(x), 0); ++ } else { ++ final long longValue = constant.asLong(); ++ assert NumUtil.isInt(longValue); ++ int maskedValue; ++ switch (constant.getJavaKind()) { ++ case Boolean: ++ case Byte: ++ maskedValue = (int) (longValue & 0xFF); ++ break; ++ case Char: ++ case Short: ++ maskedValue = (int) (longValue & 0xFFFF); ++ break; ++ case Int: ++ case Long: ++ maskedValue = (int) longValue; ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ masm.cmp(size, asRegister(x), maskedValue); ++ } ++ } ++ } ++ ++ public static class FloatCompareOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatCompareOp.class); ++ ++ @Use protected Value x; ++ @Use({REG, CONST}) protected Value y; ++ private final Condition condition; ++ private final boolean unorderedIsTrue; ++ ++ public FloatCompareOp(Value x, Value y, Condition condition, boolean unorderedIsTrue) { ++ super(TYPE); ++ assert !isJavaConstant(y) || isFloatCmpConstant(y, condition, unorderedIsTrue); ++ this.x = x; ++ this.y = y; ++ this.condition = condition; ++ this.unorderedIsTrue = unorderedIsTrue; ++ } ++ ++ /** ++ * Checks if val can be used as a constant for the gpCompare operation or not. ++ */ ++ public static boolean isFloatCmpConstant(Value val, Condition condition, boolean unorderedIsTrue) { ++ // If the condition is "EQ || unordered" or "NE && unordered" we have to use 2 registers ++ // in any case. ++ if (!(condition == Condition.EQ && unorderedIsTrue || condition == Condition.NE && !unorderedIsTrue)) { ++ return false; ++ } ++ return isJavaConstant(val) && asJavaConstant(val).isDefaultForKind(); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ assert isRegister(x); ++ int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ if (isRegister(y)) { ++ masm.fcmp(size, asRegister(x), asRegister(y)); ++ // There is no condition code for "EQ || unordered" nor one for "NE && unordered", ++ // so we have to fix them up ourselves. ++ // In both cases we combine the asked for condition into the EQ, respectively NE ++ // condition, i.e. ++ // if EQ && unoreredIsTrue, then the EQ flag will be set if the two values gpCompare ++ // unequal but are ++ // unordered. ++ if (condition == Condition.EQ && unorderedIsTrue) { ++ // if f1 ordered f2: ++ // result = f1 == f2 ++ // else: ++ // result = EQUAL ++ int nzcv = 0b0100; // EQUAL -> Z = 1 ++ masm.fccmp(size, asRegister(x), asRegister(y), nzcv, SW64Assembler.ConditionFlag.VC); ++ } else if (condition == Condition.NE && !unorderedIsTrue) { ++ // if f1 ordered f2: ++ // result = f1 != f2 ++ // else: ++ // result = !NE == EQUAL ++ int nzcv = 0b0100; // EQUAL -> Z = 1 ++ masm.fccmp(size, asRegister(x), asRegister(y), nzcv, SW64Assembler.ConditionFlag.VC); ++ } ++ } else { ++ // cmp against +0.0 ++ masm.fcmpZero(size, asRegister(x)); ++ } ++ } ++ ++ @Override ++ public void verify() { ++ assert x.getPlatformKind().equals(y.getPlatformKind()) : "a: " + x + " b: " + y; ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ControlFlow.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ControlFlow.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ControlFlow.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ControlFlow.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,300 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asAllocatableValue; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import java.util.function.Function; ++ ++import org.graalvm.compiler.asm.Label; ++import org.graalvm.compiler.core.common.NumUtil; ++import org.graalvm.compiler.asm.sw64.SW64Assembler; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ConditionFlag; ++import org.graalvm.compiler.asm.sw64.SW64Assembler.ExtendType; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.code.CompilationResult.JumpTable; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.calc.Condition; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.ConstantValue; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.LabelRef; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.StandardOp; ++import org.graalvm.compiler.lir.SwitchStrategy; ++import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; ++import org.graalvm.compiler.lir.Variable; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.Constant; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64ControlFlow { ++ ++ /** ++ * Compares integer register to 0 and branches if condition is true. Condition may only be equal ++ * or non-equal. ++ */ ++ // TODO (das) where do we need this? ++ // public static class CompareAndBranchOp extends SW64LIRInstruction implements ++ // StandardOp.BranchOp { ++ // private final ConditionFlag condition; ++ // private final LabelRef destination; ++ // @Use({REG}) private Value x; ++ // ++ // public CompareAndBranchOp(Condition condition, LabelRef destination, Value x) { ++ // assert condition == Condition.EQ || condition == Condition.NE; ++ // assert ARMv8.isGpKind(x.getKind()); ++ // this.condition = condition == Condition.EQ ? ConditionFlag.EQ : ConditionFlag.NE; ++ // this.destination = destination; ++ // this.x = x; ++ // } ++ // ++ // @Override ++ // public void emitCode(CompilationResultBuilder crb, ARMv8MacroAssembler masm) { ++ // int size = ARMv8.bitsize(x.getKind()); ++ // if (condition == ConditionFlag.EQ) { ++ // masm.cbz(size, asRegister(x), destination.label()); ++ // } else { ++ // masm.cbnz(size, asRegister(x), destination.label()); ++ // } ++ // } ++ // } ++ ++ public static class BranchOp extends SW64BlockEndOp implements StandardOp.BranchOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BranchOp.class); ++ ++ private final SW64Assembler.ConditionFlag condition; ++ private final LabelRef trueDestination; ++ private final LabelRef falseDestination; ++ ++ private final double trueDestinationProbability; ++ ++ public BranchOp(SW64Assembler.ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { ++ super(TYPE); ++ this.condition = condition; ++ this.trueDestination = trueDestination; ++ this.falseDestination = falseDestination; ++ this.trueDestinationProbability = trueDestinationProbability; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ /* ++ * Explanation: Depending on what the successor edge is, we can use the fall-through to ++ * optimize the generated code. If neither is a successor edge, use the branch ++ * probability to try to take the conditional jump as often as possible to avoid ++ * executing two instructions instead of one. ++ */ ++ if (crb.isSuccessorEdge(trueDestination)) { ++ masm.branchConditionally(condition.negate(), falseDestination.label()); ++ } else if (crb.isSuccessorEdge(falseDestination)) { ++ masm.branchConditionally(condition, trueDestination.label()); ++ } else if (trueDestinationProbability < 0.5) { ++ masm.branchConditionally(condition.negate(), falseDestination.label()); ++ masm.jmp(trueDestination.label()); ++ } else { ++ masm.branchConditionally(condition, trueDestination.label()); ++ masm.jmp(falseDestination.label()); ++ } ++ } ++ ++ } ++ ++ @Opcode("CMOVE") ++ public static class CondMoveOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CondMoveOp.class); ++ ++ @Def protected Value result; ++ @Use protected Value trueValue; ++ @Use protected Value falseValue; ++ private final SW64Assembler.ConditionFlag condition; ++ ++ public CondMoveOp(Variable result, SW64Assembler.ConditionFlag condition, Value trueValue, Value falseValue) { ++ super(TYPE); ++ assert trueValue.getPlatformKind() == falseValue.getPlatformKind() && trueValue.getPlatformKind() == result.getPlatformKind(); ++ this.result = result; ++ this.condition = condition; ++ this.trueValue = trueValue; ++ this.falseValue = falseValue; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ SW64Kind kind = (SW64Kind) trueValue.getPlatformKind(); ++ int size = kind.getSizeInBytes() * Byte.SIZE; ++ if (kind.isInteger()) { ++ masm.cmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition); ++ } else { ++ masm.fcmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition); ++ } ++ } ++ } ++ ++ public static class StrategySwitchOp extends SW64BlockEndOp implements StandardOp.BlockEndOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StrategySwitchOp.class); ++ ++ private final Constant[] keyConstants; ++ protected final SwitchStrategy strategy; ++ private final Function converter; ++ private final LabelRef[] keyTargets; ++ private final LabelRef defaultTarget; ++ @Alive protected Value key; ++ // TODO (das) This could be optimized: We only need the scratch register in case of a ++ // datapatch, or too large immediates. ++ @Temp protected Value scratch; ++ ++ public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, ++ Function converter) { ++ this(TYPE, strategy, keyTargets, defaultTarget, key, scratch, converter); ++ } ++ ++ protected StrategySwitchOp(LIRInstructionClass c, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, ++ Function converter) { ++ super(c); ++ this.strategy = strategy; ++ this.converter = converter; ++ this.keyConstants = strategy.getKeyConstants(); ++ this.keyTargets = keyTargets; ++ this.defaultTarget = defaultTarget; ++ this.key = key; ++ this.scratch = scratch; ++ assert keyConstants.length == keyTargets.length; ++ assert keyConstants.length == strategy.keyProbabilities.length; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ strategy.run(new SwitchClosure(asRegister(key), crb, masm)); ++ } ++ ++ public class SwitchClosure extends BaseSwitchClosure { ++ ++ protected final Register keyRegister; ++ protected final CompilationResultBuilder crb; ++ protected final SW64MacroAssembler masm; ++ ++ protected SwitchClosure(Register keyRegister, CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ super(crb, masm, keyTargets, defaultTarget); ++ this.keyRegister = keyRegister; ++ this.crb = crb; ++ this.masm = masm; ++ } ++ ++ protected void emitComparison(Constant c) { ++ JavaConstant jc = (JavaConstant) c; ++ ConstantValue constVal = new ConstantValue(LIRKind.value(key.getPlatformKind()), c); ++ switch (jc.getJavaKind()) { ++ case Int: ++ long lc = jc.asLong(); ++ assert NumUtil.isInt(lc); ++ emitCompare(crb, masm, key, scratch, constVal); ++ break; ++ case Long: ++ emitCompare(crb, masm, key, scratch, constVal); ++ break; ++ case Object: ++ emitCompare(crb, masm, key, scratch, constVal); ++ break; ++ default: ++ throw new GraalError("switch only supported for int, long and object"); ++ } ++ } ++ ++ @Override ++ protected void conditionalJump(int index, Condition condition, Label target) { ++ emitComparison(keyConstants[index]); ++ masm.branchConditionally(converter.apply(condition), target); ++ } ++ } ++ } ++ ++ public static final class TableSwitchOp extends SW64BlockEndOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(TableSwitchOp.class); ++ private final int lowKey; ++ private final LabelRef defaultTarget; ++ private final LabelRef[] targets; ++ @Use protected Value index; ++ @Temp({REG, HINT}) protected Value idxScratch; ++ @Temp protected Value scratch; ++ ++ public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Value index, Variable scratch, Variable idxScratch) { ++ super(TYPE); ++ this.lowKey = lowKey; ++ this.defaultTarget = defaultTarget; ++ this.targets = targets; ++ this.index = index; ++ this.scratch = scratch; ++ this.idxScratch = idxScratch; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register indexReg = asRegister(index, SW64Kind.DWORD); ++ Register idxScratchReg = asRegister(idxScratch, SW64Kind.DWORD); ++ Register scratchReg = asRegister(scratch, SW64Kind.QWORD); ++ ++ // Compare index against jump table bounds ++ int highKey = lowKey + targets.length - 1; ++ masm.sub(32, idxScratchReg, indexReg, lowKey); ++ masm.cmp(32, idxScratchReg, highKey - lowKey); ++ ++ // Jump to default target if index is not within the jump table ++ if (defaultTarget != null) { ++ masm.branchConditionally(ConditionFlag.HI, defaultTarget.label()); ++ } ++ ++ Label jumpTable = new Label(); ++ masm.adr(scratchReg, jumpTable); ++ masm.add(64, scratchReg, scratchReg, idxScratchReg, ExtendType.UXTW, 2); ++ masm.jmp(scratchReg); ++ masm.bind(jumpTable); ++ // emit jump table entries ++ for (LabelRef target : targets) { ++ masm.jmp(target.label()); ++ } ++ JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey - 1, 4); ++ crb.compilationResult.addAnnotation(jt); ++ } ++ } ++ ++ private static void emitCompare(CompilationResultBuilder crb, SW64MacroAssembler masm, Value key, Value scratchValue, ConstantValue c) { ++ long imm = c.getJavaConstant().asLong(); ++ final int size = key.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ if (SW64MacroAssembler.isComparisonImmediate(imm)) { ++ masm.cmp(size, asRegister(key), (int) imm); ++ } else { ++ SW64Move.move(crb, masm, asAllocatableValue(scratchValue), c); ++ masm.cmp(size, asRegister(key), asRegister(scratchValue)); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMapBuilder.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMapBuilder.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMapBuilder.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMapBuilder.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.lir.framemap.FrameMap; ++import org.graalvm.compiler.lir.framemap.FrameMapBuilderImpl; ++ ++import jdk.vm.ci.code.CodeCacheProvider; ++import jdk.vm.ci.code.RegisterConfig; ++import jdk.vm.ci.code.StackSlot; ++ ++public class SW64FrameMapBuilder extends FrameMapBuilderImpl { ++ ++ public SW64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) { ++ super(frameMap, codeCache, registerConfig); ++ } ++ ++ public StackSlot allocateDeoptimizationRescueSlot() { ++ return ((SW64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot(); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMap.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMap.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMap.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64FrameMap.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.lir.framemap.FrameMap; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.CodeCacheProvider; ++import jdk.vm.ci.code.RegisterConfig; ++import jdk.vm.ci.code.StackSlot; ++ ++/** ++ * SW64 specific frame map. ++ *

    ++ * This is the format of an SW64 stack frame: ++ *

    ++ * ++ *

    ++ *   Base       Contents
    ++ *
    ++ *            :                                :  -----
    ++ *   caller   | incoming overflow argument n   |    ^
    ++ *   frame    :     ...                        :    | positive
    ++ *            | incoming overflow argument 0   |    | offsets
    ++ *   ---------+--------------------------------+-------------------------
    ++ *            | return address                 |    |            ^
    ++ *            | prev. frame pointer            |    |            |
    ++ *            +--------------------------------+    |            |
    ++ *            | spill slot 0                   |    | negative   |      ^
    ++ *    callee  :     ...                        :    v offsets    |      |
    ++ *    frame   | spill slot n                   |  -----        total  frame
    ++ *            +--------------------------------+               frame  size
    ++ *            | alignment padding              |               size     |
    ++ *            +--------------------------------+  -----          |      |
    ++ *            | outgoing overflow argument n   |    ^            |      |
    ++ *            :     ...                        :    | positive   |      |
    ++ *            | outgoing overflow argument 0   |    | offsets    v      v
    ++ *    %sp-->  +--------------------------------+---------------------------
    ++ *
    ++ * 
    ++ * ++ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such ++ * a block may be greater than the size of a normal spill slot or the word size. ++ *

    ++ * A runtime can reserve space at the beginning of the overflow argument area. The calling ++ * convention can specify that the first overflow stack argument is not at offset 0, but at a ++ * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that ++ * call-free methods also have this space reserved. Then the VM can use the memory at offset 0 ++ * relative to the stack pointer. ++ *

    ++ */ ++public class SW64FrameMap extends FrameMap { ++ // Note: Spill size includes callee save area ++ ++ /** ++ * Creates a new frame map for the specified method. ++ */ ++ public SW64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) { ++ super(codeCache, registerConfig, referenceMapFactory); ++ initialSpillSize = frameSetupSize(); ++ spillSize = initialSpillSize; ++ } ++ ++ @Override ++ public int totalFrameSize() { ++ // frameSize + return address + frame pointer ++ return frameSize() + frameSetupSize(); ++ } ++ ++ private int frameSetupSize() { ++ // Size of return address and frame pointer that are saved in function prologue ++ return getTarget().arch.getWordSize() * 2; ++ } ++ ++ @Override ++ public int currentFrameSize() { ++ return alignFrameSize(outgoingSize + spillSize); ++ } ++ ++ public StackSlot allocateDeoptimizationRescueSlot() { ++ assert spillSize == initialSpillSize : "Deoptimization rescue slot must be the first stack slot"; ++ return allocateSpillSlot(LIRKind.value(SW64Kind.QWORD)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRFlagsVersioned.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRFlagsVersioned.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRFlagsVersioned.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRFlagsVersioned.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2018, 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import jdk.vm.ci.sw64.SW64; ++import jdk.vm.ci.sw64.SW64.CPUFeature; ++import jdk.vm.ci.sw64.SW64.Flag; ++import jdk.vm.ci.code.Architecture; ++ ++public class SW64LIRFlagsVersioned { ++ public static boolean useLSE(Architecture arch) { ++ SW64 sw64 = (SW64) arch; ++ return sw64.getFeatures().contains(CPUFeature.LSE) || sw64.getFlags().contains(Flag.UseLSE); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRInstruction.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRInstruction.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRInstruction.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64LIRInstruction.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstruction; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++public abstract class SW64LIRInstruction extends LIRInstruction { ++ protected SW64LIRInstruction(LIRInstructionClass c) { ++ super(c); ++ } ++ ++ @Override ++ public final void emitCode(CompilationResultBuilder crb) { ++ emitCode(crb, (SW64MacroAssembler) crb.asm); ++ } ++ ++ protected abstract void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm); ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Move.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Move.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Move.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Move.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,557 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; ++import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; ++import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; ++import static jdk.vm.ci.sw64.SW64.sp; ++import static jdk.vm.ci.sw64.SW64.zr; ++import static jdk.vm.ci.code.ValueUtil.asAllocatableValue; ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static jdk.vm.ci.code.ValueUtil.asStackSlot; ++import static jdk.vm.ci.code.ValueUtil.isRegister; ++import static jdk.vm.ci.code.ValueUtil.isStackSlot; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler.ScratchRegister; ++import org.graalvm.compiler.core.common.LIRKind; ++import org.graalvm.compiler.core.common.type.DataPointerConstant; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.StandardOp; ++import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; ++import org.graalvm.compiler.lir.StandardOp.NullCheck; ++import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; ++import org.graalvm.compiler.lir.VirtualStackSlot; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Constant; ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.PlatformKind; ++import jdk.vm.ci.meta.Value; ++ ++public class SW64Move { ++ ++ public static class LoadInlineConstant extends SW64LIRInstruction implements LoadConstantOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadInlineConstant.class); ++ ++ private JavaConstant constant; ++ @Def({REG, STACK}) AllocatableValue result; ++ ++ public LoadInlineConstant(JavaConstant constant, AllocatableValue result) { ++ super(TYPE); ++ this.constant = constant; ++ this.result = result; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ if (isRegister(result)) { ++ const2reg(crb, masm, result, constant); ++ } else if (isStackSlot(result)) { ++ StackSlot slot = asStackSlot(result); ++ const2stack(crb, masm, slot, constant); ++ } ++ } ++ ++ @Override ++ public Constant getConstant() { ++ return constant; ++ } ++ ++ @Override ++ public AllocatableValue getResult() { ++ return result; ++ } ++ } ++ ++ @Opcode("MOVE") ++ public static class Move extends SW64LIRInstruction implements ValueMoveOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Move.class); ++ ++ @Def({REG, STACK, HINT}) protected AllocatableValue result; ++ @Use({REG, STACK}) protected AllocatableValue input; ++ ++ public Move(AllocatableValue result, AllocatableValue input) { ++ super(TYPE); ++ this.result = result; ++ this.input = input; ++ assert !(isStackSlot(result) && isStackSlot(input)); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ move(crb, masm, getResult(), getInput()); ++ } ++ ++ @Override ++ public AllocatableValue getInput() { ++ return input; ++ } ++ ++ @Override ++ public AllocatableValue getResult() { ++ return result; ++ } ++ } ++ ++ public static class LoadAddressOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadAddressOp.class); ++ ++ @Def protected AllocatableValue result; ++ @Use(COMPOSITE) protected SW64AddressValue address; ++ ++ public LoadAddressOp(AllocatableValue result, SW64AddressValue address) { ++ super(TYPE); ++ this.result = result; ++ this.address = address; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register dst = asRegister(result); ++ SW64Address adr = address.toAddress(); ++ masm.loadAddress(dst, adr, address.getScaleFactor()); ++ } ++ } ++ ++ public static class LoadDataOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadDataOp.class); ++ ++ @Def protected AllocatableValue result; ++ private final DataPointerConstant data; ++ ++ public LoadDataOp(AllocatableValue result, DataPointerConstant data) { ++ super(TYPE); ++ this.result = result; ++ this.data = data; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register dst = asRegister(result); ++ if (crb.compilationResult.isImmutablePIC()) { ++ crb.recordDataReferenceInCode(data); ++ masm.addressOf(dst); ++ } else { ++ masm.loadAddress(dst, (SW64Address) crb.recordDataReferenceInCode(data), data.getAlignment()); ++ } ++ } ++ } ++ ++ public static class StackLoadAddressOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StackLoadAddressOp.class); ++ ++ @Def protected AllocatableValue result; ++ @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot; ++ ++ public StackLoadAddressOp(AllocatableValue result, AllocatableValue slot) { ++ super(TYPE); ++ assert slot instanceof VirtualStackSlot || slot instanceof StackSlot; ++ this.result = result; ++ this.slot = slot; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ try (ScratchRegister addrReg = masm.getScratchRegister()) { ++ SW64Address address = loadStackSlotAddress(crb, masm, (StackSlot) slot, addrReg.getRegister()); ++ PlatformKind kind = SW64Kind.QWORD; ++ masm.loadAddress(asRegister(result, kind), address, kind.getSizeInBytes()); ++ } ++ } ++ } ++ ++ public static class MembarOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MembarOp.class); ++ ++ // For future use. ++ @SuppressWarnings("unused") private final int barriers; ++ ++ public MembarOp(int barriers) { ++ super(TYPE); ++ this.barriers = barriers; ++ } ++ ++ @Override ++ // The odd-looking @SuppressWarnings("all") is here because of ++ // a compiler bug which warns that crb is unused, and also ++ // warns that @SuppressWarnings("unused") is unnecessary. ++ public void emitCode(@SuppressWarnings("all") CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // As I understand it load acquire/store release have the same semantics as on IA64 ++ // and allow us to handle LoadStore, LoadLoad and StoreStore without an explicit ++ // barrier. ++ // But Graal support to figure out if a load/store is volatile is non-existant so for ++ // now just use memory barriers everywhere. ++ // if ((barrier & MemoryBarriers.STORE_LOAD) != 0) { ++ masm.dmb(SW64MacroAssembler.BarrierKind.ANY_ANY); ++ // } ++ } ++ } ++ ++ abstract static class MemOp extends SW64LIRInstruction implements StandardOp.ImplicitNullCheck { ++ ++ protected final SW64Kind kind; ++ @Use({COMPOSITE}) protected SW64AddressValue addressValue; ++ @State protected LIRFrameState state; ++ ++ MemOp(LIRInstructionClass c, SW64Kind kind, SW64AddressValue address, LIRFrameState state) { ++ super(c); ++ this.kind = kind; ++ this.addressValue = address; ++ this.state = state; ++ } ++ ++ protected abstract void emitMemAccess(CompilationResultBuilder crb, SW64MacroAssembler masm); ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ if (state != null) { ++ crb.recordImplicitException(masm.position(), state); ++ } ++ emitMemAccess(crb, masm); ++ } ++ ++ @Override ++ public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { ++ int displacement = addressValue.getDisplacement(); ++ if (state == null && value.equals(addressValue.getBase()) && addressValue.getOffset().equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit) { ++ state = nullCheckState; ++ return true; ++ } ++ return false; ++ } ++ } ++ ++ public static final class LoadOp extends MemOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadOp.class); ++ ++ @Def protected AllocatableValue result; ++ ++ public LoadOp(SW64Kind kind, AllocatableValue result, SW64AddressValue address, LIRFrameState state) { ++ super(TYPE, kind, address, state); ++ this.result = result; ++ } ++ ++ @Override ++ protected void emitMemAccess(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ SW64Address address = addressValue.toAddress(); ++ Register dst = asRegister(result); ++ ++ int destSize = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; ++ int srcSize = kind.getSizeInBytes() * Byte.SIZE; ++ if (kind.isInteger()) { ++ masm.ldr(srcSize, dst, address); ++ } else { ++ assert srcSize == destSize; ++ masm.fldr(srcSize, dst, address); ++ } ++ } ++ } ++ ++ public static class StoreOp extends MemOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StoreOp.class); ++ @Use protected AllocatableValue input; ++ ++ public StoreOp(SW64Kind kind, SW64AddressValue address, AllocatableValue input, LIRFrameState state) { ++ super(TYPE, kind, address, state); ++ this.input = input; ++ } ++ ++ @Override ++ protected void emitMemAccess(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ emitStore(crb, masm, kind, addressValue.toAddress(), input); ++ } ++ } ++ ++ public static final class StoreConstantOp extends MemOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StoreConstantOp.class); ++ ++ protected final JavaConstant input; ++ ++ public StoreConstantOp(SW64Kind kind, SW64AddressValue address, JavaConstant input, LIRFrameState state) { ++ super(TYPE, kind, address, state); ++ this.input = input; ++ if (!input.isDefaultForKind()) { ++ throw GraalError.shouldNotReachHere("Can only store null constants to memory"); ++ } ++ } ++ ++ @Override ++ public void emitMemAccess(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ emitStore(crb, masm, kind, addressValue.toAddress(), zr.asValue(LIRKind.combine(addressValue))); ++ } ++ } ++ ++ public static final class NullCheckOp extends SW64LIRInstruction implements NullCheck { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(NullCheckOp.class); ++ ++ @Use(COMPOSITE) protected SW64AddressValue address; ++ @State protected LIRFrameState state; ++ ++ public NullCheckOp(SW64AddressValue address, LIRFrameState state) { ++ super(TYPE); ++ this.address = address; ++ this.state = state; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ crb.recordImplicitException(masm.position(), state); ++ masm.ldr(64, zr, address.toAddress()); ++ } ++ ++ @Override ++ public Value getCheckedValue() { ++ return address.base; ++ } ++ ++ @Override ++ public LIRFrameState getState() { ++ return state; ++ } ++ } ++ ++ private static void emitStore(@SuppressWarnings("unused") CompilationResultBuilder crb, SW64MacroAssembler masm, SW64Kind kind, SW64Address dst, Value src) { ++ int destSize = kind.getSizeInBytes() * Byte.SIZE; ++ if (kind.isInteger()) { ++ masm.str(destSize, asRegister(src), dst); ++ } else { ++ masm.fstr(destSize, asRegister(src), dst); ++ } ++ } ++ ++ public static void move(CompilationResultBuilder crb, SW64MacroAssembler masm, AllocatableValue result, Value input) { ++ if (isRegister(input)) { ++ if (isRegister(result)) { ++ reg2reg(crb, masm, result, asAllocatableValue(input)); ++ } else if (isStackSlot(result)) { ++ reg2stack(crb, masm, result, asAllocatableValue(input)); ++ } else { ++ throw GraalError.shouldNotReachHere(); ++ } ++ } else if (isStackSlot(input)) { ++ if (isRegister(result)) { ++ stack2reg(crb, masm, result, asAllocatableValue(input)); ++ } else if (isStackSlot(result)) { ++ emitStackMove(crb, masm, result, input); ++ } else { ++ throw GraalError.shouldNotReachHere(); ++ } ++ } else if (isJavaConstant(input)) { ++ if (isRegister(result)) { ++ const2reg(crb, masm, result, asJavaConstant(input)); ++ } else { ++ throw GraalError.shouldNotReachHere(); ++ } ++ } else { ++ throw GraalError.shouldNotReachHere(); ++ } ++ } ++ ++ private static void emitStackMove(CompilationResultBuilder crb, SW64MacroAssembler masm, AllocatableValue result, Value input) { ++ try (ScratchRegister r1 = masm.getScratchRegister()) { ++ try (ScratchRegister r2 = masm.getScratchRegister()) { ++ Register rscratch1 = r1.getRegister(); ++ Register rscratch2 = r2.getRegister(); ++ // use the slot kind to define the operand size ++ PlatformKind kind = input.getPlatformKind(); ++ final int size = kind.getSizeInBytes() * Byte.SIZE; ++ ++ // Always perform stack -> stack copies through integer registers ++ crb.blockComment("[stack -> stack copy]"); ++ SW64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), rscratch2); ++ masm.ldr(size, rscratch1, src); ++ SW64Address dst = loadStackSlotAddress(crb, masm, asStackSlot(result), rscratch2); ++ masm.str(size, rscratch1, dst); ++ } ++ } ++ } ++ ++ private static void reg2reg(@SuppressWarnings("unused") CompilationResultBuilder crb, SW64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { ++ Register dst = asRegister(result); ++ Register src = asRegister(input); ++ if (src.equals(dst)) { ++ return; ++ } ++ SW64Kind kind = (SW64Kind) input.getPlatformKind(); ++ int size = kind.getSizeInBytes() * Byte.SIZE; ++ if (kind.isInteger()) { ++ masm.mov(size, dst, src); ++ } else { ++ masm.fmov(size, dst, src); ++ } ++ } ++ ++ static void reg2stack(CompilationResultBuilder crb, SW64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { ++ SW64Address dest = loadStackSlotAddress(crb, masm, asStackSlot(result), Value.ILLEGAL); ++ Register src = asRegister(input); ++ // use the slot kind to define the operand size ++ SW64Kind kind = (SW64Kind) result.getPlatformKind(); ++ final int size = kind.getSizeInBytes() * Byte.SIZE; ++ if (kind.isInteger()) { ++ masm.str(size, src, dest); ++ } else { ++ masm.fstr(size, src, dest); ++ } ++ } ++ ++ static void stack2reg(CompilationResultBuilder crb, SW64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { ++ SW64Kind kind = (SW64Kind) input.getPlatformKind(); ++ // use the slot kind to define the operand size ++ final int size = kind.getSizeInBytes() * Byte.SIZE; ++ if (kind.isInteger()) { ++ SW64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), result); ++ masm.ldr(size, asRegister(result), src); ++ } else { ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ AllocatableValue scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input)); ++ SW64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), scratchRegisterValue); ++ masm.fldr(size, asRegister(result), src); ++ } ++ } ++ } ++ ++ private static void const2reg(CompilationResultBuilder crb, SW64MacroAssembler masm, Value result, JavaConstant input) { ++ Register dst = asRegister(result); ++ switch (input.getJavaKind().getStackKind()) { ++ case Int: ++ final int value = input.asInt(); ++ int maskedValue; ++ switch (input.getJavaKind()) { ++ case Boolean: ++ case Byte: ++ maskedValue = value & 0xFF; ++ break; ++ case Char: ++ case Short: ++ maskedValue = value & 0xFFFF; ++ break; ++ case Int: ++ maskedValue = value; ++ break; ++ default: ++ throw GraalError.shouldNotReachHere(); ++ } ++ masm.mov(dst, maskedValue); ++ break; ++ case Long: ++ masm.mov(dst, input.asLong()); ++ break; ++ case Float: ++ if (SW64MacroAssembler.isFloatImmediate(input.asFloat())) { ++ masm.fmov(32, dst, input.asFloat()); ++ } else if (crb.compilationResult.isImmutablePIC()) { ++ try (ScratchRegister scr = masm.getScratchRegister()) { ++ Register scratch = scr.getRegister(); ++ masm.mov(scratch, Float.floatToRawIntBits(input.asFloat())); ++ masm.fmov(32, dst, scratch); ++ } ++ } else { ++ masm.fldr(32, dst, (SW64Address) crb.asFloatConstRef(input)); ++ } ++ break; ++ case Double: ++ if (SW64MacroAssembler.isDoubleImmediate(input.asDouble())) { ++ masm.fmov(64, dst, input.asDouble()); ++ } else if (crb.compilationResult.isImmutablePIC()) { ++ try (ScratchRegister scr = masm.getScratchRegister()) { ++ Register scratch = scr.getRegister(); ++ masm.mov(scratch, Double.doubleToRawLongBits(input.asDouble())); ++ masm.fmov(64, dst, scratch); ++ } ++ } else { ++ masm.fldr(64, dst, (SW64Address) crb.asDoubleConstRef(input)); ++ } ++ break; ++ case Object: ++ if (input.isNull()) { ++ masm.mov(dst, 0); ++ } else if (crb.target.inlineObjects) { ++ crb.recordInlineDataInCode(input); ++ masm.movNativeAddress(dst, 0xDEADDEADDEADDEADL); ++ } else { ++ masm.ldr(64, dst, (SW64Address) crb.recordDataReferenceInCode(input, 8)); ++ } ++ break; ++ default: ++ throw GraalError.shouldNotReachHere("kind=" + input.getJavaKind().getStackKind()); ++ } ++ } ++ ++ private static void const2stack(CompilationResultBuilder crb, SW64MacroAssembler masm, Value result, JavaConstant constant) { ++ try (ScratchRegister addrReg = masm.getScratchRegister()) { ++ StackSlot slot = (StackSlot) result; ++ SW64Address resultAddress = loadStackSlotAddress(crb, masm, slot, addrReg.getRegister()); ++ if (constant.isDefaultForKind() || constant.isNull()) { ++ emitStore(crb, masm, (SW64Kind) result.getPlatformKind(), resultAddress, zr.asValue(LIRKind.combine(result))); ++ } else { ++ try (ScratchRegister sc = masm.getScratchRegister()) { ++ Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(result)); ++ const2reg(crb, masm, scratchRegisterValue, constant); ++ emitStore(crb, masm, (SW64Kind) result.getPlatformKind(), resultAddress, scratchRegisterValue); ++ } ++ } ++ } ++ } ++ ++ /** ++ * Returns SW64Address of given StackSlot. We cannot use CompilationResultBuilder.asAddress ++ * since this calls SW64MacroAssembler.makeAddress with displacements that may be larger than ++ * 9-bit signed, which cannot be handled by that method. ++ * ++ * Instead we create an address ourselves. We use scaled unsigned addressing since we know the ++ * transfersize, which gives us a 15-bit address range (for longs/doubles) respectively a 14-bit ++ * range (for everything else). ++ * ++ * @param scratch Scratch register that can be used to load address. If Value.ILLEGAL this ++ * instruction fails if we try to access a StackSlot that is too large to be loaded ++ * directly. ++ * @return SW64Address of given StackSlot. Uses scratch register if necessary to do so. ++ */ ++ private static SW64Address loadStackSlotAddress(CompilationResultBuilder crb, SW64MacroAssembler masm, StackSlot slot, AllocatableValue scratch) { ++ Register scratchReg = Value.ILLEGAL.equals(scratch) ? zr : asRegister(scratch); ++ return loadStackSlotAddress(crb, masm, slot, scratchReg); ++ } ++ ++ private static SW64Address loadStackSlotAddress(CompilationResultBuilder crb, SW64MacroAssembler masm, StackSlot slot, Register scratchReg) { ++ int displacement = crb.frameMap.offsetForStackSlot(slot); ++ int transferSize = slot.getPlatformKind().getSizeInBytes(); ++ return masm.makeAddress(sp, displacement, scratchReg, transferSize, /* allowOverwrite */false); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PauseOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PauseOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PauseOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PauseOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++/** ++ * Emits a pause. ++ */ ++@Opcode("PAUSE") ++public final class SW64PauseOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64PauseOp.class); ++ ++ public SW64PauseOp() { ++ super(TYPE); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ masm.pause(); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PrefetchOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PrefetchOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PrefetchOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64PrefetchOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,52 @@ ++/* ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; ++ ++import org.graalvm.compiler.asm.sw64.SW64Assembler.PrefetchMode; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++public final class SW64PrefetchOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64PrefetchOp.class); ++ ++ private final PrefetchMode mode; // AllocatePrefetchInstr ++ @Alive({COMPOSITE}) protected SW64AddressValue address; ++ ++ public SW64PrefetchOp(SW64AddressValue address, PrefetchMode mode) { ++ super(TYPE); ++ this.address = address; ++ this.mode = mode; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ // instr gets ignored! ++ masm.prfm(address.toAddress(), mode); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ReinterpretOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ReinterpretOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ReinterpretOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64ReinterpretOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.sw64.SW64Kind; ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Instruction that reinterprets some bit pattern as a different type. It is possible to reinterpret ++ * the following: - int <-> float - long <-> double ++ */ ++public class SW64ReinterpretOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64ReinterpretOp.class); ++ ++ @Def protected AllocatableValue resultValue; ++ @Use protected AllocatableValue inputValue; ++ ++ public SW64ReinterpretOp(AllocatableValue resultValue, AllocatableValue inputValue) { ++ super(TYPE); ++ SW64Kind from = (SW64Kind) inputValue.getPlatformKind(); ++ SW64Kind to = (SW64Kind) resultValue.getPlatformKind(); ++ assert from.getSizeInBytes() == to.getSizeInBytes() && from.isInteger() ^ to.isInteger(); ++ this.resultValue = resultValue; ++ this.inputValue = inputValue; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register result = asRegister(resultValue); ++ Register input = asRegister(inputValue); ++ SW64Kind to = (SW64Kind) resultValue.getPlatformKind(); ++ final int size = to.getSizeInBytes() * Byte.SIZE; ++ masm.fmov(size, result, input); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64RestoreRegistersOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64RestoreRegistersOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64RestoreRegistersOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64RestoreRegistersOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++import static jdk.vm.ci.code.ValueUtil.asStackSlot; ++import static jdk.vm.ci.code.ValueUtil.isStackSlot; ++ ++import java.util.Arrays; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.LIRValueUtil; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Restores registers from stack slots. ++ */ ++@Opcode("RESTORE_REGISTER") ++public class SW64RestoreRegistersOp extends SW64LIRInstruction { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64RestoreRegistersOp.class); ++ ++ /** ++ * The slots from which the registers are restored. ++ */ ++ @Use(STACK) protected final AllocatableValue[] slots; ++ ++ /** ++ * The operation that saved the registers restored by this operation. ++ */ ++ private final SW64SaveRegistersOp save; ++ ++ public SW64RestoreRegistersOp(AllocatableValue[] values, SW64SaveRegistersOp save) { ++ this(TYPE, values, save); ++ } ++ ++ protected SW64RestoreRegistersOp(LIRInstructionClass c, AllocatableValue[] values, SW64SaveRegistersOp save) { ++ super(c); ++ assert Arrays.asList(values).stream().allMatch(LIRValueUtil::isVirtualStackSlot); ++ this.slots = values; ++ this.save = save; ++ } ++ ++ protected Register[] getSavedRegisters() { ++ return save.savedRegisters; ++ } ++ ++ protected void restoreRegister(CompilationResultBuilder crb, SW64MacroAssembler masm, Register result, StackSlot input) { ++ SW64Move.stack2reg(crb, masm, result.asValue(), input); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register[] savedRegisters = getSavedRegisters(); ++ for (int i = 0; i < savedRegisters.length; i++) { ++ if (savedRegisters[i] != null) { ++ assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; ++ restoreRegister(crb, masm, savedRegisters[i], asStackSlot(slots[i])); ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SaveRegistersOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SaveRegistersOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SaveRegistersOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SaveRegistersOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asStackSlot; ++import static jdk.vm.ci.code.ValueUtil.isStackSlot; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; ++ ++import java.util.Arrays; ++ ++import jdk.internal.vm.compiler.collections.EconomicSet; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.LIRValueUtil; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++import org.graalvm.compiler.lir.framemap.FrameMap; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.code.RegisterSaveLayout; ++import jdk.vm.ci.code.StackSlot; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++/** ++ * Saves registers to stack slots. ++ */ ++@Opcode("SAVE_REGISTER") ++public class SW64SaveRegistersOp extends SW64LIRInstruction implements SaveRegistersOp { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64SaveRegistersOp.class); ++ ++ /** ++ * The registers (potentially) saved by this operation. ++ */ ++ protected final Register[] savedRegisters; ++ ++ /** ++ * The slots to which the registers are saved. ++ */ ++ @Def(STACK) protected final AllocatableValue[] slots; ++ ++ /** ++ * Specifies if {@link #remove(EconomicSet)} should have an effect. ++ */ ++ protected final boolean supportsRemove; ++ ++ /** ++ * ++ * @param savedRegisters the registers saved by this operation which may be subject to ++ * {@linkplain #remove(EconomicSet) pruning} ++ * @param savedRegisterLocations the slots to which the registers are saved ++ * @param supportsRemove determines if registers can be {@linkplain #remove(EconomicSet) pruned} ++ */ ++ public SW64SaveRegistersOp(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { ++ this(TYPE, savedRegisters, savedRegisterLocations, supportsRemove); ++ } ++ ++ public SW64SaveRegistersOp(LIRInstructionClass c, Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { ++ super(c); ++ assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot); ++ this.savedRegisters = savedRegisters; ++ this.slots = savedRegisterLocations; ++ this.supportsRemove = supportsRemove; ++ } ++ ++ protected void saveRegister(CompilationResultBuilder crb, SW64MacroAssembler masm, StackSlot result, Register input) { ++ SW64Move.reg2stack(crb, masm, result, input.asValue()); ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ for (int i = 0; i < savedRegisters.length; i++) { ++ if (savedRegisters[i] != null) { ++ assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; ++ saveRegister(crb, masm, asStackSlot(slots[i]), savedRegisters[i]); ++ } ++ } ++ } ++ ++ public AllocatableValue[] getSlots() { ++ return slots; ++ } ++ ++ @Override ++ public boolean supportsRemove() { ++ return supportsRemove; ++ } ++ ++ @Override ++ public int remove(EconomicSet doNotSave) { ++ if (!supportsRemove) { ++ throw new UnsupportedOperationException(); ++ } ++ return prune(doNotSave, savedRegisters); ++ } ++ ++ static int prune(EconomicSet toRemove, Register[] registers) { ++ int pruned = 0; ++ for (int i = 0; i < registers.length; i++) { ++ if (registers[i] != null) { ++ if (toRemove.contains(registers[i])) { ++ registers[i] = null; ++ pruned++; ++ } ++ } ++ } ++ return pruned; ++ } ++ ++ @Override ++ public RegisterSaveLayout getMap(FrameMap frameMap) { ++ int total = 0; ++ for (int i = 0; i < savedRegisters.length; i++) { ++ if (savedRegisters[i] != null) { ++ total++; ++ } ++ } ++ Register[] keys = new Register[total]; ++ int[] values = new int[total]; ++ if (total != 0) { ++ int mapIndex = 0; ++ for (int i = 0; i < savedRegisters.length; i++) { ++ if (savedRegisters[i] != null) { ++ keys[mapIndex] = savedRegisters[i]; ++ assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; ++ StackSlot slot = asStackSlot(slots[i]); ++ values[mapIndex] = indexForStackSlot(frameMap, slot); ++ mapIndex++; ++ } ++ } ++ assert mapIndex == total; ++ } ++ return new RegisterSaveLayout(keys, values); ++ } ++ ++ /** ++ * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack ++ * slots in the reference map. ++ * ++ * @param slot a stack slot ++ * @return the index of the stack slot ++ */ ++ private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) { ++ assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0; ++ int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize; ++ return value; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SignExtendOp.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SignExtendOp.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SignExtendOp.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64SignExtendOp.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (c) 2015, 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++ ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.Opcode; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++ ++@Opcode("SIGNEXTEND") ++public class SW64SignExtendOp extends SW64LIRInstruction { ++ private static final LIRInstructionClass TYPE = LIRInstructionClass.create(SW64SignExtendOp.class); ++ ++ @Def protected AllocatableValue resultValue; ++ @Use protected AllocatableValue inputValue; ++ private final int fromBits; ++ private final int toBits; ++ ++ public SW64SignExtendOp(AllocatableValue resultValue, AllocatableValue inputValue, int fromBits, int toBits) { ++ super(TYPE); ++ this.resultValue = resultValue; ++ this.inputValue = inputValue; ++ this.fromBits = fromBits; ++ this.toBits = toBits; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ Register result = asRegister(resultValue); ++ Register input = asRegister(inputValue); ++ masm.sxt(toBits <= 32 ? 32 : 64, fromBits, result, input); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Unary.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Unary.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Unary.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sw64/src/org/graalvm/compiler/lir/sw64/SW64Unary.java 2025-05-09 10:05:57.844290601 +0800 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.lir.sw64; ++ ++import static jdk.vm.ci.code.ValueUtil.asRegister; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; ++import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; ++ ++import org.graalvm.compiler.asm.sw64.SW64Address; ++import org.graalvm.compiler.asm.sw64.SW64MacroAssembler; ++import org.graalvm.compiler.lir.LIRFrameState; ++import org.graalvm.compiler.lir.LIRInstructionClass; ++import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; ++import org.graalvm.compiler.lir.asm.CompilationResultBuilder; ++ ++import jdk.vm.ci.code.Register; ++import jdk.vm.ci.meta.AllocatableValue; ++import jdk.vm.ci.meta.Value; ++ ++/** ++ * AARCH64 LIR instructions that have one input and one output. ++ */ ++public class SW64Unary { ++ ++ /** ++ * Instruction with a {@link SW64AddressValue memory} operand. ++ */ ++ public static class MemoryOp extends SW64LIRInstruction implements ImplicitNullCheck { ++ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryOp.class); ++ ++ private final boolean isSigned; ++ ++ @Def({REG}) protected AllocatableValue result; ++ @Use({COMPOSITE}) protected SW64AddressValue input; ++ ++ @State protected LIRFrameState state; ++ ++ private int targetSize; ++ private int srcSize; ++ ++ public MemoryOp(boolean isSigned, int targetSize, int srcSize, AllocatableValue result, SW64AddressValue input, LIRFrameState state) { ++ super(TYPE); ++ this.targetSize = targetSize; ++ this.srcSize = srcSize; ++ this.isSigned = isSigned; ++ this.result = result; ++ this.input = input; ++ this.state = state; ++ } ++ ++ @Override ++ public void emitCode(CompilationResultBuilder crb, SW64MacroAssembler masm) { ++ if (state != null) { ++ crb.recordImplicitException(masm.position(), state); ++ } ++ SW64Address address = input.toAddress(); ++ Register dst = asRegister(result); ++ if (isSigned) { ++ masm.ldrs(targetSize, srcSize, dst, address); ++ } else { ++ masm.ldr(srcSize, dst, address); ++ } ++ } ++ ++ @Override ++ public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { ++ int displacement = input.getDisplacement(); ++ if (state == null && value.equals(input.getBase()) && input.getOffset().equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit) { ++ state = nullCheckState; ++ return true; ++ } ++ return false; ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountLeadingZerosNode.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountLeadingZerosNode.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountLeadingZerosNode.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountLeadingZerosNode.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; ++import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; ++ ++import org.graalvm.compiler.core.common.type.IntegerStamp; ++import org.graalvm.compiler.core.common.type.Stamp; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.graph.spi.CanonicalizerTool; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.ConstantNode; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.UnaryNode; ++import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++import org.graalvm.compiler.nodes.type.StampTool; ++ ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.JavaKind; ++ ++@NodeInfo(cycles = CYCLES_2, size = SIZE_1) ++public final class SW64CountLeadingZerosNode extends UnaryNode implements ArithmeticLIRLowerable { ++ ++ public static final NodeClass TYPE = NodeClass.create(SW64CountLeadingZerosNode.class); ++ ++ public SW64CountLeadingZerosNode(ValueNode value) { ++ super(TYPE, computeStamp(value.stamp(NodeView.DEFAULT), value), value); ++ } ++ ++ @Override ++ public Stamp foldStamp(Stamp newStamp) { ++ return computeStamp(newStamp, getValue()); ++ } ++ ++ private static Stamp computeStamp(Stamp newStamp, ValueNode theValue) { ++ assert newStamp.isCompatible(theValue.stamp(NodeView.DEFAULT)); ++ assert theValue.getStackKind() == JavaKind.Int || theValue.getStackKind() == JavaKind.Long; ++ return StampTool.stampForLeadingZeros((IntegerStamp) newStamp); ++ } ++ ++ public static ValueNode tryFold(ValueNode value) { ++ if (value.isConstant()) { ++ JavaConstant c = value.asJavaConstant(); ++ if (value.getStackKind() == JavaKind.Int) { ++ return ConstantNode.forInt(Integer.numberOfLeadingZeros(c.asInt())); ++ } else { ++ return ConstantNode.forInt(Long.numberOfLeadingZeros(c.asLong())); ++ } ++ } ++ return null; ++ } ++ ++ @Override ++ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { ++ ValueNode folded = tryFold(forValue); ++ return folded != null ? folded : this; ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) { ++ builder.setResult(this, ((SW64ArithmeticLIRGeneratorTool) gen).emitCountLeadingZeros(builder.operand(getValue()))); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountTrailingZerosNode.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountTrailingZerosNode.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountTrailingZerosNode.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64CountTrailingZerosNode.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; ++import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; ++ ++import org.graalvm.compiler.core.common.type.IntegerStamp; ++import org.graalvm.compiler.core.common.type.Stamp; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.graph.spi.CanonicalizerTool; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.ConstantNode; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.UnaryNode; ++import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++import org.graalvm.compiler.nodes.type.StampTool; ++ ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.JavaKind; ++ ++/** ++ * Count the number of trailing zeros using the {@code rbit; clz} instructions. ++ */ ++@NodeInfo(cycles = CYCLES_2, size = SIZE_2) ++public final class SW64CountTrailingZerosNode extends UnaryNode implements ArithmeticLIRLowerable { ++ public static final NodeClass TYPE = NodeClass.create(SW64CountTrailingZerosNode.class); ++ ++ public SW64CountTrailingZerosNode(ValueNode value) { ++ super(TYPE, computeStamp(value.stamp(NodeView.DEFAULT), value), value); ++ assert value.getStackKind() == JavaKind.Int || value.getStackKind() == JavaKind.Long; ++ } ++ ++ @Override ++ public Stamp foldStamp(Stamp newStamp) { ++ return computeStamp(newStamp, getValue()); ++ } ++ ++ static Stamp computeStamp(Stamp newStamp, ValueNode value) { ++ assert newStamp.isCompatible(value.stamp(NodeView.DEFAULT)); ++ IntegerStamp valueStamp = (IntegerStamp) newStamp; ++ return StampTool.stampForTrailingZeros(valueStamp); ++ } ++ ++ public static ValueNode tryFold(ValueNode value) { ++ if (value.isConstant()) { ++ JavaConstant c = value.asJavaConstant(); ++ if (value.getStackKind() == JavaKind.Int) { ++ return ConstantNode.forInt(Integer.numberOfTrailingZeros(c.asInt())); ++ } else { ++ return ConstantNode.forInt(Long.numberOfTrailingZeros(c.asLong())); ++ } ++ } ++ return null; ++ } ++ ++ @Override ++ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { ++ ValueNode folded = tryFold(forValue); ++ return folded != null ? folded : this; ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) { ++ builder.setResult(this, ((SW64ArithmeticLIRGeneratorTool) gen).emitCountTrailingZeros(builder.operand(getValue()))); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64FloatArithmeticSnippets.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64FloatArithmeticSnippets.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64FloatArithmeticSnippets.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64FloatArithmeticSnippets.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,156 @@ ++/* ++ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; ++import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; ++ ++import org.graalvm.compiler.api.replacements.Snippet; ++import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; ++import org.graalvm.compiler.debug.DebugHandlersFactory; ++import org.graalvm.compiler.graph.Node.NodeIntrinsic; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.RemNode; ++import org.graalvm.compiler.nodes.spi.LoweringTool; ++import org.graalvm.compiler.options.OptionValues; ++import org.graalvm.compiler.phases.util.Providers; ++import org.graalvm.compiler.replacements.SnippetTemplate; ++import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; ++import org.graalvm.compiler.replacements.Snippets; ++ ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.meta.JavaKind; ++ ++/** ++ * SW64 does not have a remainder operation. We use n % d == n - Truncate(n / d) * d ++ * for it instead. This is not correct for some edge cases, so we have to fix it up using these ++ * snippets. ++ */ ++public class SW64FloatArithmeticSnippets extends SnippetTemplate.AbstractTemplates implements Snippets { ++ ++ private final SnippetTemplate.SnippetInfo drem; ++ private final SnippetTemplate.SnippetInfo frem; ++ ++ public SW64FloatArithmeticSnippets(OptionValues options, Iterable factories, Providers providers, SnippetReflectionProvider snippetReflection, ++ TargetDescription target) { ++ super(options, factories, providers, snippetReflection, target); ++ drem = snippet(SW64FloatArithmeticSnippets.class, "dremSnippet"); ++ frem = snippet(SW64FloatArithmeticSnippets.class, "fremSnippet"); ++ } ++ ++ public void lower(RemNode node, LoweringTool tool) { ++ JavaKind kind = node.stamp(NodeView.DEFAULT).getStackKind(); ++ assert kind == JavaKind.Float || kind == JavaKind.Double; ++ if (node instanceof SafeNode) { ++ // We already introduced the necessary checks, nothing to do. ++ return; ++ } ++ SnippetTemplate.SnippetInfo snippet = kind == JavaKind.Float ? frem : drem; ++ StructuredGraph graph = node.graph(); ++ Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); ++ args.add("x", node.getX()); ++ args.add("y", node.getY()); ++ template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args); ++ } ++ ++ @Snippet ++ public static float fremSnippet(float x, float y) { ++ // JVMS: If either value1' or value2' is NaN, the result is NaN. ++ // JVMS: If the dividend is an infinity or the divisor is a zero or both, the result is NaN. ++ if (Float.isInfinite(x) || y == 0.0f || Float.isNaN(y)) { ++ return Float.NaN; ++ } ++ // JVMS: If the dividend is finite and the divisor is an infinity, the result equals the ++ // dividend. ++ // JVMS: If the dividend is a zero and the divisor is finite, the result equals the ++ // dividend. ++ if (x == 0.0f || Float.isInfinite(y)) { ++ return x; ++ } ++ ++ float result = safeRem(x, y); ++ ++ // JVMS: If neither value1' nor value2' is NaN, the sign of the result equals the sign of ++ // the dividend. ++ if (result == 0.0f && x < 0.0f) { ++ return -result; ++ } ++ return result; ++ } ++ ++ @Snippet ++ public static double dremSnippet(double x, double y) { ++ // JVMS: If either value1' or value2' is NaN, the result is NaN. ++ // JVMS: If the dividend is an infinity or the divisor is a zero or both, the result is NaN. ++ if (Double.isInfinite(x) || y == 0.0 || Double.isNaN(y)) { ++ return Double.NaN; ++ } ++ // JVMS: If the dividend is finite and the divisor is an infinity, the result equals the ++ // dividend. ++ // JVMS: If the dividend is a zero and the divisor is finite, the result equals the ++ // dividend. ++ if (x == 0.0 || Double.isInfinite(y)) { ++ return x; ++ } ++ ++ double result = safeRem(x, y); ++ ++ // JVMS: If neither value1' nor value2' is NaN, the sign of the result equals the sign of ++ // the dividend. ++ if (result == 0.0 && x < 0.0) { ++ return -result; ++ } ++ return result; ++ } ++ ++ @NodeIntrinsic(SafeFloatRemNode.class) ++ private static native float safeRem(float x, float y); ++ ++ @NodeIntrinsic(SafeFloatRemNode.class) ++ private static native double safeRem(double x, double y); ++ ++ /** ++ * Marker interface to distinguish untreated nodes from ones where we have installed the ++ * additional checks. ++ */ ++ private interface SafeNode { ++ } ++ ++ @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) ++ // static class SafeFloatRemNode extends FloatRemNode implements SafeNode { ++ static class SafeFloatRemNode extends RemNode implements SafeNode { ++ public static final NodeClass TYPE = NodeClass.create(SafeFloatRemNode.class); ++ ++ protected SafeFloatRemNode(ValueNode x, ValueNode y) { ++ super(TYPE, x, y); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64GraphBuilderPlugins.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64GraphBuilderPlugins.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64GraphBuilderPlugins.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64GraphBuilderPlugins.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,209 @@ ++/* ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import static org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.registerPlatformSpecificUnsafePlugins; ++import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS; ++import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP; ++import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG; ++import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; ++import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; ++import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; ++import static org.graalvm.compiler.serviceprovider.GraalServices.JAVA_SPECIFICATION_VERSION; ++import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; ++ ++import org.graalvm.compiler.bytecode.BytecodeProvider; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticLIRGeneratorTool.RoundingMode; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; ++import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; ++import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; ++import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; ++import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; ++import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; ++import org.graalvm.compiler.nodes.java.AtomicReadAndAddNode; ++import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode; ++import org.graalvm.compiler.nodes.memory.address.AddressNode; ++import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; ++import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; ++import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; ++import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; ++import jdk.internal.vm.compiler.word.LocationIdentity; ++ ++import jdk.vm.ci.meta.JavaKind; ++import jdk.vm.ci.meta.ResolvedJavaMethod; ++import sun.misc.Unsafe; ++ ++public class SW64GraphBuilderPlugins { ++ ++ public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) { ++ InvocationPlugins invocationPlugins = plugins.getInvocationPlugins(); ++ invocationPlugins.defer(new Runnable() { ++ @Override ++ public void run() { ++ registerIntegerLongPlugins(invocationPlugins, SW64IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider); ++ registerIntegerLongPlugins(invocationPlugins, SW64LongSubstitutions.class, JavaKind.Long, bytecodeProvider); ++ registerMathPlugins(invocationPlugins); ++ registerStringLatin1Plugins(invocationPlugins, bytecodeProvider); ++ registerStringUTF16Plugins(invocationPlugins, bytecodeProvider); ++ registerUnsafePlugins(invocationPlugins, bytecodeProvider); ++ // This is temporarily disabled until we implement correct emitting of the CAS ++ // instructions of the proper width. ++ registerPlatformSpecificUnsafePlugins(invocationPlugins, bytecodeProvider, explicitUnsafeNullChecks, ++ new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}); ++ } ++ }); ++ } ++ ++ private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class substituteDeclaringClass, JavaKind kind, BytecodeProvider bytecodeProvider) { ++ Class declaringClass = kind.toBoxedJavaClass(); ++ Class type = kind.toJavaClass(); ++ Registration r = new Registration(plugins, declaringClass, bytecodeProvider); ++ r.register1("numberOfLeadingZeros", type, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ++ ValueNode folded = SW64CountLeadingZerosNode.tryFold(value); ++ if (folded != null) { ++ b.addPush(JavaKind.Int, folded); ++ } else { ++ b.addPush(JavaKind.Int, new SW64CountLeadingZerosNode(value)); ++ } ++ return true; ++ } ++ }); ++ r.register1("numberOfTrailingZeros", type, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ++ ValueNode folded = SW64CountTrailingZerosNode.tryFold(value); ++ if (folded != null) { ++ b.addPush(JavaKind.Int, folded); ++ } else { ++ b.addPush(JavaKind.Int, new SW64CountTrailingZerosNode(value)); ++ } ++ return true; ++ } ++ }); ++ r.registerMethodSubstitution(substituteDeclaringClass, "bitCount", type); ++ } ++ ++ private static void registerMathPlugins(InvocationPlugins plugins) { ++ Registration r = new Registration(plugins, Math.class); ++ registerUnaryMath(r, "sin", SIN); ++ registerUnaryMath(r, "cos", COS); ++ registerUnaryMath(r, "tan", TAN); ++ registerUnaryMath(r, "exp", EXP); ++ registerUnaryMath(r, "log", LOG); ++ registerUnaryMath(r, "log10", LOG10); ++ r.register2("pow", Double.TYPE, Double.TYPE, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { ++ b.push(JavaKind.Double, b.append(BinaryMathIntrinsicNode.create(x, y, BinaryMathIntrinsicNode.BinaryOperation.POW))); ++ return true; ++ } ++ }); ++ registerRound(r, "rint", RoundingMode.NEAREST); ++ registerRound(r, "ceil", RoundingMode.UP); ++ registerRound(r, "floor", RoundingMode.DOWN); ++ } ++ ++ private static void registerUnaryMath(Registration r, String name, UnaryOperation operation) { ++ r.register1(name, Double.TYPE, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ++ b.push(JavaKind.Double, b.append(UnaryMathIntrinsicNode.create(value, operation))); ++ return true; ++ } ++ }); ++ } ++ ++ private static void registerRound(Registration r, String name, RoundingMode mode) { ++ r.register1(name, Double.TYPE, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { ++ b.push(JavaKind.Double, b.append(new SW64RoundNode(arg, mode))); ++ return true; ++ } ++ }); ++ } ++ ++ private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { ++ if (JAVA_SPECIFICATION_VERSION >= 9) { ++ Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider); ++ r.setAllowOverwrite(true); ++ r.registerMethodSubstitution(SW64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class); ++ r.registerMethodSubstitution(SW64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class); ++ } ++ } ++ ++ private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { ++ if (JAVA_SPECIFICATION_VERSION >= 9) { ++ Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider); ++ r.setAllowOverwrite(true); ++ r.registerMethodSubstitution(SW64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class); ++ r.registerMethodSubstitution(SW64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class); ++ } ++ } ++ ++ private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { ++ Registration r; ++ JavaKind[] unsafeJavaKinds; ++ if (Java8OrEarlier) { ++ r = new Registration(plugins, Unsafe.class); ++ unsafeJavaKinds = new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}; ++ } else { ++ r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider); ++ unsafeJavaKinds = new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}; ++ } ++ ++ for (JavaKind kind : unsafeJavaKinds) { ++ Class javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass(); ++ ++ r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { ++ // Emits a null-check for the otherwise unused receiver ++ unsafe.get(); ++ b.addPush(kind, new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any())); ++ b.getGraph().markUnsafeAccess(); ++ return true; ++ } ++ }); ++ ++ if (kind != JavaKind.Boolean && kind.isNumericInteger()) { ++ r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { ++ @Override ++ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) { ++ // Emits a null-check for the otherwise unused receiver ++ unsafe.get(); ++ AddressNode address = b.add(new OffsetAddressNode(object, offset)); ++ b.addPush(kind, new AtomicReadAndAddNode(address, delta, kind, LocationIdentity.any())); ++ b.getGraph().markUnsafeAccess(); ++ return true; ++ } ++ }); ++ } ++ } ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerArithmeticSnippets.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerArithmeticSnippets.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerArithmeticSnippets.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerArithmeticSnippets.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,294 @@ ++/* ++ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import org.graalvm.compiler.api.replacements.Snippet; ++import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; ++import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; ++import org.graalvm.compiler.core.common.type.IntegerStamp; ++import org.graalvm.compiler.debug.DebugHandlersFactory; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.graph.Node.NodeIntrinsic; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.DeoptimizeNode; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.StructuredGraph; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; ++import org.graalvm.compiler.nodes.calc.SignedDivNode; ++import org.graalvm.compiler.nodes.calc.SignedRemNode; ++import org.graalvm.compiler.nodes.calc.UnsignedDivNode; ++import org.graalvm.compiler.nodes.calc.UnsignedRemNode; ++import org.graalvm.compiler.nodes.spi.LoweringTool; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++import org.graalvm.compiler.options.OptionValues; ++import org.graalvm.compiler.phases.util.Providers; ++import org.graalvm.compiler.replacements.SnippetTemplate; ++import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; ++import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; ++import org.graalvm.compiler.replacements.Snippets; ++ ++import jdk.vm.ci.code.TargetDescription; ++import jdk.vm.ci.meta.DeoptimizationAction; ++import jdk.vm.ci.meta.DeoptimizationReason; ++import jdk.vm.ci.meta.JavaKind; ++ ++/** ++ * Division in SW64 ISA does not generate a trap when dividing by zero, but instead sets the ++ * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise ++ * forward to the LIRGenerator. ++ */ ++public class SW64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets { ++ ++ private final SnippetTemplate.SnippetInfo idiv; ++ private final SnippetTemplate.SnippetInfo ldiv; ++ private final SnippetTemplate.SnippetInfo irem; ++ private final SnippetTemplate.SnippetInfo lrem; ++ ++ private final SnippetTemplate.SnippetInfo uidiv; ++ private final SnippetTemplate.SnippetInfo uldiv; ++ private final SnippetTemplate.SnippetInfo uirem; ++ private final SnippetTemplate.SnippetInfo ulrem; ++ ++ public SW64IntegerArithmeticSnippets(OptionValues options, Iterable factories, Providers providers, SnippetReflectionProvider snippetReflection, ++ TargetDescription target) { ++ super(options, factories, providers, snippetReflection, target); ++ idiv = snippet(SW64IntegerArithmeticSnippets.class, "idivSnippet"); ++ ldiv = snippet(SW64IntegerArithmeticSnippets.class, "ldivSnippet"); ++ irem = snippet(SW64IntegerArithmeticSnippets.class, "iremSnippet"); ++ lrem = snippet(SW64IntegerArithmeticSnippets.class, "lremSnippet"); ++ ++ uidiv = snippet(SW64IntegerArithmeticSnippets.class, "uidivSnippet"); ++ uldiv = snippet(SW64IntegerArithmeticSnippets.class, "uldivSnippet"); ++ uirem = snippet(SW64IntegerArithmeticSnippets.class, "uiremSnippet"); ++ ulrem = snippet(SW64IntegerArithmeticSnippets.class, "ulremSnippet"); ++ } ++ ++ public void lower(IntegerDivRemNode node, LoweringTool tool) { ++ JavaKind kind = node.stamp(NodeView.DEFAULT).getStackKind(); ++ assert kind == JavaKind.Int || kind == JavaKind.Long; ++ SnippetTemplate.SnippetInfo snippet; ++ if (node instanceof SafeNode) { ++ // We already introduced the zero division check, nothing to do. ++ return; ++ } else if (node instanceof SignedDivNode) { ++ snippet = kind == JavaKind.Int ? idiv : ldiv; ++ } else if (node instanceof SignedRemNode) { ++ snippet = kind == JavaKind.Int ? irem : lrem; ++ } else if (node instanceof UnsignedDivNode) { ++ snippet = kind == JavaKind.Int ? uidiv : uldiv; ++ } else if (node instanceof UnsignedRemNode) { ++ snippet = kind == JavaKind.Int ? uirem : ulrem; ++ } else { ++ throw GraalError.shouldNotReachHere(); ++ } ++ StructuredGraph graph = node.graph(); ++ Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); ++ args.add("x", node.getX()); ++ args.add("y", node.getY()); ++ ++ IntegerStamp yStamp = (IntegerStamp) node.getY().stamp(NodeView.DEFAULT); ++ args.addConst("needsZeroCheck", node.getZeroCheck() == null && yStamp.contains(0)); ++ ++ template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); ++ } ++ ++ @Snippet ++ public static int idivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeDiv(x, y); ++ } ++ ++ @Snippet ++ public static long ldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeDiv(x, y); ++ } ++ ++ @Snippet ++ public static int iremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeRem(x, y); ++ } ++ ++ @Snippet ++ public static long lremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeRem(x, y); ++ } ++ ++ @Snippet ++ public static int uidivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeUDiv(x, y); ++ } ++ ++ @Snippet ++ public static long uldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeUDiv(x, y); ++ } ++ ++ @Snippet ++ public static int uiremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeURem(x, y); ++ } ++ ++ @Snippet ++ public static long ulremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) { ++ if (needsZeroCheck) { ++ checkForZero(y); ++ } ++ return safeURem(x, y); ++ } ++ ++ private static void checkForZero(int y) { ++ if (y == 0) { ++ // "/ by zero" ++ DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException); ++ } ++ } ++ ++ private static void checkForZero(long y) { ++ if (y == 0) { ++ // "/ by zero" ++ DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException); ++ } ++ } ++ ++ @NodeIntrinsic(SafeSignedDivNode.class) ++ private static native int safeDiv(int x, int y); ++ ++ @NodeIntrinsic(SafeSignedDivNode.class) ++ private static native long safeDiv(long x, long y); ++ ++ @NodeIntrinsic(SafeSignedRemNode.class) ++ private static native int safeRem(int x, int y); ++ ++ @NodeIntrinsic(SafeSignedRemNode.class) ++ private static native long safeRem(long x, long y); ++ ++ @NodeIntrinsic(SafeUnsignedDivNode.class) ++ private static native int safeUDiv(int x, int y); ++ ++ @NodeIntrinsic(SafeUnsignedDivNode.class) ++ private static native long safeUDiv(long x, long y); ++ ++ @NodeIntrinsic(SafeUnsignedRemNode.class) ++ private static native int safeURem(int x, int y); ++ ++ @NodeIntrinsic(SafeUnsignedRemNode.class) ++ private static native long safeURem(long x, long y); ++ ++ /** ++ * Marker interface to distinguish untreated nodes from ones where we have installed the ++ * additional checks. ++ */ ++ private interface SafeNode { ++ } ++ ++ @NodeInfo ++ static class SafeSignedDivNode extends SignedDivNode implements SafeNode { ++ public static final NodeClass TYPE = NodeClass.create(SafeSignedDivNode.class); ++ ++ protected SafeSignedDivNode(ValueNode x, ValueNode y) { ++ super(TYPE, x, y, null); ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool gen) { ++ // override to ensure we always pass a null frame state ++ // the parent method expects to create one from a non null before state ++ gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitDiv(gen.operand(getX()), gen.operand(getY()), null)); ++ } ++ } ++ ++ @NodeInfo ++ static class SafeSignedRemNode extends SignedRemNode implements SafeNode { ++ public static final NodeClass TYPE = NodeClass.create(SafeSignedRemNode.class); ++ ++ protected SafeSignedRemNode(ValueNode x, ValueNode y) { ++ super(TYPE, x, y, null); ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool gen) { ++ // override to ensure we always pass a null frame state ++ // the parent method expects to create one from a non null before state ++ gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitRem(gen.operand(getX()), gen.operand(getY()), null)); ++ } ++ } ++ ++ @NodeInfo ++ static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode { ++ public static final NodeClass TYPE = NodeClass.create(SafeUnsignedDivNode.class); ++ ++ protected SafeUnsignedDivNode(ValueNode x, ValueNode y) { ++ super(TYPE, x, y, null); ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool gen) { ++ // override to ensure we always pass a null frame state ++ // the parent method expects to create one from a non null before state ++ gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitUDiv(gen.operand(getX()), gen.operand(getY()), null)); ++ } ++ } ++ ++ @NodeInfo ++ static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode { ++ public static final NodeClass TYPE = NodeClass.create(SafeUnsignedRemNode.class); ++ ++ protected SafeUnsignedRemNode(ValueNode x, ValueNode y) { ++ super(TYPE, x, y, null); ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool gen) { ++ // override to ensure we always pass a null frame state ++ // the parent method expects to create one from a non null before state ++ gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitURem(gen.operand(getX()), gen.operand(getY()), null)); ++ } ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerSubstitutions.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerSubstitutions.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerSubstitutions.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64IntegerSubstitutions.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. ++ * 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import org.graalvm.compiler.api.replacements.ClassSubstitution; ++import org.graalvm.compiler.api.replacements.MethodSubstitution; ++ ++/** ++ * SW64 ISA offers a count leading zeros instruction which can be used to implement ++ * numberOfLeadingZeros more efficiently than using BitScanReverse. ++ */ ++@ClassSubstitution(Integer.class) ++public class SW64IntegerSubstitutions { ++ ++ @MethodSubstitution ++ public static int bitCount(int value) { ++ // Based on Warren, Hacker's Delight, slightly adapted to profit from Aarch64 add + shift ++ // instruction. ++ // Assuming the peephole optimizer optimizes all x - y >>> z into a single instruction ++ // this takes 10 instructions. ++ int x = value; ++ x = x - ((x & 0xaaaaaaaa) >>> 1); ++ x = (x & 0x33333333) + ((x & 0xcccccccc) >>> 2); ++ x = (x + (x >>> 4)) & 0x0f0f0f0f; ++ x = x + (x >>> 8); ++ x = x + (x >>> 16); ++ return x & 0x3f; ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64LongSubstitutions.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64LongSubstitutions.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64LongSubstitutions.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64LongSubstitutions.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (c) 2013, 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import org.graalvm.compiler.api.replacements.ClassSubstitution; ++import org.graalvm.compiler.api.replacements.MethodSubstitution; ++ ++/** ++ * Aarch64 ISA offers a count leading zeros instruction which can be used to implement ++ * numberOfLeadingZeros more efficiently than using BitScanReverse. ++ */ ++@ClassSubstitution(Long.class) ++public class SW64LongSubstitutions { ++ ++ @MethodSubstitution ++ public static int bitCount(long value) { ++ // Based on Warren, Hacker's Delight, slightly adapted to profit from Aarch64 add + shift ++ // instruction. ++ // Assuming the peephole optimizer optimizes all x - y >>> z into a single instruction ++ // this takes 11 instructions. ++ long x = value; ++ x = x - ((x & 0xaaaaaaaaaaaaaaaaL) >>> 1); ++ x = (x & 0x3333333333333333L) + ((x & 0xccccccccccccccccL) >>> 2); ++ x = (x + (x >>> 4)) & 0x0f0f0f0f0f0f0f0fL; ++ x = x + (x >>> 8); ++ x = x + (x >>> 16); ++ x = x + (x >>> 32); ++ return (int) x & 0x7f; ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64RoundNode.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64RoundNode.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64RoundNode.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64RoundNode.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,115 @@ ++/* ++ * 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. ++ */ ++ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import jdk.vm.ci.meta.JavaConstant; ++import jdk.vm.ci.meta.JavaKind; ++import org.graalvm.compiler.core.common.type.FloatStamp; ++import org.graalvm.compiler.core.common.type.Stamp; ++import org.graalvm.compiler.debug.GraalError; ++import org.graalvm.compiler.graph.NodeClass; ++import org.graalvm.compiler.graph.spi.CanonicalizerTool; ++import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticLIRGeneratorTool; ++import org.graalvm.compiler.lir.sw64.SW64ArithmeticLIRGeneratorTool.RoundingMode; ++import org.graalvm.compiler.nodeinfo.NodeInfo; ++import org.graalvm.compiler.nodes.ConstantNode; ++import org.graalvm.compiler.nodes.NodeView; ++import org.graalvm.compiler.nodes.ValueNode; ++import org.graalvm.compiler.nodes.calc.UnaryNode; ++import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; ++import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; ++ ++import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; ++ ++/** ++ * Round floating-point value. ++ */ ++@NodeInfo(cycles = CYCLES_8) ++public final class SW64RoundNode extends UnaryNode implements ArithmeticLIRLowerable { ++ public static final NodeClass TYPE = NodeClass.create(SW64RoundNode.class); ++ ++ private final RoundingMode mode; ++ ++ public SW64RoundNode(ValueNode value, RoundingMode mode) { ++ super(TYPE, roundStamp((FloatStamp) value.stamp(NodeView.DEFAULT), mode), value); ++ this.mode = mode; ++ } ++ ++ private static double round(RoundingMode mode, double input) { ++ switch (mode) { ++ case DOWN: ++ return Math.floor(input); ++ case NEAREST: ++ return Math.rint(input); ++ case UP: ++ return Math.ceil(input); ++ case TRUNCATE: ++ return (long) input; ++ default: ++ throw GraalError.unimplemented("unimplemented RoundingMode " + mode); ++ } ++ } ++ ++ private static FloatStamp roundStamp(FloatStamp stamp, RoundingMode mode) { ++ double min = stamp.lowerBound(); ++ min = Math.min(min, round(mode, min)); ++ ++ double max = stamp.upperBound(); ++ max = Math.max(max, round(mode, max)); ++ ++ return new FloatStamp(stamp.getBits(), min, max, stamp.isNonNaN()); ++ } ++ ++ @Override ++ public Stamp foldStamp(Stamp newStamp) { ++ assert newStamp.isCompatible(getValue().stamp(NodeView.DEFAULT)); ++ return roundStamp((FloatStamp) newStamp, mode); ++ } ++ ++ private ValueNode tryFold(ValueNode input) { ++ if (input.isConstant()) { ++ JavaConstant c = input.asJavaConstant(); ++ if (c.getJavaKind() == JavaKind.Double) { ++ return ConstantNode.forDouble(round(mode, c.asDouble())); ++ } else if (c.getJavaKind() == JavaKind.Float) { ++ return ConstantNode.forFloat((float) round(mode, c.asFloat())); ++ } ++ } ++ return null; ++ } ++ ++ @Override ++ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { ++ ValueNode folded = tryFold(forValue); ++ return folded != null ? folded : this; ++ } ++ ++ @Override ++ public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) { ++ builder.setResult(this, ((SW64ArithmeticLIRGeneratorTool) gen).emitRound(builder.operand(getValue()), mode)); ++ } ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringLatin1Substitutions.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringLatin1Substitutions.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringLatin1Substitutions.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringLatin1Substitutions.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (c) 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import org.graalvm.compiler.api.replacements.ClassSubstitution; ++import org.graalvm.compiler.api.replacements.MethodSubstitution; ++import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; ++ ++import jdk.vm.ci.meta.JavaKind; ++ ++// JaCoCo Exclude ++ ++/** ++ * Substitutions for {@code java.lang.StringLatin1} methods. ++ * ++ * Since JDK 9. ++ */ ++@ClassSubstitution(className = "java.lang.StringLatin1", optional = true) ++public class SW64StringLatin1Substitutions { ++ ++ /** ++ * @param value is byte[] ++ * @param other is char[] ++ */ ++ @MethodSubstitution ++ public static int compareTo(byte[] value, byte[] other) { ++ return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Byte); ++ } ++ ++ /** ++ * @param value is byte[] ++ * @param other is char[] ++ */ ++ @MethodSubstitution ++ public static int compareToUTF16(byte[] value, byte[] other) { ++ return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Char); ++ } ++ ++} +diff -uNr openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringUTF16Substitutions.java afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringUTF16Substitutions.java +--- openjdk/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringUTF16Substitutions.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sw64/src/org/graalvm/compiler/replacements/sw64/SW64StringUTF16Substitutions.java 2025-05-09 10:05:57.892290602 +0800 +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (c) 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. ++ */ ++ ++ ++package org.graalvm.compiler.replacements.sw64; ++ ++import org.graalvm.compiler.api.replacements.ClassSubstitution; ++import org.graalvm.compiler.api.replacements.MethodSubstitution; ++import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; ++ ++import jdk.vm.ci.meta.JavaKind; ++ ++// JaCoCo Exclude ++ ++/** ++ * Substitutions for {@code java.lang.StringUTF16} methods. ++ * ++ * Since JDK 9. ++ */ ++@ClassSubstitution(className = "java.lang.StringUTF16", optional = true) ++public class SW64StringUTF16Substitutions { ++ ++ /** ++ * @param value is char[] ++ * @param other is char[] ++ */ ++ @MethodSubstitution ++ public static int compareTo(byte[] value, byte[] other) { ++ return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Char, JavaKind.Char); ++ } ++ ++ /** ++ * @param value is char[] ++ * @param other is byte[] ++ */ ++ @MethodSubstitution ++ public static int compareToLatin1(byte[] value, byte[] other) { ++ /* ++ * Swapping array arguments because intrinsic expects order to be byte[]/char[] but kind ++ * arguments stay in original order. ++ */ ++ return ArrayCompareToNode.compareTo(other, value, other.length, value.length, JavaKind.Char, JavaKind.Byte); ++ } ++ ++} +diff -uNr openjdk/.src-rev afu11u/.src-rev +--- openjdk/.src-rev 2022-10-12 23:00:15.000000000 +0800 ++++ afu11u/.src-rev 1970-01-01 08:00:00.000000000 +0800 +@@ -1 +0,0 @@ +-.:git:69ce82b96fce+ +diff -uNr openjdk/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java afu11u/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java +--- openjdk/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java 2022-10-12 23:00:04.000000000 +0800 ++++ afu11u/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java 2025-05-09 10:05:58.476290622 +0800 +@@ -42,7 +42,7 @@ + * The jtreg test execution observer, which gathers info about + * system and dumps it to a file. + */ +-public class GatherDiagnosticInfoObserver implements Harness.Observer { ++ public class GatherDiagnosticInfoObserver implements Harness.Observer { + public static final String LOG_FILENAME = "environment.log"; + public static final String ENVIRONMENT_OUTPUT = "environment.html"; + +diff -uNr openjdk/test/hotspot/jtreg/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java afu11u/test/hotspot/jtreg/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java +--- openjdk/test/hotspot/jtreg/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java 2022-10-12 23:00:04.000000000 +0800 ++++ afu11u/test/hotspot/jtreg/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java 2025-05-09 10:06:54.488292514 +0800 +@@ -45,7 +45,7 @@ + */ + public class TestMutuallyExclusivePlatformPredicates { + private static enum MethodGroup { +- ARCH("isAArch64", "isARM", "isPPC", "isS390x", "isSparc", "isX64", "isX86"), ++ ARCH("isAArch64", "isARM", "isPPC", "isS390x", "isSparc", "isX64", "isX86", "isSW64"), + BITNESS("is32bit", "is64bit"), + OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"), + VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero", "isEmbedded"), +diff -uNr openjdk/test/jdk/java/lang/invoke/MethodHandles/CatchExceptionTest.java afu11u/test/jdk/java/lang/invoke/MethodHandles/CatchExceptionTest.java +--- openjdk/test/jdk/java/lang/invoke/MethodHandles/CatchExceptionTest.java 2022-10-12 23:00:05.000000000 +0800 ++++ afu11u/test/jdk/java/lang/invoke/MethodHandles/CatchExceptionTest.java 2025-05-09 10:06:54.516292515 +0800 +@@ -46,7 +46,7 @@ + * @library /lib/testlibrary /java/lang/invoke/common /test/lib + * @build jdk.test.lib.TimeLimitedRunner + * @compile CatchExceptionTest.java +- * @run main/othervm -esa test.java.lang.invoke.MethodHandles.CatchExceptionTest ++ * @run main/othervm/timeout=900000 -esa test.java.lang.invoke.MethodHandles.CatchExceptionTest + * @key intermittent randomness + */ + public class CatchExceptionTest { +diff -uNr openjdk/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java afu11u/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java +--- openjdk/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java 2025-05-09 10:05:59.952290672 +0800 +@@ -67,9 +67,27 @@ + // EC curve supported for KeyGeneration can found between intersection + // of curves define in + // "java.base/share/classes/sun/security/util/CurveDB.java" +- +- ECDH("secp256k1", "secp256r1", "secp384r1", "secp521r1"), +- XDH("X25519", "X448", "x25519"), ++ // and ++ // "jdk.crypto.ec/share/native/libsunec/impl/ecdecode.c" ++ ECDH( ++ // SEC2 prime curves ++ "secp112r1", "secp112r2", "secp128r1", "secp128r2", "secp160k1", ++ "secp160r1", "secp192k1", "secp192r1", "secp224k1", "secp224r1", ++ "secp256k1", "secp256r1", "secp384r1", "secp521r1", ++ // ANSI X9.62 prime curves ++ "X9.62 prime192v2", "X9.62 prime192v3", "X9.62 prime239v1", ++ "X9.62 prime239v2", "X9.62 prime239v3", ++ // SEC2 binary curves ++ "sect113r1", "sect113r2", "sect131r1", "sect131r2", "sect163k1", ++ "sect163r1", "sect163r2", "sect193r1", "sect193r2", "sect233k1", ++ "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", ++ "sect409r1", "sect571k1", "sect571r1", ++ // ANSI X9.62 binary curves ++ "X9.62 c2tnb191v1", "X9.62 c2tnb191v2", "X9.62 c2tnb191v3", ++ "X9.62 c2tnb239v1", "X9.62 c2tnb239v2", "X9.62 c2tnb239v3", ++ "X9.62 c2tnb359v1", "X9.62 c2tnb431r1" ++ ), ++ XDH("X25519", "X448"), + // There is no curve for DiffieHellman + DiffieHellman(new String[]{}); + +@@ -101,7 +119,7 @@ + } + + /** +- * Perform KeyAgreement operation ++ * Perform KeyAgreement operation using native as well as JCE provider. + */ + private static void testKeyAgreement(String provider, String kaAlgo, + String kpgAlgo, AlgorithmParameterSpec spec) throws Exception { +diff -uNr openjdk/test/jdk/java/security/KeyAgreement/KeySizeTest.java afu11u/test/jdk/java/security/KeyAgreement/KeySizeTest.java +--- openjdk/test/jdk/java/security/KeyAgreement/KeySizeTest.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/java/security/KeyAgreement/KeySizeTest.java 2025-05-09 10:05:59.952290672 +0800 +@@ -37,9 +37,9 @@ + * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 4096 + * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 6144 + * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 8192 +- * @run main/othervm KeySizeTest ECDH SunEC EC 256 +- * @run main/othervm KeySizeTest ECDH SunEC EC 384 +- * @run main/othervm KeySizeTest ECDH SunEC EC 521 ++ * @run main KeySizeTest ECDH SunEC EC 128 ++ * @run main KeySizeTest ECDH SunEC EC 192 ++ * @run main KeySizeTest ECDH SunEC EC 256 + * @run main KeySizeTest XDH SunEC XDH 255 + * @run main KeySizeTest XDH SunEC XDH 448 + */ +diff -uNr openjdk/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java afu11u/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java +--- openjdk/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java 2022-10-12 23:00:06.000000000 +0800 ++++ afu11u/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java 2025-05-09 10:06:00.068290676 +0800 +@@ -155,7 +155,7 @@ + }}}; + + for (Thread thread : new Thread[] { offerer, drainer, scanner }) { +- thread.join(timeoutMillis + testDurationMillis); ++ thread.join(timeoutMillis*100 + testDurationMillis); + if (thread.isAlive()) { + System.err.printf("Hung thread: %s%n", thread.getName()); + failed++; +diff -uNr openjdk/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java afu11u/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java +--- openjdk/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java 2022-10-12 23:00:06.000000000 +0800 ++++ afu11u/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java 2025-05-09 10:06:00.072290676 +0800 +@@ -156,7 +156,7 @@ + done.countDown(); + }}; + +- if (! done.await(timeoutMillis + testDurationMillis, MILLISECONDS)) { ++ if (! done.await(timeoutMillis * 100 + testDurationMillis, MILLISECONDS)) { + for (Thread thread : new Thread[] { offerer, remover, scanner }) { + if (thread.isAlive()) { + System.err.printf("Hung thread: %s%n", thread.getName()); +diff -uNr openjdk/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java afu11u/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +--- openjdk/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java 2025-05-09 10:06:54.536292515 +0800 +@@ -358,12 +358,14 @@ + // Trusted certificates. + protected final static Cert[] TRUSTED_CERTS = { + Cert.CA_ECDSA_SECP256R1, ++ Cert.CA_ECDSA_SECT283R1, + Cert.CA_RSA_2048, + Cert.CA_DSA_2048 }; + + // End entity certificate. + protected final static Cert[] END_ENTITY_CERTS = { + Cert.EE_ECDSA_SECP256R1, ++ Cert.EE_ECDSA_SECT283R1, + Cert.EE_RSA_2048, + Cert.EE_EC_RSA_SECP256R1, + Cert.EE_DSA_2048 }; +@@ -697,6 +699,32 @@ + "p1YdWENftmDoNTJ3O6TNlXb90jKWgAirCXNBUompPtHKkO592eDyGcT1h8qjrKlm\n" + + "Kw=="), + ++ CA_ECDSA_SECT283R1( ++ "EC", ++ // SHA1withECDSA, curve sect283r1 ++ // Validity ++ // Not Before: May 26 06:06:52 2020 GMT ++ // Not After : May 21 06:06:52 2040 GMT ++ // Subject Key Identifier: ++ // CF:A3:99:ED:4C:6E:04:41:09:21:31:33:B6:80:D5:A7:BF:2B:98:04 ++ "-----BEGIN CERTIFICATE-----\n" + ++ "MIIB8TCCAY+gAwIBAgIJANQFsBngZ3iMMAsGByqGSM49BAEFADBdMQswCQYDVQQG\n" + ++ "EwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNBMQ8wDQYDVQQKEwZPcmFjbGUx\n" + ++ "DzANBgNVBAsTBkpQR1NRRTESMBAGA1UEAxMJc2VjdDI4M3IxMB4XDTIwMDUyNjE4\n" + ++ "MDY1MloXDTQwMDUyMTE4MDY1MlowXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB\n" + ++ "MQswCQYDVQQHEwJTQTEPMA0GA1UEChMGT3JhY2xlMQ8wDQYDVQQLEwZKUEdTUUUx\n" + ++ "EjAQBgNVBAMTCXNlY3QyODNyMTBeMBAGByqGSM49AgEGBSuBBAARA0oABALatmDt\n" + ++ "QIhjpK4vJjv4GgC8CUH/VAWLUSQRU7yGGQ3NF8rVBARv0aehiII0nzjDVX5KrP/A\n" + ++ "w/DmW7q8PfEAIktuaA/tcKv/OKMyMDAwHQYDVR0OBBYEFM+jme1MbgRBCSExM7aA\n" + ++ "1ae/K5gEMA8GA1UdEwEB/wQFMAMBAf8wCwYHKoZIzj0EAQUAA08AMEwCJAGHsAP8\n" + ++ "HlcVqszra+fxq35juTxHJIfxTKIr7f54Ywtz7AJowgIkAxydv8g+dkuniOUAj0Xt\n" + ++ "FnGVp6HzKX5KM1zLpfqmix8ZPP/A\n" + ++ "-----END CERTIFICATE-----", ++ "MIGQAgEAMBAGByqGSM49AgEGBSuBBAARBHkwdwIBAQQkAdcyn/FxiNvuTsSgDehq\n" + ++ "SGFiTxAKNMMJfmsO6GHekzszFqjPoUwDSgAEAtq2YO1AiGOkri8mO/gaALwJQf9U\n" + ++ "BYtRJBFTvIYZDc0XytUEBG/Rp6GIgjSfOMNVfkqs/8DD8OZburw98QAiS25oD+1w\n" + ++ "q/84"), ++ + CA_RSA_2048( + "RSA", + // SHA256withRSA, 2048 bits +diff -uNr openjdk/test/jdk/jdk/jfr/event/os/TestCPUInformation.java afu11u/test/jdk/jdk/jfr/event/os/TestCPUInformation.java +--- openjdk/test/jdk/jdk/jfr/event/os/TestCPUInformation.java 2022-10-12 23:00:06.000000000 +0800 ++++ afu11u/test/jdk/jdk/jfr/event/os/TestCPUInformation.java 2025-05-09 10:06:00.300290684 +0800 +@@ -54,8 +54,8 @@ + Events.assertField(event, "hwThreads").atLeast(1); + Events.assertField(event, "cores").atLeast(1); + Events.assertField(event, "sockets").atLeast(1); +- Events.assertField(event, "cpu").containsAny("Intel", "AMD", "Unknown x86", "sparc", "ARM", "PPC", "PowerPC", "AArch64", "s390"); +- Events.assertField(event, "description").containsAny("Intel", "AMD", "Unknown x86", "SPARC", "ARM", "PPC", "PowerPC", "AArch64", "s390"); ++ Events.assertField(event, "cpu").containsAny("Intel", "AMD", "Unknown x86", "sparc", "ARM", "PPC", "PowerPC", "AArch64", "s390", "Sw64"); ++ Events.assertField(event, "description").containsAny("Intel", "AMD", "Unknown x86", "SPARC", "ARM", "PPC", "PowerPC", "AArch64", "s390", "Sw64"); + } + } + } +diff -uNr openjdk/test/jdk/jdk/security/jarsigner/Spec.java afu11u/test/jdk/jdk/security/jarsigner/Spec.java +--- openjdk/test/jdk/jdk/security/jarsigner/Spec.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/jdk/security/jarsigner/Spec.java 2025-05-09 10:06:00.320290684 +0800 +@@ -31,7 +31,7 @@ + * jdk.jartool + * jdk.crypto.ec + * @build jdk.test.lib.util.JarUtils +- * @run main/othervm Spec ++ * @run main Spec + */ + + import com.sun.jarsigner.ContentSigner; +@@ -190,7 +190,7 @@ + .equals("SHA256withDSA")); + + kpg = KeyPairGenerator.getInstance("EC"); +- kpg.initialize(256); ++ kpg.initialize(192); + assertTrue(JarSigner.Builder + .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) + .equals("SHA256withECDSA")); +@@ -198,7 +198,7 @@ + assertTrue(JarSigner.Builder + .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) + .equals("SHA384withECDSA")); +- kpg.initialize(521); ++ kpg.initialize(571); + assertTrue(JarSigner.Builder + .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) + .equals("SHA512withECDSA")); +diff -uNr openjdk/test/jdk/sun/misc/SunMiscSignalTest.java afu11u/test/jdk/sun/misc/SunMiscSignalTest.java +--- openjdk/test/jdk/sun/misc/SunMiscSignalTest.java 2022-10-12 23:00:06.000000000 +0800 ++++ afu11u/test/jdk/sun/misc/SunMiscSignalTest.java 2025-05-09 10:06:00.396290687 +0800 +@@ -141,6 +141,11 @@ + {"INFO", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, + }; + ++ Object[][] posixSW64Signals = { ++ {"BUS", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, ++ {"INFO", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, ++ }; ++ + Object[][] windowsSignals = { + {"HUP", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO}, + {"QUIT", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO}, +@@ -164,8 +169,16 @@ + {"SYS", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO}, + }; + +- Object[][] combinedPosixSignals = concatArrays(posixSignals, +- (Platform.isOSX() ? posixOSXSignals : posixNonOSXSignals)); ++ Object[][] combinedPosixSignals; ++ ++ if(Platform.isOSX()){ ++ combinedPosixSignals = concatArrays(posixSignals, posixOSXSignals); ++ }else if(Platform.isSW64()){ ++ combinedPosixSignals = concatArrays(posixSignals, posixSW64Signals); ++ }else{ ++ combinedPosixSignals = concatArrays(posixSignals, posixNonOSXSignals); ++ } ++ + return concatArrays(commonSignals, (Platform.isWindows() ? windowsSignals : combinedPosixSignals)); + } + +二进制文件 openjdk/test/jdk/sun/security/ec/keystore 和 afu11u/test/jdk/sun/security/ec/keystore 不同 +二进制文件 openjdk/test/jdk/sun/security/ec/pkcs12/sect193r1server-rsa1024ca.p12 和 afu11u/test/jdk/sun/security/ec/pkcs12/sect193r1server-rsa1024ca.p12 不同 +diff -uNr openjdk/test/jdk/sun/security/ec/SignatureDigestTruncate.java afu11u/test/jdk/sun/security/ec/SignatureDigestTruncate.java +--- openjdk/test/jdk/sun/security/ec/SignatureDigestTruncate.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/ec/SignatureDigestTruncate.java 2025-05-09 10:06:00.548290692 +0800 +@@ -36,7 +36,7 @@ + * group order. + * @library /test/lib + * @build jdk.test.lib.Convert +- * @run main/othervm SignatureDigestTruncate ++ * @run main SignatureDigestTruncate + */ + public class SignatureDigestTruncate { + +@@ -117,12 +117,12 @@ + } + + public static void main(String[] args) throws Exception { +- runTest("SHA384withECDSAinP1363Format", "secp256r1", ++ runTest("SHA384withECDSAinP1363Format", "sect283r1", + "abcdef10234567", "010203040506070809", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d" + +- "1e1f20212223", +- "d83534beccde787f9a4c6b0408337d9b9ca2e0a0259228526c15cc17a1d6" + +- "4da6b34bf21b3bc4488c591d8ac9c33d93c7c6137e2ab4c503a42da7" + +- "2fe0b6dda4c4"); ++ "1e1f20212223", ++ "01d7544b5d3935216bd45e2f8042537e1e0296a11e0eb96666199281b409" + ++ "42abccd5358a035de8a314d3e6c2a97614daebf5fb1313540eec3f9a3272" + ++ "068aa10922ccae87d255c84c"); + } + } +diff -uNr openjdk/test/jdk/sun/security/ec/TestEC.java afu11u/test/jdk/sun/security/ec/TestEC.java +--- openjdk/test/jdk/sun/security/ec/TestEC.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/ec/TestEC.java 2025-05-09 10:06:00.548290692 +0800 +@@ -37,8 +37,8 @@ + * @library ../../../java/security/testlibrary + * @library ../../../javax/net/ssl/TLSCommon + * @modules jdk.crypto.cryptoki/sun.security.pkcs11.wrapper +- * @run main/othervm -Djdk.tls.namedGroups="secp256r1" TestEC +- * @run main/othervm/java.security.policy=TestEC.policy -Djdk.tls.namedGroups="secp256r1" TestEC ++ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC ++ * @run main/othervm/java.security.policy=TestEC.policy -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC + */ + + import java.security.NoSuchProviderException; +@@ -48,12 +48,13 @@ + /* + * Leverage the collection of EC tests used by PKCS11 + * +- * NOTE: the following 5 files were copied here from the PKCS11 EC Test area ++ * NOTE: the following 6 files were copied here from the PKCS11 EC Test area + * and must be kept in sync with the originals: + * + * ../pkcs11/ec/p12passwords.txt + * ../pkcs11/ec/certs/sunlabscerts.pem + * ../pkcs11/ec/pkcs12/secp256r1server-secp384r1ca.p12 ++ * ../pkcs11/ec/pkcs12/sect193r1server-rsa1024ca.p12 + * ../pkcs11/sslecc/keystore + * ../pkcs11/sslecc/truststore + */ +@@ -98,26 +99,18 @@ + * The entry point used for each test is its instance method + * called main (not its static method called main). + */ +- System.out.println("TestECDH"); + new TestECDH().main(p); +- System.out.println("TestECDSA"); + new TestECDSA().main(p); +- System.out.println("TestCurves"); + new TestCurves().main(p); +- System.out.println("TestKeyFactory"); + new TestKeyFactory().main(p); +- System.out.println("TestECGenSpec"); + new TestECGenSpec().main(p); +- System.out.println("ReadPKCS12"); + new ReadPKCS12().main(p); +- System.out.println("ReadCertificate"); + new ReadCertificates().main(p); + + // ClientJSSEServerJSSE fails on Solaris 11 when both SunEC and + // SunPKCS11-Solaris providers are enabled. + // Workaround: + // Security.removeProvider("SunPKCS11-Solaris"); +- System.out.println("ClientJSSEServerJSSE"); + new ClientJSSEServerJSSE().main(p); + + long stop = System.currentTimeMillis(); +二进制文件 openjdk/test/jdk/sun/security/pkcs11/ec/pkcs12/sect193r1server-rsa1024ca.p12 和 afu11u/test/jdk/sun/security/pkcs11/ec/pkcs12/sect193r1server-rsa1024ca.p12 不同 +diff -uNr openjdk/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java afu11u/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java +--- openjdk/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java 2025-05-09 10:06:00.576290693 +0800 +@@ -29,7 +29,7 @@ + * @library /test/lib .. + * @library ../../../../java/security/testlibrary + * @key randomness +- * @modules jdk.crypto.cryptoki jdk.crypto.ec/sun.security.ec ++ * @modules jdk.crypto.cryptoki + * @run main/othervm ReadPKCS12 + * @run main/othervm ReadPKCS12 sm policy + */ +diff -uNr openjdk/test/jdk/sun/security/pkcs11/ec/TestECDH.java afu11u/test/jdk/sun/security/pkcs11/ec/TestECDH.java +--- openjdk/test/jdk/sun/security/pkcs11/ec/TestECDH.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/pkcs11/ec/TestECDH.java 2025-05-09 10:06:00.576290693 +0800 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2006, 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 +@@ -124,12 +124,9 @@ + return; + } + +- if (getSupportedECParameterSpec("secp192r1", p).isPresent()) { +- test(p, pub192a, priv192a, pub192b, priv192b, secret192); +- } +- if (getSupportedECParameterSpec("sect163r1", p).isPresent()) { +- test(p, pub163a, priv163a, pub163b, priv163b, secret163); +- } ++ test(p, pub192a, priv192a, pub192b, priv192b, secret192); ++ test(p, pub163a, priv163a, pub163b, priv163b, secret163); ++ + if (getSupportedECParameterSpec("brainpoolP256r1", p).isPresent()) { + test(p, pubBrainpoolP256r1a, privBrainpoolP256r1a, pubBrainpoolP256r1b, privBrainpoolP256r1b, secretBrainpoolP256r1); + } +diff -uNr openjdk/test/jdk/sun/security/pkcs11/ec/TestECDSA.java afu11u/test/jdk/sun/security/pkcs11/ec/TestECDSA.java +--- openjdk/test/jdk/sun/security/pkcs11/ec/TestECDSA.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/pkcs11/ec/TestECDSA.java 2025-05-09 10:06:00.576290693 +0800 +@@ -156,14 +156,12 @@ + return; + } + +- if (getSupportedECParameterSpec("secp192r1", provider).isPresent()) { ++ if (getNSSECC() != ECCState.Basic) { + test(provider, pub192, priv192, sig192); +- } +- if (getSupportedECParameterSpec("sect163r1", provider).isPresent()) { + test(provider, pub163, priv163, sig163); +- } +- if (getSupportedECParameterSpec("sect571r1", provider).isPresent()) { + test(provider, pub571, priv571, sig571); ++ } else { ++ System.out.println("ECC Basic only, skipping 192, 163 and 571."); + } + test(provider, pub521, priv521, sig521); + +diff -uNr openjdk/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java afu11u/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java +--- openjdk/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java 2025-05-09 10:06:00.576290693 +0800 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2006, 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 +@@ -130,12 +130,17 @@ + System.out.println("Provider does not support EC, skipping"); + return; + } +- int[] keyLengths = {256, 521}; ++ int[] keyLengths = {192, 163, 409, 521}; ++ int len = 0; ++ if (getNSSECC() == ECCState.Basic) { ++ System.out.println("NSS Basic ECC only. Skipping 192, 163, & 409"); ++ len = 3; ++ } + KeyFactory kf = KeyFactory.getInstance("EC", p); +- for (int len : keyLengths) { +- System.out.println("Length " + len); ++ for (; keyLengths.length > len ; len++) { ++ System.out.println("Length "+keyLengths[len]); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); +- kpg.initialize(len); ++ kpg.initialize(keyLengths[len]); + KeyPair kp = kpg.generateKeyPair(); + test(kf, kp.getPrivate()); + test(kf, kp.getPublic()); +diff -uNr openjdk/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java afu11u/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java +--- openjdk/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 2025-05-09 10:06:00.600290694 +0800 +@@ -34,9 +34,9 @@ + * @library /test/lib .. ../../../../javax/net/ssl/TLSCommon + * @library ../../../../java/security/testlibrary + * @modules jdk.crypto.cryptoki +- * @run main/othervm -Djdk.tls.namedGroups="secp256r1" ++ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" + * ClientJSSEServerJSSE +- * @run main/othervm -Djdk.tls.namedGroups="secp256r1" ++ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" + * ClientJSSEServerJSSE sm policy + */ + +二进制文件 openjdk/test/jdk/sun/security/pkcs11/sslecc/keystore 和 afu11u/test/jdk/sun/security/pkcs11/sslecc/keystore 不同 +diff -uNr openjdk/test/jdk/sun/security/provider/KeyStore/DKSTest.java afu11u/test/jdk/sun/security/provider/KeyStore/DKSTest.java +--- openjdk/test/jdk/sun/security/provider/KeyStore/DKSTest.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/provider/KeyStore/DKSTest.java 2025-05-09 10:06:00.604290694 +0800 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -52,6 +52,8 @@ + new KeyStore.PasswordProtection("test12".toCharArray())); + put("eckeystore1", + new KeyStore.PasswordProtection("password".toCharArray())); ++ put("eckeystore2", ++ new KeyStore.PasswordProtection("password".toCharArray())); + put("truststore", + new KeyStore.PasswordProtection("changeit".toCharArray())); + put("empty", +@@ -67,6 +69,8 @@ + new KeyStore.PasswordProtection("wrong".toCharArray())); + put("eckeystore1", + new KeyStore.PasswordProtection("wrong".toCharArray())); ++ put("eckeystore2", ++ new KeyStore.PasswordProtection("wrong".toCharArray())); + }}; + + public static void main(String[] args) throws Exception { +@@ -150,7 +154,7 @@ + * domain keystore: keystores + */ + config = new URI(CONFIG + "#keystores"); +- expected = 2 + 1 + 1; ++ expected = 2 + 1 + 1 + 1; + keystore = KeyStore.getInstance("DKS"); + // load entries + keystore.load(new DomainLoadStoreParameter(config, PASSWORDS)); +diff -uNr openjdk/test/jdk/sun/security/provider/KeyStore/domains.cfg afu11u/test/jdk/sun/security/provider/KeyStore/domains.cfg +--- openjdk/test/jdk/sun/security/provider/KeyStore/domains.cfg 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/provider/KeyStore/domains.cfg 2025-05-09 10:06:00.604290694 +0800 +@@ -25,6 +25,8 @@ + keystoreType="CaseExactJKS" + keystoreURI="${test.src}/pw.jks"; + keystore eckeystore1 ++ keystoreURI="${test.src}/../../pkcs11/ec/pkcs12/sect193r1server-rsa1024ca.p12"; ++ keystore eckeystore2 + keystoreURI="${test.src}/../../pkcs11/ec/pkcs12/secp256r1server-secp384r1ca.p12"; + }; + +@@ -38,6 +40,8 @@ + keystoreType="CaseExactJKS" + keystoreURI="${user.dir}/pw.jks_tmp"; + keystore eckeystore1 ++ keystoreURI="${user.dir}/sect193r1server-rsa1024ca.p12_tmp"; ++ keystore eckeystore2 + keystoreURI="${user.dir}/secp256r1server-secp384r1ca.p12_tmp"; + }; + +diff -uNr openjdk/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java afu11u/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +--- openjdk/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java 2025-05-09 10:06:00.620290694 +0800 +@@ -25,10 +25,10 @@ + * @test + * @bug 8246330 + * @library /javax/net/ssl/templates /test/lib +- * @run main/othervm -Djdk.tls.namedGroups="secp384r1" ++ * @run main/othervm -Djdk.tls.namedGroups="sect283r1" + DisabledCurve DISABLE_NONE PASS +- * @run main/othervm -Djdk.tls.namedGroups="secp384r1" +- DisabledCurve secp384r1 FAIL ++ * @run main/othervm -Djdk.tls.namedGroups="sect283r1" ++ DisabledCurve sect283r1 FAIL + */ + import java.security.Security; + import java.util.Arrays; +@@ -51,18 +51,18 @@ + protected SSLContext createClientSSLContext() throws Exception { + return createSSLContext( + new SSLSocketTemplate.Cert[] { +- SSLSocketTemplate.Cert.CA_ECDSA_SECP384R1 }, ++ SSLSocketTemplate.Cert.CA_ECDSA_SECT283R1 }, + new SSLSocketTemplate.Cert[] { +- SSLSocketTemplate.Cert.EE_ECDSA_SECP384R1 }, ++ SSLSocketTemplate.Cert.EE_ECDSA_SECT283R1 }, + getClientContextParameters()); + } + + protected SSLContext createServerSSLContext() throws Exception { + return createSSLContext( + new SSLSocketTemplate.Cert[] { +- SSLSocketTemplate.Cert.CA_ECDSA_SECP384R1 }, ++ SSLSocketTemplate.Cert.CA_ECDSA_SECT283R1 }, + new SSLSocketTemplate.Cert[] { +- SSLSocketTemplate.Cert.EE_ECDSA_SECP384R1 }, ++ SSLSocketTemplate.Cert.EE_ECDSA_SECT283R1 }, + getServerContextParameters()); + } + +@@ -91,13 +91,10 @@ + public static void main(String[] args) throws Exception { + String expected = args[1]; + String disabledName = ("DISABLE_NONE".equals(args[0]) ? "" : args[0]); +- boolean disabled = false; + if (disabledName.equals("")) { + Security.setProperty("jdk.disabled.namedCurves", ""); +- } else { +- disabled = true; +- Security.setProperty("jdk.certpath.disabledAlgorithms", "secp384r1"); + } ++ System.setProperty("jdk.sunec.disableNative", "false"); + + // Re-enable TLSv1 and TLSv1.1 since test depends on it. + SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); +@@ -107,10 +104,12 @@ + (new DisabledCurve()).run(); + if (expected.equals("FAIL")) { + throw new RuntimeException( +- "Expected test to fail, but it passed"); ++ "The test case should not reach here"); + } + } catch (SSLException | IllegalStateException ssle) { +- if (expected.equals("FAIL") && disabled) { ++ if ((expected.equals("FAIL")) ++ && Security.getProperty("jdk.disabled.namedCurves") ++ .contains(disabledName)) { + System.out.println( + "Expected exception was thrown: TEST PASSED"); + } else { +diff -uNr openjdk/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java afu11u/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java +--- openjdk/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java 2025-05-09 10:06:00.640290695 +0800 +@@ -93,6 +93,11 @@ + System.out.println("\nTesting DSA Keysize: DSA keySize < 1024\n"); + test("DSA", "SHA256withDSA", "KeySizeDSA", "SHA-256", true, + "-keysize", "512"); ++ ++ System.out.println("\nTesting Native Curve:" ++ + " include jdk.disabled.namedCurves\n"); ++ test("EC", "SHA256withECDSA", "curve", "SHA-256", true, ++ "-groupname", "secp112r1"); + } + + private static void test(String keyAlg, String sigAlg, String aliasPrefix, +@@ -118,7 +123,8 @@ + "-ext", "bc:c", + "-keyalg", keyAlg, + "-sigalg", sigAlg, +- "-alias", alias); ++ "-alias", alias, ++ "-J-Djdk.sunec.disableNative=false"); + for (String additionalCMDArg : additionalCmdArgs) { + cmd.add(additionalCMDArg); + } +@@ -141,7 +147,8 @@ + "-digestalg", digestAlg, + "-signedjar", SIGNED_JARFILE, + UNSIGNED_JARFILE, +- alias); ++ alias, ++ "-J-Djdk.sunec.disableNative=false"); + + OutputAnalyzer analyzer = SecurityTools.jarsigner(cmd) + .shouldHaveExitValue(0); +@@ -155,7 +162,8 @@ + System.out.println("\nTesting JarSigner Verification\n"); + List cmd = prepareCommand( + "-verify", +- SIGNED_JARFILE); ++ SIGNED_JARFILE, ++ "-J-Djdk.sunec.disableNative=false"); + + OutputAnalyzer analyzer = SecurityTools.jarsigner(cmd) + .shouldHaveExitValue(0); +diff -uNr openjdk/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java afu11u/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java +--- openjdk/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java 2025-05-09 10:06:00.644290695 +0800 +@@ -60,9 +60,11 @@ + check("DSA", 1024, null, "SHA256withDSA"); + check("DSA", 3072, null, "SHA256withDSA"); + ++ check("EC", 192, null, "SHA256withECDSA"); + check("EC", 384, null, "SHA384withECDSA"); ++ check("EC", 571, null, "SHA512withECDSA"); + +- check("EC", 384, "SHA256withECDSA", "SHA256withECDSA"); ++ check("EC", 571, "SHA256withECDSA", "SHA256withECDSA"); + } + + private static void check(String keyAlg, int keySize, +diff -uNr openjdk/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java afu11u/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java +--- openjdk/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java 2025-05-09 10:06:00.648290695 +0800 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. ++ * 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 +@@ -58,6 +58,14 @@ + public KeyPair generateKeyPair() { + BigInteger s, x, y; + switch (keySize) { ++ case 192: ++ s = new BigInteger("144089953963995451666433763881605261867377" ++ + "0287449914970417"); ++ x = new BigInteger("527580219290493448707803038403444129676461" ++ + "560927008883862"); ++ y = new BigInteger("171489247081620145247240656640887886126295" ++ + "376102134763235"); ++ break; + case 384: + s = new BigInteger("230878276322370828604837367594276033697165" + + "328633328282930557390817326627704675451851870430805" +@@ -69,10 +77,22 @@ + + "792287657810480793861620950159864617021540168828129" + + "97920015041145259782242"); + break; ++ case 571: ++ s = new BigInteger("102950007413729156017516513076331886543538" ++ + "947044937190140406420556321983301533699021909556189" ++ + "150601557539520495361099574425100081169640300555562" ++ + "4280643194744140660275077121"); ++ x = new BigInteger("640598847385582251482893323029655037929442" ++ + "593800810090252942944624854811134311418807076811195" ++ + "132373308708007447666896675761104237802118413642543" ++ + "8277858107132017492037336593"); ++ y = new BigInteger("254271270803422773271985083014247202480077" ++ + "131823713050110789460550383275777195766342550786766" ++ + "080401402424961690914429074822281551140068729472439" ++ + "477216613432839953714415981"); ++ break; + default: +- throw new AssertionError("SunEC ECKeyPairGenerator" + +- "has been patched. Key size " + keySize + +- " is not supported"); ++ throw new AssertionError("Unsupported keysize " + keySize); + } + ECParameterSpec ecParams = ECUtil.getECParameterSpec(null, keySize); + try { +diff -uNr openjdk/test/jdk/sun/security/tools/keytool/GroupName.java afu11u/test/jdk/sun/security/tools/keytool/GroupName.java +--- openjdk/test/jdk/sun/security/tools/keytool/GroupName.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/jdk/sun/security/tools/keytool/GroupName.java 2025-05-09 10:06:00.644290695 +0800 +@@ -65,9 +65,10 @@ + .shouldNotContain("Specifying -keysize for generating EC keys is deprecated"); + checkCurveName("e", "secp256r1"); + +- kt("-list -v") ++ gen("f", "-keyalg EC -groupname brainpoolP256r1") + .shouldHaveExitValue(0) +- .shouldContain("Subject Public Key Algorithm: 256-bit EC (secp256r1) key"); ++ .shouldNotContain("Specifying -keysize for generating EC keys is deprecated"); ++ checkCurveName("f", "brainpoolP256r1"); + } + + private static void checkCurveName(String a, String name) +diff -uNr openjdk/test/langtools/tools/javadoc/api/basic/taglets/UnderlineTaglet.java afu11u/test/langtools/tools/javadoc/api/basic/taglets/UnderlineTaglet.java +--- openjdk/test/langtools/tools/javadoc/api/basic/taglets/UnderlineTaglet.java 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/test/langtools/tools/javadoc/api/basic/taglets/UnderlineTaglet.java 2025-05-09 10:06:01.036290708 +0800 +@@ -0,0 +1,152 @@ ++/* ++ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * -Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * -Redistribution in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * Neither the name of Oracle nor the names of ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * This software is provided "AS IS," without a warranty of any ++ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY ++ * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY ++ * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR ++ * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ++ * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE ++ * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, ++ * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER ++ * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF ++ * THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ++ * ++ * You acknowledge that Software is not designed, licensed or ++ * intended for use in the design, construction, operation or ++ * maintenance of any nuclear facility. ++ */ ++ ++import com.sun.tools.doclets.Taglet; ++import com.sun.javadoc.*; ++import java.util.Map; ++ ++/** ++ * A sample Inline Taglet representing {@underline ...}. This tag can ++ * be used in any kind of {@link com.sun.javadoc.Doc}. ++ * The text is underlined. For example, ++ * "@underline UNDERLINE ME" would be shown as: UNDERLINE ME. ++ * ++ * @author Jamie Ho ++ * @since 1.4 ++ */ ++ ++public class UnderlineTaglet implements Taglet { ++ ++ private static final String NAME = "underline"; ++ ++ /** ++ * Return the name of this custom tag. ++ */ ++ public String getName() { ++ return NAME; ++ } ++ ++ /** ++ * @return true since this tag can be used in a field ++ * doc comment ++ */ ++ public boolean inField() { ++ return true; ++ } ++ ++ /** ++ * @return true since this tag can be used in a constructor ++ * doc comment ++ */ ++ public boolean inConstructor() { ++ return true; ++ } ++ ++ /** ++ * @return true since this tag can be used in a method ++ * doc comment ++ */ ++ public boolean inMethod() { ++ return true; ++ } ++ ++ /** ++ * @return true since this tag can be used in an overview ++ * doc comment ++ */ ++ public boolean inOverview() { ++ return true; ++ } ++ ++ /** ++ * @return true since this tag can be used in a package ++ * doc comment ++ */ ++ public boolean inPackage() { ++ return true; ++ } ++ ++ /** ++ * @return true since this ++ */ ++ public boolean inType() { ++ return true; ++ } ++ ++ /** ++ * Will return true since this is an inline tag. ++ * @return true since this is an inline tag. ++ */ ++ ++ public boolean isInlineTag() { ++ return true; ++ } ++ ++ /** ++ * Register this Taglet. ++ * @param tagletMap the map to register this tag to. ++ */ ++ public static void register(Map tagletMap) { ++ UnderlineTaglet tag = new UnderlineTaglet(); ++ Taglet t = (Taglet) tagletMap.get(tag.getName()); ++ if (t != null) { ++ tagletMap.remove(tag.getName()); ++ } ++ tagletMap.put(tag.getName(), tag); ++ } ++ ++ /** ++ * Given the Tag representation of this custom ++ * tag, return its string representation. ++ * @param tag he Tag representation of this custom tag. ++ */ ++ public String toString(Tag tag) { ++ return "" + tag.text() + ""; ++ } ++ ++ /** ++ * This method should not be called since arrays of inline tags do not ++ * exist. Method {@link #tostring(Tag)} should be used to convert this ++ * inline tag to a string. ++ * @param tags the array of Tags representing of this custom tag. ++ */ ++ public String toString(Tag[] tags) { ++ return null; ++ } ++} ++ +diff -uNr openjdk/test/lib/jdk/test/lib/Platform.java afu11u/test/lib/jdk/test/lib/Platform.java +--- openjdk/test/lib/jdk/test/lib/Platform.java 2022-10-12 23:00:07.000000000 +0800 ++++ afu11u/test/lib/jdk/test/lib/Platform.java 2025-05-09 10:06:54.568292516 +0800 +@@ -225,6 +225,11 @@ + return isArch("(i386)|(x86(?!_64))"); + } + ++ public static boolean isSW64() { ++ // On Linux it's 'sw_64' or 'sw64'. ++ return isArch("(sw_64)|(sw64)"); ++ } ++ + public static String getOsArch() { + return osArch; + } +diff -uNr openjdk/UPGRADE_GUIDE.md afu11u/UPGRADE_GUIDE.md +--- openjdk/UPGRADE_GUIDE.md 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/UPGRADE_GUIDE.md 2025-05-09 10:05:55.520290522 +0800 +@@ -0,0 +1,49 @@ ++# 升级指南 ++ ++> 假设从版本a升级到版本b,参考x86代码。 ++ ++## S1: 建立x86的b版本和sw的a版本代码查看环境 ++ ++## S2: 在sw版本上如下操作 ++ ++1. git merge b ++ ++2. 可能有冲突,就解决冲突。这个过程中可能要阅读理解b版本的x86冲突代码 ++ ++3. 解决后将sw版本与刚才的x86的b版本作目录级对比,主要关注三个目录:make、src和test。 ++如下文件目前的确存在差异,可能需要仔细检查: ++ ++src/hotspot/os/linux/os_linux.cpp ++src/hotspot/share/asm/codeBuffer.cpp ++src/hotspot/share/code/codeBlob.cpp ++src/hotspot/share/interpreter/abstractInterpreter.cpp src/hotspot/share/interpreter/abstractInterpreter.hpp src/hotspot/share/interpreter/interpreterRuntime.cpp src/hotspot/share/interpreter/interpreterRuntime.hpp src/hotspot/share/interpreter/templateInterpreterGenerator.cpp src/hotspot/share/interpreter/templateInterpreterGenerator.hpp src/hotspot/share/jfr/utilities/jfrBigEndian.hpp ++src/hotspot/share/oops/method.cpp ++src/hotspot/share/runtime/arguments.cpp src/hotspot/share/runtime/safepointMechanism.cpp src/hotspot/share/runtime/sharedRuntime.cpp src/hotspot/share/runtime/sharedRuntime.hpp src/hotspot/share/runtime/sharedRuntimeTrig.cpp src/hotspot/share/runtime/stubRoutines.cpp ++src/hotspot/share/runtime/thread.cpp ++src/hotspot/share/runtime/vm_version.cpp ++src/hotspot/share/utilities/macros.hpp ++ ++make/autoconf/build-aux/autoconf-config.guess ++make/autoconf/build-performance.m4 ++make/autoconf/flags-cflags.m4 ++make/autoconf/hotspot.m4 ++make/autoconf/jdk-version.m4 ++make/autoconf/platform.m4 ++make/CompileJavaModules.gmk ++make/conf/jib-profiles.js ++make/devkit/Tools.gmk ++make/gensrc/Gensrc-jdk.internal.vm.compiler.gm ++make/hotspot/ide/CreateVSProject.gmk ++make/hotspot/lib/JvmFeatures.gmk ++make/launcher/Launcher-jdk.aot.gmk ++make/RunTestsPrebuilt.gmk ++make/test/JtregGraalUnit.gmk ++ ++## S3: 在x86的b版本上做如下操作 ++ ++在git log中找到a版本,然后compare with current. ++ ++关注如下目录的改动,在基本理解x86升级目的的基础上对sw相应目录做相应升级: ++ ++src/hotspot/cpu/x86, src/hotspot/os_cpu/linux_x86 ++ +diff -uNr openjdk/version_patch.sh afu11u/version_patch.sh +--- openjdk/version_patch.sh 1970-01-01 08:00:00.000000000 +0800 ++++ afu11u/version_patch.sh 2025-05-09 10:06:01.268290716 +0800 +@@ -0,0 +1,2 @@ ++gitnum=`git log| head -n 1 |cut -b 8-15` ++sed -i 's/\$srcgitnumber/'$gitnum'/g' ./make/autoconf/jdk-version.m4 diff --git a/java-11-openjdk.spec b/java-11-openjdk.spec index 5c9004ff06a5294849ce03c486338b7b1793f588..b212a6ea8bd50a4d636c2833f50bd64a9b717742 100644 --- a/java-11-openjdk.spec +++ b/java-11-openjdk.spec @@ -13,7 +13,9 @@ # Only produce a release build on x86_64: # $ rhpkg mockbuild --without slowdebug --without fastdebug -%global anolis_release 4 +ExcludeArch: x86_64 aarch64 + +%global anolis_release 5 # Enable fastdebug builds by default on relevant arches. %bcond_without fastdebug # Enable slowdebug builds by default on relevant arches. @@ -114,11 +116,11 @@ %global is_system_jdk 0 # Set of architectures for which we build slowdebug builds -%global debug_arches loongarch64 +%global debug_arches loongarch64 sw_64 # Set of architectures for which we build fastdebug builds -%global fastdebug_arches loongarch64 +%global fastdebug_arches loongarch64 sw_64 # Set of architectures with a Just-In-Time (JIT) compiler -%global jit_arches loongarch64 +%global jit_arches loongarch64 sw_64 # Set of architectures which use the Zero assembler port (!jit_arches) # Set of architectures which run a full bootstrap cycle %global bootstrap_arches %{jit_arches} @@ -127,7 +129,7 @@ # Set of architectures with a Ahead-Of-Time (AOT) compiler %global aot_arches x86_64 # Set of architectures which support the serviceability agent -%global sa_arches loongarch64 +%global sa_arches loongarch64 sw_64 # Set of architectures which support class data sharing # As of JDK-8005165 in OpenJDK 10, class sharing is not arch-specific # However, it does segfault on the Zero assembler port, so currently JIT only @@ -265,6 +267,10 @@ %global archinstall loongarch64 %global stapinstall loongarch64 %endif +%ifarch sw_64 +%global archinstall sw64 +%global stapinstall sw64 +%endif %ifarch noarch %global archinstall %{nil} %global stapinstall %{nil} @@ -766,7 +772,7 @@ exit 0 %{_jvmdir}/%{sdkdir -- %{?1}}/bin/rmiregistry %{_jvmdir}/%{sdkdir -- %{?1}}/bin/unpack200 %dir %{_jvmdir}/%{sdkdir -- %{?1}}/lib -%ifarch %{jit_arches} +%ifnarch sw_64 %{_jvmdir}/%{sdkdir -- %{?1}}/lib/classlist %endif %{_jvmdir}/%{sdkdir -- %{?1}}/lib/jexec @@ -1349,6 +1355,16 @@ Patch2003: jdk8295173-tzdata2022e.patch # Init support for LoongArch64 Patch3000: jdk11-LoongArch64.patch +############################################# +# +# sw_64 patches +# +# This section includes patches which are +# added by sw_64. +############################################# +# Init support for sw_64 +Patch4000: 4000-sw_64.patch + BuildRequires: autoconf BuildRequires: automake BuildRequires: alsa-lib-devel @@ -1731,6 +1747,9 @@ pushd %{top_level_dir_name} %ifarch loongarch64 %patch3000 -p1 %endif +%ifarch sw_64 +%patch4000 -p1 +%endif popd # openjdk %patch600 @@ -1795,7 +1814,7 @@ export NUM_PROC=${NUM_PROC:-1} [ ${NUM_PROC} -gt %{?_smp_ncpus_max} ] && export NUM_PROC=%{?_smp_ncpus_max} %endif -%ifarch loongarch64 +%ifarch loongarch64 sw_64 export ARCH_DATA_MODEL=64 %endif @@ -1863,13 +1882,24 @@ function buildjdk() { --with-lcms=${link_opt} \ --with-harfbuzz=${link_opt} \ --with-stdc++lib=${libc_link_opt} \ +%ifarch sw_64 + --with-extra-cxxflags="-mieee -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=type-limits -Wno-error=format-security -Wno-error=conversion-null -Wno-error=sign-compare -Wno-error=int-to-pointer-cast -mgprel-size=32" \ + --with-extra-cflags="-mieee -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=type-limits -Wno-error=format-security -Wno-error=conversion-null -Wno-error=sign-compare -Wno-error=int-to-pointer-cast -mgprel-size=32" \ + --with-extra-ldflags="-mieee -Wl,-no-relax" \ +%else --with-extra-cxxflags="$EXTRA_CPP_FLAGS" \ --with-extra-cflags="$EXTRA_CFLAGS" \ --with-extra-asflags="$EXTRA_ASFLAGS" \ --with-extra-ldflags="%{ourldflags}" \ +%endif --with-num-cores="$NUM_PROC" \ --disable-javac-server \ +%ifarch sw_64 + --with-jvm-variants=custom \ + --with-jvm-features=serialgc,vm-structs,parallelgc,compiler2,management,nmt,g1gc,cmsgc,jvmti,services,jni-check,jfr \ +%else --with-jvm-features="%{shenandoah_feature},%{zgc_feature}" \ +%endif --disable-warnings-as-errors cat spec.gmk @@ -2069,9 +2099,11 @@ if ! nm $JAVA_HOME/bin/%{alt_java_name} | grep set_speculation ; then true ; els %endif # Check translations are available for new timezones +%ifnarch sw_64 $JAVA_HOME/bin/javac -d . %{SOURCE18} $JAVA_HOME/bin/java $(echo $(basename %{SOURCE18})|sed "s|\.java||") JRE $JAVA_HOME/bin/java -Djava.locale.providers=CLDR $(echo $(basename %{SOURCE18})|sed "s|\.java||") CLDR +%endif %if %{include_staticlibs} # Check debug symbols in static libraries (smoke test) @@ -2131,7 +2163,7 @@ done # Using line number 1 might cause build problems. See: # https://bugzilla.redhat.com/show_bug.cgi?id=1539664 # https://bugzilla.redhat.com/show_bug.cgi?id=1538767 -%ifnarch loongarch64 +%ifnarch loongarch64 sw_64 gdb -q "$JAVA_HOME/bin/java" < - 1:11.0.17.0.8-5 +- Add sw_64 ISA support + * Thu Nov 09 2023 Leslie Zhai - 1:11.0.17.0.8-4 - Disable gdb