8200545: Improve filter for enqueued deferred cards

Reviewed-by: kbarrett, sangheki
This commit is contained in:
Thomas Schatzl 2019-05-14 15:36:26 +02:00
parent 2a48a29c33
commit 3d149df158
24 changed files with 422 additions and 401 deletions

View File

@ -27,7 +27,7 @@
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/g1EvacStats.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
class G1CollectedHeap;
@ -249,14 +249,14 @@ public:
class G1GCAllocRegion : public G1AllocRegion {
protected:
G1EvacStats* _stats;
InCSetState::in_cset_state_t _purpose;
G1HeapRegionAttr::region_type_t _purpose;
virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes);
virtual size_t retire(bool fill_up);
G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, InCSetState::in_cset_state_t purpose)
G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, G1HeapRegionAttr::region_type_t purpose)
: G1AllocRegion(name, bot_updates), _stats(stats), _purpose(purpose) {
assert(stats != NULL, "Must pass non-NULL PLAB statistics");
}
@ -265,13 +265,13 @@ protected:
class SurvivorGCAllocRegion : public G1GCAllocRegion {
public:
SurvivorGCAllocRegion(G1EvacStats* stats)
: G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, InCSetState::Young) { }
: G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, G1HeapRegionAttr::Young) { }
};
class OldGCAllocRegion : public G1GCAllocRegion {
public:
OldGCAllocRegion(G1EvacStats* stats)
: G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, InCSetState::Old) { }
: G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, G1HeapRegionAttr::Old) { }
// This specialization of release() makes sure that the last card that has
// been allocated into has been completely filled by a dummy object. This

View File

