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