< prev index next > src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
Print this page
// Continue the cycle with evacuation and optional update-refs.
// This may be skipped if there is nothing to evacuate.
// If so, evac_in_progress would be unset by collection set preparation code.
if (heap->is_evacuation_in_progress()) {
+ // Roots processing is complete, put the weak roots/ref flags down.
+ vmop_entry_final_roots(false);
+
// Concurrently evacuate
entry_evacuate();
if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_evac)) {
return false;
}
// Update references freed up collection set, kick the cleanup to reclaim the space.
entry_cleanup_complete();
} else {
_abbreviated = true;
! if (!entry_final_roots()) {
! assert(_degen_point != _degenerated_unset, "Need to know where to start degenerated cycle");
! return false;
}
// In normal cycle, final-update-refs would verify at the end of the cycle.
// In abbreviated cycle, we need to verify separately.
! if (ShenandoahVerify) {
! vmop_entry_final_verify();
- }
}
// We defer generation resizing actions until after cset regions have been recycled. We do this even following an
// abbreviated cycle.
if (heap->mode()->is_generational()) {
// Update references freed up collection set, kick the cleanup to reclaim the space.
entry_cleanup_complete();
} else {
_abbreviated = true;
!
! if (heap->mode()->is_generational()) {
! entry_complete_abbreviated_cycle();
+
+ // If the promote-in-place operation was cancelled, we can have the degenerated
+ // cycle complete the operation. It will see that no evacuations are in progress,
+ // and that there are regions wanting promotion. The risk with not handling the
+ // cancellation would be failing to restore top for these regions and leaving
+ // them unable to serve allocations for the old generation.
+ if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_evac)) {
+ return false;
+ }
}
// In normal cycle, final-update-refs would verify at the end of the cycle.
// In abbreviated cycle, we need to verify separately.
! // This is now also puts the barriers down at the end of the cycle. TODO: Refine.
! vmop_entry_final_roots(true);
}
// We defer generation resizing actions until after cset regions have been recycled. We do this even following an
// abbreviated cycle.
if (heap->mode()->is_generational()) {
entry_reset_after_collect();
return true;
}
! bool ShenandoahConcurrentGC::complete_abbreviated_cycle() {
shenandoah_assert_generational();
ShenandoahGenerationalHeap* const heap = ShenandoahGenerationalHeap::heap();
// We chose not to evacuate because we found sufficient immediate garbage.
// However, there may still be regions to promote in place, so do that now.
if (heap->old_generation()->has_in_place_promotions()) {
! entry_promote_in_place();
!
! // If the promote-in-place operation was cancelled, we can have the degenerated
- // cycle complete the operation. It will see that no evacuations are in progress,
- // and that there are regions wanting promotion. The risk with not handling the
- // cancellation would be failing to restore top for these regions and leaving
- // them unable to serve allocations for the old generation.This will leave the weak
- // roots flag set (the degenerated cycle will unset it).
- if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_evac)) {
- return false;
- }
}
// At this point, the cycle is effectively complete. If the cycle has been cancelled here,
// the control thread will detect it on its next iteration and run a degenerated young cycle.
! if (!_generation->is_old()) {
heap->update_region_ages(_generation->complete_marking_context());
}
-
- return true;
}
void ShenandoahConcurrentGC::vmop_entry_init_mark() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());
entry_reset_after_collect();
return true;
}
! void ShenandoahConcurrentGC::entry_complete_abbreviated_cycle() {
shenandoah_assert_generational();
ShenandoahGenerationalHeap* const heap = ShenandoahGenerationalHeap::heap();
+ static const char* msg = "Concurrent complete abbreviated cycle";
+ ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::complete_abbreviated);
+ EventMark em("%s", msg);
+ ShenandoahWorkerScope scope(heap->workers(),
+ ShenandoahWorkerPolicy::calc_workers_for_conc_evac(),
+ "complete abbreviated");
+
// We chose not to evacuate because we found sufficient immediate garbage.
// However, there may still be regions to promote in place, so do that now.
if (heap->old_generation()->has_in_place_promotions()) {
! ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::complete_abbreviated_promote_in_place);
! ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::complete_abbreviated_promote_in_place);
! heap->promote_regions_in_place(_generation, true);
}
// At this point, the cycle is effectively complete. If the cycle has been cancelled here,
// the control thread will detect it on its next iteration and run a degenerated young cycle.
! if (!heap->cancelled_gc() && !_generation->is_old()) {
+ ShenandoahTimingsTracker tracker(ShenandoahPhaseTimings::complete_abbreviated_update_region_ages);
heap->update_region_ages(_generation->complete_marking_context());
}
}
void ShenandoahConcurrentGC::vmop_entry_init_mark() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());
heap->try_inject_alloc_failure();
VM_ShenandoahFinalUpdateRefs op(this);
VMThread::execute(&op);
}
! void ShenandoahConcurrentGC::vmop_entry_final_verify() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());
! ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_verify_gross);
// This phase does not use workers, no need for setup
heap->try_inject_alloc_failure();
! VM_ShenandoahFinalVerify op(this);
VMThread::execute(&op);
}
void ShenandoahConcurrentGC::entry_init_mark() {
const char* msg = init_mark_event_message();
heap->try_inject_alloc_failure();
VM_ShenandoahFinalUpdateRefs op(this);
VMThread::execute(&op);
}
! void ShenandoahConcurrentGC::vmop_entry_final_roots(bool at_gc_end) {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());
! ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_roots_gross);
// This phase does not use workers, no need for setup
heap->try_inject_alloc_failure();
! VM_ShenandoahFinalRoots op(this, at_gc_end);
VMThread::execute(&op);
}
void ShenandoahConcurrentGC::entry_init_mark() {
const char* msg = init_mark_event_message();
"final reference update");
op_final_update_refs();
}
- void ShenandoahConcurrentGC::entry_final_verify() {
- const char* msg = verify_final_event_message();
- ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_verify);
- EventMark em("%s", msg);
-
- op_verify_final();
- }
-
void ShenandoahConcurrentGC::entry_reset() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
heap->try_inject_alloc_failure();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
heap->try_inject_alloc_failure();
op_evacuate();
}
- void ShenandoahConcurrentGC::entry_promote_in_place() const {
- shenandoah_assert_generational();
-
- ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::promote_in_place);
- ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::promote_in_place);
- EventMark em("%s", "Promote in place");
-
- ShenandoahGenerationalHeap::heap()->promote_regions_in_place(_generation, true);
- }
-
void ShenandoahConcurrentGC::entry_update_thread_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Concurrent update thread roots";
assert(_generation->is_bitmap_clear(), "need clear marking bitmap");
assert(!_generation->is_mark_complete(), "should not be complete");
assert(!heap->has_forwarded_objects(), "No forwarded objects on this path");
+ // First pause in cycle, check that barriers were not left enabled.
+ ShenandoahCodeRoots::check_barriers();
+
if (heap->mode()->is_generational()) {
if (_generation->is_global()) {
heap->old_generation()->cancel_gc();
}
}
heap->set_evacuation_in_progress(true);
// From here on, we need to update references.
heap->set_has_forwarded_objects(true);
-
- // Arm nmethods/stack for concurrent processing
- ShenandoahCodeRoots::arm_nmethods();
- ShenandoahStackWatermark::change_epoch_id();
-
} else {
if (ShenandoahVerify) {
ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_mark_verify);
if (has_in_place_promotions(heap)) {
heap->verifier()->verify_after_concmark_with_promotions(_generation);
}
}
}
}
+ // Arm nmethods/stack for concurrent processing
+ ShenandoahCodeRoots::arm_nmethods();
+ ShenandoahStackWatermark::change_epoch_id();
+
{
ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_propagate_gc_state);
heap->propagate_gc_state_to_all_threads();
}
}
void do_nmethod(nmethod* n) {
ShenandoahNMethod* data = ShenandoahNMethod::gc_data(n);
ShenandoahNMethodLocker locker(data->lock());
data->oops_do(&_cl, /* fix_relocations = */ true);
! ShenandoahNMethod::disarm_nmethod(n);
}
};
class ShenandoahConcurrentRootsEvacUpdateTask : public WorkerTask {
private:
void do_nmethod(nmethod* n) {
ShenandoahNMethod* data = ShenandoahNMethod::gc_data(n);
ShenandoahNMethodLocker locker(data->lock());
data->oops_do(&_cl, /* fix_relocations = */ true);
! ShenandoahNMethod::complete_and_disarm_nmethod_unlocked(n);
}
};
class ShenandoahConcurrentRootsEvacUpdateTask : public WorkerTask {
private:
}
heap->rebuild_free_set(true /*concurrent*/);
_generation->heuristics()->start_idle_span();
{
ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_update_refs_propagate_gc_state);
heap->propagate_gc_state_to_all_threads();
}
}
! bool ShenandoahConcurrentGC::entry_final_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
!
! const char* msg = conc_final_roots_event_message();
- ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_final_roots);
EventMark em("%s", msg);
ShenandoahWorkerScope scope(heap->workers(),
! ShenandoahWorkerPolicy::calc_workers_for_conc_evac(),
msg);
! if (heap->mode()->is_generational()) {
- if (!complete_abbreviated_cycle()) {
- return false;
- }
- }
-
- heap->concurrent_final_roots();
- return true;
- }
-
- void ShenandoahConcurrentGC::op_verify_final() {
- assert(ShenandoahVerify, "Should have been checked before");
- ShenandoahHeap* const heap = ShenandoahHeap::heap();
- heap->verifier()->verify_after_gc(_generation);
}
void ShenandoahConcurrentGC::op_cleanup_complete() {
ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),
ShenandoahWorkerPolicy::calc_workers_for_conc_cleanup(),
}
heap->rebuild_free_set(true /*concurrent*/);
_generation->heuristics()->start_idle_span();
+ {
+ // Final pause: update GC barriers to idle state.
+ ShenandoahCodeRoots::arm_nmethods();
+ ShenandoahStackWatermark::change_epoch_id();
+ }
+
{
ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_update_refs_propagate_gc_state);
heap->propagate_gc_state_to_all_threads();
}
}
! void ShenandoahConcurrentGC::entry_final_roots(bool at_gc_end) {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
! const char* msg = final_roots_event_message();
! ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_roots);
EventMark em("%s", msg);
ShenandoahWorkerScope scope(heap->workers(),
! ParallelGCThreads,
msg);
! heap->op_final_roots(at_gc_end);
}
void ShenandoahConcurrentGC::op_cleanup_complete() {
ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),
ShenandoahWorkerPolicy::calc_workers_for_conc_cleanup(),
void ShenandoahConcurrentGC::op_reset_after_collect() {
ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),
ShenandoahWorkerPolicy::calc_workers_for_conc_reset(),
"reset after collection.");
+ // Final concurrent phase: complete disabling all barriers.
+ ShenandoahCodeRoots::disarm_nmethods();
+
+ // Check that barriers were not left enabled.
+ ShenandoahCodeRoots::check_barriers();
+
ShenandoahHeap* const heap = ShenandoahHeap::heap();
if (heap->mode()->is_generational()) {
// If we are in the midst of an old gc bootstrap or an old marking, we want to leave the mark bit map of
// the young generation intact. In particular, reference processing in the old generation may potentially
// need the reachability of a young generation referent of a Reference object in the old generation.
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", "");
}
}
! const char* ShenandoahConcurrentGC::verify_final_event_message() const {
- if (ShenandoahHeap::heap()->unload_classes()) {
- SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", " (unload classes)");
- } else {
- SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", "");
- }
- }
-
- const char* ShenandoahConcurrentGC::conc_final_roots_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
! SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Final Roots", " (unload classes)");
} else {
! SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Final Roots", "");
}
}
const char* ShenandoahConcurrentGC::conc_weak_refs_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", "");
}
}
! const char* ShenandoahConcurrentGC::final_roots_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
! SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Roots", " (unload classes)");
} else {
! SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Roots", "");
}
}
const char* ShenandoahConcurrentGC::conc_weak_refs_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
< prev index next >