Projects
Mega:23.03
openjdk-1.8.0
_service:tar_scm:8160369.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:8160369.patch of Package openjdk-1.8.0
From be5a699028cd0b8fd49eb2df0c4b3d1653eca4f3 Mon Sep 17 00:00:00 2001 Date: Mon, 25 Jan 2021 17:22:52 +0800 Subject: Backport of JDK-8160369 Summary:<GC>:[Backport of JDK-8160369 and it's subtasks] Memory fences needed around setting and reading object lengths LLT: bug url: https://bugs.openjdk.java.net/browse/JDK-8160369 --- .../vm/gc_implementation/g1/g1RemSet.cpp | 101 +++++++++---- .../vm/gc_implementation/g1/heapRegion.cpp | 25 +--- .../vm/gc_implementation/g1/heapRegion.hpp | 2 + .../gc_implementation/g1/heapRegionType.hpp | 3 + 4 files changed, 82 insertions(+), 49 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 4cad9234c..b062947c8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -460,18 +460,26 @@ bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, // And find the region containing it. HeapRegion* r = _g1->heap_region_containing(start); - // 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()) { + // 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; } @@ -503,26 +511,69 @@ bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, assert(!check_for_refs_into_cset, "sanity"); assert(!SafepointSynchronize::is_at_safepoint(), "sanity"); + const jbyte* orig_card_ptr = card_ptr; card_ptr = hot_card_cache->insert(card_ptr); if (card_ptr == NULL) { // There was no eviction. Nothing to do. return false; - } - - start = _ct_bs->addr_for(card_ptr); - r = _g1->heap_region_containing(start); + } else if (card_ptr != orig_card_ptr) { + // Original card was inserted and an old card was evicted. + start = _ct_bs->addr_for(card_ptr); + r = _g1->heap_region_containing(start); + + // Check whether the region formerly in the cache should be + // ignored, as discussed earlier for the original card. The + // region could have been freed while in the cache. The cset is + // not relevant here, since we're in concurrent phase. + if (!r->is_old_or_humongous()) { + return false; + } + } // Else we still have the original card. + } - // 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. + // 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. + HeapWord* scan_limit; + if (_g1->is_gc_active()) { + // 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. + scan_limit = r->scan_top(); + } else { + // Non-humongous objects are only allocated in the old-gen during + // GC, so if region is old then top is stable. Humongous object + // allocation sets top last; if top has not yet been set, this is + // a stale card and we'll end up with an empty intersection. If + // this is not a stale card, the synchronization between the + // enqueuing of the card and processing it here will have ensured + // we see the up-to-date top here. + scan_limit = r->top(); + } + if (scan_limit <= start) { + // If the trimmed region is empty, the card must be stale. + return false; } + // Okay to clean and process the card now. There are still some + // stale card cases that may be detected by iteration and dealt with + // as iteration failure. + *const_cast<volatile jbyte*>(card_ptr) = CardTableModRefBS::clean_card_val(); + + // This fence serves two purposes. First, the card must be cleaned + // before processing the contents. Second, we can't proceed with + // processing until after the read of top, for synchronization with + // possibly concurrent humongous object allocation. It's okay that + // reading top and reading type were racy wrto each other. We need + // both set, in any order, to proceed. + OrderAccess::fence(); + // Don't use addr_for(card_ptr + 1) which can ask for - // a card beyond the heap. This is not safe without a perm - // gen at the upper end of the heap. - HeapWord* end = start + CardTableModRefBS::card_size_in_words; - MemRegion dirtyRegion(start, end); + // a card beyond the heap. + HeapWord* end = start + CardTableModRefBS::card_size_in_words; + MemRegion dirty_region(start, MIN2(scan_limit, end)); + assert(!dirty_region.is_empty(), "sanity"); #if CARD_REPEAT_HISTO init_ct_freq_table(_g1->max_capacity()); @@ -570,7 +621,7 @@ bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, // allocation in this region and making it safe to check the young type. bool card_processed = - r->oops_on_card_seq_iterate_careful(dirtyRegion, + r->oops_on_card_seq_iterate_careful(dirty_region, &filter_then_update_rs_oop_cl, card_ptr); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 794911ef6..7c48501f3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -399,9 +443,6 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr, } else if (!g1h->is_obj_dead(obj)) { cl->do_object(obj); } - if (cl->abort()) return cur; - // The check above must occur before the operation below, since an - // abort might invalidate the "size" operation. cur += block_size(cur); } return NULL; @@ -454,29 +495,9 @@ bool HeapRegion::oops_on_card_seq_iterate_careful(MemRegion mr, FilterOutOfRegionClosure* cl, jbyte* card_ptr) { assert(card_ptr != NULL, "pre-condition"); + assert(MemRegion(bottom(), end()).contains(mr), "Card region not in heap region"); G1CollectedHeap* g1h = G1CollectedHeap::heap(); - // If we're within a stop-world GC, then we might look at a card in a - // GC alloc region that extends onto a GC LAB, which may not be - // parseable. Stop such at the "scan_top" of the region. - if (g1h->is_gc_active()) { - mr = mr.intersection(MemRegion(bottom(), scan_top())); - } else { - mr = mr.intersection(used_region()); - } - if (mr.is_empty()) { - return true; - } - - // The intersection of the incoming mr (for the card) and the - // allocated part of the region is non-empty. This implies that - // we have actually allocated into this region. The code in - // G1CollectedHeap.cpp that allocates a new region sets the - // is_young tag on the region before allocating. Thus we - // safely know if this region is young. - if (is_young()) { - return true; - } // We can only clean the card here, after we make the decision that // the card is not young. diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 52ef1d0d2..8a45b3915 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -422,6 +422,8 @@ class HeapRegion: public G1OffsetTableContigSpace { bool is_old() const { return _type.is_old(); } + bool is_old_or_humongous() const { return _type.is_old_or_humongous(); } + // For a humongous region, region in which it starts. HeapRegion* humongous_start_region() const { return _humongous_start_region; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp index a9a4fbc25..007dabf19 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp @@ -111,6 +111,9 @@ public: bool is_old() const { return get() == OldTag; } + bool is_old_or_humongous() const { return (get() & (OldTag | HumMask)) != 0; } + + // Setters void set_free() { set(FreeTag); } -- 2.19.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2