mmtk/plan/tracing/gc_work/
mod.rs

1pub(crate) mod closure;
2pub(crate) mod root;
3pub(crate) mod weakref;
4
5use std::marker::PhantomData;
6
7use crate::{
8    plan::{
9        tracing::{gc_work::closure::ProcessNodes, Trace},
10        VectorObjectQueue,
11    },
12    scheduler::{GCWorker, WorkBucketStage},
13    util::ObjectReference,
14    vm::{ObjectTracer, ObjectTracerContext},
15};
16
17/// This implementation of [`ObjectTracerContext`] creates the [`DefaultObjectTracer`] to expand the
18/// transitive closure during a stop-the-world tracing GC or the final mark pause of a concurrent
19/// GC.  It is used during object scanning as well as weak reference processing.
20#[derive(Clone)]
21pub(crate) struct DefaultObjectTracerContext<T: Trace> {
22    stage: WorkBucketStage,
23    phantom_data: PhantomData<T>,
24}
25
26impl<T: Trace> DefaultObjectTracerContext<T> {
27    pub fn new(stage: WorkBucketStage) -> Self {
28        Self {
29            stage,
30            phantom_data: PhantomData,
31        }
32    }
33}
34
35impl<T: Trace> ObjectTracerContext<T::VM> for DefaultObjectTracerContext<T> {
36    type TracerType<'w> = DefaultObjectTracer<'w, T>;
37
38    fn with_tracer<'w, R, F>(&self, worker: &'w mut GCWorker<T::VM>, func: F) -> R
39    where
40        F: FnOnce(&mut Self::TracerType<'w>) -> R,
41    {
42        let mmtk = worker.mmtk;
43
44        // Create the callback tracer.
45        let mut tracer = DefaultObjectTracer::new(worker, T::from_mmtk(mmtk), self.stage);
46
47        // The caller can use the tracer here.
48        let result = func(&mut tracer);
49
50        // Flush the queued nodes.
51        tracer.flush_if_not_empty();
52
53        result
54    }
55}
56
57/// This implementation of [`ObjectTracer`] queues newly visited objects and create the
58/// [`ProcessNodes`] work packets to scan and trace objects.
59pub(crate) struct DefaultObjectTracer<'w, T: Trace> {
60    worker: &'w mut GCWorker<T::VM>,
61    trace: T,
62    queue: VectorObjectQueue,
63    stage: WorkBucketStage,
64}
65
66impl<T: Trace> ObjectTracer for DefaultObjectTracer<'_, T> {
67    /// Forward the `trace_object` call to the underlying `Trace`,
68    /// and flush as soon as `self.queue` is full.
69    fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
70        let result = self
71            .trace
72            .trace_object(self.worker, object, &mut self.queue);
73        self.flush_if_full();
74        result
75    }
76}
77
78impl<'w, T: Trace> DefaultObjectTracer<'w, T> {
79    fn new(worker: &'w mut GCWorker<T::VM>, trace: T, stage: WorkBucketStage) -> Self {
80        Self {
81            worker,
82            trace,
83            queue: VectorObjectQueue::new(),
84            stage,
85        }
86    }
87
88    fn flush_if_full(&mut self) {
89        if self.queue.is_full() {
90            self.flush();
91        }
92    }
93
94    pub fn flush_if_not_empty(&mut self) {
95        if !self.queue.is_empty() {
96            self.flush();
97        }
98    }
99
100    fn flush(&mut self) {
101        let next_nodes = self.queue.take();
102        assert!(!next_nodes.is_empty());
103        let work_packet = ProcessNodes::<T>::new(next_nodes, self.stage);
104        self.worker.scheduler().work_buckets[self.stage].add(work_packet);
105    }
106}