325 _card_live_data.pretouch(); |
325 _card_live_data.pretouch(); |
326 } |
326 } |
327 } |
327 } |
328 |
328 |
329 G1ScanRSClosure::G1ScanRSClosure(G1RemSetScanState* scan_state, |
329 G1ScanRSClosure::G1ScanRSClosure(G1RemSetScanState* scan_state, |
330 G1ParPushHeapRSClosure* push_heap_cl, |
330 G1ScanObjsDuringScanRSClosure* scan_obj_on_card, |
331 CodeBlobClosure* code_root_cl, |
331 CodeBlobClosure* code_root_cl, |
332 uint worker_i) : |
332 uint worker_i) : |
333 _scan_state(scan_state), |
333 _scan_state(scan_state), |
334 _push_heap_cl(push_heap_cl), |
334 _scan_objs_on_card_cl(scan_obj_on_card), |
335 _code_root_cl(code_root_cl), |
335 _code_root_cl(code_root_cl), |
336 _strong_code_root_scan_time_sec(0.0), |
336 _strong_code_root_scan_time_sec(0.0), |
337 _cards_claimed(0), |
337 _cards_claimed(0), |
338 _cards_scanned(0), |
338 _cards_scanned(0), |
339 _cards_skipped(0), |
339 _cards_skipped(0), |
351 if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) { |
351 if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) { |
352 // We make the card as "claimed" lazily (so races are possible |
352 // We make the card as "claimed" lazily (so races are possible |
353 // but they're benign), which reduces the number of duplicate |
353 // but they're benign), which reduces the number of duplicate |
354 // scans (the rsets of the regions in the cset can intersect). |
354 // scans (the rsets of the regions in the cset can intersect). |
355 _ct_bs->set_card_claimed(index); |
355 _ct_bs->set_card_claimed(index); |
356 _push_heap_cl->set_region(r); |
356 _scan_objs_on_card_cl->set_region(r); |
357 r->oops_on_card_seq_iterate_careful<true>(mr, _push_heap_cl); |
357 r->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl); |
358 _cards_scanned++; |
358 _cards_scanned++; |
359 } |
359 } |
360 } |
360 } |
361 |
361 |
362 void G1ScanRSClosure::scan_strong_code_roots(HeapRegion* r) { |
362 void G1ScanRSClosure::scan_strong_code_roots(HeapRegion* r) { |
411 scan_strong_code_roots(r); |
411 scan_strong_code_roots(r); |
412 } |
412 } |
413 return false; |
413 return false; |
414 } |
414 } |
415 |
415 |
416 void G1RemSet::scan_rem_set(G1ParPushHeapRSClosure* oops_in_heap_closure, |
416 void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, |
417 CodeBlobClosure* heap_region_codeblobs, |
417 CodeBlobClosure* heap_region_codeblobs, |
418 uint worker_i) { |
418 uint worker_i) { |
419 double rs_time_start = os::elapsedTime(); |
419 double rs_time_start = os::elapsedTime(); |
420 |
420 |
421 G1ScanRSClosure cl(_scan_state, oops_in_heap_closure, heap_region_codeblobs, worker_i); |
421 G1ScanObjsDuringScanRSClosure scan_cl(_g1, pss); |
|
422 G1ScanRSClosure cl(_scan_state, &scan_cl, heap_region_codeblobs, worker_i); |
422 _g1->collection_set_iterate_from(&cl, worker_i); |
423 _g1->collection_set_iterate_from(&cl, worker_i); |
423 |
424 |
424 double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) - |
425 double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) - |
425 cl.strong_code_root_scan_time_sec(); |
426 cl.strong_code_root_scan_time_sec(); |
426 |
427 |
439 // evacuation pause. |
440 // evacuation pause. |
440 |
441 |
441 class RefineRecordRefsIntoCSCardTableEntryClosure: public CardTableEntryClosure { |
442 class RefineRecordRefsIntoCSCardTableEntryClosure: public CardTableEntryClosure { |
442 G1RemSet* _g1rs; |
443 G1RemSet* _g1rs; |
443 DirtyCardQueue* _into_cset_dcq; |
444 DirtyCardQueue* _into_cset_dcq; |
444 G1ParPushHeapRSClosure* _cl; |
445 G1ScanObjsDuringUpdateRSClosure* _update_rs_cl; |
445 public: |
446 public: |
446 RefineRecordRefsIntoCSCardTableEntryClosure(G1CollectedHeap* g1h, |
447 RefineRecordRefsIntoCSCardTableEntryClosure(G1CollectedHeap* g1h, |
447 DirtyCardQueue* into_cset_dcq, |
448 DirtyCardQueue* into_cset_dcq, |
448 G1ParPushHeapRSClosure* cl) : |
449 G1ScanObjsDuringUpdateRSClosure* update_rs_cl) : |
449 _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq), _cl(cl) |
450 _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq), _update_rs_cl(update_rs_cl) |
450 {} |
451 {} |
451 |
452 |
452 bool do_card_ptr(jbyte* card_ptr, uint worker_i) { |
453 bool do_card_ptr(jbyte* card_ptr, uint worker_i) { |
453 // The only time we care about recording cards that |
454 // The only time we care about recording cards that |
454 // contain references that point into the collection set |
455 // contain references that point into the collection set |
455 // is during RSet updating within an evacuation pause. |
456 // is during RSet updating within an evacuation pause. |
456 // In this case worker_i should be the id of a GC worker thread. |
457 // In this case worker_i should be the id of a GC worker thread. |
457 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); |
458 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); |
458 assert(worker_i < ParallelGCThreads, "should be a GC worker"); |
459 |
459 |
460 if (_g1rs->refine_card_during_gc(card_ptr, _update_rs_cl)) { |
460 if (_g1rs->refine_card_during_gc(card_ptr, worker_i, _cl)) { |
|
461 // 'card_ptr' contains references that point into the collection |
461 // 'card_ptr' contains references that point into the collection |
462 // set. We need to record the card in the DCQS |
462 // set. We need to record the card in the DCQS |
463 // (_into_cset_dirty_card_queue_set) |
463 // (_into_cset_dirty_card_queue_set) |
464 // that's used for that purpose. |
464 // that's used for that purpose. |
465 // |
465 // |
469 return true; |
469 return true; |
470 } |
470 } |
471 }; |
471 }; |
472 |
472 |
473 void G1RemSet::update_rem_set(DirtyCardQueue* into_cset_dcq, |
473 void G1RemSet::update_rem_set(DirtyCardQueue* into_cset_dcq, |
474 G1ParPushHeapRSClosure* oops_in_heap_closure, |
474 G1ParScanThreadState* pss, |
475 uint worker_i) { |
475 uint worker_i) { |
476 RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq, oops_in_heap_closure); |
476 G1ScanObjsDuringUpdateRSClosure update_rs_cl(_g1, pss, worker_i); |
|
477 RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq, &update_rs_cl); |
477 |
478 |
478 G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); |
479 G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); |
479 if (G1HotCardCache::default_use_cache()) { |
480 if (G1HotCardCache::default_use_cache()) { |
480 // Apply the closure to the entries of the hot card cache. |
481 // Apply the closure to the entries of the hot card cache. |
481 G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); |
482 G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); |
487 |
488 |
488 void G1RemSet::cleanupHRRS() { |
489 void G1RemSet::cleanupHRRS() { |
489 HeapRegionRemSet::cleanup(); |
490 HeapRegionRemSet::cleanup(); |
490 } |
491 } |
491 |
492 |
492 void G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* cl, |
493 void G1RemSet::oops_into_collection_set_do(G1ParScanThreadState* pss, |
493 CodeBlobClosure* heap_region_codeblobs, |
494 CodeBlobClosure* heap_region_codeblobs, |
494 uint worker_i) { |
495 uint worker_i) { |
495 // A DirtyCardQueue that is used to hold cards containing references |
496 // A DirtyCardQueue that is used to hold cards containing references |
496 // that point into the collection set. This DCQ is associated with a |
497 // that point into the collection set. This DCQ is associated with a |
497 // special DirtyCardQueueSet (see g1CollectedHeap.hpp). Under normal |
498 // special DirtyCardQueueSet (see g1CollectedHeap.hpp). Under normal |
501 // are wholly 'free' of live objects. In the event of an evacuation |
502 // are wholly 'free' of live objects. In the event of an evacuation |
502 // failure the cards/buffers in this queue set are passed to the |
503 // failure the cards/buffers in this queue set are passed to the |
503 // DirtyCardQueueSet that is used to manage RSet updates |
504 // DirtyCardQueueSet that is used to manage RSet updates |
504 DirtyCardQueue into_cset_dcq(&_into_cset_dirty_card_queue_set); |
505 DirtyCardQueue into_cset_dcq(&_into_cset_dirty_card_queue_set); |
505 |
506 |
506 update_rem_set(&into_cset_dcq, cl, worker_i); |
507 update_rem_set(&into_cset_dcq, pss, worker_i); |
507 scan_rem_set(cl, heap_region_codeblobs, worker_i);; |
508 scan_rem_set(pss, heap_region_codeblobs, worker_i);; |
508 } |
509 } |
509 |
510 |
510 void G1RemSet::prepare_for_oops_into_collection_set_do() { |
511 void G1RemSet::prepare_for_oops_into_collection_set_do() { |
511 _g1->set_refine_cte_cl_concurrency(false); |
512 _g1->set_refine_cte_cl_concurrency(false); |
512 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); |
513 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); |
576 ct_bs->index_for(ct_bs->addr_for(card_ptr)), |
577 ct_bs->index_for(ct_bs->addr_for(card_ptr)), |
577 p2i(ct_bs->addr_for(card_ptr)), |
578 p2i(ct_bs->addr_for(card_ptr)), |
578 g1->addr_to_region(ct_bs->addr_for(card_ptr))); |
579 g1->addr_to_region(ct_bs->addr_for(card_ptr))); |
579 #endif |
580 #endif |
580 } |
581 } |
581 |
|
582 G1UpdateRSOrPushRefOopClosure::G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h, |
|
583 G1ParPushHeapRSClosure* push_ref_cl, |
|
584 bool record_refs_into_cset, |
|
585 uint worker_i) : |
|
586 _g1(g1h), |
|
587 _from(NULL), |
|
588 _record_refs_into_cset(record_refs_into_cset), |
|
589 _has_refs_into_cset(false), |
|
590 _push_ref_cl(push_ref_cl), |
|
591 _worker_i(worker_i) { } |
|
592 |
582 |
593 void G1RemSet::refine_card_concurrently(jbyte* card_ptr, |
583 void G1RemSet::refine_card_concurrently(jbyte* card_ptr, |
594 uint worker_i) { |
584 uint worker_i) { |
595 assert(!_g1->is_gc_active(), "Only call concurrently"); |
585 assert(!_g1->is_gc_active(), "Only call concurrently"); |
596 |
586 |
738 _conc_refine_cards++; |
728 _conc_refine_cards++; |
739 } |
729 } |
740 } |
730 } |
741 |
731 |
742 bool G1RemSet::refine_card_during_gc(jbyte* card_ptr, |
732 bool G1RemSet::refine_card_during_gc(jbyte* card_ptr, |
743 uint worker_i, |
733 G1ScanObjsDuringUpdateRSClosure* update_rs_cl) { |
744 G1ParPushHeapRSClosure* oops_in_heap_closure) { |
|
745 assert(_g1->is_gc_active(), "Only call during GC"); |
734 assert(_g1->is_gc_active(), "Only call during GC"); |
746 |
735 |
747 check_card_ptr(card_ptr, _ct_bs); |
736 check_card_ptr(card_ptr, _ct_bs); |
748 |
737 |
749 // If the card is no longer dirty, nothing to do. This covers cards that were already |
738 // If the card is no longer dirty, nothing to do. This covers cards that were already |
773 // a card beyond the heap. |
762 // a card beyond the heap. |
774 HeapWord* card_end = card_start + CardTableModRefBS::card_size_in_words; |
763 HeapWord* card_end = card_start + CardTableModRefBS::card_size_in_words; |
775 MemRegion dirty_region(card_start, MIN2(scan_limit, card_end)); |
764 MemRegion dirty_region(card_start, MIN2(scan_limit, card_end)); |
776 assert(!dirty_region.is_empty(), "sanity"); |
765 assert(!dirty_region.is_empty(), "sanity"); |
777 |
766 |
778 G1UpdateRSOrPushRefOopClosure update_rs_oop_cl(_g1, |
767 update_rs_cl->set_region(r); |
779 oops_in_heap_closure, |
768 update_rs_cl->reset_has_refs_into_cset(); |
780 true, |
769 |
781 worker_i); |
770 bool card_processed = r->oops_on_card_seq_iterate_careful<true>(dirty_region, update_rs_cl); |
782 update_rs_oop_cl.set_from(r); |
|
783 |
|
784 bool card_processed = |
|
785 r->oops_on_card_seq_iterate_careful<true>(dirty_region, |
|
786 &update_rs_oop_cl); |
|
787 assert(card_processed, "must be"); |
771 assert(card_processed, "must be"); |
788 _conc_refine_cards++; |
772 _conc_refine_cards++; |
789 |
773 |
790 return update_rs_oop_cl.has_refs_into_cset(); |
774 return update_rs_cl->has_refs_into_cset(); |
791 } |
775 } |
792 |
776 |
793 void G1RemSet::print_periodic_summary_info(const char* header, uint period_count) { |
777 void G1RemSet::print_periodic_summary_info(const char* header, uint period_count) { |
794 if ((G1SummarizeRSetStatsPeriod > 0) && log_is_enabled(Trace, gc, remset) && |
778 if ((G1SummarizeRSetStatsPeriod > 0) && log_is_enabled(Trace, gc, remset) && |
795 (period_count % G1SummarizeRSetStatsPeriod == 0)) { |
779 (period_count % G1SummarizeRSetStatsPeriod == 0)) { |