Top


定義場所(file name)

hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp

名前(function name)

void TemplateTable::fast_binaryswitch() {

本体部(body)

  {- -------------------------------------------
  (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.