Top


定義場所(file name)

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

名前(function name)

void MacroAssembler::g1_write_barrier_post(Register store_addr,
                                           Register new_val,
                                           Register thread,
                                           Register tmp,
                                           Register tmp2) {

本体部(body)

  {- -------------------------------------------
  (1) (assert)
      ---------------------------------------- -}

    #ifdef _LP64
      assert(thread == r15_thread, "must be");
    #endif // _LP64

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

      Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
                                           PtrQueue::byte_offset_of_index()));
      Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
                                           PtrQueue::byte_offset_of_buf()));

      BarrierSet* bs = Universe::heap()->barrier_set();
      CardTableModRefBS* ct = (CardTableModRefBS*)bs;
      Label done;
      Label runtime;

  {- -------------------------------------------
  (1) コード生成:
      「書き込まれる値が同一 HeapRegion 内を指している場合は 
        (記録する必要が無いので) done ラベルまでジャンプ.」

       (あるオブジェクトのフィールドに同じ HeapRegion 内のオブジェクトへのポインタが代入された場合.
        HeapRegion 間の参照関係を追うための記録処理なので, 同一 HeapRegion 内での参照は無視していい.)

       (なお具体的な検査処理は, 書き込み先のアドレス(store_addr)と書き込まれる値(new_val)の xor を取り, 
        それを HeapRegion の大きさ(のlog2)分だけシフトして 0 かどうか調べる, というもの.
        二つの値の違いが HeapRegion 未満(= 同一 HeapRegion 内)であれば結果は 0 になる)

       (sparc 版では, このコードは G1RSBarrierRegionFilter オプションで生成するかどうかを制御できるようだが... #TODO)
      ---------------------------------------- -}

      // Does store cross heap regions?

      movptr(tmp, store_addr);
      xorptr(tmp, new_val);
      shrptr(tmp, HeapRegion::LogOfHRGrainBytes);
      jcc(Assembler::equal, done);

  {- -------------------------------------------
  (1) コード生成: 
      「書き込まれる値が 0 かどうかチェックする. 
        0 であれば, 記録する必要は無いので,  done ラベルまでジャンプ.」
      ---------------------------------------- -}

      // crosses regions, storing NULL?

      cmpptr(new_val, (int32_t) NULL_WORD);
      jcc(Assembler::equal, done);

  {- -------------------------------------------
  (1) コード生成: 
      「書き込み先のアドレスに対応する card table 中の値を確認する.
        既に dirty (= 0) になっている場合は, もう記録処理は必要無いので, done ラベルまでジャンプ.」

      (より具体的には, 
       まず, 書き込み先のアドレス(card_addr)の値を CardTableModRefBS::card_shift 分だけ右シフトさせて, 
       対応する card table 内の index を計算する.
       次に, それに card table のアドレス(byte_map_base 引数の値)を足し込んだアドレスから
       1byte ロードし, 0 と比較する)

      (なお, 0 が dirty を示す (See: dirty_card))
      ---------------------------------------- -}

      // storing region crossing non-NULL, is card already dirty?

      ExternalAddress cardtable((address) ct->byte_map_base);
      assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
    #ifdef _LP64
      const Register card_addr = tmp;

      movq(card_addr, store_addr);
      shrq(card_addr, CardTableModRefBS::card_shift);

      lea(tmp2, cardtable);

      // get the address of the card
      addq(card_addr, tmp2);
    #else
      const Register card_index = tmp;

      movl(card_index, store_addr);
      shrl(card_index, CardTableModRefBS::card_shift);

      Address index(noreg, card_index, Address::times_1);
      const Register card_addr = tmp;
      lea(card_addr, as_Address(ArrayAddress(cardtable, index)));
    #endif
      cmpb(Address(card_addr, 0), 0);
      jcc(Assembler::equal, done);

  {- -------------------------------------------
  (1) コード生成: 
      「card table 中の該当箇所に 0 を書き込んで dirty 化する」
      ---------------------------------------- -}

      // storing a region crossing, non-NULL oop, card is clean.
      // dirty card and log.

      movb(Address(card_addr, 0), 0);

  {- -------------------------------------------
  (1) コード生成:
      「JavaThread::_dirty_card_queue フィールドの DirtyCardQueue オブジェクト内の
        _index フィールドの値をチェックする.
        もし値が 0 の場合は, 次のバッファを用意する必要があるので, runtime ラベルにジャンプする.」

       (なお, _index がバッファ中の現在の終端位置を示す. 値が 0 であればもう空き領域はない)
      ---------------------------------------- -}

      cmpl(queue_index, 0);
      jcc(Assembler::equal, runtime);

  {- -------------------------------------------
  (1) コード生成:
      「JavaThread::_dirty_card_queue フィールドの DirtyCardQueue オブジェクト内の
        _index フィールドの値を 
        wordSize 分だけ小さくし, _index フィールドに書き戻す.」
      ---------------------------------------- -}

      subl(queue_index, wordSize);

  {- -------------------------------------------
  (1) コード生成:
      「JavaThread::_satb_mark_queue フィールドの ObjPtrQueue オブジェクト内の
       _buf 内の _index の位置に保存対象の値(以下の card_addr または card_index)を書き込む.」
      ---------------------------------------- -}

      movptr(tmp2, buffer);
    #ifdef _LP64
      movslq(rscratch1, queue_index);
      addq(tmp2, rscratch1);
      movq(Address(tmp2, 0), card_addr);
    #else
      addl(tmp2, queue_index);
      movl(Address(tmp2, 0), card_index);
    #endif

  {- -------------------------------------------
  (1) コード生成:
      「done ラベルにジャンプする (これで write barrier 処理は終了)」
      ---------------------------------------- -}

      jmp(done);

  {- -------------------------------------------
  (1) (以降が runtime ラベルに飛んだ場合の処理)
      ---------------------------------------- -}

      bind(runtime);

  {- -------------------------------------------
  (1) 生きているレジスタを待避するコードを生成しておく.
      ---------------------------------------- -}

      // save the live input values
      push(store_addr);
      push(new_val);

  {- -------------------------------------------
  (1) コード生成:
      「SharedRuntime::g1_wb_post() を呼び出し, バッファの確保及び write barrier 処理を行う.」

      (また, NOT_LP64 の場合には, 呼び出しの前後で thread 引数が示すレジスタの待避/復帰も行う)
      ---------------------------------------- -}

    #ifdef _LP64
      call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, r15_thread);
    #else
      push(thread);
      call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
      pop(thread);
    #endif

  {- -------------------------------------------
  (1) 待避したレジスタを復帰させるコードを生成しておく.
      ---------------------------------------- -}

      pop(new_val);
      pop(store_addr);

  {- -------------------------------------------
  (1) (ここが done ラベルの位置)
      ---------------------------------------- -}

      bind(done);
    }

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