Top


定義場所(file name)

hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp

名前(function name)

bool G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
                                              bool check_for_refs_into_cset) {

本体部(body)

  {- -------------------------------------------
  (1) (ここに来た時点では) もう dirty でなかった場合, することは何もない, ここでリターン.
      ---------------------------------------- -}

      // If the card is no longer dirty, nothing to do.
      if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
        // No need to return that this card contains refs that point
        // into the collection set.
        return false;
      }

  {- -------------------------------------------
  (1) 処理対象の card に対応する HeapRegion を取得する(以下の r).
      (見つからなければ, ここでリターン)
      (どういうケース?? #TODO)
      ---------------------------------------- -}

      // Construct the region representing the card.
      HeapWord* start = _ct_bs->addr_for(card_ptr);
      // And find the region containing it.
      HeapRegion* r = _g1->heap_region_containing(start);
      if (r == NULL) {
        guarantee(_g1->is_in_permanent(start), "Or else where?");
        // Again no need to return that this card contains refs that
        // point into the collection set.
        return false;  // Not in the G1 heap (might be in perm, for example.)
      }

  {- -------------------------------------------
  (1) Young な HeapRegion であれば, 処理する必要は無いので(?), ここでリターン.

      (<= Remembered Set は処理対象じゃない領域用のものだから, そもそも処理対象なら要らないか?? #TODO)
      ---------------------------------------- -}

      // Why do we have to check here whether a card is on a young region,
      // given that we dirty young regions and, as a result, the
      // post-barrier is supposed to filter them out and never to enqueue
      // them? When we allocate a new region as the "allocation region" we
      // actually dirty its cards after we release the lock, since card
      // dirtying while holding the lock was a performance bottleneck. So,
      // as a result, it is possible for other threads to actually
      // allocate objects in the region (after the acquire the lock)
      // before all the cards on the region are dirtied. This is unlikely,
      // and it doesn't happen often, but it can happen. So, the extra
      // check below filters out those cards.
      if (r->is_young()) {
        return false;
      }

  {- -------------------------------------------
  (1) Collection Set に選ばれている HeapRegion であれば, 処理する必要は無いので(?), ここでリターン.

      (<= Remembered Set は処理対象じゃない領域用のものだから, そもそも処理対象なら要らないか?? #TODO)
      ---------------------------------------- -}

      // While we are processing RSet buffers during the collection, we
      // actually don't want to scan any cards on the collection set,
      // since we don't want to update remebered sets with entries that
      // point into the collection set, given that live objects from the
      // collection set are about to move and such entries will be stale
      // very soon. This change also deals with a reliability issue which
      // involves scanning a card in the collection set and coming across
      // an array that was being chunked and looking malformed. Note,
      // however, that if evacuation fails, we have to scan any objects
      // that were not moved and create any missing entries.
      if (r->in_collection_set()) {
        return false;
      }

  {- -------------------------------------------
  (1) (以下の処理で, まず遅延処理するかどうかを判定する. ...#TODO)
      ---------------------------------------- -}

      // Should we defer processing the card?
      //
      // Previously the result from the insert_cache call would be
      // either card_ptr (implying that card_ptr was currently "cold"),
      // null (meaning we had inserted the card ptr into the "hot"
      // cache, which had some headroom), or a "hot" card ptr
      // extracted from the "hot" cache.
      //
      // Now that the _card_counts cache in the ConcurrentG1Refine
      // instance is an evicting hash table, the result we get back
      // could be from evicting the card ptr in an already occupied
      // bucket (in which case we have replaced the card ptr in the
      // bucket with card_ptr and "defer" is set to false). To avoid
      // having a data structure (updates to which would need a lock)
      // to hold these unprocessed dirty cards, we need to immediately
      // process card_ptr. The actions needed to be taken on return
      // from cache_insert are summarized in the following table:
      //
      // res      defer   action
      // --------------------------------------------------------------
      // null     false   card evicted from _card_counts & replaced with
      //                  card_ptr; evicted ptr added to hot cache.
      //                  No need to process res; immediately process card_ptr
      //
      // null     true    card not evicted from _card_counts; card_ptr added
      //                  to hot cache.
      //                  Nothing to do.
      //
      // non-null false   card evicted from _card_counts & replaced with
      //                  card_ptr; evicted ptr is currently "cold" or
      //                  caused an eviction from the hot cache.
      //                  Immediately process res; process card_ptr.
      //
      // non-null true    card not evicted from _card_counts; card_ptr is
      //                  currently cold, or caused an eviction from hot
      //                  cache.
      //                  Immediately process res; no need to process card_ptr.


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

      jbyte* res = card_ptr;
      bool defer = false;

      // This gets set to true if the card being refined has references
      // that point into the collection set.
      bool oops_into_cset = false;

    {- -------------------------------------------
  (1.1) cache_insert() でキャッシュに突っ込み, ついでに defer するかどうか判定する(?? #TODO)
        ...
        ---------------------------------------- -}

      if (_cg1r->use_cache()) {
        jbyte* res = _cg1r->cache_insert(card_ptr, &defer);
        if (res != NULL && (res != card_ptr || defer)) {
          start = _ct_bs->addr_for(res);
          r = _g1->heap_region_containing(start);
          if (r == NULL) {
            assert(_g1->is_in_permanent(start), "Or else where?");
          } else {
            // Checking whether the region we got back from the cache
            // is young here is inappropriate. The region could have been
            // freed, reallocated and tagged as young while in the cache.
            // Hence we could see its young type change at any time.
            //
            // Process card pointer we get back from the hot card cache. This
            // will check whether the region containing the card is young
            // _after_ checking that the region has been allocated from.
            oops_into_cset = concurrentRefineOneCard_impl(res, worker_i,
                                                          false /* check_for_refs_into_cset */);
            // The above call to concurrentRefineOneCard_impl is only
            // performed if the hot card cache is enabled. This cache is
            // disabled during an evacuation pause - which is the only
            // time when we need know if the card contains references
            // that point into the collection set. Also when the hot card
            // cache is enabled, this code is executed by the concurrent
            // refine threads - rather than the GC worker threads - and
            // concurrentRefineOneCard_impl will return false.
            assert(!oops_into_cset, "should not see true here");
          }
        }
      }

    {- -------------------------------------------
  (1.1) (以下は遅延処理しない場合(= この場で処理する場合) の処理)
        G1RemSet::concurrentRefineOneCard_impl() を呼んで処理を行う.
        ---------------------------------------- -}

      if (!defer) {
        oops_into_cset =
          concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset);
        // We should only be detecting that the card contains references
        // that point into the collection set if the current thread is
        // a GC worker thread.
        assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(),
               "invalid result at non safepoint");
      }

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

      return oops_into_cset;
    }

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