334 _heap->workers()->run_task(&update_roots);
335
336 #if COMPILER2_OR_JVMCI
337 DerivedPointerTable::update_pointers();
338 #endif
339 }
340
341 class ShenandoahUpdateThreadRootsTask : public AbstractGangTask {
342 private:
343 ShenandoahThreadRoots _thread_roots;
344 ShenandoahPhaseTimings::Phase _phase;
345 ShenandoahGCWorkerPhase _worker_phase;
346 public:
347 ShenandoahUpdateThreadRootsTask(bool is_par, ShenandoahPhaseTimings::Phase phase) :
348 AbstractGangTask("Shenandoah Update Thread Roots"),
349 _thread_roots(phase, is_par),
350 _phase(phase),
351 _worker_phase(phase) {}
352
353 void work(uint worker_id) {
354 ShenandoahUpdateRefsClosure cl;
355 _thread_roots.oops_do(&cl, NULL, worker_id);
356 }
357 };
358
359 void ShenandoahConcurrentMark::update_thread_roots(ShenandoahPhaseTimings::Phase root_phase) {
360 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
361
362 ShenandoahGCPhase phase(root_phase);
363
364 #if COMPILER2_OR_JVMCI
365 DerivedPointerTable::clear();
366 #endif
367
368 WorkGang* workers = _heap->workers();
369 bool is_par = workers->active_workers() > 1;
370
371 ShenandoahUpdateThreadRootsTask task(is_par, root_phase);
372 workers->run_task(&task);
373
571 };
572
573 class ShenandoahRefProcTaskProxy : public AbstractGangTask {
574 private:
575 AbstractRefProcTaskExecutor::ProcessTask& _proc_task;
576 TaskTerminator* _terminator;
577
578 public:
579 ShenandoahRefProcTaskProxy(AbstractRefProcTaskExecutor::ProcessTask& proc_task,
580 TaskTerminator* t) :
581 AbstractGangTask("Process reference objects in parallel"),
582 _proc_task(proc_task),
583 _terminator(t) {
584 }
585
586 void work(uint worker_id) {
587 ResourceMark rm;
588 HandleMark hm;
589 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
590 ShenandoahHeap* heap = ShenandoahHeap::heap();
591 ShenandoahCMDrainMarkingStackClosure complete_gc(worker_id, _terminator);
592 if (heap->has_forwarded_objects()) {
593 ShenandoahForwardedIsAliveClosure is_alive;
594 ShenandoahCMKeepAliveUpdateClosure keep_alive(heap->concurrent_mark()->get_queue(worker_id));
595 _proc_task.work(worker_id, is_alive, keep_alive, complete_gc);
596 } else {
597 ShenandoahIsAliveClosure is_alive;
598 ShenandoahCMKeepAliveClosure keep_alive(heap->concurrent_mark()->get_queue(worker_id));
599 _proc_task.work(worker_id, is_alive, keep_alive, complete_gc);
600 }
601 }
602 };
603
604 class ShenandoahRefProcTaskExecutor : public AbstractRefProcTaskExecutor {
605 private:
606 WorkGang* _workers;
607
608 public:
609 ShenandoahRefProcTaskExecutor(WorkGang* workers) :
610 _workers(workers) {
665 uint nworkers = workers->active_workers();
666
667 rp->setup_policy(_heap->soft_ref_policy()->should_clear_all_soft_refs());
668 rp->set_active_mt_degree(nworkers);
669
670 assert(task_queues()->is_empty(), "Should be empty");
671
672 // complete_gc and keep_alive closures instantiated here are only needed for
673 // single-threaded path in RP. They share the queue 0 for tracking work, which
674 // simplifies implementation. Since RP may decide to call complete_gc several
675 // times, we need to be able to reuse the terminator.
676 uint serial_worker_id = 0;
677 TaskTerminator terminator(1, task_queues());
678 ShenandoahCMDrainMarkingStackClosure complete_gc(serial_worker_id, &terminator, /* reset_terminator = */ true);
679
680 ShenandoahRefProcTaskExecutor executor(workers);
681
682 ReferenceProcessorPhaseTimes pt(_heap->gc_timer(), rp->num_queues());
683
684 {
685 ShenandoahGCPhase phase(phase_process);
686
687 if (_heap->has_forwarded_objects()) {
688 ShenandoahCMKeepAliveUpdateClosure keep_alive(get_queue(serial_worker_id));
689 const ReferenceProcessorStats& stats =
690 rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive,
691 &complete_gc, &executor,
692 &pt);
693 _heap->tracer()->report_gc_reference_stats(stats);
694 } else {
695 ShenandoahCMKeepAliveClosure keep_alive(get_queue(serial_worker_id));
696 const ReferenceProcessorStats& stats =
697 rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive,
698 &complete_gc, &executor,
699 &pt);
700 _heap->tracer()->report_gc_reference_stats(stats);
701 }
702
703 pt.print_all_references();
704
705 assert(task_queues()->is_empty(), "Should be empty");
|
334 _heap->workers()->run_task(&update_roots);
335
336 #if COMPILER2_OR_JVMCI
337 DerivedPointerTable::update_pointers();
338 #endif
339 }
340
341 class ShenandoahUpdateThreadRootsTask : public AbstractGangTask {
342 private:
343 ShenandoahThreadRoots _thread_roots;
344 ShenandoahPhaseTimings::Phase _phase;
345 ShenandoahGCWorkerPhase _worker_phase;
346 public:
347 ShenandoahUpdateThreadRootsTask(bool is_par, ShenandoahPhaseTimings::Phase phase) :
348 AbstractGangTask("Shenandoah Update Thread Roots"),
349 _thread_roots(phase, is_par),
350 _phase(phase),
351 _worker_phase(phase) {}
352
353 void work(uint worker_id) {
354 ShenandoahParallelWorkerSession worker_session(worker_id);
355 ShenandoahUpdateRefsClosure cl;
356 _thread_roots.oops_do(&cl, NULL, worker_id);
357 }
358 };
359
360 void ShenandoahConcurrentMark::update_thread_roots(ShenandoahPhaseTimings::Phase root_phase) {
361 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
362
363 ShenandoahGCPhase phase(root_phase);
364
365 #if COMPILER2_OR_JVMCI
366 DerivedPointerTable::clear();
367 #endif
368
369 WorkGang* workers = _heap->workers();
370 bool is_par = workers->active_workers() > 1;
371
372 ShenandoahUpdateThreadRootsTask task(is_par, root_phase);
373 workers->run_task(&task);
374
572 };
573
574 class ShenandoahRefProcTaskProxy : public AbstractGangTask {
575 private:
576 AbstractRefProcTaskExecutor::ProcessTask& _proc_task;
577 TaskTerminator* _terminator;
578
579 public:
580 ShenandoahRefProcTaskProxy(AbstractRefProcTaskExecutor::ProcessTask& proc_task,
581 TaskTerminator* t) :
582 AbstractGangTask("Process reference objects in parallel"),
583 _proc_task(proc_task),
584 _terminator(t) {
585 }
586
587 void work(uint worker_id) {
588 ResourceMark rm;
589 HandleMark hm;
590 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");
591 ShenandoahHeap* heap = ShenandoahHeap::heap();
592 ShenandoahParallelWorkerSession worker_session(worker_id);
593 ShenandoahCMDrainMarkingStackClosure complete_gc(worker_id, _terminator);
594 if (heap->has_forwarded_objects()) {
595 ShenandoahForwardedIsAliveClosure is_alive;
596 ShenandoahCMKeepAliveUpdateClosure keep_alive(heap->concurrent_mark()->get_queue(worker_id));
597 _proc_task.work(worker_id, is_alive, keep_alive, complete_gc);
598 } else {
599 ShenandoahIsAliveClosure is_alive;
600 ShenandoahCMKeepAliveClosure keep_alive(heap->concurrent_mark()->get_queue(worker_id));
601 _proc_task.work(worker_id, is_alive, keep_alive, complete_gc);
602 }
603 }
604 };
605
606 class ShenandoahRefProcTaskExecutor : public AbstractRefProcTaskExecutor {
607 private:
608 WorkGang* _workers;
609
610 public:
611 ShenandoahRefProcTaskExecutor(WorkGang* workers) :
612 _workers(workers) {
667 uint nworkers = workers->active_workers();
668
669 rp->setup_policy(_heap->soft_ref_policy()->should_clear_all_soft_refs());
670 rp->set_active_mt_degree(nworkers);
671
672 assert(task_queues()->is_empty(), "Should be empty");
673
674 // complete_gc and keep_alive closures instantiated here are only needed for
675 // single-threaded path in RP. They share the queue 0 for tracking work, which
676 // simplifies implementation. Since RP may decide to call complete_gc several
677 // times, we need to be able to reuse the terminator.
678 uint serial_worker_id = 0;
679 TaskTerminator terminator(1, task_queues());
680 ShenandoahCMDrainMarkingStackClosure complete_gc(serial_worker_id, &terminator, /* reset_terminator = */ true);
681
682 ShenandoahRefProcTaskExecutor executor(workers);
683
684 ReferenceProcessorPhaseTimes pt(_heap->gc_timer(), rp->num_queues());
685
686 {
687 // Note: Don't emit JFR event for this phase, to avoid overflow nesting phase level.
688 // Reference Processor emits 2 levels JFR event, that can get us over the JFR
689 // event nesting level limits, in case of degenerated GC gets upgraded to
690 // full GC.
691 ShenandoahGCPhaseTiming phase_timing(phase_process);
692
693 if (_heap->has_forwarded_objects()) {
694 ShenandoahCMKeepAliveUpdateClosure keep_alive(get_queue(serial_worker_id));
695 const ReferenceProcessorStats& stats =
696 rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive,
697 &complete_gc, &executor,
698 &pt);
699 _heap->tracer()->report_gc_reference_stats(stats);
700 } else {
701 ShenandoahCMKeepAliveClosure keep_alive(get_queue(serial_worker_id));
702 const ReferenceProcessorStats& stats =
703 rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive,
704 &complete_gc, &executor,
705 &pt);
706 _heap->tracer()->report_gc_reference_stats(stats);
707 }
708
709 pt.print_all_references();
710
711 assert(task_queues()->is_empty(), "Should be empty");
|