Top


定義場所(file name)

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

名前(function name)

void MacroAssembler::g1_write_barrier_pre(Register obj,
                                          Register pre_val,
                                          Register thread,
                                          Register tmp,
                                          bool tosca_live,
                                          bool expand_call) {

本体部(body)

  {- -------------------------------------------
  (1) (コメントによると, 
        expand_call 引数が true の場合には
        InterpreterMacroAssember::call_VM_leaf_base() の代わりに
        MacroAssember::call_VM_leaf_base() を使用している.
        これは, InterpreterMacroAssembler::call_VM_leaf_base() が生成する 
        _last_sp のチェックコードを回避したい場合用, 
      とのこと)
      ---------------------------------------- -}

      // 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.

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

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

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

      Label done;
      Label runtime;

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

      assert(pre_val != noreg, "check this code");

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

      if (obj != noreg) {
        assert_different_registers(obj, pre_val, tmp);
        assert(pre_val != rax, "check this code");
      }

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

      Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
                                           PtrQueue::byte_offset_of_active()));
      Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
                                           PtrQueue::byte_offset_of_index()));
      Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
                                           PtrQueue::byte_offset_of_buf()));


  {- -------------------------------------------
  (1) コード生成:
      「JavaThread::_satb_mark_queue フィールドの ObjPtrQueue オブジェクト内の
        _active フィールドをチェックする.
        もし _active フィールドの値が 0 (= false) であれば,
        何もする必要が無いので, done ラベルまでジャンプ」

      (このフィールドは, write barrier でポインタの記録が必要かどうかを示す.
       ConcurrentMarkThread が動作中であれば true になる.
       See: SATBMarkQueueSet::set_active_all_threads())

      (なおコンパイラによって bool のバイト数が異なるので, 
       バイト数に応じて2通りのコードを生成する.
       ここでは 4byte になる場合と 1byte になる場合を想定している模様)
      ---------------------------------------- -}

      // Is marking active?
      if (in_bytes(PtrQueue::byte_width_of_active()) == 4) {
        cmpl(in_progress, 0);
      } else {
        assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption");
        cmpb(in_progress, 0);
      }
      jcc(Assembler::equal, done);

  {- -------------------------------------------
  (1) コード生成:
      「書き換え対象箇所の現在の値をロードする」
      ---------------------------------------- -}

      // Do we need to load the previous value?
      if (obj != noreg) {
        load_heap_oop(pre_val, Address(obj, 0));
      }

  {- -------------------------------------------
  (1) コード生成:
      「もし現在の値が NULL であれば, 記録する価値はないので, done ラベルまでジャンプ」
      ---------------------------------------- -}

      // Is the previous value null?
      cmpptr(pre_val, (int32_t) NULL_WORD);
      jcc(Assembler::equal, done);

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

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

      // Can we store original value in the thread's buffer?
      // Is index == 0?
      // (The index field is typed as size_t.)

      movptr(tmp, index);                   // tmp := *index_adr
      cmpptr(tmp, 0);                       // tmp == 0?
      jcc(Assembler::equal, runtime);       // If yes, goto runtime

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

      subptr(tmp, wordSize);                // tmp := tmp - wordSize
      movptr(index, tmp);                   // *index_adr := tmp

  {- -------------------------------------------
  (1) コード生成:
      「JavaThread::_satb_mark_queue フィールドの ObjPtrQueue オブジェクト内の
       _buf 内の _index の位置に保存対象の値(O0/I0レジスタの値)を書き込む.
       (より具体的に言うと, tmp レジスタの値と buffer アドレスを足したアドレスに値を書き込む)」
      ---------------------------------------- -}

      addptr(tmp, buffer);                  // tmp := tmp + *buffer_adr

      // Record the previous value
      movptr(Address(tmp, 0), pre_val);

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

      jmp(done);

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

      bind(runtime);

  {- -------------------------------------------
  (1) 必要に応じて, 生きているレジスタを待避するコードを生成しておく
      ---------------------------------------- -}

      // save the live input values
      if(tosca_live) push(rax);

      if (obj != noreg && obj != rax)
        push(obj);

      if (pre_val != rax)
        push(pre_val);

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

      なお, この呼び出し処理は expand_call 引数に応じて少し異なる
      * true の場合:
        MacroAssembler::call_VM_leaf_base() が生成するコードによって行う.
      * false の場合:
        MacroAssembler::call_VM_leaf_base() をサブクラスがオーバーライドしたメソッドが生成するコードによって行う.
        (InterpreterMacroAssember::call_VM_leaf_base())
      (コメントによると, Reference.get() 用のルーチンの場合等にはスタックフレームがないせいで
      InterpreterMacroAssember::call_VM_leaf_base() 内のランタイムチェックが失敗することがあるので, 
      呼び出し先を切り替えられるようにしている, とのこと)

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

      // 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.

      NOT_LP64( push(thread); )

      if (expand_call) {
        LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); )
        pass_arg1(this, thread);
        pass_arg0(this, pre_val);
        MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), 2);
      } else {
        call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
      }

      NOT_LP64( pop(thread); )

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

      // save the live input values
      if (pre_val != rax)
        pop(pre_val);

      if (obj != noreg && obj != rax)
        pop(obj);

      if(tosca_live) pop(rax);

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

      bind(done);
    }

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