mmtk/plan/generational/
gc_work.rs

1use atomic::Ordering;
2
3use crate::plan::tracing::gc_work::closure::{ProcessNodes, ProcessSlots};
4use crate::plan::tracing::Trace;
5use crate::plan::PlanTraceObject;
6use crate::policy::gc_work::TraceKind;
7use crate::scheduler::{GCWork, GCWorker, WorkBucketStage};
8use crate::util::os::*;
9use crate::util::ObjectReference;
10use crate::vm::slot::MemorySlice;
11use crate::vm::*;
12use crate::MMTK;
13use std::marker::PhantomData;
14
15use super::global::GenerationalPlanExt;
16
17/// A [`Trace`] implementation that dispatches the `trace_object` method through
18/// [`GenerationalPlanExt::trace_object_nursery`].  It is applicable to all plans that implement
19/// [`GenerationalPlanExt`].
20pub struct GenNurseryTrace<
21    VM: VMBinding,
22    P: GenerationalPlanExt<VM> + PlanTraceObject<VM>,
23    const KIND: TraceKind,
24> {
25    plan: &'static P,
26    phantom_data: PhantomData<VM>,
27}
28
29impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>, const KIND: TraceKind> Clone
30    for GenNurseryTrace<VM, P, KIND>
31{
32    fn clone(&self) -> Self {
33        Self {
34            plan: self.plan,
35            phantom_data: PhantomData,
36        }
37    }
38}
39
40impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>, const KIND: TraceKind> Trace
41    for GenNurseryTrace<VM, P, KIND>
42{
43    type VM = VM;
44
45    fn from_mmtk(mmtk: &'static MMTK<Self::VM>) -> Self {
46        Self {
47            plan: mmtk.get_plan().downcast_ref().unwrap(),
48            phantom_data: PhantomData,
49        }
50    }
51
52    fn trace_object<Q: crate::ObjectQueue>(
53        &self,
54        worker: &mut GCWorker<Self::VM>,
55        object: ObjectReference,
56        queue: &mut Q,
57    ) -> ObjectReference {
58        self.plan
59            .trace_object_nursery::<_, KIND>(queue, object, worker)
60    }
61
62    fn post_scan_object(&self, object: ObjectReference) {
63        self.plan.post_scan_object(object);
64    }
65
66    fn may_move_objects() -> bool {
67        // This is conservative.  Some nursery GCs do not move objects.
68        // For example, StickyImmix will not move objects during nursery GC
69        // if the "sticky_immix_non_moving_nursery" feature is enabled.
70        true
71    }
72}
73
74/// The modbuf contains a list of objects in mature space(s) that
75/// may contain pointers to the nursery space.
76/// This work packet scans the recorded objects and forwards pointers if necessary.
77pub struct ProcessModBuf<T: Trace> {
78    modbuf: Vec<ObjectReference>,
79    phantom: PhantomData<T>,
80}
81
82impl<T: Trace> ProcessModBuf<T> {
83    pub fn new(modbuf: Vec<ObjectReference>) -> Self {
84        debug_assert!(!modbuf.is_empty());
85        Self {
86            modbuf,
87            phantom: PhantomData,
88        }
89    }
90}
91
92impl<T: Trace> GCWork<T::VM> for ProcessModBuf<T> {
93    fn do_work(&mut self, worker: &mut GCWorker<T::VM>, mmtk: &'static MMTK<T::VM>) {
94        // Process and scan modbuf only if the current GC is a nursery GC
95        let gen = mmtk.get_plan().generational().unwrap();
96        if gen.is_current_gc_nursery() {
97            // Flip the per-object unlogged bits to "unlogged" state.
98            for obj in &self.modbuf {
99                debug_assert!(
100                    !gen.is_object_in_nursery(*obj),
101                    "{} was logged but is not mature. Dumping process memory maps:\n{}",
102                    *obj,
103                    OS::get_process_memory_maps().unwrap(),
104                );
105                <T::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::<T::VM, u8>(
106                    *obj,
107                    1,
108                    None,
109                    Ordering::SeqCst,
110                );
111            }
112            // Scan objects in the modbuf and forward pointers
113            let modbuf = std::mem::take(&mut self.modbuf);
114            GCWork::do_work(
115                &mut ProcessNodes::<T>::new(modbuf, WorkBucketStage::Closure),
116                worker,
117                mmtk,
118            )
119        }
120    }
121}
122
123/// The array-copy modbuf contains a list of array slices in mature space(s) that
124/// may contain pointers to the nursery space.
125/// This work packet forwards and updates each entry in the recorded slices.
126pub struct ProcessRegionModBuf<T: Trace> {
127    /// A list of `(start_address, bytes)` tuple.
128    modbuf: Vec<<T::VM as VMBinding>::VMMemorySlice>,
129    phantom: PhantomData<T>,
130}
131
132impl<T: Trace> ProcessRegionModBuf<T> {
133    pub fn new(modbuf: Vec<<T::VM as VMBinding>::VMMemorySlice>) -> Self {
134        Self {
135            modbuf,
136            phantom: PhantomData,
137        }
138    }
139}
140
141impl<T: Trace> GCWork<T::VM> for ProcessRegionModBuf<T> {
142    fn do_work(&mut self, worker: &mut GCWorker<T::VM>, mmtk: &'static MMTK<T::VM>) {
143        // Scan modbuf only if the current GC is a nursery GC
144        if mmtk
145            .get_plan()
146            .generational()
147            .unwrap()
148            .is_current_gc_nursery()
149        {
150            // Collect all the entries in all the slices
151            let mut slots = vec![];
152            for slice in &self.modbuf {
153                for slot in slice.iter_slots() {
154                    slots.push(slot);
155                }
156            }
157            // Forward entries
158            GCWork::do_work(
159                &mut ProcessSlots::<T>::new(slots, WorkBucketStage::Closure),
160                worker,
161                mmtk,
162            )
163        }
164    }
165}