Top


定義場所(file name)

hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp

名前(function name)

void TemplateTable::branch(bool is_jsr, bool is_wide) {

本体部(body)

  {- -------------------------------------------
  (1) コード生成: (verify)
      ---------------------------------------- -}

      // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also.
      __ verify_oop(Lmethod);
      __ verify_thread();

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      const Register O2_bumped_count = O2;

  {- -------------------------------------------
  (1) コード生成: (JIT コンパイラ用のプロファイル情報の取得) (See: [here](no2935fdD.html) for details)
      ---------------------------------------- -}

      __ profile_taken_branch(G3_scratch, O2_bumped_count);

  {- -------------------------------------------
  (1) コード生成:
      「飛び先のオフセットを取得する」
      ---------------------------------------- -}

      // get (wide) offset to O1_disp
      const Register O1_disp = O1;
      if (is_wide)  __ get_4_byte_integer_at_bcp( 1,  G4_scratch, O1_disp,                                    InterpreterMacroAssembler::set_CC);
      else          __ get_2_byte_integer_at_bcp( 1,  G4_scratch, O1_disp, InterpreterMacroAssembler::Signed, InterpreterMacroAssembler::set_CC);

  {- -------------------------------------------
  (1) コード生成: (jsr 用のコードを生成する場合)
      jsr 用の場合は, 以下のようなコードを出力し, ここでリターン.
      「リターンアドレスとして現在値を表す bci 値を算出し, オペランドスタックの先頭に乗せる.
      さらに Lbcp を飛び先の値に変更する.
      その後, dispatch_next() が生成するコードで, 
      次のバイトコードに対応するテンプレートへとジャンプする」
      ---------------------------------------- -}

      // Handle all the JSR stuff here, then exit.
      // It's much shorter and cleaner than intermingling with the
      // non-JSR normal-branch stuff occurring below.
      if( is_jsr ) {
        // compute return address as bci in Otos_i
        __ ld_ptr(Lmethod, methodOopDesc::const_offset(), G3_scratch);
        __ sub(Lbcp, G3_scratch, G3_scratch);
        __ sub(G3_scratch, in_bytes(constMethodOopDesc::codes_offset()) - (is_wide ? 5 : 3), Otos_i);

        // Bump Lbcp to target of JSR
        __ add(Lbcp, O1_disp, Lbcp);
        // Push returnAddress for "ret" on stack
        __ push_ptr(Otos_i);
        // And away we go!
        __ dispatch_next(vtos);
        return;
      }

  {- -------------------------------------------
  (1) (以下は, jsr ではない場合のコード生成)
      ---------------------------------------- -}

      // Normal (non-jsr) branch handling

  {- -------------------------------------------
  (1) コード生成:
      「Lbcp レジスタの値を一旦待避しておく」
      ---------------------------------------- -}

      // Save the current Lbcp
      const Register O0_cur_bcp = O0;
      __ mov( Lbcp, O0_cur_bcp );


  {- -------------------------------------------
  (1) もし UseCompiler と UseLoopCounter の両方が指定されていれば,
      以下の処理パスで backward branch 用の処理を行うコードを出力する.
      ---------------------------------------- -}

      bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter;
      if ( increment_invocation_counter_for_backward_branches ) {

    {- -------------------------------------------
  (1.1) コード生成:
        「Lbcp の値を更新する (O1_disp に入っているオフセット分を足す).

          さらに, 分岐の向きをチェックして, 
          forward branch であれば (backward branch 用の処理は不要なので) Lforward まで進む.」

          (<= より正確に言うと, Lbcp の更新は分岐の遅延スロットを使って行っている)
        ---------------------------------------- -}

        Label Lforward;
        // check branch direction
        __ br( Assembler::positive, false,  Assembler::pn, Lforward );
        // Bump bytecode pointer by displacement (take the branch)
        __ delayed()->add( O1_disp, Lbcp, Lbcp );     // add to bc addr

    {- -------------------------------------------
  (1.1) TieredCompilation が指定されている場合, 以下の処理パスでコードを生成する
        ---------------------------------------- -}

        if (TieredCompilation) {

      {- -------------------------------------------
  (1.1.1) (変数宣言など)
          ---------------------------------------- -}

          Label Lno_mdo, Loverflow;
          int increment = InvocationCounter::count_increment;
          int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift;

      {- -------------------------------------------
  (1.1.1) コード生成: (ただし, ProfileInterpreter オプションが指定されていない場合には生成しない)
          「もし methodDataOopDesc(mdo) が付いていれば, 
            InterpreterMacroAssembler::increment_mask_and_jump() が生成するコードによって
            mdo の _backedge_counter フィールドのカウンタ値をインクリメントし, 閾値チェックを行う.
            閾値に達していなかった場合は, Lforward ラベルにジャンプする.
            そうでなければ, Loverflow ラベルまでジャンプする.

            もし methodDataOopDesc が付いていなければ, 
            Lno_mdo ラベルまでジャンプする」
          ---------------------------------------- -}

          if (ProfileInterpreter) {
            // If no method data exists, go to profile_continue.
            __ ld_ptr(Lmethod, methodOopDesc::method_data_offset(), G4_scratch);
            __ br_null(G4_scratch, false, Assembler::pn, Lno_mdo);
            __ delayed()->nop();

            // Increment backedge counter in the MDO
            Address mdo_backedge_counter(G4_scratch, in_bytes(methodDataOopDesc::backedge_counter_offset()) +
                                                     in_bytes(InvocationCounter::counter_offset()));
            __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, Lscratch,
                                       Assembler::notZero, &Lforward);
            __ ba(false, Loverflow);
            __ delayed()->nop();
          }

      {- -------------------------------------------
  (1.1.1) コード生成:
          「(ここが Lno_mdo ラベルの位置)」
          ---------------------------------------- -}

          // If there's no MDO, increment counter in methodOop
          __ bind(Lno_mdo);

      {- -------------------------------------------
  (1.1.1) (変数宣言など)
          ---------------------------------------- -}

          Address backedge_counter(Lmethod, in_bytes(methodOopDesc::backedge_counter_offset()) +
                                            in_bytes(InvocationCounter::counter_offset()));

      {- -------------------------------------------
  (1.1.1) コード生成:
          「InterpreterMacroAssembler::increment_mask_and_jump() が生成するコードによって
            実行中のメソッドに対応する methodOopDesc の 
            _backedge_counter フィールドのカウンタ値をインクリメントし, 閾値チェックを行う.
            閾値に達していなかった場合は, Lforward ラベルにジャンプする.
            そうでなければ, このままフォールスルーする」
          ---------------------------------------- -}

          __ increment_mask_and_jump(backedge_counter, increment, mask, G3_scratch, Lscratch,
                                     Assembler::notZero, &Lforward);

      {- -------------------------------------------
  (1.1.1) コード生成:
          「(ここが Loverflow ラベルの位置)」
          ---------------------------------------- -}

          __ bind(Loverflow);

      {- -------------------------------------------
  (1.1.1) コード生成:
          「InterpreterRuntime::frequency_counter_overflow() を呼び出して JIT コンパイル処理を開始する.」
          ---------------------------------------- -}

          // notify point for loop, pass branch bytecode
          __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), O0_cur_bcp);

      {- -------------------------------------------
  (1.1.1) コード生成:
          「もし InterpreterRuntime::frequency_counter_overflow() の返り値が NULL だったら,
            (まだ JIT 生成されたコードがないということなので) Lforward ラベルまで飛ぶ.
            また, nmethod が既に invalidate されていた場合も, Lforward ラベルまで飛ぶ.」
          ---------------------------------------- -}

          // Was an OSR adapter generated?
          // O0 = osr nmethod
          __ br_null(O0, false, Assembler::pn, Lforward);
          __ delayed()->nop();

          // Has the nmethod been invalidated already?
          __ ld(O0, nmethod::entry_bci_offset(), O2);
          __ cmp(O2, InvalidOSREntryBci);
          __ br(Assembler::equal, false, Assembler::pn, Lforward);
          __ delayed()->nop();

      {- -------------------------------------------
  (1.1.1) (ここまで来たら, JIT 生成された nmethod が得られたということになる)
          ---------------------------------------- -}

          // migrate the interpreter frame off of the stack

      {- -------------------------------------------
  (1.1.1) コード生成:
          「SharedRuntime::OSR_migration_begin() を呼んで, 
            interpreter frame 中の局所変数とモニタを C ヒープ上に取ったバッファに退避する.
            (呼び出しの前後で G2_thread や O0(に入っている nmethod) の退避復帰を行っている)」
          ---------------------------------------- -}

          __ mov(G2_thread, L7);
          // save nmethod
          __ mov(O0, L6);
          __ set_last_Java_frame(SP, noreg);
          __ call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), L7);
          __ reset_last_Java_frame();
          __ mov(L7, G2_thread);

      {- -------------------------------------------
  (1.1.1) コード生成:
          「nmethod や SharedRuntime::OSR_migration_begin() が返したバッファを I0/I1 に退避してから, 
           restore 命令で interpreter frame を削除する.」
          ---------------------------------------- -}

          // move OSR nmethod to I1
          __ mov(L6, I1);

          // OSR buffer to I0
          __ mov(O0, I0);

          // remove the interpreter frame
          __ restore(I5_savedSP, 0, SP);

      {- -------------------------------------------
  (1.1.1) コード生成:
          「nmethod からエントリポイントを取得し, osr コードにジャンプする.」
          ---------------------------------------- -}

          // Jump to the osr code.
          __ ld_ptr(O1, nmethod::osr_entry_point_offset(), O2);
          __ jmp(O2, G0);
          __ delayed()->nop();

    {- -------------------------------------------
  (1.1) TieredCompilation が指定されていない場合, 以下の処理パスでコードを生成する
        ---------------------------------------- -}

        } else {

      {- -------------------------------------------
  (1.1.1) コード生成: (TieredCompilation が指定されていない場合)
          まず, 以下のコードを生成する.
          「InterpreterMacroAssembler::increment_backedge_counter() が生成するコードで
           backedge_counter のカウント値をインクリメントする.」

          その後, ProfileInterpreter が指定されていれば, 以下のコードを生成する.
          「InterpreterMacroAssembler::test_invocation_counter_for_mdp() が生成するコードで
            methodDataOop(mdp) に関するチェックを行う.
            チェック結果に応じて, 以下の3通りに分岐.
            * 既に methodDataOop が作成済みの場合:
              このままフォールスルー 
              (UseOnStackReplacement が指定されていれば, 
              InterpreterMacroAssembler::test_backedge_count_for_osr() が生成するコードに突入する)

            * 監視対象になる閾値を超えているが, まだ mdp が確保されていない場合:
              新しい methodDataOop オブジェクトを methodOop 内にセットし, Lforward ラベルまで分岐.

            * まだ監視対象になる閾値を超えていない場合:
              Lforward ラベルまで分岐.」

          その後, UseOnStackReplacement が指定されていれば, 以下のコードを生成する.
          「InterpreterMacroAssembler::test_backedge_count_for_osr() が生成するコードで, 
          カウント値と閾値を比較し, 閾値を超えていれば JIT コンパイルを行う.
          あるいは, 既に JIT コンパイル済みのコードがあれば, OSR を行ってそのコードに遷移する.」


          (なお, InterpreterMacroAssembler::test_backedge_count_for_osr() でチェックされるカウント値は, 
          ProfileInterpreter が有効な場合は O2_bumped_count レジスタ.
          これは InterpreterMacroAssembler::profile_taken_branch() が生成するコードがセットしている.
          ProfileInterpreter が無効な場合は G4_invoke_ctr レジスタ.
          これは InterpreterMacroAssembler::increment_backedge_counter() が生成するコードがセットしている)
          ---------------------------------------- -}

          // Update Backedge branch separately from invocations
          const Register G4_invoke_ctr = G4;
          __ increment_backedge_counter(G4_invoke_ctr, G1_scratch);
          if (ProfileInterpreter) {
            __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward);
            if (UseOnStackReplacement) {
              __ test_backedge_count_for_osr(O2_bumped_count, O0_cur_bcp, G3_scratch);
            }
          } else {
            if (UseOnStackReplacement) {
              __ test_backedge_count_for_osr(G4_invoke_ctr, O0_cur_bcp, G3_scratch);
            }
          }
        }

    {- -------------------------------------------
  (1.1) コード生成:
        「(ここが Lforward ラベルの位置)」
        ---------------------------------------- -}

        __ bind(Lforward);

  {- -------------------------------------------
  (1) コード生成:
      UseCompiler または UseLoopCounter のどちらかが指定されていない場合は, 以下のコードを出力するだけ
      「Lbcp の値を更新する (O1_disp に入っているオフセット分を足す)」
      ---------------------------------------- -}

      } else
        // Bump bytecode pointer by displacement (take the branch)
        __ add( O1_disp, Lbcp, Lbcp );// add to bc addr

  {- -------------------------------------------
  (1) コード生成:
      「dispatch_next() が生成するコードで, 
        次のバイトコードに対応するテンプレートへとジャンプする」
      ---------------------------------------- -}

      // continue with bytecode @ target
      // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above,
      // %%%%% and changing dispatch_next to dispatch_only
      __ dispatch_next(vtos);
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.