--- old/src/share/vm/gc/g1/g1Allocator.cpp 2017-05-11 16:15:05.952823503 +0200 +++ new/src/share/vm/gc/g1/g1Allocator.cpp 2017-05-11 16:15:05.850820352 +0200 @@ -109,9 +109,6 @@ // want either way so no reason to check explicitly for either // condition. _retained_old_gc_alloc_region = old_gc_alloc_region(context)->release(); - if (_retained_old_gc_alloc_region != NULL) { - _retained_old_gc_alloc_region->record_retained_region(); - } } void G1DefaultAllocator::abandon_gc_alloc_regions() { --- old/src/share/vm/gc/g1/g1OopClosures.hpp 2017-05-11 16:15:06.490840123 +0200 +++ new/src/share/vm/gc/g1/g1OopClosures.hpp 2017-05-11 16:15:06.384836849 +0200 @@ -199,7 +199,7 @@ G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h, G1ParPushHeapRSClosure* push_ref_cl, bool record_refs_into_cset, - uint worker_i = 0); + uint worker_i); void set_from(HeapRegion* from) { assert(from != NULL, "from region must be non-NULL"); --- old/src/share/vm/gc/g1/g1RemSet.cpp 2017-05-11 16:15:07.035856959 +0200 +++ new/src/share/vm/gc/g1/g1RemSet.cpp 2017-05-11 16:15:06.931853747 +0200 @@ -116,6 +116,32 @@ // to avoid duplicates. Uses jbyte since there are no atomic instructions for bools. IsDirtyRegionState* _in_dirty_region_buffer; size_t _cur_dirty_region; + + // Creates a snapshot of the current _top values at the start of collection to + // filter out card marks that we do not want to scan. + class G1ResetScanTopClosure : public HeapRegionClosure { + private: + HeapWord** _scan_top; + public: + G1ResetScanTopClosure(HeapWord** scan_top) : _scan_top(scan_top) { } + + virtual bool doHeapRegion(HeapRegion* r) { + uint hrm_index = r->hrm_index(); + if (!r->in_collection_set() && r->is_old_or_humongous()) { + _scan_top[hrm_index] = r->top(); + } else { + _scan_top[hrm_index] = r->bottom(); + } + return false; + } + }; + + // For each region, contains the maximum top() value to be used during this garbage + // collection. Subsumes common checks like filtering out everything but old and + // humongous regions outside the collection set. + // This is valid because we are not interested in scanning stray remembered set + // entries from free or archive regions. + HeapWord** _scan_top; public: G1RemSetScanState() : _max_regions(0), @@ -123,8 +149,8 @@ _iter_claims(NULL), _dirty_region_buffer(NULL), _in_dirty_region_buffer(NULL), - _cur_dirty_region(0) { - + _cur_dirty_region(0), + _scan_top(NULL) { } ~G1RemSetScanState() { @@ -140,6 +166,9 @@ if (_in_dirty_region_buffer != NULL) { FREE_C_HEAP_ARRAY(IsDirtyRegionState, _in_dirty_region_buffer); } + if (_scan_top != NULL) { + FREE_C_HEAP_ARRAY(HeapWord*, _scan_top); + } } void initialize(uint max_regions) { @@ -150,12 +179,18 @@ _iter_claims = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC); _dirty_region_buffer = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC); _in_dirty_region_buffer = NEW_C_HEAP_ARRAY(IsDirtyRegionState, max_regions, mtGC); + _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_regions, mtGC); } void reset() { for (uint i = 0; i < _max_regions; i++) { _iter_states[i] = Unclaimed; } + + memset(_scan_top, 0, _max_regions * sizeof(HeapWord*)); + G1ResetScanTopClosure cl(_scan_top); + G1CollectedHeap::heap()->heap_region_iterate(&cl); + memset((void*)_iter_claims, 0, _max_regions * sizeof(size_t)); memset(_in_dirty_region_buffer, Clean, _max_regions * sizeof(IsDirtyRegionState)); _cur_dirty_region = 0; @@ -212,6 +247,10 @@ } } + HeapWord* scan_top(uint region_idx) const { + return _scan_top[region_idx]; + } + // Clear the card table of "dirty" regions. void clear_card_table(WorkGang* workers) { if (_cur_dirty_region == 0) { @@ -307,7 +346,7 @@ void G1ScanRSClosure::scan_card(size_t index, HeapWord* card_start, HeapRegion *r) { MemRegion card_region(card_start, BOTConstants::N_words); - MemRegion pre_gc_allocated(r->bottom(), r->scan_top()); + MemRegion pre_gc_allocated(r->bottom(), _scan_state->scan_top(r->hrm_index())); MemRegion mr = pre_gc_allocated.intersection(card_region); if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) { // We make the card as "claimed" lazily (so races are possible @@ -694,55 +733,9 @@ // And find the region containing it. HeapRegion* r = _g1->heap_region_containing(start); - // This check is needed for some uncommon cases where we should - // ignore the card. - // - // The region could be young. Cards for young regions are - // distinctly marked (set to g1_young_gen), so the post-barrier will - // filter them out. However, that marking is performed - // concurrently. A write to a young object could occur before the - // card has been marked young, slipping past the filter. - // - // The card could be stale, because the region has been freed since - // the card was recorded. In this case the region type could be - // anything. If (still) free or (reallocated) young, just ignore - // it. If (reallocated) old or humongous, the later card trimming - // and additional checks in iteration may detect staleness. At - // worst, we end up processing a stale card unnecessarily. - // - // In the normal (non-stale) case, the synchronization between the - // enqueueing of the card and processing it here will have ensured - // we see the up-to-date region type here. - if (!r->is_old_or_humongous()) { - return false; - } - - // 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 remembered 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; - } - - // Trim the region designated by the card to what's been allocated - // in the region. The card could be stale, or the card could cover - // (part of) an object at the end of the allocated space and extend - // beyond the end of allocation. - - // If we're in a STW GC, then a card might be in a GC alloc region - // and extend onto a GC LAB, which may not be parsable. Stop such - // at the "scan_top" of the region. - HeapWord* scan_limit = r->scan_top(); - + HeapWord* scan_limit = _scan_state->scan_top(r->hrm_index()); if (scan_limit <= start) { - // If the trimmed region is empty, the card must be stale. + // If the card starts above the area in the region containing objects to scan, skip it. return false; } --- old/src/share/vm/gc/g1/heapRegion.cpp 2017-05-11 16:15:07.599874382 +0200 +++ new/src/share/vm/gc/g1/heapRegion.cpp 2017-05-11 16:15:07.494871139 +0200 @@ -833,7 +833,6 @@ void G1ContiguousSpace::clear(bool mangle_space) { set_top(bottom()); - _scan_top = bottom(); CompactibleSpace::clear(mangle_space); reset_bot(); } @@ -865,42 +864,15 @@ return _bot_part.threshold(); } -HeapWord* G1ContiguousSpace::scan_top() const { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - HeapWord* local_top = top(); - OrderAccess::loadload(); - const unsigned local_time_stamp = _gc_time_stamp; - assert(local_time_stamp <= g1h->get_gc_time_stamp(), "invariant"); - if (local_time_stamp < g1h->get_gc_time_stamp()) { - return local_top; - } else { - return _scan_top; - } -} - void G1ContiguousSpace::record_timestamp() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); uint curr_gc_time_stamp = g1h->get_gc_time_stamp(); if (_gc_time_stamp < curr_gc_time_stamp) { - // Setting the time stamp here tells concurrent readers to look at - // scan_top to know the maximum allowed address to look at. - - // scan_top should be bottom for all regions except for the - // retained old alloc region which should have scan_top == top - HeapWord* st = _scan_top; - guarantee(st == _bottom || st == _top, "invariant"); - _gc_time_stamp = curr_gc_time_stamp; } } -void G1ContiguousSpace::record_retained_region() { - // scan_top is the maximum address where it's safe for the next gc to - // scan this region. - _scan_top = top(); -} - void G1ContiguousSpace::safe_object_iterate(ObjectClosure* blk) { object_iterate(blk); } @@ -925,7 +897,6 @@ void G1ContiguousSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space) { CompactibleSpace::initialize(mr, clear_space, mangle_space); _top = bottom(); - _scan_top = bottom(); set_saved_mark_word(NULL); reset_bot(); } --- old/src/share/vm/gc/g1/heapRegion.hpp 2017-05-11 16:15:08.158891651 +0200 +++ new/src/share/vm/gc/g1/heapRegion.hpp 2017-05-11 16:15:08.055888469 +0200 @@ -96,7 +96,6 @@ class G1ContiguousSpace: public CompactibleSpace { friend class VMStructs; HeapWord* volatile _top; - HeapWord* volatile _scan_top; protected: G1BlockOffsetTablePart _bot_part; Mutex _par_alloc_lock; @@ -147,11 +146,9 @@ void mangle_unused_area() PRODUCT_RETURN; void mangle_unused_area_complete() PRODUCT_RETURN; - HeapWord* scan_top() const; void record_timestamp(); void reset_gc_time_stamp() { _gc_time_stamp = 0; } uint get_gc_time_stamp() { return _gc_time_stamp; } - void record_retained_region(); // See the comment above in the declaration of _pre_dummy_top for an // explanation of what it is.