--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Mon Aug 03 12:59:30 2009 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue Aug 04 16:00:17 2009 -0700
@@ -676,6 +676,55 @@
static IntHistogram out_of_histo(50, 50);
+void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i) {
+ // 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);
+ assert(r != NULL, "unexpected null");
+
+ HeapWord* end = _ct_bs->addr_for(card_ptr + 1);
+ MemRegion dirtyRegion(start, end);
+
+#if CARD_REPEAT_HISTO
+ init_ct_freq_table(_g1->g1_reserved_obj_bytes());
+ ct_freq_note_card(_ct_bs->index_for(start));
+#endif
+
+ UpdateRSOopClosure update_rs_oop_cl(this, worker_i);
+ update_rs_oop_cl.set_from(r);
+ FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl);
+
+ // Undirty the card.
+ *card_ptr = CardTableModRefBS::clean_card_val();
+ // We must complete this write before we do any of the reads below.
+ OrderAccess::storeload();
+ // And process it, being careful of unallocated portions of TLAB's.
+ HeapWord* stop_point =
+ r->oops_on_card_seq_iterate_careful(dirtyRegion,
+ &filter_then_update_rs_oop_cl);
+ // If stop_point is non-null, then we encountered an unallocated region
+ // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the
+ // card and re-enqueue: if we put off the card until a GC pause, then the
+ // unallocated portion will be filled in. Alternatively, we might try
+ // the full complexity of the technique used in "regular" precleaning.
+ if (stop_point != NULL) {
+ // The card might have gotten re-dirtied and re-enqueued while we
+ // worked. (In fact, it's pretty likely.)
+ if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
+ *card_ptr = CardTableModRefBS::dirty_card_val();
+ MutexLockerEx x(Shared_DirtyCardQ_lock,
+ Mutex::_no_safepoint_check_flag);
+ DirtyCardQueue* sdcq =
+ JavaThread::dirty_card_queue_set().shared_dirty_card_queue();
+ sdcq->enqueue(card_ptr);
+ }
+ } else {
+ out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region());
+ _conc_refine_cards++;
+ }
+}
+
void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {
// If the card is no longer dirty, nothing to do.
if (*card_ptr != CardTableModRefBS::dirty_card_val()) return;
@@ -716,61 +765,63 @@
return;
}
- // Should we defer it?
- if (_cg1r->use_cache()) {
- card_ptr = _cg1r->cache_insert(card_ptr);
- // If it was not an eviction, nothing to do.
- if (card_ptr == NULL) return;
+ // 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.
- // OK, we have to reset the card start, region, etc.
- start = _ct_bs->addr_for(card_ptr);
- r = _g1->heap_region_containing(start);
- if (r == NULL) {
- guarantee(_g1->is_in_permanent(start), "Or else where?");
- return; // Not in the G1 heap (might be in perm, for example.)
+ jbyte* res = card_ptr;
+ bool defer = false;
+ 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 {
+ guarantee(!r->is_young(), "It was evicted in the current minor cycle.");
+ // Process card pointer we get back from the hot card cache
+ concurrentRefineOneCard_impl(res, worker_i);
+ }
}
- guarantee(!r->is_young(), "It was evicted in the current minor cycle.");
}
- HeapWord* end = _ct_bs->addr_for(card_ptr + 1);
- MemRegion dirtyRegion(start, end);
-
-#if CARD_REPEAT_HISTO
- init_ct_freq_table(_g1->g1_reserved_obj_bytes());
- ct_freq_note_card(_ct_bs->index_for(start));
-#endif
-
- UpdateRSOopClosure update_rs_oop_cl(this, worker_i);
- update_rs_oop_cl.set_from(r);
- FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl);
-
- // Undirty the card.
- *card_ptr = CardTableModRefBS::clean_card_val();
- // We must complete this write before we do any of the reads below.
- OrderAccess::storeload();
- // And process it, being careful of unallocated portions of TLAB's.
- HeapWord* stop_point =
- r->oops_on_card_seq_iterate_careful(dirtyRegion,
- &filter_then_update_rs_oop_cl);
- // If stop_point is non-null, then we encountered an unallocated region
- // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the
- // card and re-enqueue: if we put off the card until a GC pause, then the
- // unallocated portion will be filled in. Alternatively, we might try
- // the full complexity of the technique used in "regular" precleaning.
- if (stop_point != NULL) {
- // The card might have gotten re-dirtied and re-enqueued while we
- // worked. (In fact, it's pretty likely.)
- if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
- *card_ptr = CardTableModRefBS::dirty_card_val();
- MutexLockerEx x(Shared_DirtyCardQ_lock,
- Mutex::_no_safepoint_check_flag);
- DirtyCardQueue* sdcq =
- JavaThread::dirty_card_queue_set().shared_dirty_card_queue();
- sdcq->enqueue(card_ptr);
- }
- } else {
- out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region());
- _conc_refine_cards++;
+ if (!defer) {
+ concurrentRefineOneCard_impl(card_ptr, worker_i);
}
}