提交 a2980567 编写于 作者: J johnc

6956639: G1: assert(cached_ptr != card_ptr) failed: shouldn't be, concurrentG1Refine.cpp:307

Summary: During concurrent refinment, filter cards in young regions after it has been determined that the region has been allocated from and the young type of the region has been set.
Reviewed-by: iveresov, tonyp, jcoomes
上级 c100f7e1
/* /*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -271,21 +271,16 @@ jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* def ...@@ -271,21 +271,16 @@ jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* def
if (cas_res == prev_epoch_entry) { if (cas_res == prev_epoch_entry) {
// We successfully updated the card num value in the epoch entry // We successfully updated the card num value in the epoch entry
count_ptr->_count = 0; // initialize counter for new card num count_ptr->_count = 0; // initialize counter for new card num
jbyte* old_card_ptr = card_num_2_ptr(old_card_num);
// Even though the region containg the card at old_card_num was not // Even though the region containg the card at old_card_num was not
// in the young list when old_card_num was recorded in the epoch // in the young list when old_card_num was recorded in the epoch
// cache it could have been added to the free list and subsequently // cache it could have been added to the free list and subsequently
// added to the young list in the intervening time. If the evicted // added to the young list in the intervening time. See CR 6817995.
// card is in a young region just return the card_ptr and the evicted // We do not deal with this case here - it will be handled in
// card will not be cleaned. See CR 6817995. // HeapRegion::oops_on_card_seq_iterate_careful after it has been
// determined that the region containing the card has been allocated
jbyte* old_card_ptr = card_num_2_ptr(old_card_num); // to, and it's safe to check the young type of the region.
if (is_young_card(old_card_ptr)) {
*count = 0;
// We can defer the processing of card_ptr
*defer = true;
return card_ptr;
}
// We do not want to defer processing of card_ptr in this case // We do not want to defer processing of card_ptr in this case
// (we need to refine old_card_ptr and card_ptr) // (we need to refine old_card_ptr and card_ptr)
...@@ -301,22 +296,22 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { ...@@ -301,22 +296,22 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
jbyte* cached_ptr = add_card_count(card_ptr, &count, defer); jbyte* cached_ptr = add_card_count(card_ptr, &count, defer);
assert(cached_ptr != NULL, "bad cached card ptr"); assert(cached_ptr != NULL, "bad cached card ptr");
if (is_young_card(cached_ptr)) { // We've just inserted a card pointer into the card count cache
// The region containing cached_ptr has been freed during a clean up // and got back the card that we just inserted or (evicted) the
// pause, reallocated, and tagged as young. // previous contents of that count slot.
assert(cached_ptr != card_ptr, "shouldn't be");
// The card we got back could be in a young region. When the
// We've just inserted a new old-gen card pointer into the card count // returned card (if evicted) was originally inserted, we had
// cache and evicted the previous contents of that count slot. // determined that its containing region was not young. However
// The evicted card pointer has been determined to be in a young region // it is possible for the region to be freed during a cleanup
// and so cannot be the newly inserted card pointer (that will be // pause, then reallocated and tagged as young which will result
// in an old region). // in the returned card residing in a young region.
// The count for newly inserted card will be set to zero during the //
// insertion, so we don't want to defer the cleaning of the newly // We do not deal with this case here - the change from non-young
// inserted card pointer. // to young could be observed at any time - it will be handled in
assert(*defer == false, "deferring non-hot card"); // HeapRegion::oops_on_card_seq_iterate_careful after it has been
return NULL; // determined that the region containing the card has been allocated
} // to.
// The card pointer we obtained from card count cache is not hot // The card pointer we obtained from card count cache is not hot
// so do not store it in the cache; return it for immediate // so do not store it in the cache; return it for immediate
...@@ -325,7 +320,7 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { ...@@ -325,7 +320,7 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
return cached_ptr; return cached_ptr;
} }
// Otherwise, the pointer we got from the _card_counts is hot. // Otherwise, the pointer we got from the _card_counts cache is hot.
jbyte* res = NULL; jbyte* res = NULL;
MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag); MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag);
if (_n_hot == _hot_cache_size) { if (_n_hot == _hot_cache_size) {
...@@ -338,17 +333,8 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { ...@@ -338,17 +333,8 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0; if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0;
_n_hot++; _n_hot++;
if (res != NULL) { // The card obtained from the hot card cache could be in a young
// Even though the region containg res was not in the young list // region. See above on how this can happen.
// when it was recorded in the hot cache it could have been added
// to the free list and subsequently added to the young list in
// the intervening time. If res is in a young region, return NULL
// so that res is not cleaned. See CR 6817995.
if (is_young_card(res)) {
res = NULL;
}
}
return res; return res;
} }
......
...@@ -638,6 +638,11 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size, ...@@ -638,6 +638,11 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size,
// Now retry the allocation. // Now retry the allocation.
if (_cur_alloc_region != NULL) { if (_cur_alloc_region != NULL) {
if (allocated_young_region != NULL) {
// We need to ensure that the store to top does not
// float above the setting of the young type.
OrderAccess::storestore();
}
res = _cur_alloc_region->allocate(word_size); res = _cur_alloc_region->allocate(word_size);
} }
} }
......
/* /*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -676,9 +676,27 @@ void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i ...@@ -676,9 +676,27 @@ void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i
// We must complete this write before we do any of the reads below. // We must complete this write before we do any of the reads below.
OrderAccess::storeload(); OrderAccess::storeload();
// And process it, being careful of unallocated portions of TLAB's. // And process it, being careful of unallocated portions of TLAB's.
// The region for the current card may be a young region. The
// current card may have been a card that was evicted from the
// card cache. When the card was inserted into the cache, we had
// determined that its region was non-young. While in the cache,
// the region may have been freed during a cleanup pause, reallocated
// and tagged as young.
//
// We wish to filter out cards for such a region but the current
// thread, if we're running conucrrently, may "see" the young type
// change at any time (so an earlier "is_young" check may pass or
// fail arbitrarily). We tell the iteration code to perform this
// filtering when it has been determined that there has been an actual
// allocation in this region and making it safe to check the young type.
bool filter_young = true;
HeapWord* stop_point = HeapWord* stop_point =
r->oops_on_card_seq_iterate_careful(dirtyRegion, r->oops_on_card_seq_iterate_careful(dirtyRegion,
&filter_then_update_rs_oop_cl); &filter_then_update_rs_oop_cl,
filter_young);
// If stop_point is non-null, then we encountered an unallocated region // 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 // (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 // card and re-enqueue: if we put off the card until a GC pause, then the
...@@ -789,8 +807,14 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { ...@@ -789,8 +807,14 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {
if (r == NULL) { if (r == NULL) {
assert(_g1->is_in_permanent(start), "Or else where?"); assert(_g1->is_in_permanent(start), "Or else where?");
} else { } else {
guarantee(!r->is_young(), "It was evicted in the current minor cycle."); // Checking whether the region we got back from the cache
// Process card pointer we get back from the hot card 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.
//
// Process card pointer we get back from the hot card cache. This
// will check whether the region containing the card is young
// _after_ checking that the region has been allocated from.
concurrentRefineOneCard_impl(res, worker_i); concurrentRefineOneCard_impl(res, worker_i);
} }
} }
......
...@@ -658,7 +658,8 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr, ...@@ -658,7 +658,8 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr,
HeapWord* HeapWord*
HeapRegion:: HeapRegion::
oops_on_card_seq_iterate_careful(MemRegion mr, oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl) { FilterOutOfRegionClosure* cl,
bool filter_young) {
G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectedHeap* g1h = G1CollectedHeap::heap();
// If we're within a stop-world GC, then we might look at a card in a // If we're within a stop-world GC, then we might look at a card in a
...@@ -672,6 +673,16 @@ oops_on_card_seq_iterate_careful(MemRegion mr, ...@@ -672,6 +673,16 @@ oops_on_card_seq_iterate_careful(MemRegion mr,
if (mr.is_empty()) return NULL; if (mr.is_empty()) return NULL;
// Otherwise, find the obj that extends onto mr.start(). // Otherwise, find the obj that extends onto mr.start().
// 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() && filter_young) {
return NULL;
}
// We used to use "block_start_careful" here. But we're actually happy // We used to use "block_start_careful" here. But we're actually happy
// to update the BOT while we do this... // to update the BOT while we do this...
HeapWord* cur = block_start(mr.start()); HeapWord* cur = block_start(mr.start());
......
...@@ -252,7 +252,7 @@ class HeapRegion: public G1OffsetTableContigSpace { ...@@ -252,7 +252,7 @@ class HeapRegion: public G1OffsetTableContigSpace {
// survivor // survivor
}; };
YoungType _young_type; volatile YoungType _young_type;
int _young_index_in_cset; int _young_index_in_cset;
SurvRateGroup* _surv_rate_group; SurvRateGroup* _surv_rate_group;
int _age_index; int _age_index;
...@@ -726,9 +726,12 @@ class HeapRegion: public G1OffsetTableContigSpace { ...@@ -726,9 +726,12 @@ class HeapRegion: public G1OffsetTableContigSpace {
HeapWord* HeapWord*
object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl); object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl);
// In this version - if filter_young is true and the region
// is a young region then we skip the iteration.
HeapWord* HeapWord*
oops_on_card_seq_iterate_careful(MemRegion mr, oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl); FilterOutOfRegionClosure* cl,
bool filter_young);
// The region "mr" is entirely in "this", and starts and ends at block // The region "mr" is entirely in "this", and starts and ends at block
// boundaries. The caller declares that all the contained blocks are // boundaries. The caller declares that all the contained blocks are
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册