diff -r b1f070f4a4ae -r ab96027e99ed src/hotspot/share/gc/g1/g1RemSet.cpp --- a/src/hotspot/share/gc/g1/g1RemSet.cpp Wed May 22 10:48:46 2019 +0200 +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Wed May 22 11:19:14 2019 +0200 @@ -308,158 +308,198 @@ _scan_state->initialize(max_regions); } -G1ScanRSForRegionClosure::G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, - G1ScanCardClosure* scan_obj_on_card, - G1ParScanThreadState* pss, - G1GCPhaseTimes::GCParPhases phase, - uint worker_i) : - _g1h(G1CollectedHeap::heap()), - _ct(_g1h->card_table()), - _pss(pss), - _scan_objs_on_card_cl(scan_obj_on_card), - _scan_state(scan_state), - _phase(phase), - _worker_i(worker_i), - _opt_refs_scanned(0), - _opt_refs_memory_used(0), - _cards_scanned(0), - _cards_claimed(0), - _cards_skipped(0), - _rem_set_root_scan_time(), - _rem_set_trim_partially_time(), - _strong_code_root_scan_time(), - _strong_code_trim_partially_time() { -} +class G1ScanRSForRegionClosure : public HeapRegionClosure { + G1CollectedHeap* _g1h; + G1CardTable *_ct; -void G1ScanRSForRegionClosure::claim_card(size_t card_index, const uint region_idx_for_card){ - _ct->set_card_claimed(card_index); - _scan_state->add_dirty_region(region_idx_for_card); -} + G1ParScanThreadState* _pss; + G1ScanCardClosure* _scan_objs_on_card_cl; + + G1RemSetScanState* _scan_state; + + G1GCPhaseTimes::GCParPhases _phase; + + uint _worker_i; -void G1ScanRSForRegionClosure::scan_card(MemRegion mr, uint region_idx_for_card) { - HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); - assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card); - card_region->oops_on_card_seq_iterate_careful(mr, _scan_objs_on_card_cl); - _scan_objs_on_card_cl->trim_queue_partially(); - _cards_scanned++; -} + size_t _opt_refs_scanned; + size_t _opt_refs_memory_used; -void G1ScanRSForRegionClosure::scan_opt_rem_set_roots(HeapRegion* r) { - EventGCPhaseParallel event; - - G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); + size_t _cards_scanned; + size_t _cards_claimed; + size_t _cards_skipped; - G1ScanCardClosure scan_cl(_g1h, _pss); - G1ScanRSForOptionalClosure cl(_g1h, &scan_cl); - _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops()); - _opt_refs_memory_used += opt_rem_set_list->used_memory(); - - event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); -} + Tickspan _rem_set_root_scan_time; + Tickspan _rem_set_trim_partially_time; -void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) { - EventGCPhaseParallel event; - uint const region_idx = r->hrm_index(); + Tickspan _strong_code_root_scan_time; + Tickspan _strong_code_trim_partially_time; - if (_scan_state->claim_iter(region_idx)) { - // If we ever free the collection set concurrently, we should also - // clear the card table concurrently therefore we won't need to - // add regions of the collection set to the dirty cards region. - _scan_state->add_dirty_region(region_idx); + void claim_card(size_t card_index, const uint region_idx_for_card) { + _ct->set_card_claimed(card_index); + _scan_state->add_dirty_region(region_idx_for_card); } - if (r->rem_set()->cardset_is_empty()) { - return; + void scan_card(MemRegion mr, uint region_idx_for_card) { + HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); + assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card); + card_region->oops_on_card_seq_iterate_careful(mr, _scan_objs_on_card_cl); + _scan_objs_on_card_cl->trim_queue_partially(); + _cards_scanned++; + } + + void scan_opt_rem_set_roots(HeapRegion* r) { + EventGCPhaseParallel event; + + G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); + + G1ScanCardClosure scan_cl(_g1h, _pss); + G1ScanRSForOptionalClosure cl(_g1h, &scan_cl); + _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops()); + _opt_refs_memory_used += opt_rem_set_list->used_memory(); + + event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); } - // We claim cards in blocks so as to reduce the contention. - size_t const block_size = G1RSetScanBlockSize; - - HeapRegionRemSetIterator iter(r->rem_set()); - size_t card_index; + void scan_rem_set_roots(HeapRegion* r) { + EventGCPhaseParallel event; + uint const region_idx = r->hrm_index(); - size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); - for (size_t current_card = 0; iter.has_next(card_index); current_card++) { - if (current_card >= claimed_card_block + block_size) { - claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); - } - if (current_card < claimed_card_block) { - _cards_skipped++; - continue; - } - _cards_claimed++; - - HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index); - uint const region_idx_for_card = _g1h->addr_to_region(card_start); - -#ifdef ASSERT - HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); - assert(hr == NULL || hr->is_in_reserved(card_start), - "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); -#endif - HeapWord* const top = _scan_state->scan_top(region_idx_for_card); - if (card_start >= top) { - continue; + if (_scan_state->claim_iter(region_idx)) { + // If we ever free the collection set concurrently, we should also + // clear the card table concurrently therefore we won't need to + // add regions of the collection set to the dirty cards region. + _scan_state->add_dirty_region(region_idx); } - // If the card is dirty, then G1 will scan it during Update RS. - if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { - continue; + if (r->rem_set()->cardset_is_empty()) { + return; } - // We claim lazily (so races are possible but they're benign), which reduces the - // number of duplicate scans (the rsets of the regions in the cset can intersect). - // Claim the card after checking bounds above: the remembered set may contain - // random cards into current survivor, and we would then have an incorrectly - // claimed card in survivor space. Card table clear does not reset the card table - // of survivor space regions. - claim_card(card_index, region_idx_for_card); + // We claim cards in blocks so as to reduce the contention. + size_t const block_size = G1RSetScanBlockSize; + + HeapRegionRemSetIterator iter(r->rem_set()); + size_t card_index; - MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top)); + size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); + for (size_t current_card = 0; iter.has_next(card_index); current_card++) { + if (current_card >= claimed_card_block + block_size) { + claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); + } + if (current_card < claimed_card_block) { + _cards_skipped++; + continue; + } + _cards_claimed++; - scan_card(mr, region_idx_for_card); - } - event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); -} + HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index); + uint const region_idx_for_card = _g1h->addr_to_region(card_start); -void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) { - EventGCPhaseParallel event; - // We pass a weak code blobs closure to the remembered set scanning because we want to avoid - // treating the nmethods visited to act as roots for concurrent marking. - // We only want to make sure that the oops in the nmethods are adjusted with regard to the - // objects copied by the current evacuation. - r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); - event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots)); -} +#ifdef ASSERT + HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); + assert(hr == NULL || hr->is_in_reserved(card_start), + "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); +#endif + HeapWord* const top = _scan_state->scan_top(region_idx_for_card); + if (card_start >= top) { + continue; + } -bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) { - assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index()); - uint const region_idx = r->hrm_index(); + // If the card is dirty, then G1 will scan it during Update RS. + if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { + continue; + } - // The individual references for the optional remembered set are per-worker, so we - // always need to scan them. - if (r->has_index_in_opt_cset()) { - G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); - scan_opt_rem_set_roots(r); + // We claim lazily (so races are possible but they're benign), which reduces the + // number of duplicate scans (the rsets of the regions in the cset can intersect). + // Claim the card after checking bounds above: the remembered set may contain + // random cards into current survivor, and we would then have an incorrectly + // claimed card in survivor space. Card table clear does not reset the card table + // of survivor space regions. + claim_card(card_index, region_idx_for_card); + + MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top)); + + scan_card(mr, region_idx_for_card); + } + event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); } - // Do an early out if we know we are complete. - if (_scan_state->iter_is_complete(region_idx)) { + void scan_strong_code_roots(HeapRegion* r) { + EventGCPhaseParallel event; + // We pass a weak code blobs closure to the remembered set scanning because we want to avoid + // treating the nmethods visited to act as roots for concurrent marking. + // We only want to make sure that the oops in the nmethods are adjusted with regard to the + // objects copied by the current evacuation. + r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); + event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots)); + } + +public: + G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, + G1ScanCardClosure* scan_obj_on_card, + G1ParScanThreadState* pss, + G1GCPhaseTimes::GCParPhases phase, + uint worker_i) : + _g1h(G1CollectedHeap::heap()), + _ct(_g1h->card_table()), + _pss(pss), + _scan_objs_on_card_cl(scan_obj_on_card), + _scan_state(scan_state), + _phase(phase), + _worker_i(worker_i), + _opt_refs_scanned(0), + _opt_refs_memory_used(0), + _cards_scanned(0), + _cards_claimed(0), + _cards_skipped(0), + _rem_set_root_scan_time(), + _rem_set_trim_partially_time(), + _strong_code_root_scan_time(), + _strong_code_trim_partially_time() { } + + bool do_heap_region(HeapRegion* r) { + assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index()); + uint const region_idx = r->hrm_index(); + + // The individual references for the optional remembered set are per-worker, so we + // always need to scan them. + if (r->has_index_in_opt_cset()) { + G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); + scan_opt_rem_set_roots(r); + } + + // Do an early out if we know we are complete. + if (_scan_state->iter_is_complete(region_idx)) { + return false; + } + + { + G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); + scan_rem_set_roots(r); + } + + if (_scan_state->set_iter_complete(region_idx)) { + G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); + // Scan the strong code root list attached to the current region + scan_strong_code_roots(r); + } return false; } - { - G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); - scan_rem_set_roots(r); - } + Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; } + Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; } + + Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; } + Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; } - if (_scan_state->set_iter_complete(region_idx)) { - G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); - // Scan the strong code root list attached to the current region - scan_strong_code_roots(r); - } - return false; -} + size_t cards_scanned() const { return _cards_scanned; } + size_t cards_claimed() const { return _cards_claimed; } + size_t cards_skipped() const { return _cards_skipped; } + + size_t opt_refs_scanned() const { return _opt_refs_scanned; } + size_t opt_refs_memory_used() const { return _opt_refs_memory_used; } +}; void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i,