use super::work_bucket::WorkBucketStage;
use super::*;
use crate::vm::*;
use crate::*;
use std::marker::PhantomData;
use std::sync::atomic::Ordering;
pub struct ScheduleCollection;
impl<VM: VMBinding> GCWork<VM> for ScheduleCollection {
fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
let is_emergency = mmtk.state.set_collection_kind(
mmtk.get_plan().last_collection_was_exhaustive(),
mmtk.gc_trigger.policy.can_heap_size_grow(),
);
if is_emergency {
mmtk.get_plan().notify_emergency_collection();
}
mmtk.state.stacks_prepared.store(false, Ordering::SeqCst);
mmtk.stats.start_gc();
mmtk.get_plan().schedule_collection(worker.scheduler());
}
}
pub struct Prepare<C: GCWorkContext> {
pub plan: *const C::PlanType,
}
unsafe impl<C: GCWorkContext> Send for Prepare<C> {}
impl<C: GCWorkContext> Prepare<C> {
pub fn new(plan: *const C::PlanType) -> Self {
Self { plan }
}
}
impl<C: GCWorkContext> GCWork<C::VM> for Prepare<C> {
fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
trace!("Prepare Global");
let plan_mut: &mut C::PlanType = unsafe { &mut *(self.plan as *const _ as *mut _) };
plan_mut.prepare(worker.tls);
if plan_mut.constraints().needs_prepare_mutator {
let prepare_mutator_packets = <C::VM as VMBinding>::VMActivePlan::mutators()
.map(|mutator| Box::new(PrepareMutator::<C::VM>::new(mutator)) as _)
.collect::<Vec<_>>();
debug_assert_eq!(
prepare_mutator_packets.len(),
<C::VM as VMBinding>::VMActivePlan::number_of_mutators()
);
mmtk.scheduler.work_buckets[WorkBucketStage::Prepare].bulk_add(prepare_mutator_packets);
}
for w in &mmtk.scheduler.worker_group.workers_shared {
let result = w.designated_work.push(Box::new(PrepareCollector));
debug_assert!(result.is_ok());
}
}
}
pub struct PrepareMutator<VM: VMBinding> {
pub mutator: &'static mut Mutator<VM>,
}
impl<VM: VMBinding> PrepareMutator<VM> {
pub fn new(mutator: &'static mut Mutator<VM>) -> Self {
Self { mutator }
}
}
impl<VM: VMBinding> GCWork<VM> for PrepareMutator<VM> {
fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
trace!("Prepare Mutator");
self.mutator.prepare(worker.tls);
}
}
#[derive(Default)]
pub struct PrepareCollector;
impl<VM: VMBinding> GCWork<VM> for PrepareCollector {
fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
trace!("Prepare Collector");
worker.get_copy_context_mut().prepare();
mmtk.get_plan().prepare_worker(worker);
}
}
pub struct Release<C: GCWorkContext> {
pub plan: *const C::PlanType,
}
impl<C: GCWorkContext> Release<C> {
pub fn new(plan: *const C::PlanType) -> Self {
Self { plan }
}
}
unsafe impl<C: GCWorkContext> Send for Release<C> {}
impl<C: GCWorkContext + 'static> GCWork<C::VM> for Release<C> {
fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
trace!("Release Global");
mmtk.gc_trigger.policy.on_gc_release(mmtk);
let plan_mut: &mut C::PlanType = unsafe { &mut *(self.plan as *const _ as *mut _) };
plan_mut.release(worker.tls);
let release_mutator_packets = <C::VM as VMBinding>::VMActivePlan::mutators()
.map(|mutator| Box::new(ReleaseMutator::<C::VM>::new(mutator)) as _)
.collect::<Vec<_>>();
debug_assert_eq!(
release_mutator_packets.len(),
<C::VM as VMBinding>::VMActivePlan::number_of_mutators()
);
mmtk.scheduler.work_buckets[WorkBucketStage::Release].bulk_add(release_mutator_packets);
for w in &mmtk.scheduler.worker_group.workers_shared {
let result = w.designated_work.push(Box::new(ReleaseCollector));
debug_assert!(result.is_ok());
}
}
}
pub struct ReleaseMutator<VM: VMBinding> {
pub mutator: &'static mut Mutator<VM>,
}
impl<VM: VMBinding> ReleaseMutator<VM> {
pub fn new(mutator: &'static mut Mutator<VM>) -> Self {
Self { mutator }
}
}
impl<VM: VMBinding> GCWork<VM> for ReleaseMutator<VM> {
fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
trace!("Release Mutator");
self.mutator.release(worker.tls);
}
}
#[derive(Default)]
pub struct ReleaseCollector;
impl<VM: VMBinding> GCWork<VM> for ReleaseCollector {
fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
trace!("Release Collector");
worker.get_copy_context_mut().release();
}
}
#[derive(Default)]
pub struct StopMutators<C: GCWorkContext> {
skip_roots: bool,
flush_mutator: bool,
phantom: PhantomData<C>,
}
impl<C: GCWorkContext> StopMutators<C> {
pub fn new() -> Self {
Self {
skip_roots: false,
flush_mutator: false,
phantom: PhantomData,
}
}
pub fn new_no_scan_roots() -> Self {
Self {
skip_roots: true,
flush_mutator: true,
phantom: PhantomData,
}
}
}
impl<C: GCWorkContext> GCWork<C::VM> for StopMutators<C> {
fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
trace!("stop_all_mutators start");
mmtk.state.prepare_for_stack_scanning();
<C::VM as VMBinding>::VMCollection::stop_all_mutators(worker.tls, |mutator| {
if self.flush_mutator {
mutator.flush();
}
if !self.skip_roots {
mmtk.scheduler.work_buckets[WorkBucketStage::Prepare]
.add(ScanMutatorRoots::<C>(mutator));
}
});
trace!("stop_all_mutators end");
mmtk.get_plan().notify_mutators_paused(mmtk);
mmtk.scheduler.notify_mutators_paused(mmtk);
mmtk.gc_trigger.policy.on_pause_start(mmtk);
if !self.skip_roots {
mmtk.scheduler.work_buckets[WorkBucketStage::Prepare]
.add(ScanVMSpecificRoots::<C>::new());
}
}
}
pub struct ScanMutatorRoots<C: GCWorkContext>(pub &'static mut Mutator<C::VM>);
impl<C: GCWorkContext> GCWork<C::VM> for ScanMutatorRoots<C> {
fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
trace!("ScanMutatorRoots for mutator {:?}", self.0.get_tls());
let mutators = <C::VM as VMBinding>::VMActivePlan::number_of_mutators();
let factory = C::make_roots_work_factory(mmtk);
<C::VM as VMBinding>::VMScanning::scan_roots_in_mutator_thread(
worker.tls,
unsafe { &mut *(self.0 as *mut _) },
factory,
);
self.0.flush();
if mmtk.state.inform_stack_scanned(mutators) {
<C::VM as VMBinding>::VMScanning::notify_initial_thread_scan_complete(
false, worker.tls,
);
}
}
}
#[derive(Default)]
pub struct ScanVMSpecificRoots<C: GCWorkContext>(PhantomData<C>);
impl<C: GCWorkContext> ScanVMSpecificRoots<C> {
pub fn new() -> Self {
Self(PhantomData)
}
}
impl<C: GCWorkContext> GCWork<C::VM> for ScanVMSpecificRoots<C> {
fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
trace!("ScanStaticRoots");
let factory = C::make_roots_work_factory(mmtk);
<C::VM as VMBinding>::VMScanning::scan_vm_specific_roots(worker.tls, factory);
}
}