8339162: [REDO] JDK-8338440 Parallel: Improve fragmentation mitigation in Full GC
Co-authored-by: Guoxiong Li <gli@openjdk.org> Reviewed-by: zgu, iwalulya, gli
This commit is contained in:
parent
f400896822
commit
423e8e0999
@ -128,73 +128,84 @@ ParallelCompactData::RegionData::dc_claimed = 0x8U << dc_shift;
|
||||
const ParallelCompactData::RegionData::region_sz_t
|
||||
ParallelCompactData::RegionData::dc_completed = 0xcU << dc_shift;
|
||||
|
||||
bool ParallelCompactData::RegionData::is_clear() {
|
||||
return (_destination == nullptr) &&
|
||||
(_source_region == 0) &&
|
||||
(_partial_obj_addr == nullptr) &&
|
||||
(_partial_obj_size == 0) &&
|
||||
(_dc_and_los == 0) &&
|
||||
(_shadow_state == 0);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void ParallelCompactData::RegionData::verify_clear() {
|
||||
assert(_destination == nullptr, "inv");
|
||||
assert(_source_region == 0, "inv");
|
||||
assert(_partial_obj_addr == nullptr, "inv");
|
||||
assert(_partial_obj_size == 0, "inv");
|
||||
assert(_dc_and_los == 0, "inv");
|
||||
assert(_shadow_state == 0, "inv");
|
||||
}
|
||||
#endif
|
||||
|
||||
SpaceInfo PSParallelCompact::_space_info[PSParallelCompact::last_space_id];
|
||||
|
||||
SpanSubjectToDiscoveryClosure PSParallelCompact::_span_based_discoverer;
|
||||
ReferenceProcessor* PSParallelCompact::_ref_processor = nullptr;
|
||||
|
||||
void SplitInfo::record(size_t src_region_idx, size_t partial_obj_size,
|
||||
HeapWord* destination)
|
||||
{
|
||||
assert(src_region_idx != 0, "invalid src_region_idx");
|
||||
assert(partial_obj_size != 0, "invalid partial_obj_size argument");
|
||||
assert(destination != nullptr, "invalid destination argument");
|
||||
void SplitInfo::record(size_t split_region_idx, HeapWord* split_point, size_t preceding_live_words) {
|
||||
assert(split_region_idx != 0, "precondition");
|
||||
|
||||
_src_region_idx = src_region_idx;
|
||||
_partial_obj_size = partial_obj_size;
|
||||
_destination = destination;
|
||||
// Obj denoted by split_point will be deferred to the next space.
|
||||
assert(split_point != nullptr, "precondition");
|
||||
|
||||
// These fields may not be updated below, so make sure they're clear.
|
||||
assert(_dest_region_addr == nullptr, "should have been cleared");
|
||||
assert(_first_src_addr == nullptr, "should have been cleared");
|
||||
|
||||
// Determine the number of destination regions for the partial object.
|
||||
HeapWord* const last_word = destination + partial_obj_size - 1;
|
||||
const ParallelCompactData& sd = PSParallelCompact::summary_data();
|
||||
HeapWord* const beg_region_addr = sd.region_align_down(destination);
|
||||
HeapWord* const end_region_addr = sd.region_align_down(last_word);
|
||||
|
||||
if (beg_region_addr == end_region_addr) {
|
||||
// One destination region.
|
||||
_destination_count = 1;
|
||||
if (end_region_addr == destination) {
|
||||
// The destination falls on a region boundary, thus the first word of the
|
||||
// partial object will be the first word copied to the destination region.
|
||||
_dest_region_addr = end_region_addr;
|
||||
_first_src_addr = sd.region_to_addr(src_region_idx);
|
||||
}
|
||||
PSParallelCompact::RegionData* split_region_ptr = sd.region(split_region_idx);
|
||||
assert(preceding_live_words < split_region_ptr->data_size(), "inv");
|
||||
|
||||
HeapWord* preceding_destination = split_region_ptr->destination();
|
||||
assert(preceding_destination != nullptr, "inv");
|
||||
|
||||
// How many regions does the preceding part occupy
|
||||
uint preceding_destination_count;
|
||||
if (preceding_live_words == 0) {
|
||||
preceding_destination_count = 0;
|
||||
} else {
|
||||
// Two destination regions. When copied, the partial object will cross a
|
||||
// destination region boundary, so a word somewhere within the partial
|
||||
// object will be the first word copied to the second destination region.
|
||||
_destination_count = 2;
|
||||
_dest_region_addr = end_region_addr;
|
||||
const size_t ofs = pointer_delta(end_region_addr, destination);
|
||||
assert(ofs < _partial_obj_size, "sanity");
|
||||
_first_src_addr = sd.region_to_addr(src_region_idx) + ofs;
|
||||
// -1 so that the ending address doesn't fall on the region-boundary
|
||||
if (sd.region_align_down(preceding_destination) ==
|
||||
sd.region_align_down(preceding_destination + preceding_live_words - 1)) {
|
||||
preceding_destination_count = 1;
|
||||
} else {
|
||||
preceding_destination_count = 2;
|
||||
}
|
||||
}
|
||||
|
||||
_split_region_idx = split_region_idx;
|
||||
_split_point = split_point;
|
||||
_preceding_live_words = preceding_live_words;
|
||||
_preceding_destination = preceding_destination;
|
||||
_preceding_destination_count = preceding_destination_count;
|
||||
}
|
||||
|
||||
void SplitInfo::clear()
|
||||
{
|
||||
_src_region_idx = 0;
|
||||
_partial_obj_size = 0;
|
||||
_destination = nullptr;
|
||||
_destination_count = 0;
|
||||
_dest_region_addr = nullptr;
|
||||
_first_src_addr = nullptr;
|
||||
_split_region_idx = 0;
|
||||
_split_point = nullptr;
|
||||
_preceding_live_words = 0;
|
||||
_preceding_destination = nullptr;
|
||||
_preceding_destination_count = 0;
|
||||
assert(!is_valid(), "sanity");
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void SplitInfo::verify_clear()
|
||||
{
|
||||
assert(_src_region_idx == 0, "not clear");
|
||||
assert(_partial_obj_size == 0, "not clear");
|
||||
assert(_destination == nullptr, "not clear");
|
||||
assert(_destination_count == 0, "not clear");
|
||||
assert(_dest_region_addr == nullptr, "not clear");
|
||||
assert(_first_src_addr == nullptr, "not clear");
|
||||
assert(_split_region_idx == 0, "not clear");
|
||||
assert(_split_point == nullptr, "not clear");
|
||||
assert(_preceding_live_words == 0, "not clear");
|
||||
assert(_preceding_destination == nullptr, "not clear");
|
||||
assert(_preceding_destination_count == 0, "not clear");
|
||||
}
|
||||
#endif // #ifdef ASSERT
|
||||
|
||||
@ -297,110 +308,105 @@ ParallelCompactData::summarize_dense_prefix(HeapWord* beg, HeapWord* end)
|
||||
}
|
||||
}
|
||||
|
||||
// Find the point at which a space can be split and, if necessary, record the
|
||||
// split point.
|
||||
//
|
||||
// If the current src region (which overflowed the destination space) doesn't
|
||||
// have a partial object, the split point is at the beginning of the current src
|
||||
// region (an "easy" split, no extra bookkeeping required).
|
||||
//
|
||||
// If the current src region has a partial object, the split point is in the
|
||||
// region where that partial object starts (call it the split_region). If
|
||||
// split_region has a partial object, then the split point is just after that
|
||||
// partial object (a "hard" split where we have to record the split data and
|
||||
// zero the partial_obj_size field). With a "hard" split, we know that the
|
||||
// partial_obj ends within split_region because the partial object that caused
|
||||
// the overflow starts in split_region. If split_region doesn't have a partial
|
||||
// obj, then the split is at the beginning of split_region (another "easy"
|
||||
// split).
|
||||
HeapWord*
|
||||
ParallelCompactData::summarize_split_space(size_t src_region,
|
||||
SplitInfo& split_info,
|
||||
HeapWord* destination,
|
||||
HeapWord* target_end,
|
||||
HeapWord** target_next)
|
||||
{
|
||||
// The total live words on src_region would overflow the target space, so find
|
||||
// the overflowing object and record the split point. The invariant is that an
|
||||
// obj should not cross space boundary.
|
||||
HeapWord* ParallelCompactData::summarize_split_space(size_t src_region,
|
||||
SplitInfo& split_info,
|
||||
HeapWord* const destination,
|
||||
HeapWord* const target_end,
|
||||
HeapWord** target_next) {
|
||||
assert(destination <= target_end, "sanity");
|
||||
assert(destination + _region_data[src_region].data_size() > target_end,
|
||||
"region should not fit into target space");
|
||||
assert(is_region_aligned(target_end), "sanity");
|
||||
|
||||
size_t split_region = src_region;
|
||||
HeapWord* split_destination = destination;
|
||||
size_t partial_obj_size = _region_data[src_region].partial_obj_size();
|
||||
|
||||
if (destination + partial_obj_size > target_end) {
|
||||
// The split point is just after the partial object (if any) in the
|
||||
// src_region that contains the start of the object that overflowed the
|
||||
// destination space.
|
||||
assert(partial_obj_size > 0, "inv");
|
||||
// The overflowing obj is from a previous region.
|
||||
//
|
||||
// Find the start of the "overflow" object and set split_region to the
|
||||
// region containing it.
|
||||
HeapWord* const overflow_obj = _region_data[src_region].partial_obj_addr();
|
||||
split_region = addr_to_region_idx(overflow_obj);
|
||||
// source-regions:
|
||||
//
|
||||
// ***************
|
||||
// | A|AA |
|
||||
// ***************
|
||||
// ^
|
||||
// | split-point
|
||||
//
|
||||
// dest-region:
|
||||
//
|
||||
// ********
|
||||
// |~~~~A |
|
||||
// ********
|
||||
// ^^
|
||||
// || target-space-end
|
||||
// |
|
||||
// | destination
|
||||
//
|
||||
// AAA would overflow target-space.
|
||||
//
|
||||
HeapWord* overflowing_obj = _region_data[src_region].partial_obj_addr();
|
||||
size_t split_region = addr_to_region_idx(overflowing_obj);
|
||||
|
||||
// Clear the source_region field of all destination regions whose first word
|
||||
// came from data after the split point (a non-null source_region field
|
||||
// implies a region must be filled).
|
||||
//
|
||||
// An alternative to the simple loop below: clear during post_compact(),
|
||||
// which uses memcpy instead of individual stores, and is easy to
|
||||
// parallelize. (The downside is that it clears the entire RegionData
|
||||
// object as opposed to just one field.)
|
||||
//
|
||||
// post_compact() would have to clear the summary data up to the highest
|
||||
// address that was written during the summary phase, which would be
|
||||
//
|
||||
// max(top, max(new_top, clear_top))
|
||||
//
|
||||
// where clear_top is a new field in SpaceInfo. Would have to set clear_top
|
||||
// to target_end.
|
||||
const RegionData* const sr = region(split_region);
|
||||
const size_t beg_idx =
|
||||
addr_to_region_idx(region_align_up(sr->destination() +
|
||||
sr->partial_obj_size()));
|
||||
const size_t end_idx = addr_to_region_idx(target_end);
|
||||
|
||||
log_develop_trace(gc, compaction)("split: clearing source_region field in [" SIZE_FORMAT ", " SIZE_FORMAT ")", beg_idx, end_idx);
|
||||
for (size_t idx = beg_idx; idx < end_idx; ++idx) {
|
||||
_region_data[idx].set_source_region(0);
|
||||
// The number of live words before the overflowing object on this split region
|
||||
size_t preceding_live_words;
|
||||
if (is_region_aligned(overflowing_obj)) {
|
||||
preceding_live_words = 0;
|
||||
} else {
|
||||
// Words accounted by the overflowing object on the split region
|
||||
size_t overflowing_size = pointer_delta(region_align_up(overflowing_obj), overflowing_obj);
|
||||
preceding_live_words = region(split_region)->data_size() - overflowing_size;
|
||||
}
|
||||
|
||||
// Set split_destination and partial_obj_size to reflect the split region.
|
||||
split_destination = sr->destination();
|
||||
partial_obj_size = sr->partial_obj_size();
|
||||
}
|
||||
split_info.record(split_region, overflowing_obj, preceding_live_words);
|
||||
|
||||
// The split is recorded only if a partial object extends onto the region.
|
||||
if (partial_obj_size != 0) {
|
||||
_region_data[split_region].set_partial_obj_size(0);
|
||||
split_info.record(split_region, partial_obj_size, split_destination);
|
||||
}
|
||||
HeapWord* src_region_start = region_to_addr(src_region);
|
||||
HeapWord* new_top = destination - pointer_delta(src_region_start, overflowing_obj);
|
||||
|
||||
// Setup the continuation addresses.
|
||||
*target_next = split_destination + partial_obj_size;
|
||||
HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size;
|
||||
|
||||
if (log_develop_is_enabled(Trace, gc, compaction)) {
|
||||
const char * split_type = partial_obj_size == 0 ? "easy" : "hard";
|
||||
log_develop_trace(gc, compaction)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT,
|
||||
split_type, p2i(source_next), split_region, partial_obj_size);
|
||||
log_develop_trace(gc, compaction)("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT " tn=" PTR_FORMAT,
|
||||
split_type, p2i(split_destination),
|
||||
addr_to_region_idx(split_destination),
|
||||
p2i(*target_next));
|
||||
|
||||
if (partial_obj_size != 0) {
|
||||
HeapWord* const po_beg = split_info.destination();
|
||||
HeapWord* const po_end = po_beg + split_info.partial_obj_size();
|
||||
log_develop_trace(gc, compaction)("%s split: po_beg=" PTR_FORMAT " " SIZE_FORMAT " po_end=" PTR_FORMAT " " SIZE_FORMAT,
|
||||
split_type,
|
||||
p2i(po_beg), addr_to_region_idx(po_beg),
|
||||
p2i(po_end), addr_to_region_idx(po_end));
|
||||
// If the overflowing obj was relocated to its original destination,
|
||||
// those destination regions would have their source_region set. Now that
|
||||
// this overflowing obj is relocated somewhere else, reset the
|
||||
// source_region.
|
||||
{
|
||||
size_t range_start = addr_to_region_idx(region_align_up(new_top));
|
||||
size_t range_end = addr_to_region_idx(region_align_up(destination));
|
||||
for (size_t i = range_start; i < range_end; ++i) {
|
||||
region(i)->set_source_region(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Update new top of target space
|
||||
*target_next = new_top;
|
||||
|
||||
return overflowing_obj;
|
||||
}
|
||||
|
||||
return source_next;
|
||||
// Obj-iteration to locate the overflowing obj
|
||||
HeapWord* region_start = region_to_addr(src_region);
|
||||
HeapWord* region_end = region_start + RegionSize;
|
||||
HeapWord* cur_addr = region_start + partial_obj_size;
|
||||
size_t live_words = partial_obj_size;
|
||||
|
||||
while (true) {
|
||||
assert(cur_addr < region_end, "inv");
|
||||
cur_addr = PSParallelCompact::mark_bitmap()->find_obj_beg(cur_addr, region_end);
|
||||
// There must be an overflowing obj in this region
|
||||
assert(cur_addr < region_end, "inv");
|
||||
|
||||
oop obj = cast_to_oop(cur_addr);
|
||||
size_t obj_size = obj->size();
|
||||
if (destination + live_words + obj_size > target_end) {
|
||||
// Found the overflowing obj
|
||||
split_info.record(src_region, cur_addr, live_words);
|
||||
*target_next = destination + live_words;
|
||||
return cur_addr;
|
||||
}
|
||||
|
||||
live_words += obj_size;
|
||||
cur_addr += obj_size;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ParallelCompactData::live_words_in_space(const MutableSpace* space,
|
||||
@ -452,70 +458,57 @@ bool ParallelCompactData::summarize(SplitInfo& split_info,
|
||||
const size_t end_region = addr_to_region_idx(region_align_up(source_end));
|
||||
|
||||
HeapWord *dest_addr = target_beg;
|
||||
while (cur_region < end_region) {
|
||||
// The destination must be set even if the region has no data.
|
||||
_region_data[cur_region].set_destination(dest_addr);
|
||||
|
||||
for (/* empty */; cur_region < end_region; cur_region++) {
|
||||
size_t words = _region_data[cur_region].data_size();
|
||||
if (words > 0) {
|
||||
// If cur_region does not fit entirely into the target space, find a point
|
||||
// at which the source space can be 'split' so that part is copied to the
|
||||
// target space and the rest is copied elsewhere.
|
||||
if (dest_addr + words > target_end) {
|
||||
assert(source_next != nullptr, "source_next is null when splitting");
|
||||
*source_next = summarize_split_space(cur_region, split_info, dest_addr,
|
||||
target_end, target_next);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the destination_count for cur_region, and if necessary, update
|
||||
// source_region for a destination region. The source_region field is
|
||||
// updated if cur_region is the first (left-most) region to be copied to a
|
||||
// destination region.
|
||||
//
|
||||
// The destination_count calculation is a bit subtle. A region that has
|
||||
// data that compacts into itself does not count itself as a destination.
|
||||
// This maintains the invariant that a zero count means the region is
|
||||
// available and can be claimed and then filled.
|
||||
uint destination_count = 0;
|
||||
if (split_info.is_split(cur_region)) {
|
||||
// The current region has been split: the partial object will be copied
|
||||
// to one destination space and the remaining data will be copied to
|
||||
// another destination space. Adjust the initial destination_count and,
|
||||
// if necessary, set the source_region field if the partial object will
|
||||
// cross a destination region boundary.
|
||||
destination_count = split_info.destination_count();
|
||||
if (destination_count == 2) {
|
||||
size_t dest_idx = addr_to_region_idx(split_info.dest_region_addr());
|
||||
_region_data[dest_idx].set_source_region(cur_region);
|
||||
}
|
||||
}
|
||||
|
||||
HeapWord* const last_addr = dest_addr + words - 1;
|
||||
const size_t dest_region_1 = addr_to_region_idx(dest_addr);
|
||||
const size_t dest_region_2 = addr_to_region_idx(last_addr);
|
||||
|
||||
// Initially assume that the destination regions will be the same and
|
||||
// adjust the value below if necessary. Under this assumption, if
|
||||
// cur_region == dest_region_2, then cur_region will be compacted
|
||||
// completely into itself.
|
||||
destination_count += cur_region == dest_region_2 ? 0 : 1;
|
||||
if (dest_region_1 != dest_region_2) {
|
||||
// Destination regions differ; adjust destination_count.
|
||||
destination_count += 1;
|
||||
// Data from cur_region will be copied to the start of dest_region_2.
|
||||
_region_data[dest_region_2].set_source_region(cur_region);
|
||||
} else if (is_region_aligned(dest_addr)) {
|
||||
// Data from cur_region will be copied to the start of the destination
|
||||
// region.
|
||||
_region_data[dest_region_1].set_source_region(cur_region);
|
||||
}
|
||||
|
||||
_region_data[cur_region].set_destination_count(destination_count);
|
||||
dest_addr += words;
|
||||
// Skip empty ones
|
||||
if (words == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++cur_region;
|
||||
if (split_info.is_split(cur_region)) {
|
||||
assert(words > split_info.preceding_live_words(), "inv");
|
||||
words -= split_info.preceding_live_words();
|
||||
}
|
||||
|
||||
_region_data[cur_region].set_destination(dest_addr);
|
||||
|
||||
// If cur_region does not fit entirely into the target space, find a point
|
||||
// at which the source space can be 'split' so that part is copied to the
|
||||
// target space and the rest is copied elsewhere.
|
||||
if (dest_addr + words > target_end) {
|
||||
assert(source_next != nullptr, "source_next is null when splitting");
|
||||
*source_next = summarize_split_space(cur_region, split_info, dest_addr,
|
||||
target_end, target_next);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint destination_count = split_info.is_split(cur_region)
|
||||
? split_info.preceding_destination_count()
|
||||
: 0;
|
||||
|
||||
HeapWord* const last_addr = dest_addr + words - 1;
|
||||
const size_t dest_region_1 = addr_to_region_idx(dest_addr);
|
||||
const size_t dest_region_2 = addr_to_region_idx(last_addr);
|
||||
|
||||
// Initially assume that the destination regions will be the same and
|
||||
// adjust the value below if necessary. Under this assumption, if
|
||||
// cur_region == dest_region_2, then cur_region will be compacted
|
||||
// completely into itself.
|
||||
destination_count += cur_region == dest_region_2 ? 0 : 1;
|
||||
if (dest_region_1 != dest_region_2) {
|
||||
// Destination regions differ; adjust destination_count.
|
||||
destination_count += 1;
|
||||
// Data from cur_region will be copied to the start of dest_region_2.
|
||||
_region_data[dest_region_2].set_source_region(cur_region);
|
||||
} else if (is_region_aligned(dest_addr)) {
|
||||
// Data from cur_region will be copied to the start of the destination
|
||||
// region.
|
||||
_region_data[dest_region_1].set_source_region(cur_region);
|
||||
}
|
||||
|
||||
_region_data[cur_region].set_destination_count(destination_count);
|
||||
dest_addr += words;
|
||||
}
|
||||
|
||||
*target_next = dest_addr;
|
||||
@ -523,12 +516,12 @@ bool ParallelCompactData::summarize(SplitInfo& split_info,
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void ParallelCompactData::verify_clear()
|
||||
{
|
||||
const size_t* const beg = (const size_t*) _region_vspace->committed_low_addr();
|
||||
const size_t* const end = (const size_t*) _region_vspace->committed_high_addr();
|
||||
for (const size_t* p = beg; p < end; ++p) {
|
||||
assert(*p == 0, "not zero");
|
||||
void ParallelCompactData::verify_clear() {
|
||||
for (uint cur_idx = 0; cur_idx < region_count(); ++cur_idx) {
|
||||
if (!region(cur_idx)->is_clear()) {
|
||||
log_warning(gc)("Uncleared Region: %u", cur_idx);
|
||||
region(cur_idx)->verify_clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // #ifdef ASSERT
|
||||
@ -695,6 +688,13 @@ void PSParallelCompact::post_compact()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
{
|
||||
mark_bitmap()->verify_clear();
|
||||
summary_data().verify_clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
ParCompactionManager::flush_all_string_dedup_requests();
|
||||
|
||||
MutableSpace* const eden_space = _space_info[eden_space_id].space();
|
||||
@ -878,10 +878,10 @@ void PSParallelCompact::summary_phase()
|
||||
bool maximum_compaction = check_maximum_compaction(total_live_words,
|
||||
old_space,
|
||||
full_region_prefix_end);
|
||||
HeapWord* dense_prefix_end =
|
||||
maximum_compaction ? full_region_prefix_end
|
||||
: compute_dense_prefix_for_old_space(old_space,
|
||||
full_region_prefix_end);
|
||||
HeapWord* dense_prefix_end = maximum_compaction
|
||||
? full_region_prefix_end
|
||||
: compute_dense_prefix_for_old_space(old_space,
|
||||
full_region_prefix_end);
|
||||
SpaceId id = old_space_id;
|
||||
_space_info[id].set_dense_prefix(dense_prefix_end);
|
||||
|
||||
@ -889,6 +889,8 @@ void PSParallelCompact::summary_phase()
|
||||
fill_dense_prefix_end(id);
|
||||
_summary_data.summarize_dense_prefix(old_space->bottom(), dense_prefix_end);
|
||||
}
|
||||
|
||||
// Compacting objs inn [dense_prefix_end, old_space->top())
|
||||
_summary_data.summarize(_space_info[id].split_info(),
|
||||
dense_prefix_end, old_space->top(), nullptr,
|
||||
dense_prefix_end, old_space->end(),
|
||||
@ -1548,6 +1550,30 @@ void PSParallelCompact::forward_to_new_addr() {
|
||||
WorkerTask("PSForward task"),
|
||||
_num_workers(num_workers) {}
|
||||
|
||||
static void forward_objs_in_range(ParCompactionManager* cm,
|
||||
HeapWord* start,
|
||||
HeapWord* end,
|
||||
HeapWord* destination) {
|
||||
HeapWord* cur_addr = start;
|
||||
HeapWord* new_addr = destination;
|
||||
|
||||
while (cur_addr < end) {
|
||||
cur_addr = mark_bitmap()->find_obj_beg(cur_addr, end);
|
||||
if (cur_addr >= end) {
|
||||
return;
|
||||
}
|
||||
assert(mark_bitmap()->is_marked(cur_addr), "inv");
|
||||
oop obj = cast_to_oop(cur_addr);
|
||||
if (new_addr != cur_addr) {
|
||||
cm->preserved_marks()->push_if_necessary(obj, obj->mark());
|
||||
FullGCForwarding::forward_to(obj, cast_to_oop(new_addr));
|
||||
}
|
||||
size_t obj_size = obj->size();
|
||||
new_addr += obj_size;
|
||||
cur_addr += obj_size;
|
||||
}
|
||||
}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id);
|
||||
for (uint id = old_space_id; id < last_space_id; ++id) {
|
||||
@ -1559,6 +1585,8 @@ void PSParallelCompact::forward_to_new_addr() {
|
||||
continue;
|
||||
}
|
||||
|
||||
const SplitInfo& split_info = _space_info[SpaceId(id)].split_info();
|
||||
|
||||
size_t dense_prefix_region = _summary_data.addr_to_region_idx(dense_prefix_addr);
|
||||
size_t top_region = _summary_data.addr_to_region_idx(_summary_data.region_align_up(top));
|
||||
size_t start_region;
|
||||
@ -1578,24 +1606,19 @@ void PSParallelCompact::forward_to_new_addr() {
|
||||
HeapWord* region_start = _summary_data.region_to_addr(cur_region);
|
||||
HeapWord* region_end = region_start + ParallelCompactData::RegionSize;
|
||||
|
||||
HeapWord* cur_addr = region_start + live_words;
|
||||
|
||||
HeapWord* destination = region_ptr->destination();
|
||||
while (cur_addr < region_end) {
|
||||
cur_addr = mark_bitmap()->find_obj_beg(cur_addr, region_end);
|
||||
if (cur_addr >= region_end) {
|
||||
break;
|
||||
}
|
||||
assert(mark_bitmap()->is_marked(cur_addr), "inv");
|
||||
HeapWord* new_addr = destination + live_words;
|
||||
oop obj = cast_to_oop(cur_addr);
|
||||
if (new_addr != cur_addr) {
|
||||
cm->preserved_marks()->push_if_necessary(obj, obj->mark());
|
||||
FullGCForwarding::forward_to(obj, cast_to_oop(new_addr));
|
||||
}
|
||||
size_t obj_size = obj->size();
|
||||
live_words += obj_size;
|
||||
cur_addr += obj_size;
|
||||
if (split_info.is_split(cur_region)) {
|
||||
// Part 1: will be relocated to space-1
|
||||
HeapWord* preceding_destination = split_info.preceding_destination();
|
||||
HeapWord* split_point = split_info.split_point();
|
||||
forward_objs_in_range(cm, region_start + live_words, split_point, preceding_destination + live_words);
|
||||
|
||||
// Part 2: will be relocated to space-2
|
||||
HeapWord* destination = region_ptr->destination();
|
||||
forward_objs_in_range(cm, split_point, region_end, destination);
|
||||
} else {
|
||||
HeapWord* destination = region_ptr->destination();
|
||||
forward_objs_in_range(cm, region_start + live_words, region_end, destination + live_words);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1627,13 +1650,16 @@ void PSParallelCompact::verify_forward() {
|
||||
break;
|
||||
}
|
||||
assert(mark_bitmap()->is_marked(cur_addr), "inv");
|
||||
assert(bump_ptr <= _space_info[bump_ptr_space].new_top(), "inv");
|
||||
// Move to the space containing cur_addr
|
||||
if (bump_ptr == _space_info[bump_ptr_space].new_top()) {
|
||||
bump_ptr = space(space_id(cur_addr))->bottom();
|
||||
bump_ptr_space = space_id(bump_ptr);
|
||||
}
|
||||
oop obj = cast_to_oop(cur_addr);
|
||||
if (cur_addr != bump_ptr) {
|
||||
if (cur_addr == bump_ptr) {
|
||||
assert(!FullGCForwarding::is_forwarded(obj), "inv");
|
||||
} else {
|
||||
assert(FullGCForwarding::forwardee(obj) == cast_to_oop(bump_ptr), "inv");
|
||||
}
|
||||
bump_ptr += obj->size();
|
||||
@ -1939,15 +1965,10 @@ PSParallelCompact::SpaceId PSParallelCompact::space_id(HeapWord* addr) {
|
||||
}
|
||||
|
||||
// Skip over count live words starting from beg, and return the address of the
|
||||
// next live word. Unless marked, the word corresponding to beg is assumed to
|
||||
// be dead. Callers must either ensure beg does not correspond to the middle of
|
||||
// an object, or account for those live words in some other way. Callers must
|
||||
// also ensure that there are enough live words in the range [beg, end) to skip.
|
||||
HeapWord*
|
||||
PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count)
|
||||
// next live word. Callers must also ensure that there are enough live words in
|
||||
// the range [beg, end) to skip.
|
||||
HeapWord* PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count)
|
||||
{
|
||||
assert(count > 0, "sanity");
|
||||
|
||||
ParMarkBitMap* m = mark_bitmap();
|
||||
HeapWord* cur_addr = beg;
|
||||
while (true) {
|
||||
@ -1963,69 +1984,94 @@ PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count)
|
||||
}
|
||||
}
|
||||
|
||||
// On filling a destination region (dest-region), we need to know the location
|
||||
// of the word that will be at the start of the dest-region after compaction.
|
||||
// A dest-region can have one or more source regions, but only the first
|
||||
// source-region contains this location. This location is retrieved by calling
|
||||
// `first_src_addr` on a dest-region.
|
||||
// Conversely, a source-region has a dest-region which holds the destination of
|
||||
// the first live word on this source-region, based on which the destination
|
||||
// for the rest of live words can be derived.
|
||||
//
|
||||
// Note:
|
||||
// There is some complication due to space-boundary-fragmentation (an obj can't
|
||||
// cross space-boundary) -- a source-region may be split and behave like two
|
||||
// distinct regions with their own dest-region, as depicted below.
|
||||
//
|
||||
// source-region: region-n
|
||||
//
|
||||
// **********************
|
||||
// | A|A~~~~B|B |
|
||||
// **********************
|
||||
// n-1 n n+1
|
||||
//
|
||||
// AA, BB denote two live objs. ~~~~ denotes unknown number of live objs.
|
||||
//
|
||||
// Assuming the dest-region for region-n is the final region before
|
||||
// old-space-end and its first-live-word is the middle of AA, the heap content
|
||||
// will look like the following after compaction:
|
||||
//
|
||||
// ************** *************
|
||||
// A|A~~~~ | |BB |
|
||||
// ************** *************
|
||||
// ^ ^
|
||||
// | old-space-end | eden-space-start
|
||||
//
|
||||
// Therefore, in this example, region-n will have two dest-regions, one for
|
||||
// the final region in old-space and the other for the first region in
|
||||
// eden-space.
|
||||
// To handle this special case, we introduce the concept of split-region, whose
|
||||
// contents are relocated to two spaces. `SplitInfo` captures all necessary
|
||||
// info about the split, the first part, spliting-point, and the second part.
|
||||
HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr,
|
||||
SpaceId src_space_id,
|
||||
size_t src_region_idx)
|
||||
{
|
||||
assert(summary_data().is_region_aligned(dest_addr), "not aligned");
|
||||
|
||||
const SplitInfo& split_info = _space_info[src_space_id].split_info();
|
||||
if (split_info.dest_region_addr() == dest_addr) {
|
||||
// The partial object ending at the split point contains the first word to
|
||||
// be copied to dest_addr.
|
||||
return split_info.first_src_addr();
|
||||
}
|
||||
|
||||
const ParallelCompactData& sd = summary_data();
|
||||
ParMarkBitMap* const bitmap = mark_bitmap();
|
||||
const size_t RegionSize = ParallelCompactData::RegionSize;
|
||||
const ParallelCompactData& sd = summary_data();
|
||||
assert(sd.is_region_aligned(dest_addr), "precondition");
|
||||
|
||||
assert(sd.is_region_aligned(dest_addr), "not aligned");
|
||||
const RegionData* const src_region_ptr = sd.region(src_region_idx);
|
||||
assert(src_region_ptr->data_size() > 0, "src region cannot be empty");
|
||||
|
||||
const size_t partial_obj_size = src_region_ptr->partial_obj_size();
|
||||
HeapWord* const src_region_destination = src_region_ptr->destination();
|
||||
|
||||
assert(dest_addr >= src_region_destination, "wrong src region");
|
||||
assert(src_region_ptr->data_size() > 0, "src region cannot be empty");
|
||||
HeapWord* const region_start = sd.region_to_addr(src_region_idx);
|
||||
HeapWord* const region_end = sd.region_to_addr(src_region_idx) + RegionSize;
|
||||
|
||||
HeapWord* const src_region_beg = sd.region_to_addr(src_region_idx);
|
||||
HeapWord* const src_region_end = src_region_beg + RegionSize;
|
||||
|
||||
HeapWord* addr = src_region_beg;
|
||||
if (dest_addr == src_region_destination) {
|
||||
// Return the first live word in the source region.
|
||||
if (partial_obj_size == 0) {
|
||||
addr = bitmap->find_obj_beg(addr, src_region_end);
|
||||
assert(addr < src_region_end, "no objects start in src region");
|
||||
// Identify the actual destination for the first live words on this region,
|
||||
// taking split-region into account.
|
||||
HeapWord* region_start_destination;
|
||||
const SplitInfo& split_info = _space_info[src_space_id].split_info();
|
||||
if (split_info.is_split(src_region_idx)) {
|
||||
// The second part of this split region; use the recorded split point.
|
||||
if (dest_addr == src_region_destination) {
|
||||
return split_info.split_point();
|
||||
}
|
||||
return addr;
|
||||
region_start_destination = split_info.preceding_destination();
|
||||
} else {
|
||||
region_start_destination = src_region_destination;
|
||||
}
|
||||
|
||||
// Must skip some live data.
|
||||
size_t words_to_skip = dest_addr - src_region_destination;
|
||||
assert(src_region_ptr->data_size() > words_to_skip, "wrong src region");
|
||||
// Calculate the offset to be skipped
|
||||
size_t words_to_skip = pointer_delta(dest_addr, region_start_destination);
|
||||
|
||||
if (partial_obj_size >= words_to_skip) {
|
||||
// All the live words to skip are part of the partial object.
|
||||
addr += words_to_skip;
|
||||
if (partial_obj_size == words_to_skip) {
|
||||
// Find the first live word past the partial object.
|
||||
addr = bitmap->find_obj_beg(addr, src_region_end);
|
||||
assert(addr < src_region_end, "wrong src region");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
// Skip over the partial object (if any).
|
||||
if (partial_obj_size != 0) {
|
||||
HeapWord* result;
|
||||
if (partial_obj_size > words_to_skip) {
|
||||
result = region_start + words_to_skip;
|
||||
} else {
|
||||
words_to_skip -= partial_obj_size;
|
||||
addr += partial_obj_size;
|
||||
result = skip_live_words(region_start + partial_obj_size, region_end, words_to_skip);
|
||||
}
|
||||
|
||||
// Skip over live words due to objects that start in the region.
|
||||
addr = skip_live_words(addr, src_region_end, words_to_skip);
|
||||
assert(addr < src_region_end, "wrong src region");
|
||||
return addr;
|
||||
if (split_info.is_split(src_region_idx)) {
|
||||
assert(result < split_info.split_point(), "postcondition");
|
||||
} else {
|
||||
assert(result < region_end, "postcondition");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PSParallelCompact::decrement_destination_counts(ParCompactionManager* cm,
|
||||
@ -2076,10 +2122,7 @@ size_t PSParallelCompact::next_src_region(MoveAndUpdateClosure& closure,
|
||||
HeapWord*& src_space_top,
|
||||
HeapWord* end_addr)
|
||||
{
|
||||
typedef ParallelCompactData::RegionData RegionData;
|
||||
|
||||
ParallelCompactData& sd = PSParallelCompact::summary_data();
|
||||
const size_t region_size = ParallelCompactData::RegionSize;
|
||||
|
||||
size_t src_region_idx = 0;
|
||||
|
||||
@ -2087,8 +2130,8 @@ size_t PSParallelCompact::next_src_region(MoveAndUpdateClosure& closure,
|
||||
HeapWord* const src_aligned_up = sd.region_align_up(end_addr);
|
||||
RegionData* src_region_ptr = sd.addr_to_region_ptr(src_aligned_up);
|
||||
HeapWord* const top_aligned_up = sd.region_align_up(src_space_top);
|
||||
const RegionData* const top_region_ptr =
|
||||
sd.addr_to_region_ptr(top_aligned_up);
|
||||
const RegionData* const top_region_ptr = sd.addr_to_region_ptr(top_aligned_up);
|
||||
|
||||
while (src_region_ptr < top_region_ptr && src_region_ptr->data_size() == 0) {
|
||||
++src_region_ptr;
|
||||
}
|
||||
@ -2105,59 +2148,50 @@ size_t PSParallelCompact::next_src_region(MoveAndUpdateClosure& closure,
|
||||
}
|
||||
|
||||
// Switch to a new source space and find the first non-empty region.
|
||||
unsigned int space_id = src_space_id + 1;
|
||||
uint space_id = src_space_id + 1;
|
||||
assert(space_id < last_space_id, "not enough spaces");
|
||||
|
||||
HeapWord* const destination = closure.destination();
|
||||
for (/* empty */; space_id < last_space_id; ++space_id) {
|
||||
HeapWord* bottom = _space_info[space_id].space()->bottom();
|
||||
HeapWord* top = _space_info[space_id].space()->top();
|
||||
// Skip empty space
|
||||
if (bottom == top) {
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
MutableSpace* space = _space_info[space_id].space();
|
||||
HeapWord* const bottom = space->bottom();
|
||||
const RegionData* const bottom_cp = sd.addr_to_region_ptr(bottom);
|
||||
// Identify the first region that contains live words in this space
|
||||
size_t cur_region = sd.addr_to_region_idx(bottom);
|
||||
size_t end_region = sd.addr_to_region_idx(sd.region_align_up(top));
|
||||
|
||||
// Iterate over the spaces that do not compact into themselves.
|
||||
if (bottom_cp->destination() != bottom) {
|
||||
HeapWord* const top_aligned_up = sd.region_align_up(space->top());
|
||||
const RegionData* const top_cp = sd.addr_to_region_ptr(top_aligned_up);
|
||||
for (/* empty */ ; cur_region < end_region; ++cur_region) {
|
||||
RegionData* cur = sd.region(cur_region);
|
||||
if (cur->live_obj_size() > 0) {
|
||||
HeapWord* region_start_addr = sd.region_to_addr(cur_region);
|
||||
HeapWord* region_end_addr = region_start_addr + ParallelCompactData::RegionSize;
|
||||
HeapWord* first_live_word = mark_bitmap()->find_obj_beg(region_start_addr, region_end_addr);
|
||||
assert(first_live_word < region_end_addr, "inv");
|
||||
|
||||
for (const RegionData* src_cp = bottom_cp; src_cp < top_cp; ++src_cp) {
|
||||
if (src_cp->live_obj_size() > 0) {
|
||||
// Found it.
|
||||
assert(src_cp->destination() == destination,
|
||||
"first live obj in the space must match the destination");
|
||||
assert(src_cp->partial_obj_size() == 0,
|
||||
"a space cannot begin with a partial obj");
|
||||
|
||||
src_space_id = SpaceId(space_id);
|
||||
src_space_top = space->top();
|
||||
const size_t src_region_idx = sd.region(src_cp);
|
||||
closure.set_source(sd.region_to_addr(src_region_idx));
|
||||
return src_region_idx;
|
||||
} else {
|
||||
assert(src_cp->data_size() == 0, "sanity");
|
||||
}
|
||||
src_space_id = SpaceId(space_id);
|
||||
src_space_top = top;
|
||||
closure.set_source(first_live_word);
|
||||
return cur_region;
|
||||
}
|
||||
}
|
||||
} while (++space_id < last_space_id);
|
||||
}
|
||||
|
||||
assert(false, "no source region was found");
|
||||
return 0;
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
HeapWord* PSParallelCompact::partial_obj_end(HeapWord* region_start_addr) {
|
||||
ParallelCompactData& sd = summary_data();
|
||||
assert(sd.is_region_aligned(region_start_addr), "precondition");
|
||||
|
||||
// Use per-region partial_obj_size to locate the end of the obj, that extends to region_start_addr.
|
||||
SplitInfo& split_info = _space_info[space_id(region_start_addr)].split_info();
|
||||
// Use per-region partial_obj_size to locate the end of the obj, that extends
|
||||
// to region_start_addr.
|
||||
size_t start_region_idx = sd.addr_to_region_idx(region_start_addr);
|
||||
size_t end_region_idx = sd.region_count();
|
||||
size_t accumulated_size = 0;
|
||||
for (size_t region_idx = start_region_idx; region_idx < end_region_idx; ++region_idx) {
|
||||
if (split_info.is_split(region_idx)) {
|
||||
accumulated_size += split_info.partial_obj_size();
|
||||
break;
|
||||
}
|
||||
size_t cur_partial_obj_size = sd.region(region_idx)->partial_obj_size();
|
||||
accumulated_size += cur_partial_obj_size;
|
||||
if (cur_partial_obj_size != ParallelCompactData::RegionSize) {
|
||||
@ -2167,6 +2201,8 @@ HeapWord* PSParallelCompact::partial_obj_end(HeapWord* region_start_addr) {
|
||||
return region_start_addr + accumulated_size;
|
||||
}
|
||||
|
||||
// Use region_idx as the destination region, and evacuate all live objs on its
|
||||
// source regions to this destination region.
|
||||
void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosure& closure, size_t region_idx)
|
||||
{
|
||||
ParMarkBitMap* const bitmap = mark_bitmap();
|
||||
@ -2187,20 +2223,43 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu
|
||||
src_region_idx += 1;
|
||||
}
|
||||
|
||||
// source-region:
|
||||
//
|
||||
// **********
|
||||
// | ~~~ |
|
||||
// **********
|
||||
// ^
|
||||
// |-- closure.source() / first_src_addr
|
||||
//
|
||||
//
|
||||
// ~~~ : live words
|
||||
//
|
||||
// destination-region:
|
||||
//
|
||||
// **********
|
||||
// | |
|
||||
// **********
|
||||
// ^
|
||||
// |-- region-start
|
||||
if (bitmap->is_unmarked(closure.source())) {
|
||||
// The first source word is in the middle of an object; copy the remainder
|
||||
// of the object or as much as will fit. The fact that pointer updates were
|
||||
// deferred will be noted when the object header is processed.
|
||||
// An object overflows the previous destination region, so this
|
||||
// destination region should copy the remainder of the object or as much as
|
||||
// will fit.
|
||||
HeapWord* const old_src_addr = closure.source();
|
||||
{
|
||||
HeapWord* region_start = sd.region_align_down(closure.source());
|
||||
HeapWord* obj_start = bitmap->find_obj_beg_reverse(region_start, closure.source());
|
||||
HeapWord* obj_end;
|
||||
if (bitmap->is_marked(obj_start)) {
|
||||
if (obj_start != closure.source()) {
|
||||
assert(bitmap->is_marked(obj_start), "inv");
|
||||
// Found the actual obj-start, try to find the obj-end using either
|
||||
// size() if this obj is completely contained in the current region.
|
||||
HeapWord* next_region_start = region_start + ParallelCompactData::RegionSize;
|
||||
HeapWord* partial_obj_start = (next_region_start >= src_space_top)
|
||||
? nullptr
|
||||
: sd.addr_to_region_ptr(next_region_start)->partial_obj_addr();
|
||||
// This obj extends to next region iff partial_obj_addr of the *next*
|
||||
// region is the same as obj-start.
|
||||
if (partial_obj_start == obj_start) {
|
||||
// This obj extends to next region.
|
||||
obj_end = partial_obj_end(next_region_start);
|
||||
@ -2217,39 +2276,41 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu
|
||||
}
|
||||
|
||||
if (closure.is_full()) {
|
||||
decrement_destination_counts(cm, src_space_id, src_region_idx,
|
||||
closure.source());
|
||||
decrement_destination_counts(cm, src_space_id, src_region_idx, closure.source());
|
||||
closure.complete_region(dest_addr, region_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Finished copying without using up the current destination-region
|
||||
HeapWord* const end_addr = sd.region_align_down(closure.source());
|
||||
if (sd.region_align_down(old_src_addr) != end_addr) {
|
||||
assert(sd.region_align_up(old_src_addr) == end_addr, "only one region");
|
||||
// The partial object was copied from more than one source region.
|
||||
decrement_destination_counts(cm, src_space_id, src_region_idx, end_addr);
|
||||
|
||||
// Move to the next source region, possibly switching spaces as well. All
|
||||
// args except end_addr may be modified.
|
||||
src_region_idx = next_src_region(closure, src_space_id, src_space_top,
|
||||
end_addr);
|
||||
src_region_idx = next_src_region(closure, src_space_id, src_space_top, end_addr);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the rest obj-by-obj, where we know obj-start.
|
||||
do {
|
||||
HeapWord* cur_addr = closure.source();
|
||||
HeapWord* const end_addr = MIN2(sd.region_align_up(cur_addr + 1),
|
||||
src_space_top);
|
||||
HeapWord* partial_obj_start = (end_addr == src_space_top)
|
||||
// To handle the case where the final obj in source region extends to next region.
|
||||
HeapWord* final_obj_start = (end_addr == src_space_top)
|
||||
? nullptr
|
||||
: sd.addr_to_region_ptr(end_addr)->partial_obj_addr();
|
||||
// apply closure on objs inside [cur_addr, end_addr)
|
||||
// Apply closure on objs inside [cur_addr, end_addr)
|
||||
do {
|
||||
cur_addr = bitmap->find_obj_beg(cur_addr, end_addr);
|
||||
if (cur_addr == end_addr) {
|
||||
break;
|
||||
}
|
||||
size_t obj_size;
|
||||
if (partial_obj_start == cur_addr) {
|
||||
if (final_obj_start == cur_addr) {
|
||||
obj_size = pointer_delta(partial_obj_end(end_addr), cur_addr);
|
||||
} else {
|
||||
// This obj doesn't extend into next region; size() is safe to use.
|
||||
@ -2260,8 +2321,7 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu
|
||||
} while (cur_addr < end_addr && !closure.is_full());
|
||||
|
||||
if (closure.is_full()) {
|
||||
decrement_destination_counts(cm, src_space_id, src_region_idx,
|
||||
closure.source());
|
||||
decrement_destination_counts(cm, src_space_id, src_region_idx, closure.source());
|
||||
closure.complete_region(dest_addr, region_ptr);
|
||||
return;
|
||||
}
|
||||
@ -2270,8 +2330,7 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu
|
||||
|
||||
// Move to the next source region, possibly switching spaces as well. All
|
||||
// args except end_addr may be modified.
|
||||
src_region_idx = next_src_region(closure, src_space_id, src_space_top,
|
||||
end_addr);
|
||||
src_region_idx = next_src_region(closure, src_space_id, src_space_top, end_addr);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
@ -116,51 +116,45 @@ public:
|
||||
// Return true if this split info is valid (i.e., if a split has been
|
||||
// recorded). The very first region cannot have a partial object and thus is
|
||||
// never split, so 0 is the 'invalid' value.
|
||||
bool is_valid() const { return _src_region_idx > 0; }
|
||||
bool is_valid() const { return _split_region_idx > 0; }
|
||||
|
||||
// Return true if this split holds data for the specified source region.
|
||||
inline bool is_split(size_t source_region) const;
|
||||
inline bool is_split(size_t region_idx) const;
|
||||
|
||||
// The index of the split region, the size of the partial object on that
|
||||
// region and the destination of the partial object.
|
||||
size_t partial_obj_size() const { return _partial_obj_size; }
|
||||
HeapWord* destination() const { return _destination; }
|
||||
// Obj at the split point doesn't fit the previous space and will be relocated to the next space.
|
||||
HeapWord* split_point() const { return _split_point; }
|
||||
|
||||
// The destination count of the partial object referenced by this split
|
||||
// (either 1 or 2). This must be added to the destination count of the
|
||||
// remainder of the source region.
|
||||
unsigned int destination_count() const { return _destination_count; }
|
||||
// Number of live words before the split point on this region.
|
||||
size_t preceding_live_words() const { return _preceding_live_words; }
|
||||
|
||||
// If a word within the partial object will be written to the first word of a
|
||||
// destination region, this is the address of the destination region;
|
||||
// otherwise this is null.
|
||||
HeapWord* dest_region_addr() const { return _dest_region_addr; }
|
||||
// A split region has two "destinations", living in two spaces. This method
|
||||
// returns the first one -- destination for the first live word on
|
||||
// this split region.
|
||||
HeapWord* preceding_destination() const {
|
||||
assert(_preceding_destination != nullptr, "inv");
|
||||
return _preceding_destination;
|
||||
}
|
||||
|
||||
// If a word within the partial object will be written to the first word of a
|
||||
// destination region, this is the address of that word within the partial
|
||||
// object; otherwise this is null.
|
||||
HeapWord* first_src_addr() const { return _first_src_addr; }
|
||||
// Number of regions the preceding live words are relocated into.
|
||||
uint preceding_destination_count() const { return _preceding_destination_count; }
|
||||
|
||||
// Record the data necessary to split the region src_region_idx.
|
||||
void record(size_t src_region_idx, size_t partial_obj_size,
|
||||
HeapWord* destination);
|
||||
void record(size_t split_region_idx, HeapWord* split_point, size_t preceding_live_words);
|
||||
|
||||
void clear();
|
||||
|
||||
DEBUG_ONLY(void verify_clear();)
|
||||
|
||||
private:
|
||||
size_t _src_region_idx;
|
||||
size_t _partial_obj_size;
|
||||
HeapWord* _destination;
|
||||
unsigned int _destination_count;
|
||||
HeapWord* _dest_region_addr;
|
||||
HeapWord* _first_src_addr;
|
||||
size_t _split_region_idx;
|
||||
HeapWord* _split_point;
|
||||
size_t _preceding_live_words;
|
||||
HeapWord* _preceding_destination;
|
||||
uint _preceding_destination_count;
|
||||
};
|
||||
|
||||
inline bool SplitInfo::is_split(size_t region_idx) const
|
||||
{
|
||||
return _src_region_idx == region_idx && is_valid();
|
||||
return _split_region_idx == region_idx && is_valid();
|
||||
}
|
||||
|
||||
class SpaceInfo
|
||||
@ -215,10 +209,18 @@ public:
|
||||
class RegionData
|
||||
{
|
||||
public:
|
||||
// Destination address of the region.
|
||||
// Destination for the first live word in this region.
|
||||
// Therefore, the new addr for every live obj on this region can be calculated as:
|
||||
//
|
||||
// new_addr := _destination + live_words_offset(old_addr);
|
||||
//
|
||||
// where, live_words_offset is the number of live words accumulated from
|
||||
// region-start to old_addr.
|
||||
HeapWord* destination() const { return _destination; }
|
||||
|
||||
// The first region containing data destined for this region.
|
||||
// A destination region can have multiple source regions; only the first
|
||||
// one is recorded. Since all live objs are slided down, subsequent source
|
||||
// regions can be found via plain heap-region iteration.
|
||||
size_t source_region() const { return _source_region; }
|
||||
|
||||
// Reuse _source_region to store the corresponding shadow region index
|
||||
@ -313,9 +315,12 @@ public:
|
||||
// Return to the normal path here
|
||||
inline void shadow_to_normal();
|
||||
|
||||
|
||||
int shadow_state() { return _shadow_state; }
|
||||
|
||||
bool is_clear();
|
||||
|
||||
void verify_clear() NOT_DEBUG_RETURN;
|
||||
|
||||
private:
|
||||
// The type used to represent object sizes within a region.
|
||||
typedef uint region_sz_t;
|
||||
@ -873,7 +878,10 @@ public:
|
||||
size_t words_remaining() const { return _words_remaining; }
|
||||
bool is_full() const { return _words_remaining == 0; }
|
||||
HeapWord* source() const { return _source; }
|
||||
void set_source(HeapWord* addr) { _source = addr; }
|
||||
void set_source(HeapWord* addr) {
|
||||
assert(addr != nullptr, "precondition");
|
||||
_source = addr;
|
||||
}
|
||||
|
||||
// If the object will fit (size <= words_remaining()), copy it to the current
|
||||
// destination, update the interior oops and the start array.
|
||||
@ -902,9 +910,8 @@ inline size_t MoveAndUpdateClosure::calculate_words_remaining(size_t region) {
|
||||
HeapWord* dest_addr = PSParallelCompact::summary_data().region_to_addr(region);
|
||||
PSParallelCompact::SpaceId dest_space_id = PSParallelCompact::space_id(dest_addr);
|
||||
HeapWord* new_top = PSParallelCompact::new_top(dest_space_id);
|
||||
assert(dest_addr < new_top, "sanity");
|
||||
|
||||
return MIN2(pointer_delta(new_top, dest_addr), ParallelCompactData::RegionSize);
|
||||
return MIN2(pointer_delta(new_top, dest_addr),
|
||||
ParallelCompactData::RegionSize);
|
||||
}
|
||||
|
||||
inline
|
||||
|
Loading…
Reference in New Issue
Block a user