hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
void TemplateTable::fast_binaryswitch() {
{- -------------------------------------------
(1) (assert) (See: TemplateTable::transition())
---------------------------------------- -}
transition(itos, vtos);
{- -------------------------------------------
(1) (この関数が生成するコードは以下の二分探索アルゴリズムを実行する)
---------------------------------------- -}
// 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;
// }
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Register allocation
const Register key = rax; // already set (tosca)
const Register array = rbx;
const Register i = rcx;
const Register j = rdx;
const Register h = rdi;
const Register temp = rsi;
{- -------------------------------------------
(1) コード生成:
「現在の r13 から 13bytes 以上先で 4bytes-align なアドレス(= match-offset pairs 情報の先頭)を算出し,
array レジスタにセットする」
(13byte は, _fast_binaryswitch 命令自体が 1byte 占めているため)
---------------------------------------- -}
// 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);
{- -------------------------------------------
(1) コード生成:
「i レジスタを 0 で初期化し, j レジスタをペアの個数で初期化しておく.
(なお, ペアの数はビッグエンディアンで埋まっているのでバイトオーダーも変更している)」
---------------------------------------- -}
// Initialize i & j
__ xorl(i, i); // i = 0;
__ movl(j, Address(array, -BytesPerInt)); // j = length(array);
// Convert j into native byteordering
__ bswapl(j);
{- -------------------------------------------
(1) コード生成:
「entry ラベルにジャンプして探索を開始する」
---------------------------------------- -}
// And start
Label entry;
__ jmp(entry);
{- -------------------------------------------
(1) (ここからが, 該当するエントリを探索するループ)
---------------------------------------- -}
// binary search loop
{
Label loop;
{- -------------------------------------------
(1.1) コード生成:
「(ここが loop ラベルの位置)」
---------------------------------------- -}
__ bind(loop);
{- -------------------------------------------
(1.1) コード生成:
「h レジスタの値を更新する (この時点で h = (i + j) >> 1 になる)」
---------------------------------------- -}
// int h = (i + j) >> 1;
__ leal(h, Address(i, j, Address::times_1)); // h = i + j;
__ sarl(h, 1); // h = (i + j) >> 1;
{- -------------------------------------------
(1.1) コード生成:
「h レジスタが指す箇所のペアのキーをロードし, 対象のキーの値(key)と比較する.
key の方が小さければ j を h で更新し, そうでなければ i を h で更新する.」
---------------------------------------- -}
// if (key < array[h].fast_match()) {
// j = h;
// } else {
// i = h;
// }
// Convert array[h].match to native byte-ordering before compare
__ movl(temp, Address(array, h, Address::times_8));
__ bswapl(temp);
__ cmpl(key, temp);
// j = h if (key < array[h].fast_match())
__ cmovl(Assembler::less, j, h);
// i = h if (key >= array[h].fast_match())
__ cmovl(Assembler::greaterEqual, i, h);
{- -------------------------------------------
(1.1) コード生成:
「(ここが entry ラベルの位置)」
「まだ残りがあるかどうかを調べるために, i + 1 が j より小さいかどうかを調べる.
小さければ(= まだ残りがあれば), loop ラベルに分岐.
もうペアがなければこのままフォールスルー」
---------------------------------------- -}
// while (i+1 < j)
__ bind(entry);
__ leal(h, Address(i, 1)); // i+1
__ cmpl(h, j); // i+1 < j
__ jcc(Assembler::less, loop);
}
{- -------------------------------------------
(1) (ここまでで, 該当するエントリを探索するループは終了.
結果は i に入っているが, 見つかったとは限らないのでチェックが必要)
---------------------------------------- -}
// end of binary search, result index is i (must check again!)
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Label default_case;
{- -------------------------------------------
(1) コード生成:
「i レジスタが指す箇所のペアのキーをロードし, 対象のキーの値(key)と比較する.
一致しない場合は, (探索対象が見つからなかったので) default_case ラベルに分岐.」
---------------------------------------- -}
// Convert array[i].match to native byte-ordering before compare
__ movl(temp, Address(array, i, Address::times_8));
__ bswapl(temp);
__ cmpl(key, temp);
__ jcc(Assembler::notEqual, default_case);
{- -------------------------------------------
(1) (以下は, 一致するペアが見つかった場合の処理)
---------------------------------------- -}
// entry found -> j = offset
__ movl(j , Address(array, i, Address::times_8, BytesPerInt));
{- -------------------------------------------
(1.1) コード生成: (JIT コンパイラ用のプロファイル情報の取得) (See: [here](no2935fdD.html) for details)
---------------------------------------- -}
__ profile_switch_case(i, key, array);
{- -------------------------------------------
(1.1) コード生成:
「見つかったペアにおけるジャンプ先オフセットを j レジスタにロードしておく」
---------------------------------------- -}
__ bswapl(j);
__ movl2ptr(j, j);
{- -------------------------------------------
(1.1) コード生成:
「r13 の値を更新し (j に入っているジャンプ先のオフセット分を足す),
rbx に次のバイトコードのセットした後,
dispatch_only() が生成するコードで
次のバイトコードに対応するテンプレートへとジャンプする」
---------------------------------------- -}
__ load_unsigned_byte(rbx, Address(r13, j, Address::times_1));
__ addptr(r13, j);
__ dispatch_only(vtos);
{- -------------------------------------------
(1) (以下は, 一致するペアが見つからなかった場合の処理)
---------------------------------------- -}
// default case -> j = default offset
__ bind(default_case);
{- -------------------------------------------
(1.1) コード生成: (JIT コンパイラ用のプロファイル情報の取得) (See: [here](no2935fdD.html) for details)
---------------------------------------- -}
__ profile_switch_default(i);
{- -------------------------------------------
(1.1) コード生成:
「デフォルトのオフセットを j レジスタにロードしておく」
---------------------------------------- -}
__ movl(j, Address(array, -2 * BytesPerInt));
__ bswapl(j);
__ movl2ptr(j, j);
{- -------------------------------------------
(1.1) コード生成:
「r13 の値を更新し (j に入っているジャンプ先のオフセット分を足す),
rbx に次のバイトコードのセットした後,
dispatch_only() が生成するコードで
次のバイトコードに対応するテンプレートへとジャンプする」
---------------------------------------- -}
__ load_unsigned_byte(rbx, Address(r13, j, Address::times_1));
__ addptr(r13, j);
__ dispatch_only(vtos);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.