@ -39,8 +39,8 @@ G1Allocator::G1Allocator(G1CollectedHeap* heap) :
_survivor_is_full(false),
_old_is_full(false),
_mutator_alloc_region(),
_survivor_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Young)),
_old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)),
_survivor_gc_alloc_region(heap->alloc_buffer_stats(G1HeapRegionAttr::Young)),
_old_gc_alloc_region(heap->alloc_buffer_stats(G1HeapRegionAttr::Old)),
_retained_old_gc_alloc_region(NULL) {
}
@ -161,7 +161,7 @@ size_t G1Allocator::used_in_alloc_regions() {
}
HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
HeapWord* G1Allocator::par_allocate_during_gc(G1HeapRegionAttr dest,
size_t word_size) {
size_t temp = 0;
HeapWord* result = par_allocate_during_gc(dest, word_size, word_size, &temp);
@ -171,14 +171,14 @@ HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
return result;
}
HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
HeapWord* G1Allocator::par_allocate_during_gc(G1HeapRegionAttr dest,
size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size) {
switch (dest.value()) {
case InCSetState::Young:
switch (dest.type()) {
case G1HeapRegionAttr::Young:
return survivor_attempt_allocation(min_word_size, desired_word_size, actual_word_size);
case InCSetState::Old:
case G1HeapRegionAttr::Old:
return old_attempt_allocation(min_word_size, desired_word_size, actual_word_size);
default:
ShouldNotReachHere();
@ -246,22 +246,22 @@ uint G1PLABAllocator::calc_survivor_alignment_bytes() {
G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
_g1h(G1CollectedHeap::heap()),
_allocator(allocator),
_surviving_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Young)),
_tenured_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Old)),
_surviving_alloc_buffer(_g1h->desired_plab_sz(G1HeapRegionAttr::Young)),
_tenured_alloc_buffer(_g1h->desired_plab_sz(G1HeapRegionAttr::Old)),
_survivor_alignment_bytes(calc_survivor_alignment_bytes()) {
for (uint state = 0; state < InCSetState::Num; state++) {
for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
_direct_allocated[state] = 0;
_alloc_buffers[state] = NULL;
}
_alloc_buffers[InCSetState::Young] = &_surviving_alloc_buffer;
_alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer;
_alloc_buffers[G1HeapRegionAttr::Young] = &_surviving_alloc_buffer;
_alloc_buffers[G1HeapRegionAttr::Old] = &_tenured_alloc_buffer;
}
bool G1PLABAllocator::may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const {
return (allocation_word_sz * 100 < buffer_size * ParallelGCBufferWastePct);
}
HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(InCSetState dest,
HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
size_t word_sz,
bool* plab_refill_failed) {
size_t plab_word_size = _g1h->desired_plab_sz(dest);
@ -300,17 +300,17 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(InCSetState dest,
// Try direct allocation.
HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz);
if (result != NULL) {
_direct_allocated[dest.value()] += word_sz;
_direct_allocated[dest.type()] += word_sz;
}
return result;
}
void G1PLABAllocator::undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz) {
void G1PLABAllocator::undo_allocation(G1HeapRegionAttr dest, HeapWord* obj, size_t word_sz) {
alloc_buffer(dest)->undo_allocation(obj, word_sz);
}
void G1PLABAllocator::flush_and_retire_stats() {
for (uint state = 0; state < InCSetState::Num; state++) {
for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
PLAB* const buf = _alloc_buffers[state];
if (buf != NULL) {
G1EvacStats* stats = _g1h->alloc_buffer_stats(state);
@ -323,7 +323,7 @@ void G1PLABAllocator::flush_and_retire_stats() {
size_t G1PLABAllocator::waste() const {
size_t result = 0;
for (uint state = 0; state < InCSetState::Num; state++) {
for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
PLAB * const buf = _alloc_buffers[state];
if (buf != NULL) {
result += buf->waste();
@ -334,7 +334,7 @@ size_t G1PLABAllocator::waste() const {
size_t G1PLABAllocator::undo_waste() const {
size_t result = 0;
for (uint state = 0; state < InCSetState::Num; state++) {
for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
PLAB * const buf = _alloc_buffers[state];
if (buf != NULL) {
result += buf->undo_waste();

View File

@ -26,7 +26,7 @@
#define SHARE_GC_G1_G1ALLOCATOR_HPP
#include "gc/g1/g1AllocRegion.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/plab.hpp"
@ -112,10 +112,10 @@ public:
// allocation region, either by picking one or expanding the
// heap, and then allocate a block of the given size. The block
// may not be a humongous - it must fit into a single heap region.
HeapWord* par_allocate_during_gc(InCSetState dest,
HeapWord* par_allocate_during_gc(G1HeapRegionAttr dest,
size_t word_size);
HeapWord* par_allocate_during_gc(InCSetState dest,
HeapWord* par_allocate_during_gc(G1HeapRegionAttr dest,
size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size);
@ -132,7 +132,7 @@ private:
PLAB _surviving_alloc_buffer;
PLAB _tenured_alloc_buffer;
PLAB* _alloc_buffers[InCSetState::Num];
PLAB* _alloc_buffers[G1HeapRegionAttr::Num];
// The survivor alignment in effect in bytes.
// == 0 : don't align survivors
@ -142,10 +142,10 @@ private:
const uint _survivor_alignment_bytes;
// Number of words allocated directly (not counting PLAB allocation).
size_t _direct_allocated[InCSetState::Num];
size_t _direct_allocated[G1HeapRegionAttr::Num];
void flush_and_retire_stats();
inline PLAB* alloc_buffer(InCSetState dest);
inline PLAB* alloc_buffer(G1HeapRegionAttr dest);
// Calculate the survivor space object alignment in bytes. Returns that or 0 if
// there are no restrictions on survivor alignment.
@ -162,20 +162,20 @@ public:
// allocating a new PLAB. Returns the address of the allocated memory, NULL if
// not successful. Plab_refill_failed indicates whether an attempt to refill the
// PLAB failed or not.
HeapWord* allocate_direct_or_new_plab(InCSetState dest,
HeapWord* allocate_direct_or_new_plab(G1HeapRegionAttr dest,
size_t word_sz,
bool* plab_refill_failed);
// Allocate word_sz words in the PLAB of dest. Returns the address of the
// allocated memory, NULL if not successful.
inline HeapWord* plab_allocate(InCSetState dest,
inline HeapWord* plab_allocate(G1HeapRegionAttr dest,
size_t word_sz);
inline HeapWord* allocate(InCSetState dest,
inline HeapWord* allocate(G1HeapRegionAttr dest,
size_t word_sz,
bool* refill_failed);
void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz);
void undo_allocation(G1HeapRegionAttr dest, HeapWord* obj, size_t word_sz);
};
// G1ArchiveRegionMap is a boolean array used to mark G1 regions as

View File

@ -63,15 +63,15 @@ inline HeapWord* G1Allocator::attempt_allocation_force(size_t word_size) {
return mutator_alloc_region()->attempt_allocation_force(word_size);
}
inline PLAB* G1PLABAllocator::alloc_buffer(InCSetState dest) {
inline PLAB* G1PLABAllocator::alloc_buffer(G1HeapRegionAttr dest) {
assert(dest.is_valid(),
"Allocation buffer index out of bounds: " CSETSTATE_FORMAT, dest.value());
assert(_alloc_buffers[dest.value()] != NULL,
"Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value());
return _alloc_buffers[dest.value()];
"Allocation buffer index out of bounds: %s", dest.get_type_str());
assert(_alloc_buffers[dest.type()] != NULL,
"Allocation buffer is NULL: %s", dest.get_type_str());
return _alloc_buffers[dest.type()];
}
inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
inline HeapWord* G1PLABAllocator::plab_allocate(G1HeapRegionAttr dest,
size_t word_sz) {
PLAB* buffer = alloc_buffer(dest);
if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
@ -81,7 +81,7 @@ inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
}
}
inline HeapWord* G1PLABAllocator::allocate(InCSetState dest,
inline HeapWord* G1PLABAllocator::allocate(G1HeapRegionAttr dest,
size_t word_sz,
bool* refill_failed) {
HeapWord* const obj = plab_allocate(dest, word_sz);

View File

@ -128,6 +128,11 @@ public:
return biased_base()[biased_index];
}
T* get_ref_by_index(uintptr_t index) const {
verify_index(index);
return &this->base()[index];
}
// Return the index of the element of the given array that covers the given
// word in the heap.
idx_t get_index_by_address(HeapWord* value) const {

View File

@ -1536,7 +1536,7 @@ G1CollectedHeap::G1CollectedHeap() :
_ref_processor_cm(NULL),
_is_alive_closure_cm(this),
_is_subject_to_discovery_cm(this),
_in_cset_fast_test() {
_region_attr() {
_verifier = new G1HeapVerifier(this);
@ -1772,7 +1772,7 @@ jint G1CollectedHeap::initialize() {
HeapWord* end = _hrm->reserved().end();
size_t granularity = HeapRegion::GrainBytes;
_in_cset_fast_test.initialize(start, end, granularity);
_region_attr.initialize(start, end, granularity);
_humongous_reclaim_candidates.initialize(start, end, granularity);
}
@ -2626,7 +2626,7 @@ bool G1CollectedHeap::is_potential_eager_reclaim_candidate(HeapRegion* r) const
G1EagerReclaimHumongousObjects && rem_set->is_empty();
}
class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
class RegisterRegionsWithRegionAttrTableClosure : public HeapRegionClosure {
private:
size_t _total_humongous;
size_t _candidate_humongous;
@ -2690,24 +2690,26 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
}
public:
RegisterHumongousWithInCSetFastTestClosure()
RegisterRegionsWithRegionAttrTableClosure()
: _total_humongous(0),
_candidate_humongous(0),
_dcq(&G1BarrierSet::dirty_card_queue_set()) {
}
virtual bool do_heap_region(HeapRegion* r) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
if (!r->is_starts_humongous()) {
g1h->register_region_with_region_attr(r);
return false;
}
G1CollectedHeap* g1h = G1CollectedHeap::heap();
bool is_candidate = humongous_region_is_candidate(g1h, r);
uint rindex = r->hrm_index();
g1h->set_humongous_reclaim_candidate(rindex, is_candidate);
if (is_candidate) {
_candidate_humongous++;
g1h->register_humongous_region_with_cset(rindex);
g1h->register_humongous_region_with_region_attr(rindex);
// Is_candidate already filters out humongous object with large remembered sets.
// If we have a humongous object with a few remembered sets, we simply flush these
// remembered set entries into the DCQS. That will result in automatic
@ -2743,8 +2745,14 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
// collecting remembered set entries for humongous regions that were not
// reclaimed.
r->rem_set()->set_state_complete();
#ifdef ASSERT
G1HeapRegionAttr region_attr = g1h->region_attr(oop(r->bottom()));
assert(region_attr.needs_remset_update(), "must be");
#endif
}
assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
} else {
g1h->register_region_with_region_attr(r);
}
_total_humongous++;
@ -2757,21 +2765,15 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
void flush_rem_set_entries() { _dcq.flush(); }
};
void G1CollectedHeap::register_humongous_regions_with_cset() {
if (!G1EagerReclaimHumongousObjects) {
phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0);
return;
}
double time = os::elapsed_counter();
void G1CollectedHeap::register_regions_with_region_attr() {
Ticks start = Ticks::now();
// Collect reclaim candidate information and register candidates with cset.
RegisterHumongousWithInCSetFastTestClosure cl;
RegisterRegionsWithRegionAttrTableClosure cl;
heap_region_iterate(&cl);
time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0;
phase_times()->record_fast_reclaim_humongous_stats(time,
cl.total_humongous(),
cl.candidate_humongous());
phase_times()->record_register_regions((Ticks::now() - start).seconds() * 1000.0,
cl.total_humongous(),
cl.candidate_humongous());
_has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
// Finally flush all remembered set entries to re-check into the global DCQS.
@ -2861,7 +2863,7 @@ void G1CollectedHeap::start_new_collection_set() {
collection_set()->start_incremental_building();
clear_cset_fast_test();
clear_region_attr();
guarantee(_eden.length() == 0, "eden should have been cleared");
policy()->transfer_survivors_to_cset(survivor());
@ -3302,17 +3304,17 @@ public:
oop obj = *p;
assert(obj != NULL, "the caller should have filtered out NULL values");
const InCSetState cset_state =_g1h->in_cset_state(obj);
if (!cset_state.is_in_cset_or_humongous()) {
const G1HeapRegionAttr region_attr =_g1h->region_attr(obj);
if (!region_attr.is_in_cset_or_humongous()) {
return;
}
if (cset_state.is_in_cset()) {
if (region_attr.is_in_cset()) {
assert( obj->is_forwarded(), "invariant" );
*p = obj->forwardee();
} else {
assert(!obj->is_forwarded(), "invariant" );
assert(cset_state.is_humongous(),
"Only allowed InCSet state is IsHumongous, but is %d", cset_state.value());
assert(region_attr.is_humongous(),
"Only allowed G1HeapRegionAttr state is IsHumongous, but is %d", region_attr.type());
_g1h->set_humongous_is_live(obj);
}
}
@ -3572,7 +3574,7 @@ void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo& evacuation_i
// Initialize the GC alloc regions.
_allocator->init_gc_alloc_regions(evacuation_info);
register_humongous_regions_with_cset();
register_regions_with_region_attr();
assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
rem_set()->prepare_for_oops_into_collection_set_do();
@ -3970,7 +3972,7 @@ private:
G1CollectedHeap* g1h = G1CollectedHeap::heap();
assert(r->in_collection_set(), "Region %u should be in collection set.", r->hrm_index());
g1h->clear_in_cset(r);
g1h->clear_region_attr(r);
if (r->is_young()) {
assert(r->young_index_in_cset() != -1 && (uint)r->young_index_in_cset() < g1h->collection_set()->young_region_length(),
@ -4031,7 +4033,7 @@ private:
G1Policy* policy = g1h->policy();
policy->add_bytes_allocated_in_old_since_last_gc(_bytes_allocated_in_old_since_last_gc);
g1h->alloc_buffer_stats(InCSetState::Old)->add_failure_used_and_waste(_failure_used_words, _failure_waste_words);
g1h->alloc_buffer_stats(G1HeapRegionAttr::Old)->add_failure_used_and_waste(_failure_used_words, _failure_waste_words);
}
};
@ -4365,7 +4367,7 @@ class G1AbandonCollectionSetClosure : public HeapRegionClosure {
public:
virtual bool do_heap_region(HeapRegion* r) {
assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index());
G1CollectedHeap::heap()->clear_in_cset(r);
G1CollectedHeap::heap()->clear_region_attr(r);
r->set_young_index_in_cset(-1);
return false;
}
@ -4582,7 +4584,7 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region,
// Methods for the GC alloc regions
bool G1CollectedHeap::has_more_regions(InCSetState dest) {
bool G1CollectedHeap::has_more_regions(G1HeapRegionAttr dest) {
if (dest.is_old()) {
return true;
} else {
@ -4590,7 +4592,7 @@ bool G1CollectedHeap::has_more_regions(InCSetState dest) {
}
}
HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, InCSetState dest) {
HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest) {
assert(FreeList_lock->owned_by_self(), "pre-condition");
if (!has_more_regions(dest)) {
@ -4618,6 +4620,7 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, InCSetState d
_verifier->check_bitmaps("Old Region Allocation", new_alloc_region);
}
_policy->remset_tracker()->update_at_allocate(new_alloc_region);
register_region_with_region_attr(new_alloc_region);
_hr_printer.alloc(new_alloc_region);
return new_alloc_region;
}
@ -4626,12 +4629,12 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, InCSetState d
void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes,
InCSetState dest) {
G1HeapRegionAttr dest) {
policy()->record_bytes_copied_during_gc(allocated_bytes);
if (dest.is_old()) {
old_set_add(alloc_region);
} else {
assert(dest.is_young(), "Retiring alloc region should be young(%d)", dest.value());
assert(dest.is_young(), "Retiring alloc region should be young (%d)", dest.type());
_survivor.add_used_bytes(allocated_bytes);
}

View File

@ -40,7 +40,7 @@
#include "gc/g1/g1HeapTransition.hpp"
#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1HRPrinter.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
#include "gc/g1/g1SurvivorRegions.hpp"
#include "gc/g1/g1YCTypes.hpp"
@ -464,10 +464,10 @@ private:
size_t allocated_bytes);
// For GC alloc regions.
bool has_more_regions(InCSetState dest);
HeapRegion* new_gc_alloc_region(size_t word_size, InCSetState dest);
bool has_more_regions(G1HeapRegionAttr dest);
HeapRegion* new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest);
void retire_gc_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes, InCSetState dest);
size_t allocated_bytes, G1HeapRegionAttr dest);
// - if explicit_gc is true, the GC is for a System.gc() etc,
// otherwise it's for a failed allocation.
@ -551,10 +551,10 @@ public:
bool expand(size_t expand_bytes, WorkGang* pretouch_workers = NULL, double* expand_time_ms = NULL);
// Returns the PLAB statistics for a given destination.
inline G1EvacStats* alloc_buffer_stats(InCSetState dest);
inline G1EvacStats* alloc_buffer_stats(G1HeapRegionAttr dest);
// Determines PLAB size for a given destination.
inline size_t desired_plab_sz(InCSetState dest);
inline size_t desired_plab_sz(G1HeapRegionAttr dest);
// Do anything common to GC's.
void gc_prologue(bool full);
@ -573,27 +573,24 @@ public:
inline void set_humongous_is_live(oop obj);
// Register the given region to be part of the collection set.
inline void register_humongous_region_with_cset(uint index);
// Register regions with humongous objects (actually on the start region) in
// the in_cset_fast_test table.
void register_humongous_regions_with_cset();
inline void register_humongous_region_with_region_attr(uint index);
// Update region attributes table with information about all regions.
void register_regions_with_region_attr();
// We register a region with the fast "in collection set" test. We
// simply set to true the array slot corresponding to this region.
void register_young_region_with_cset(HeapRegion* r) {
_in_cset_fast_test.set_in_young(r->hrm_index());
void register_young_region_with_region_attr(HeapRegion* r) {
_region_attr.set_in_young(r->hrm_index());
}
void register_old_region_with_cset(HeapRegion* r) {
_in_cset_fast_test.set_in_old(r->hrm_index());
}
void register_optional_region_with_cset(HeapRegion* r) {
_in_cset_fast_test.set_optional(r->hrm_index());
}
void clear_in_cset(const HeapRegion* hr) {
_in_cset_fast_test.clear(hr);
inline void register_region_with_region_attr(HeapRegion* r);
inline void register_old_region_with_region_attr(HeapRegion* r);
inline void register_optional_region_with_region_attr(HeapRegion* r);
void clear_region_attr(const HeapRegion* hr) {
_region_attr.clear(hr);
}
void clear_cset_fast_test() {
_in_cset_fast_test.clear();
void clear_region_attr() {
_region_attr.clear();
}
bool is_user_requested_concurrent_full_gc(GCCause::Cause cause);
@ -1110,11 +1107,11 @@ public:
// This array is used for a quick test on whether a reference points into
// the collection set or not. Each of the array's elements denotes whether the
// corresponding region is in the collection set or not.
G1InCSetStateFastTestBiasedMappedArray _in_cset_fast_test;
G1HeapRegionAttrBiasedMappedArray _region_attr;
public:
inline InCSetState in_cset_state(const oop obj);
inline G1HeapRegionAttr region_attr(const oop obj);
// Return "TRUE" iff the given object address is in the reserved
// region of g1.

View File

@ -30,6 +30,7 @@
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1Policy.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "runtime/orderAccess.hpp"
@ -38,11 +39,11 @@ G1GCPhaseTimes* G1CollectedHeap::phase_times() const {
return _policy->phase_times();
}
G1EvacStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
switch (dest.value()) {
case InCSetState::Young:
G1EvacStats* G1CollectedHeap::alloc_buffer_stats(G1HeapRegionAttr dest) {
switch (dest.type()) {
case G1HeapRegionAttr::Young:
return &_survivor_evac_stats;
case InCSetState::Old:
case G1HeapRegionAttr::Old:
return &_old_evac_stats;
default:
ShouldNotReachHere();
@ -50,7 +51,7 @@ G1EvacStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
}
}
size_t G1CollectedHeap::desired_plab_sz(InCSetState dest) {
size_t G1CollectedHeap::desired_plab_sz(G1HeapRegionAttr dest) {
size_t gclab_word_size = alloc_buffer_stats(dest)->desired_plab_sz(workers()->active_workers());
// Prevent humongous PLAB sizes for two reasons:
// * PLABs are allocated using a similar paths as oops, but should
@ -150,23 +151,35 @@ inline bool G1CollectedHeap::is_in_cset(oop obj) {
}
inline bool G1CollectedHeap::is_in_cset(HeapWord* addr) {
return _in_cset_fast_test.is_in_cset(addr);
return _region_attr.is_in_cset(addr);
}
bool G1CollectedHeap::is_in_cset(const HeapRegion* hr) {
return _in_cset_fast_test.is_in_cset(hr);
return _region_attr.is_in_cset(hr);
}
bool G1CollectedHeap::is_in_cset_or_humongous(const oop obj) {
return _in_cset_fast_test.is_in_cset_or_humongous((HeapWord*)obj);
return _region_attr.is_in_cset_or_humongous((HeapWord*)obj);
}
InCSetState G1CollectedHeap::in_cset_state(const oop obj) {
return _in_cset_fast_test.at((HeapWord*)obj);
G1HeapRegionAttr G1CollectedHeap::region_attr(const oop obj) {
return _region_attr.at((HeapWord*)obj);
}
void G1CollectedHeap::register_humongous_region_with_cset(uint index) {
_in_cset_fast_test.set_humongous(index);
void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) {
_region_attr.set_humongous(index, region_at(index)->rem_set()->is_tracked());
}
void G1CollectedHeap::register_region_with_region_attr(HeapRegion* r) {
_region_attr.set_has_remset(r->hrm_index(), r->rem_set()->is_tracked());
}
void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) {
_region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked());
}
void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) {
_region_attr.set_optional(r->hrm_index(), r->rem_set()->is_tracked());
}
#ifndef PRODUCT
@ -294,7 +307,7 @@ inline void G1CollectedHeap::set_humongous_is_live(oop obj) {
// thread (i.e. within the VM thread).
if (is_humongous_reclaim_candidate(region)) {
set_humongous_reclaim_candidate(region, false);
_in_cset_fast_test.clear_humongous(region);
_region_attr.clear_humongous(region);
}
}

View File

@ -121,7 +121,7 @@ void G1CollectionSet::add_old_region(HeapRegion* hr) {
assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the collection set");
_g1h->register_old_region_with_cset(hr);
_g1h->register_old_region_with_region_attr(hr);
_collection_set_regions[_collection_set_cur_length++] = hr->hrm_index();
assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size.");
@ -137,7 +137,7 @@ void G1CollectionSet::add_optional_region(HeapRegion* hr) {
assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the CSet");
_g1h->register_optional_region_with_cset(hr);
_g1h->register_optional_region_with_region_attr(hr);
hr->set_index_in_opt_cset(_num_optional_regions++);
}
@ -316,7 +316,7 @@ void G1CollectionSet::add_young_region_common(HeapRegion* hr) {
}
assert(!hr->in_collection_set(), "invariant");
_g1h->register_young_region_with_cset(hr);
_g1h->register_young_region_with_region_attr(hr);
}
void G1CollectionSet::add_survivor_regions(HeapRegion* hr) {
@ -492,7 +492,7 @@ void G1CollectionSet::move_candidates_to_collection_set(uint num_old_candidate_r
HeapRegion* r = candidates()->at(candidate_idx + i);
// This potentially optional candidate region is going to be an actual collection
// set region. Clear cset marker.
_g1h->clear_in_cset(r);
_g1h->clear_region_attr(r);
add_old_region(r);
}
candidates()->remove(num_old_candidate_regions);
@ -526,7 +526,7 @@ void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* p
for (uint i = 0; i < _num_optional_regions; i++) {
HeapRegion* r = candidates()->at(candidates()->cur_idx() + i);
pss->record_unused_optional_region(r);
_g1h->clear_in_cset(r);
_g1h->clear_region_attr(r);
r->clear_index_in_opt_cset();
}
free_optional_regions();

View File

@ -170,7 +170,7 @@ void G1GCPhaseTimes::reset() {
_recorded_total_free_cset_time_ms = 0.0;
_recorded_serial_free_cset_time_ms = 0.0;
_cur_fast_reclaim_humongous_time_ms = 0.0;
_cur_fast_reclaim_humongous_register_time_ms = 0.0;
_cur_region_register_time = 0.0;
_cur_fast_reclaim_humongous_total = 0;
_cur_fast_reclaim_humongous_candidates = 0;
_cur_fast_reclaim_humongous_reclaimed = 0;
@ -364,7 +364,7 @@ double G1GCPhaseTimes::print_pre_evacuate_collection_set() const {
const double sum_ms = _root_region_scan_wait_time_ms +
_recorded_young_cset_choice_time_ms +
_recorded_non_young_cset_choice_time_ms +
_cur_fast_reclaim_humongous_register_time_ms +
_cur_region_register_time +
_recorded_clear_claimed_marks_time_ms;
info_time("Pre Evacuate Collection Set", sum_ms);
@ -374,8 +374,8 @@ double G1GCPhaseTimes::print_pre_evacuate_collection_set() const {
}
debug_time("Prepare TLABs", _cur_prepare_tlab_time_ms);
debug_time("Choose Collection Set", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms));
debug_time("Region Register", _cur_region_register_time);
if (G1EagerReclaimHumongousObjects) {
debug_time("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
trace_count("Humongous Total", _cur_fast_reclaim_humongous_total);
trace_count("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
}

View File

@ -176,8 +176,9 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
double _recorded_serial_free_cset_time_ms;
double _cur_region_register_time;
double _cur_fast_reclaim_humongous_time_ms;
double _cur_fast_reclaim_humongous_register_time_ms;
size_t _cur_fast_reclaim_humongous_total;
size_t _cur_fast_reclaim_humongous_candidates;
size_t _cur_fast_reclaim_humongous_reclaimed;
@ -305,8 +306,8 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
_recorded_serial_free_cset_time_ms = time_ms;
}
void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) {
_cur_fast_reclaim_humongous_register_time_ms = time_ms;
void record_register_regions(double time_ms, size_t total, size_t candidates) {
_cur_region_register_time = time_ms;
_cur_fast_reclaim_humongous_total = total;
_cur_fast_reclaim_humongous_candidates = candidates;
}

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1HEAPREGIONATTR_HPP
#define SHARE_GC_G1_G1HEAPREGIONATTR_HPP
#include "gc/g1/g1BiasedArray.hpp"
#include "gc/g1/heapRegion.hpp"
// Per-region attributes often used during garbage collection to avoid costly
// lookups for that information all over the place.
struct G1HeapRegionAttr {
public:
// We use different types to represent the state value depending on platform as
// some have issues loading parts of words.
#ifdef SPARC
typedef int32_t region_type_t;
typedef uint32_t needs_remset_update_t;
#else
typedef int8_t region_type_t;
typedef uint8_t needs_remset_update_t;
#endif
private:
needs_remset_update_t _needs_remset_update;
region_type_t _type;
public:
// Selection of the values for the _type field were driven to micro-optimize the
// encoding and frequency of the checks.
// The most common check for a given reference is whether the region is in the
// collection set or not, and which generation this region is in.
// The selected encoding allows us to use a single check (> NotInCSet) for the
// former.
//
// The other values are used for objects requiring various special cases,
// for example eager reclamation of humongous objects or optional regions.
static const region_type_t Optional = -2; // The region is optional and NOT in the current collection set.
static const region_type_t Humongous = -1; // The region is a humongous candidate not in the current collection set.
static const region_type_t NotInCSet = 0; // The region is not in the collection set.
static const region_type_t Young = 1; // The region is in the collection set and a young region.
static const region_type_t Old = 2; // The region is in the collection set and an old region.
static const region_type_t Num = 3;
G1HeapRegionAttr(region_type_t type = NotInCSet, bool needs_remset_update = false) :
_needs_remset_update(needs_remset_update), _type(type) {
assert(is_valid(), "Invalid type %d", _type);
}
region_type_t type() const { return _type; }
const char* get_type_str() const {
switch (type()) {
case Optional: return "Optional";
case Humongous: return "Humongous";
case NotInCSet: return "NotInCSet";
case Young: return "Young";
case Old: return "Old";
default: ShouldNotReachHere(); return "";
}
}
bool needs_remset_update() const { return _needs_remset_update != 0; }
void set_old() { _type = Old; }
void clear_humongous() {
assert(is_humongous() || !is_in_cset(), "must be");
_type = NotInCSet;
}
void set_has_remset(bool value) { _needs_remset_update = value ? 1 : 0; }
bool is_in_cset_or_humongous() const { return is_in_cset() || is_humongous(); }
bool is_in_cset() const { return type() > NotInCSet; }
bool is_humongous() const { return type() == Humongous; }
bool is_young() const { return type() == Young; }
bool is_old() const { return type() == Old; }
bool is_optional() const { return type() == Optional; }
#ifdef ASSERT
bool is_default() const { return type() == NotInCSet; }
bool is_valid() const { return (type() >= Optional && type() < Num); }
bool is_valid_gen() const { return (type() >= Young && type() <= Old); }
#endif
};
// Table for all regions in the heap for above.
//
// We use this to speed up reference processing during young collection and
// quickly reclaim humongous objects. For the latter, at the start of GC, by adding
// it as a humongous region we enable special handling for that region. During the
// reference iteration closures, when we see a humongous region, we then simply mark
// it as referenced, i.e. live, and remove it from this table to prevent further
// processing on it.
//
// This means that this does NOT completely correspond to the information stored
// in a HeapRegion, but only to what is interesting for the current young collection.
class G1HeapRegionAttrBiasedMappedArray : public G1BiasedMappedArray<G1HeapRegionAttr> {
protected:
G1HeapRegionAttr default_value() const { return G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet); }
public:
void set_optional(uintptr_t index, bool needs_remset_update) {
assert(get_by_index(index).is_default(),
"Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Optional, needs_remset_update));
}
void set_humongous(uintptr_t index, bool needs_remset_update) {
assert(get_by_index(index).is_default(),
"Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Humongous, needs_remset_update));
}
void clear_humongous(uintptr_t index) {
get_ref_by_index(index)->clear_humongous();
}
void set_has_remset(uintptr_t index, bool needs_remset_update) {
get_ref_by_index(index)->set_has_remset(needs_remset_update);
}
void set_in_young(uintptr_t index) {
assert(get_by_index(index).is_default(),
"Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Young, true));
}
void set_in_old(uintptr_t index, bool needs_remset_update) {
assert(get_by_index(index).is_default(),
"Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Old, needs_remset_update));
}
bool is_in_cset_or_humongous(HeapWord* addr) const { return at(addr).is_in_cset_or_humongous(); }
bool is_in_cset(HeapWord* addr) const { return at(addr).is_in_cset(); }
bool is_in_cset(const HeapRegion* hr) const { return get_by_index(hr->hrm_index()).is_in_cset(); }
G1HeapRegionAttr at(HeapWord* addr) const { return get_by_address(addr); }
void clear() { G1BiasedMappedArray<G1HeapRegionAttr>::clear(); }
void clear(const HeapRegion* hr) { return set_by_index(hr->hrm_index(), G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet)); }
};
#endif // SHARE_GC_G1_G1HEAPREGIONATTR_HPP

View File

@ -790,50 +790,50 @@ class G1CheckCSetFastTableClosure : public HeapRegionClosure {
virtual bool do_heap_region(HeapRegion* hr) {
uint i = hr->hrm_index();
InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
G1HeapRegionAttr region_attr = (G1HeapRegionAttr) G1CollectedHeap::heap()->_region_attr.get_by_index(i);
if (hr->is_humongous()) {
if (hr->in_collection_set()) {
log_error(gc, verify)("## humongous region %u in CSet", i);
_failures = true;
return true;
}
if (cset_state.is_in_cset()) {
log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
if (region_attr.is_in_cset()) {
log_error(gc, verify)("## inconsistent region attr type %s for humongous region %u", region_attr.get_type_str(), i);
_failures = true;
return true;
}
if (hr->is_continues_humongous() && cset_state.is_humongous()) {
log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
if (hr->is_continues_humongous() && region_attr.is_humongous()) {
log_error(gc, verify)("## inconsistent region attr type %s for continues humongous region %u", region_attr.get_type_str(), i);
_failures = true;
return true;
}
} else {
if (cset_state.is_humongous()) {
log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
if (region_attr.is_humongous()) {
log_error(gc, verify)("## inconsistent region attr type %s for non-humongous region %u", region_attr.get_type_str(), i);
_failures = true;
return true;
}
if (hr->in_collection_set() != cset_state.is_in_cset()) {
log_error(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
hr->in_collection_set(), cset_state.value(), i);
if (hr->in_collection_set() != region_attr.is_in_cset()) {
log_error(gc, verify)("## in CSet %d / region attr type %s inconsistency for region %u",
hr->in_collection_set(), region_attr.get_type_str(), i);
_failures = true;
return true;
}
if (cset_state.is_in_cset()) {
if (region_attr.is_in_cset()) {
if (hr->is_archive()) {
log_error(gc, verify)("## is_archive in collection set for region %u", i);
_failures = true;
return true;
}
if (hr->is_young() != (cset_state.is_young())) {
log_error(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
hr->is_young(), cset_state.value(), i);
if (hr->is_young() != (region_attr.is_young())) {
log_error(gc, verify)("## is_young %d / region attr type %s inconsistency for region %u",
hr->is_young(), region_attr.get_type_str(), i);
_failures = true;
return true;
}
if (hr->is_old() != (cset_state.is_old())) {
log_error(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
hr->is_old(), cset_state.value(), i);
if (hr->is_old() != (region_attr.is_old())) {
log_error(gc, verify)("## is_old %d / region attr type %s inconsistency for region %u",
hr->is_old(), region_attr.get_type_str(), i);
_failures = true;
return true;
}

View File

@ -1,142 +0,0 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1INCSETSTATE_HPP
#define SHARE_GC_G1_G1INCSETSTATE_HPP
#include "gc/g1/g1BiasedArray.hpp"
#include "gc/g1/heapRegion.hpp"
// Per-region state during garbage collection.
struct InCSetState {
public:
// We use different types to represent the state value. Particularly SPARC puts
// values in structs from "left to right", i.e. MSB to LSB. This results in many
// unnecessary shift operations when loading and storing values of this type.
// This degrades performance significantly (>10%) on that platform.
// Other tested ABIs do not seem to have this problem, and actually tend to
// favor smaller types, so we use the smallest usable type there.
#ifdef SPARC
#define CSETSTATE_FORMAT INTPTR_FORMAT
typedef intptr_t in_cset_state_t;
#else
#define CSETSTATE_FORMAT "%d"
typedef int8_t in_cset_state_t;
#endif
private:
in_cset_state_t _value;
public:
enum {
// Selection of the values were driven to micro-optimize the encoding and
// frequency of the checks.
// The most common check is whether the region is in the collection set or not,
// this encoding allows us to use an > 0 check.
// The positive values are encoded in increasing generation order, which
// makes getting the next generation fast by a simple increment. They are also
// used to index into arrays.
// The negative values are used for objects requiring various special cases,
// for example eager reclamation of humongous objects or optional regions.
Optional = -2, // The region is optional
Humongous = -1, // The region is humongous
NotInCSet = 0, // The region is not in the collection set.
Young = 1, // The region is in the collection set and a young region.
Old = 2, // The region is in the collection set and an old region.
Num
};
InCSetState(in_cset_state_t value = NotInCSet) : _value(value) {
assert(is_valid(), "Invalid state %d", _value);
}
in_cset_state_t value() const { return _value; }
void set_old() { _value = Old; }
bool is_in_cset_or_humongous() const { return is_in_cset() || is_humongous(); }
bool is_in_cset() const { return _value > NotInCSet; }
bool is_humongous() const { return _value == Humongous; }
bool is_young() const { return _value == Young; }
bool is_old() const { return _value == Old; }
bool is_optional() const { return _value == Optional; }
#ifdef ASSERT
bool is_default() const { return _value == NotInCSet; }
bool is_valid() const { return (_value >= Optional) && (_value < Num); }
bool is_valid_gen() const { return (_value >= Young && _value <= Old); }
#endif
};
// Instances of this class are used for quick tests on whether a reference points
// into the collection set and into which generation or is a humongous object
//
// Each of the array's elements indicates whether the corresponding region is in
// the collection set and if so in which generation, or a humongous region.
//
// We use this to speed up reference processing during young collection and
// quickly reclaim humongous objects. For the latter, by making a humongous region
// succeed this test, we sort-of add it to the collection set. During the reference
// iteration closures, when we see a humongous region, we then simply mark it as
// referenced, i.e. live.
class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArray<InCSetState> {
protected:
InCSetState default_value() const { return InCSetState::NotInCSet; }
public:
void set_optional(uintptr_t index) {
assert(get_by_index(index).is_default(),
"State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
set_by_index(index, InCSetState::Optional);
}
void set_humongous(uintptr_t index) {
assert(get_by_index(index).is_default(),
"State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
set_by_index(index, InCSetState::Humongous);
}
void clear_humongous(uintptr_t index) {
set_by_index(index, InCSetState::NotInCSet);
}
void set_in_young(uintptr_t index) {
assert(get_by_index(index).is_default(),
"State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
set_by_index(index, InCSetState::Young);
}
void set_in_old(uintptr_t index) {
assert(get_by_index(index).is_default(),
"State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
set_by_index(index, InCSetState::Old);
}
bool is_in_cset_or_humongous(HeapWord* addr) const { return at(addr).is_in_cset_or_humongous(); }
bool is_in_cset(HeapWord* addr) const { return at(addr).is_in_cset(); }
bool is_in_cset(const HeapRegion* hr) const { return get_by_index(hr->hrm_index()).is_in_cset(); }
InCSetState at(HeapWord* addr) const { return get_by_address(addr); }
void clear() { G1BiasedMappedArray<InCSetState>::clear(); }
void clear(const HeapRegion* hr) { return set_by_index(hr->hrm_index(), InCSetState::NotInCSet); }
};
#endif // SHARE_GC_G1_G1INCSETSTATE_HPP

View File

@ -25,7 +25,7 @@
#ifndef SHARE_GC_G1_G1OOPCLOSURES_HPP
#define SHARE_GC_G1_G1OOPCLOSURES_HPP
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
#include "memory/iterator.hpp"
#include "oops/markOop.hpp"
@ -52,18 +52,18 @@ protected:
inline void prefetch_and_push(T* p, oop const obj);
template <class T>
inline void handle_non_cset_obj_common(InCSetState const state, T* p, oop const obj);
inline void handle_non_cset_obj_common(G1HeapRegionAttr const region_attr, T* p, oop const obj);
public:
virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; }
inline void trim_queue_partially();
};
// Used during the Update RS phase to refine remaining cards in the DCQ during garbage collection.
class G1ScanObjsDuringUpdateRSClosure : public G1ScanClosureBase {
// Used to scan cards from the DCQS or the remembered sets during garbage collection.
class G1ScanCardClosure : public G1ScanClosureBase {
public:
G1ScanObjsDuringUpdateRSClosure(G1CollectedHeap* g1h,
G1ParScanThreadState* pss) :
G1ScanCardClosure(G1CollectedHeap* g1h,
G1ParScanThreadState* pss) :
G1ScanClosureBase(g1h, pss) { }
template <class T> void do_oop_work(T* p);
@ -71,23 +71,11 @@ public:
virtual void do_oop(oop* p) { do_oop_work(p); }
};
// Used during the Scan RS phase to scan cards from the remembered set during garbage collection.
class G1ScanObjsDuringScanRSClosure : public G1ScanClosureBase {
public:
G1ScanObjsDuringScanRSClosure(G1CollectedHeap* g1h,
G1ParScanThreadState* par_scan_state):
G1ScanClosureBase(g1h, par_scan_state) { }
template <class T> void do_oop_work(T* p);
virtual void do_oop(oop* p) { do_oop_work(p); }
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
};
// Used during Optional RS scanning to make sure we trim the queues in a timely manner.
class G1ScanRSForOptionalClosure : public OopClosure {
G1ScanObjsDuringScanRSClosure* _scan_cl;
G1ScanCardClosure* _scan_cl;
public:
G1ScanRSForOptionalClosure(G1ScanObjsDuringScanRSClosure* cl) : _scan_cl(cl) { }
G1ScanRSForOptionalClosure(G1ScanCardClosure* cl) : _scan_cl(cl) { }
template <class T> void do_oop_work(T* p);
virtual void do_oop(oop* p) { do_oop_work(p); }

View File

@ -61,10 +61,10 @@ inline void G1ScanClosureBase::prefetch_and_push(T* p, const oop obj) {
}
template <class T>
inline void G1ScanClosureBase::handle_non_cset_obj_common(InCSetState const state, T* p, oop const obj) {
if (state.is_humongous()) {
inline void G1ScanClosureBase::handle_non_cset_obj_common(G1HeapRegionAttr const region_attr, T* p, oop const obj) {
if (region_attr.is_humongous()) {
_g1h->set_humongous_is_live(obj);
} else if (state.is_optional()) {
} else if (region_attr.is_optional()) {
_par_scan_state->remember_reference_into_optional_region(p);
}
}
@ -81,16 +81,16 @@ inline void G1ScanEvacuatedObjClosure::do_oop_work(T* p) {
return;
}
oop obj = CompressedOops::decode_not_null(heap_oop);
const InCSetState state = _g1h->in_cset_state(obj);
if (state.is_in_cset()) {
const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
if (region_attr.is_in_cset()) {
prefetch_and_push(p, obj);
} else if (!HeapRegion::is_in_same_region(p, obj)) {
handle_non_cset_obj_common(state, p, obj);
handle_non_cset_obj_common(region_attr, p, obj);
assert(_scanning_in_young != Uninitialized, "Scan location has not been initialized.");
if (_scanning_in_young == True) {
return;
}
_par_scan_state->enqueue_card_if_tracked(p, obj);
_par_scan_state->enqueue_card_if_tracked(region_attr, p, obj);
}
}
@ -160,7 +160,7 @@ inline void G1ConcurrentRefineOopClosure::do_oop_work(T* p) {
}
template <class T>
inline void G1ScanObjsDuringUpdateRSClosure::do_oop_work(T* p) {
inline void G1ScanCardClosure::do_oop_work(T* p) {
T o = RawAccess<>::oop_load(p);
if (CompressedOops::is_null(o)) {
return;
@ -169,31 +169,15 @@ inline void G1ScanObjsDuringUpdateRSClosure::do_oop_work(T* p) {
check_obj_during_refinement(p, obj);
assert(!_g1h->is_in_cset((HeapWord*)p), "Oop originates from " PTR_FORMAT " (region: %u) which is in the collection set.", p2i(p), _g1h->addr_to_region((HeapWord*)p));
const InCSetState state = _g1h->in_cset_state(obj);
if (state.is_in_cset()) {
// Since the source is always from outside the collection set, here we implicitly know
// that this is a cross-region reference too.
// We can not check for references from the collection set: the remembered sets
// may contain such entries and we do not filter them before.
const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
if (region_attr.is_in_cset()) {
prefetch_and_push(p, obj);
} else if (!HeapRegion::is_in_same_region(p, obj)) {
handle_non_cset_obj_common(state, p, obj);
_par_scan_state->enqueue_card_if_tracked(p, obj);
}
}
template <class T>
inline void G1ScanObjsDuringScanRSClosure::do_oop_work(T* p) {
T heap_oop = RawAccess<>::oop_load(p);
if (CompressedOops::is_null(heap_oop)) {
return;
}
oop obj = CompressedOops::decode_not_null(heap_oop);
const InCSetState state = _g1h->in_cset_state(obj);
if (state.is_in_cset()) {
prefetch_and_push(p, obj);
} else if (!HeapRegion::is_in_same_region(p, obj)) {
handle_non_cset_obj_common(state, p, obj);
handle_non_cset_obj_common(region_attr, p, obj);
_par_scan_state->enqueue_card_if_tracked(region_attr, p, obj);
}
}
@ -233,7 +217,7 @@ void G1ParCopyClosure<barrier, do_mark_object>::do_oop_work(T* p) {
assert(_worker_id == _par_scan_state->worker_id(), "sanity");
const InCSetState state = _g1h->in_cset_state(obj);
const G1HeapRegionAttr state = _g1h->region_attr(obj);
if (state.is_in_cset()) {
oop forwardee;
markOop m = obj->mark_raw();

View File

@ -75,11 +75,11 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
_plab_allocator = new G1PLABAllocator(_g1h->allocator());
_dest[InCSetState::NotInCSet] = InCSetState::NotInCSet;
_dest[G1HeapRegionAttr::NotInCSet] = G1HeapRegionAttr::NotInCSet;
// The dest for Young is used when the objects are aged enough to
// need to be moved to the next space.
_dest[InCSetState::Young] = InCSetState::Old;
_dest[InCSetState::Old] = InCSetState::Old;
_dest[G1HeapRegionAttr::Young] = G1HeapRegionAttr::Old;
_dest[G1HeapRegionAttr::Old] = G1HeapRegionAttr::Old;
_closures = G1EvacuationRootClosures::create_root_closures(this, _g1h);
@ -157,18 +157,18 @@ void G1ParScanThreadState::trim_queue() {
} while (!_refs->is_empty());
}
HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state,
InCSetState* dest,
HeapWord* G1ParScanThreadState::allocate_in_next_plab(G1HeapRegionAttr const region_attr,
G1HeapRegionAttr* dest,
size_t word_sz,
bool previous_plab_refill_failed) {
assert(state.is_in_cset_or_humongous(), "Unexpected state: " CSETSTATE_FORMAT, state.value());
assert(dest->is_in_cset_or_humongous(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value());
assert(region_attr.is_in_cset_or_humongous(), "Unexpected region attr type: %s", region_attr.get_type_str());
assert(dest->is_in_cset_or_humongous(), "Unexpected dest: %s region attr", dest->get_type_str());
// Right now we only have two types of regions (young / old) so
// let's keep the logic here simple. We can generalize it when necessary.
if (dest->is_young()) {
bool plab_refill_in_old_failed = false;
HeapWord* const obj_ptr = _plab_allocator->allocate(InCSetState::Old,
HeapWord* const obj_ptr = _plab_allocator->allocate(G1HeapRegionAttr::Old,
word_sz,
&plab_refill_in_old_failed);
// Make sure that we won't attempt to copy any other objects out
@ -190,38 +190,38 @@ HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state,
return obj_ptr;
} else {
_old_gen_is_full = previous_plab_refill_failed;
assert(dest->is_old(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value());
assert(dest->is_old(), "Unexpected dest region attr: %s", dest->get_type_str());
// no other space to try.
return NULL;
}
}
InCSetState G1ParScanThreadState::next_state(InCSetState const state, markOop const m, uint& age) {
if (state.is_young()) {
G1HeapRegionAttr G1ParScanThreadState::next_region_attr(G1HeapRegionAttr const region_attr, markOop const m, uint& age) {
if (region_attr.is_young()) {
age = !m->has_displaced_mark_helper() ? m->age()
: m->displaced_mark_helper()->age();
if (age < _tenuring_threshold) {
return state;
return region_attr;
}
}
return dest(state);
return dest(region_attr);
}
void G1ParScanThreadState::report_promotion_event(InCSetState const dest_state,
void G1ParScanThreadState::report_promotion_event(G1HeapRegionAttr const dest_attr,
oop const old, size_t word_sz, uint age,
HeapWord * const obj_ptr) const {
PLAB* alloc_buf = _plab_allocator->alloc_buffer(dest_state);
PLAB* alloc_buf = _plab_allocator->alloc_buffer(dest_attr);
if (alloc_buf->contains(obj_ptr)) {
_g1h->_gc_tracer_stw->report_promotion_in_new_plab_event(old->klass(), word_sz * HeapWordSize, age,
dest_state.value() == InCSetState::Old,
dest_attr.type() == G1HeapRegionAttr::Old,
alloc_buf->word_sz() * HeapWordSize);
} else {
_g1h->_gc_tracer_stw->report_promotion_outside_plab_event(old->klass(), word_sz * HeapWordSize, age,
dest_state.value() == InCSetState::Old);
dest_attr.type() == G1HeapRegionAttr::Old);
}
}
oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
oop G1ParScanThreadState::copy_to_survivor_space(G1HeapRegionAttr const region_attr,
oop const old,
markOop const old_mark) {
const size_t word_sz = old->size();
@ -232,21 +232,21 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
(!from_region->is_young() && young_index == 0), "invariant" );
uint age = 0;
InCSetState dest_state = next_state(state, old_mark, age);
G1HeapRegionAttr dest_attr = next_region_attr(region_attr, old_mark, age);
// The second clause is to prevent premature evacuation failure in case there
// is still space in survivor, but old gen is full.
if (_old_gen_is_full && dest_state.is_old()) {
if (_old_gen_is_full && dest_attr.is_old()) {
return handle_evacuation_failure_par(old, old_mark);
}
HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_state, word_sz);
HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_attr, word_sz);
// PLAB allocations should succeed most of the time, so we'll
// normally check against NULL once and that's it.
if (obj_ptr == NULL) {
bool plab_refill_failed = false;
obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_state, word_sz, &plab_refill_failed);
obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_attr, word_sz, &plab_refill_failed);
if (obj_ptr == NULL) {
obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, plab_refill_failed);
obj_ptr = allocate_in_next_plab(region_attr, &dest_attr, word_sz, plab_refill_failed);
if (obj_ptr == NULL) {
// This will either forward-to-self, or detect that someone else has
// installed a forwarding pointer.
@ -255,7 +255,7 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
}
if (_g1h->_gc_tracer_stw->should_report_promotion_events()) {
// The events are checked individually as part of the actual commit
report_promotion_event(dest_state, old, word_sz, age, obj_ptr);
report_promotion_event(dest_attr, old, word_sz, age, obj_ptr);
}
}
@ -267,7 +267,7 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
if (_g1h->evacuation_should_fail()) {
// Doing this after all the allocation attempts also tests the
// undo_allocation() method too.
_plab_allocator->undo_allocation(dest_state, obj_ptr, word_sz);
_plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz);
return handle_evacuation_failure_par(old, old_mark);
}
#endif // !PRODUCT
@ -280,7 +280,7 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
if (forward_ptr == NULL) {
Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz);
if (dest_state.is_young()) {
if (dest_attr.is_young()) {
if (age < markOopDesc::max_age) {
age++;
}
@ -300,8 +300,8 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
}
if (G1StringDedup::is_enabled()) {
const bool is_from_young = state.is_young();
const bool is_to_young = dest_state.is_young();
const bool is_from_young = region_attr.is_young();
const bool is_to_young = dest_attr.is_young();
assert(is_from_young == _g1h->heap_region_containing(old)->is_young(),
"sanity");
assert(is_to_young == _g1h->heap_region_containing(obj)->is_young(),
@ -322,12 +322,12 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
oop* old_p = set_partial_array_mask(old);
do_oop_partial_array(old_p);
} else {
G1ScanInYoungSetter x(&_scanner, dest_state.is_young());
G1ScanInYoungSetter x(&_scanner, dest_attr.is_young());
obj->oop_iterate_backwards(&_scanner);
}
return obj;
} else {
_plab_allocator->undo_allocation(dest_state, obj_ptr, word_sz);
_plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz);
return forward_ptr;
}
}

View File

@ -45,17 +45,17 @@ class outputStream;
class G1ParScanThreadState : public CHeapObj<mtGC> {
G1CollectedHeap* _g1h;
RefToScanQueue* _refs;
RefToScanQueue* _refs;
G1DirtyCardQueue _dcq;
G1CardTable* _ct;
G1CardTable* _ct;
G1EvacuationRootClosures* _closures;
G1PLABAllocator* _plab_allocator;
G1PLABAllocator* _plab_allocator;
AgeTable _age_table;
InCSetState _dest[InCSetState::Num];
AgeTable _age_table;
G1HeapRegionAttr _dest[G1HeapRegionAttr::Num];
// Local tenuring threshold.
uint _tenuring_threshold;
uint _tenuring_threshold;
G1ScanEvacuatedObjClosure _scanner;
uint _worker_id;
@ -80,12 +80,12 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
G1DirtyCardQueue& dirty_card_queue() { return _dcq; }
G1CardTable* ct() { return _ct; }
InCSetState dest(InCSetState original) const {
G1HeapRegionAttr dest(G1HeapRegionAttr original) const {
assert(original.is_valid(),
"Original state invalid: " CSETSTATE_FORMAT, original.value());
assert(_dest[original.value()].is_valid_gen(),
"Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value());
return _dest[original.value()];
"Original region attr invalid: %s", original.get_type_str());
assert(_dest[original.type()].is_valid_gen(),
"Dest region attr is invalid: %s", _dest[original.type()].get_type_str());
return _dest[original.type()];
}
size_t _num_optional_regions;
@ -111,10 +111,19 @@ public:
template <class T> void do_oop_ext(T* ref);
template <class T> void push_on_queue(T* ref);
template <class T> void enqueue_card_if_tracked(T* p, oop o) {
template <class T> void enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) {
assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already.");
assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already.");
if (!_g1h->heap_region_containing((HeapWord*)o)->rem_set()->is_tracked()) {
#ifdef ASSERT
HeapRegion* const hr_obj = _g1h->heap_region_containing((HeapWord*)o);
assert(region_attr.needs_remset_update() == hr_obj->rem_set()->is_tracked(),
"State flag indicating remset tracking disagrees (%s) with actual remembered set (%s) for region %u",
BOOL_TO_STR(region_attr.needs_remset_update()),
BOOL_TO_STR(hr_obj->rem_set()->is_tracked()),
hr_obj->hrm_index());
#endif
if (!region_attr.needs_remset_update()) {
return;
}
size_t card_index = ct()->index_for(p);
@ -184,14 +193,14 @@ private:
// Returns a non-NULL pointer if successful, and updates dest if required.
// Also determines whether we should continue to try to allocate into the various
// generations or just end trying to allocate.
HeapWord* allocate_in_next_plab(InCSetState const state,
InCSetState* dest,
HeapWord* allocate_in_next_plab(G1HeapRegionAttr const region_attr,
G1HeapRegionAttr* dest,
size_t word_sz,
bool previous_plab_refill_failed);
inline InCSetState next_state(InCSetState const state, markOop const m, uint& age);
inline G1HeapRegionAttr next_region_attr(G1HeapRegionAttr const region_attr, markOop const m, uint& age);
void report_promotion_event(InCSetState const dest_state,
void report_promotion_event(G1HeapRegionAttr const dest_attr,
oop const old, size_t word_sz, uint age,
HeapWord * const obj_ptr) const;
@ -200,7 +209,7 @@ private:
inline void trim_queue_to_threshold(uint threshold);
public:
oop copy_to_survivor_space(InCSetState const state, oop const obj, markOop const old_mark);
oop copy_to_survivor_space(G1HeapRegionAttr const region_attr, oop const obj, markOop const old_mark);
void trim_queue();
void trim_queue_partially();

View File

@ -41,14 +41,14 @@ template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
// than one thread might claim the same card. So the same card may be
// processed multiple times, and so we might get references into old gen here.
// So we need to redo this check.
const InCSetState in_cset_state = _g1h->in_cset_state(obj);
const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
// References pushed onto the work stack should never point to a humongous region
// as they are not added to the collection set due to above precondition.
assert(!in_cset_state.is_humongous(),
assert(!region_attr.is_humongous(),
"Obj " PTR_FORMAT " should not refer to humongous region %u from " PTR_FORMAT,
p2i(obj), _g1h->addr_to_region((HeapWord*)obj), p2i(p));
if (!in_cset_state.is_in_cset()) {
if (!region_attr.is_in_cset()) {
// In this case somebody else already did all the work.
return;
}
@ -57,7 +57,7 @@ template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
if (m->is_marked()) {
obj = (oop) m->decode_pointer();
} else {
obj = copy_to_survivor_space(in_cset_state, obj, m);
obj = copy_to_survivor_space(region_attr, obj, m);
}
RawAccess<IS_NOT_NULL>::oop_store(p, obj);
@ -67,7 +67,7 @@ template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
}
HeapRegion* from = _g1h->heap_region_containing(p);
if (!from->is_young()) {
enqueue_card_if_tracked(p, obj);
enqueue_card_if_tracked(_g1h->region_attr(obj), p, obj);
}
}

View File

@ -27,7 +27,7 @@
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/g1/g1InitialMarkToMixedTimeTracker.hpp"
#include "gc/g1/g1MMUTracker.hpp"
#include "gc/g1/g1RemSetTrackingPolicy.hpp"

View File

@ -305,7 +305,7 @@ void G1RemSet::initialize(size_t capacity, uint max_regions) {
}
G1ScanRSForRegionClosure::G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
G1ScanObjsDuringScanRSClosure* scan_obj_on_card,
G1ScanCardClosure* scan_obj_on_card,
G1ParScanThreadState* pss,
G1GCPhaseTimes::GCParPhases phase,
uint worker_i) :
@ -345,7 +345,7 @@ void G1ScanRSForRegionClosure::scan_opt_rem_set_roots(HeapRegion* r) {
G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
G1ScanObjsDuringScanRSClosure scan_cl(_g1h, _pss);
G1ScanCardClosure scan_cl(_g1h, _pss);
G1ScanRSForOptionalClosure cl(&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();
@ -464,7 +464,7 @@ void G1RemSet::scan_rem_set(G1ParScanThreadState* pss,
G1GCPhaseTimes::GCParPhases coderoots_phase) {
assert(pss->trim_ticks().value() == 0, "Queues must have been trimmed before entering.");
G1ScanObjsDuringScanRSClosure scan_cl(_g1h, pss);
G1ScanCardClosure scan_cl(_g1h, pss);
G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, scan_phase, worker_i);
_g1h->collection_set_iterate_increment_from(&cl, worker_i);
@ -489,12 +489,12 @@ void G1RemSet::scan_rem_set(G1ParScanThreadState* pss,
// Closure used for updating rem sets. Only called during an evacuation pause.
class G1RefineCardClosure: public G1CardTableEntryClosure {
G1RemSet* _g1rs;
G1ScanObjsDuringUpdateRSClosure* _update_rs_cl;
G1ScanCardClosure* _update_rs_cl;
size_t _cards_scanned;
size_t _cards_skipped;
public:
G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanObjsDuringUpdateRSClosure* update_rs_cl) :
G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanCardClosure* update_rs_cl) :
_g1rs(g1h->rem_set()), _update_rs_cl(update_rs_cl), _cards_scanned(0), _cards_skipped(0)
{}
@ -527,7 +527,7 @@ void G1RemSet::update_rem_set(G1ParScanThreadState* pss, uint worker_i) {
if (G1HotCardCache::default_use_cache()) {
G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i);
G1ScanObjsDuringUpdateRSClosure scan_hcc_cl(_g1h, pss);
G1ScanCardClosure scan_hcc_cl(_g1h, pss);
G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl);
_g1h->iterate_hcc_closure(&refine_card_cl, worker_i);
}
@ -536,7 +536,7 @@ void G1RemSet::update_rem_set(G1ParScanThreadState* pss, uint worker_i) {
{
G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i);
G1ScanObjsDuringUpdateRSClosure update_rs_cl(_g1h, pss);
G1ScanCardClosure update_rs_cl(_g1h, pss);
G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl);
_g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i);
@ -712,7 +712,7 @@ void G1RemSet::refine_card_concurrently(CardValue* card_ptr,
}
bool G1RemSet::refine_card_during_gc(CardValue* card_ptr,
G1ScanObjsDuringUpdateRSClosure* update_rs_cl) {
G1ScanCardClosure* update_rs_cl) {
assert(_g1h->is_gc_active(), "Only call during GC");
// Construct the region representing the card.

View File

@ -47,8 +47,7 @@ class G1HotCardCache;
class G1RemSetScanState;
class G1ParScanThreadState;
class G1Policy;
class G1ScanObjsDuringScanRSClosure;
class G1ScanObjsDuringUpdateRSClosure;
class G1ScanCardClosure;
class HeapRegionClaimer;
// A G1RemSet in which each heap region has a rem set that records the
@ -115,7 +114,7 @@ public:
// Refine the card corresponding to "card_ptr", applying the given closure to
// all references found. Must only be called during gc.
// Returns whether the card has been scanned.
bool refine_card_during_gc(CardValue* card_ptr, G1ScanObjsDuringUpdateRSClosure* update_rs_cl);
bool refine_card_during_gc(CardValue* card_ptr, G1ScanCardClosure* update_rs_cl);
// Print accumulated summary info from the start of the VM.
void print_summary_info();
@ -135,7 +134,7 @@ class G1ScanRSForRegionClosure : public HeapRegionClosure {
G1CardTable *_ct;
G1ParScanThreadState* _pss;
G1ScanObjsDuringScanRSClosure* _scan_objs_on_card_cl;
G1ScanCardClosure* _scan_objs_on_card_cl;
G1RemSetScanState* _scan_state;
@ -164,7 +163,7 @@ class G1ScanRSForRegionClosure : public HeapRegionClosure {
void scan_strong_code_roots(HeapRegion* r);
public:
G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
G1ScanObjsDuringScanRSClosure* scan_obj_on_card,
G1ScanCardClosure* scan_obj_on_card,
G1ParScanThreadState* pss,
G1GCPhaseTimes::GCParPhases phase,
uint worker_i);

View File

@ -71,7 +71,7 @@ public class TestEagerReclaimHumongousRegionsLog {
// This gives an array of lines containing eager reclaim of humongous regions
// log messages contents after the ":" in the following order for every GC:
// Humongous Register: a.ams
// Region Register: a.ams
// Humongous Total: b
// Humongous Candidate: c
// Humongous Reclaim: d.dms
@ -79,7 +79,7 @@ public class TestEagerReclaimHumongousRegionsLog {
// Humongous Regions: f->g
String[] lines = Arrays.stream(output.getStdout().split("\\R"))
.filter(s -> s.contains("Humongous")).map(s -> s.substring(s.indexOf(LogSeparator) + LogSeparator.length()))
.filter(s -> (s.contains("Humongous") || s.contains("Region Register"))).map(s -> s.substring(s.indexOf(LogSeparator) + LogSeparator.length()))
.toArray(String[]::new);
Asserts.assertTrue(lines.length % 6 == 0, "There seems to be an unexpected amount of log messages (total: " + lines.length + ") per GC");

View File

@ -132,6 +132,7 @@ public class TestGCLogMessages {
new LogMessageWithLevel("Queue Fixup", Level.DEBUG),
new LogMessageWithLevel("Table Fixup", Level.DEBUG),
new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG),
new LogMessageWithLevel("Region Register", Level.DEBUG),
// Free CSet
new LogMessageWithLevel("Free Collection Set", Level.DEBUG),
new LogMessageWithLevel("Free Collection Set Serial", Level.TRACE),
@ -139,7 +140,6 @@ public class TestGCLogMessages {
new LogMessageWithLevel("Non-Young Free Collection Set", Level.TRACE),
// Humongous Eager Reclaim
new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG),
new LogMessageWithLevel("Humongous Register", Level.DEBUG),
// Merge PSS
new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG),
// TLAB handling