Top


定義場所(file name)

hotspot/src/share/vm/memory/referenceProcessor.cpp

名前(function name)

inline void
ReferenceProcessor::add_to_discovered_list_mt(DiscoveredList& refs_list,
                                              oop             obj,
                                              HeapWord*       discovered_addr) {

本体部(body)

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

      assert(_discovery_is_mt, "!_discovery_is_mt should have been handled by caller");

  {- -------------------------------------------
  (1) (同一の参照オブジェクトが複数回 enqueue されると困るので discovered フィールドの書き換えは CAS で行う, とのこと)
      ---------------------------------------- -}

      // First we must make sure this object is only enqueued once. CAS in a non null
      // discovered_addr.

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

      oop current_head = refs_list.head();

  {- -------------------------------------------
  (1) write barrier の実行が要求されている場合(_discovered_list_needs_barrier が true の場合)であっても
      G1GC の場合は BarrierSet::write_ref_field_pre() の実行までは必要ない.
      (というのは, 書き込む前の discovered フィールドの値が NULL だから)

      コメントによると, 「将来の GC アルゴリズムで pre-barrier を
      必要とするものが出てくるかもしれないので, この if 文を書いてある」とのこと.
      (現状だと, そもそも _discovered_list_needs_barrier が true になるのが G1GC の場合しかないような...)
      ---------------------------------------- -}

      // Note: In the case of G1, this specific pre-barrier is strictly
      // not necessary because the only case we are interested in
      // here is when *discovered_addr is NULL (see the CAS further below),
      // so this will expand to nothing. As a result, we have manually
      // elided this out for G1, but left in the test for some future
      // collector that might have need for a pre-barrier here.
      if (_discovered_list_needs_barrier && !UseG1GC) {
        if (UseCompressedOops) {
          _bs->write_ref_field_pre((narrowOop*)discovered_addr, current_head);
        } else {
          _bs->write_ref_field_pre((oop*)discovered_addr, current_head);
        }
        guarantee(false, "Need to check non-G1 collector");
      }

  {- -------------------------------------------
  (1) CAS を用いて, 
      処理対象の参照オブジェクトの discovered フィールドを
      現在リストの先頭になっている参照オブジェクトに置き換える.
      (なお, 書き換え前の discovered フィールドは NULL だという想定)
      ---------------------------------------- -}

      oop retest = oopDesc::atomic_compare_exchange_oop(current_head, discovered_addr,
                                                        NULL);

  {- -------------------------------------------
  (1) もし CAS が成功していれば, 以下の処理を行う.
      * リストの先頭を今回処理した参照オブジェクトに置き換える (ついでにリストの長さをインクリメントする).
      * write barrier の実行が要求されている場合(_discovered_list_needs_barrier が true の場合)には
        BarrierSet::write_ref_field() を呼び出して barrier set を書き換えておく.
      * (トレース出力)
      ---------------------------------------- -}

      if (retest == NULL) {
        // This thread just won the right to enqueue the object.
        // We have separate lists for enqueueing so no synchronization
        // is necessary.
        refs_list.set_head(obj);
        refs_list.inc_length(1);
        if (_discovered_list_needs_barrier) {
          _bs->write_ref_field((void*)discovered_addr, current_head);
        }

        if (TraceReferenceGC) {
          gclog_or_tty->print_cr("Enqueued reference (mt) (" INTPTR_FORMAT ": %s)",
                                 obj, obj->blueprint()->internal_name());
        }

  {- -------------------------------------------
  (1) もし CAS が失敗していたら, (トレース出力)を出すだけ.
      ---------------------------------------- -}

      } else {
        // If retest was non NULL, another thread beat us to it:
        // The reference has already been discovered...
        if (TraceReferenceGC) {
          gclog_or_tty->print_cr("Already enqueued reference (" INTPTR_FORMAT ": %s)",
                                 obj, obj->blueprint()->internal_name());
        }
      }
    }

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