256 void ShenandoahPrepareForGenerationalCompactionObjectClosure::finish_young_region() {
257 if (_young_to_region != nullptr) {
258 log_debug(gc)("Worker %u planned compaction into Young Region %zu, used: %zu",
259 _worker_id, _young_to_region->index(), _young_compact_point - _young_to_region->bottom());
260 _young_to_region->set_new_top(_young_compact_point);
261 _young_to_region = nullptr;
262 }
263 }
264
265 bool ShenandoahPrepareForGenerationalCompactionObjectClosure::is_compact_same_region() {
266 return (_from_region == _old_to_region) || (_from_region == _young_to_region);
267 }
268
269 void ShenandoahPrepareForGenerationalCompactionObjectClosure::do_object(oop p) {
270 assert(_from_region != nullptr, "must set before work");
271 assert((_from_region->bottom() <= cast_from_oop<HeapWord*>(p)) && (cast_from_oop<HeapWord*>(p) < _from_region->top()),
272 "Object must reside in _from_region");
273 assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
274 assert(!_heap->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked");
275
276 size_t obj_size = p->size();
277 uint from_region_age = _from_region->age();
278 uint object_age = p->age();
279
280 bool promote_object = false;
281 if ((_from_affiliation == ShenandoahAffiliation::YOUNG_GENERATION) &&
282 (from_region_age + object_age >= _tenuring_threshold)) {
283 if ((_old_to_region != nullptr) && (_old_compact_point + obj_size > _old_to_region->end())) {
284 finish_old_region();
285 _old_to_region = nullptr;
286 }
287 if (_old_to_region == nullptr) {
288 if (_empty_regions_pos < _empty_regions.length()) {
289 ShenandoahHeapRegion* new_to_region = _empty_regions.at(_empty_regions_pos);
290 _empty_regions_pos++;
291 new_to_region->set_affiliation(OLD_GENERATION);
292 _old_to_region = new_to_region;
293 _old_compact_point = _old_to_region->bottom();
294 promote_object = true;
295 }
296 // Else this worker thread does not yet have any empty regions into which this aged object can be promoted so
297 // we leave promote_object as false, deferring the promotion.
298 } else {
299 promote_object = true;
300 }
301 }
302
303 if (promote_object || (_from_affiliation == ShenandoahAffiliation::OLD_GENERATION)) {
304 assert(_old_to_region != nullptr, "_old_to_region should not be nullptr when evacuating to OLD region");
305 if (_old_compact_point + obj_size > _old_to_region->end()) {
306 ShenandoahHeapRegion* new_to_region;
307
308 log_debug(gc)("Worker %u finishing old region %zu, compact_point: " PTR_FORMAT ", obj_size: %zu"
309 ", &compact_point[obj_size]: " PTR_FORMAT ", region end: " PTR_FORMAT, _worker_id, _old_to_region->index(),
310 p2i(_old_compact_point), obj_size, p2i(_old_compact_point + obj_size), p2i(_old_to_region->end()));
311
312 // Object does not fit. Get a new _old_to_region.
313 finish_old_region();
314 if (_empty_regions_pos < _empty_regions.length()) {
315 new_to_region = _empty_regions.at(_empty_regions_pos);
316 _empty_regions_pos++;
317 new_to_region->set_affiliation(OLD_GENERATION);
318 } else {
319 // If we've exhausted the previously selected _old_to_region, we know that the _old_to_region is distinct
320 // from _from_region. That's because there is always room for _from_region to be compacted into itself.
321 // Since we're out of empty regions, let's use _from_region to hold the results of its own compaction.
322 new_to_region = _from_region;
323 }
324
325 assert(new_to_region != _old_to_region, "must not reuse same OLD to-region");
326 assert(new_to_region != nullptr, "must not be nullptr");
327 _old_to_region = new_to_region;
328 _old_compact_point = _old_to_region->bottom();
329 }
330
331 // Object fits into current region, record new location, if object does not move:
332 assert(_old_compact_point + obj_size <= _old_to_region->end(), "must fit");
333 shenandoah_assert_not_forwarded(nullptr, p);
334 if (_old_compact_point != cast_from_oop<HeapWord*>(p)) {
335 _preserved_marks->push_if_necessary(p, p->mark());
336 FullGCForwarding::forward_to(p, cast_to_oop(_old_compact_point));
337 }
338 _old_compact_point += obj_size;
339 } else {
340 assert(_from_affiliation == ShenandoahAffiliation::YOUNG_GENERATION,
341 "_from_region must be OLD_GENERATION or YOUNG_GENERATION");
342 assert(_young_to_region != nullptr, "_young_to_region should not be nullptr when compacting YOUNG _from_region");
343
344 // After full gc compaction, all regions have age 0. Embed the region's age into the object's age in order to preserve
345 // tenuring progress.
346 if (_heap->is_aging_cycle()) {
347 ShenandoahHeap::increase_object_age(p, from_region_age + 1);
348 } else {
349 ShenandoahHeap::increase_object_age(p, from_region_age);
350 }
351
352 if (_young_compact_point + obj_size > _young_to_region->end()) {
353 ShenandoahHeapRegion* new_to_region;
354
355 log_debug(gc)("Worker %u finishing young region %zu, compact_point: " PTR_FORMAT ", obj_size: %zu"
356 ", &compact_point[obj_size]: " PTR_FORMAT ", region end: " PTR_FORMAT, _worker_id, _young_to_region->index(),
357 p2i(_young_compact_point), obj_size, p2i(_young_compact_point + obj_size), p2i(_young_to_region->end()));
358
359 // Object does not fit. Get a new _young_to_region.
360 finish_young_region();
361 if (_empty_regions_pos < _empty_regions.length()) {
362 new_to_region = _empty_regions.at(_empty_regions_pos);
363 _empty_regions_pos++;
364 new_to_region->set_affiliation(YOUNG_GENERATION);
365 } else {
366 // If we've exhausted the previously selected _young_to_region, we know that the _young_to_region is distinct
367 // from _from_region. That's because there is always room for _from_region to be compacted into itself.
368 // Since we're out of empty regions, let's use _from_region to hold the results of its own compaction.
369 new_to_region = _from_region;
370 }
371
372 assert(new_to_region != _young_to_region, "must not reuse same OLD to-region");
373 assert(new_to_region != nullptr, "must not be nullptr");
374 _young_to_region = new_to_region;
375 _young_compact_point = _young_to_region->bottom();
376 }
377
378 // Object fits into current region, record new location, if object does not move:
379 assert(_young_compact_point + obj_size <= _young_to_region->end(), "must fit");
380 shenandoah_assert_not_forwarded(nullptr, p);
381
382 if (_young_compact_point != cast_from_oop<HeapWord*>(p)) {
383 _preserved_marks->push_if_necessary(p, p->mark());
384 FullGCForwarding::forward_to(p, cast_to_oop(_young_compact_point));
385 }
386 _young_compact_point += obj_size;
387 }
388 }
|
256 void ShenandoahPrepareForGenerationalCompactionObjectClosure::finish_young_region() {
257 if (_young_to_region != nullptr) {
258 log_debug(gc)("Worker %u planned compaction into Young Region %zu, used: %zu",
259 _worker_id, _young_to_region->index(), _young_compact_point - _young_to_region->bottom());
260 _young_to_region->set_new_top(_young_compact_point);
261 _young_to_region = nullptr;
262 }
263 }
264
265 bool ShenandoahPrepareForGenerationalCompactionObjectClosure::is_compact_same_region() {
266 return (_from_region == _old_to_region) || (_from_region == _young_to_region);
267 }
268
269 void ShenandoahPrepareForGenerationalCompactionObjectClosure::do_object(oop p) {
270 assert(_from_region != nullptr, "must set before work");
271 assert((_from_region->bottom() <= cast_from_oop<HeapWord*>(p)) && (cast_from_oop<HeapWord*>(p) < _from_region->top()),
272 "Object must reside in _from_region");
273 assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
274 assert(!_heap->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked");
275
276 size_t old_size = p->size();
277 size_t new_size = p->copy_size(old_size, p->mark());
278 uint from_region_age = _from_region->age();
279 uint object_age = p->age();
280
281 bool promote_object = false;
282 if ((_from_affiliation == ShenandoahAffiliation::YOUNG_GENERATION) &&
283 (from_region_age + object_age >= _tenuring_threshold)) {
284 if ((_old_to_region != nullptr) && (_old_compact_point + new_size > _old_to_region->end())) {
285 finish_old_region();
286 _old_to_region = nullptr;
287 }
288 if (_old_to_region == nullptr) {
289 if (_empty_regions_pos < _empty_regions.length()) {
290 ShenandoahHeapRegion* new_to_region = _empty_regions.at(_empty_regions_pos);
291 _empty_regions_pos++;
292 new_to_region->set_affiliation(OLD_GENERATION);
293 _old_to_region = new_to_region;
294 _old_compact_point = _old_to_region->bottom();
295 promote_object = true;
296 }
297 // Else this worker thread does not yet have any empty regions into which this aged object can be promoted so
298 // we leave promote_object as false, deferring the promotion.
299 } else {
300 promote_object = true;
301 }
302 }
303
304 if (promote_object || (_from_affiliation == ShenandoahAffiliation::OLD_GENERATION)) {
305 assert(_old_to_region != nullptr, "_old_to_region should not be nullptr when evacuating to OLD region");
306 size_t obj_size = _old_compact_point == cast_from_oop<HeapWord*>(p) ? old_size : new_size;
307 if (_old_compact_point + obj_size > _old_to_region->end()) {
308 ShenandoahHeapRegion* new_to_region;
309
310 log_debug(gc)("Worker %u finishing old region %zu, compact_point: " PTR_FORMAT ", obj_size: %zu"
311 ", &compact_point[obj_size]: " PTR_FORMAT ", region end: " PTR_FORMAT, _worker_id, _old_to_region->index(),
312 p2i(_old_compact_point), obj_size, p2i(_old_compact_point + obj_size), p2i(_old_to_region->end()));
313
314 // Object does not fit. Get a new _old_to_region.
315 finish_old_region();
316 if (_empty_regions_pos < _empty_regions.length()) {
317 new_to_region = _empty_regions.at(_empty_regions_pos);
318 _empty_regions_pos++;
319 new_to_region->set_affiliation(OLD_GENERATION);
320 } else {
321 // If we've exhausted the previously selected _old_to_region, we know that the _old_to_region is distinct
322 // from _from_region. That's because there is always room for _from_region to be compacted into itself.
323 // Since we're out of empty regions, let's use _from_region to hold the results of its own compaction.
324 new_to_region = _from_region;
325 }
326
327 assert(new_to_region != _old_to_region, "must not reuse same OLD to-region");
328 assert(new_to_region != nullptr, "must not be nullptr");
329 _old_to_region = new_to_region;
330 _old_compact_point = _old_to_region->bottom();
331 obj_size = _old_compact_point == cast_from_oop<HeapWord*>(p) ? old_size : new_size;
332 }
333
334 // Object fits into current region, record new location, if object does not move:
335 assert(_old_compact_point + obj_size <= _old_to_region->end(), "must fit");
336 shenandoah_assert_not_forwarded(nullptr, p);
337 if (_old_compact_point != cast_from_oop<HeapWord*>(p)) {
338 _preserved_marks->push_if_necessary(p, p->mark());
339 FullGCForwarding::forward_to(p, cast_to_oop(_old_compact_point));
340 }
341 _old_compact_point += obj_size;
342 } else {
343 assert(_from_affiliation == ShenandoahAffiliation::YOUNG_GENERATION,
344 "_from_region must be OLD_GENERATION or YOUNG_GENERATION");
345 assert(_young_to_region != nullptr, "_young_to_region should not be nullptr when compacting YOUNG _from_region");
346
347 // After full gc compaction, all regions have age 0. Embed the region's age into the object's age in order to preserve
348 // tenuring progress.
349 if (_heap->is_aging_cycle()) {
350 ShenandoahHeap::increase_object_age(p, from_region_age + 1);
351 } else {
352 ShenandoahHeap::increase_object_age(p, from_region_age);
353 }
354
355 size_t obj_size = _young_compact_point == cast_from_oop<HeapWord*>(p) ? old_size : new_size;
356 if (_young_compact_point + obj_size > _young_to_region->end()) {
357 ShenandoahHeapRegion* new_to_region;
358
359 log_debug(gc)("Worker %u finishing young region %zu, compact_point: " PTR_FORMAT ", obj_size: %zu"
360 ", &compact_point[obj_size]: " PTR_FORMAT ", region end: " PTR_FORMAT, _worker_id, _young_to_region->index(),
361 p2i(_young_compact_point), obj_size, p2i(_young_compact_point + obj_size), p2i(_young_to_region->end()));
362
363 // Object does not fit. Get a new _young_to_region.
364 finish_young_region();
365 if (_empty_regions_pos < _empty_regions.length()) {
366 new_to_region = _empty_regions.at(_empty_regions_pos);
367 _empty_regions_pos++;
368 new_to_region->set_affiliation(YOUNG_GENERATION);
369 } else {
370 // If we've exhausted the previously selected _young_to_region, we know that the _young_to_region is distinct
371 // from _from_region. That's because there is always room for _from_region to be compacted into itself.
372 // Since we're out of empty regions, let's use _from_region to hold the results of its own compaction.
373 new_to_region = _from_region;
374 }
375
376 assert(new_to_region != _young_to_region, "must not reuse same OLD to-region");
377 assert(new_to_region != nullptr, "must not be nullptr");
378 _young_to_region = new_to_region;
379 obj_size = _young_compact_point == cast_from_oop<HeapWord*>(p) ? old_size : new_size;
380 _young_compact_point = _young_to_region->bottom();
381 }
382
383 // Object fits into current region, record new location, if object does not move:
384 assert(_young_compact_point + obj_size <= _young_to_region->end(), "must fit");
385 shenandoah_assert_not_forwarded(nullptr, p);
386
387 if (_young_compact_point != cast_from_oop<HeapWord*>(p)) {
388 _preserved_marks->push_if_necessary(p, p->mark());
389 FullGCForwarding::forward_to(p, cast_to_oop(_young_compact_point));
390 }
391 _young_compact_point += obj_size;
392 }
393 }
|