1use std::marker::PhantomData;
5
6use crate::scheduler::gc_work::{ProcessEdgesWork, SlotOf};
7use crate::scheduler::{GCWorker, WorkBucketStage, EDGES_WORK_BUFFER_SIZE};
8use crate::util::{ObjectReference, VMThread, VMWorkerThread};
9use crate::vm::{Scanning, SlotVisitor, VMBinding};
10
11pub trait ObjectQueue {
13 fn enqueue(&mut self, object: ObjectReference);
15}
16
17pub type VectorObjectQueue = VectorQueue<ObjectReference>;
19
20pub struct VectorQueue<T> {
24 buffer: Vec<T>,
26}
27
28impl<T> VectorQueue<T> {
29 const CAPACITY: usize = EDGES_WORK_BUFFER_SIZE;
31
32 pub fn new() -> Self {
34 Self { buffer: Vec::new() }
35 }
36
37 pub fn is_empty(&self) -> bool {
39 self.buffer.is_empty()
40 }
41
42 pub fn take(&mut self) -> Vec<T> {
44 std::mem::take(&mut self.buffer)
45 }
46
47 pub fn into_vec(self) -> Vec<T> {
49 self.buffer
50 }
51
52 pub fn is_full(&self) -> bool {
54 self.buffer.len() >= Self::CAPACITY
55 }
56
57 pub fn push(&mut self, v: T) {
63 if self.buffer.is_empty() {
64 self.buffer.reserve(Self::CAPACITY);
65 }
66 self.buffer.push(v);
67 }
68
69 pub fn len(&self) -> usize {
71 self.buffer.len()
72 }
73
74 pub fn clear(&mut self) {
76 self.buffer.clear()
77 }
78}
79
80impl<T> Default for VectorQueue<T> {
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86impl ObjectQueue for VectorQueue<ObjectReference> {
87 fn enqueue(&mut self, v: ObjectReference) {
88 self.push(v);
89 }
90}
91
92pub struct ObjectsClosure<'a, E: ProcessEdgesWork> {
96 buffer: VectorQueue<SlotOf<E>>,
97 pub(crate) worker: &'a mut GCWorker<E::VM>,
98 bucket: WorkBucketStage,
99}
100
101impl<'a, E: ProcessEdgesWork> ObjectsClosure<'a, E> {
102 pub fn new(worker: &'a mut GCWorker<E::VM>, bucket: WorkBucketStage) -> Self {
108 Self {
109 buffer: VectorQueue::new(),
110 worker,
111 bucket,
112 }
113 }
114
115 fn flush(&mut self) {
116 let buf = self.buffer.take();
117 if !buf.is_empty() {
118 self.worker.add_work(
119 self.bucket,
120 E::new(buf, false, self.worker.mmtk, self.bucket),
121 );
122 }
123 }
124}
125
126impl<E: ProcessEdgesWork> SlotVisitor<SlotOf<E>> for ObjectsClosure<'_, E> {
127 fn visit_slot(&mut self, slot: SlotOf<E>) {
128 #[cfg(debug_assertions)]
129 {
130 use crate::vm::slot::Slot;
131 trace!(
132 "(ObjectsClosure) Visit slot {:?} (pointing to {:?})",
133 slot,
134 slot.load()
135 );
136 }
137 self.buffer.push(slot);
138 if self.buffer.is_full() {
139 self.flush();
140 }
141 }
142}
143
144impl<E: ProcessEdgesWork> Drop for ObjectsClosure<'_, E> {
145 fn drop(&mut self) {
146 self.flush();
147 }
148}
149
150pub(crate) struct SlotIterator<VM: VMBinding> {
155 _p: PhantomData<VM>,
156}
157
158impl<VM: VMBinding> SlotIterator<VM> {
159 pub fn iterate_fields<F: FnMut(VM::VMSlot)>(object: ObjectReference, _tls: VMThread, mut f: F) {
161 let fake_tls = VMWorkerThread(VMThread::UNINITIALIZED);
164 if !<VM::VMScanning as Scanning<VM>>::support_slot_enqueuing(fake_tls, object) {
165 panic!("SlotIterator::iterate_fields cannot be used on objects that don't support slot-enqueuing");
166 }
167 <VM::VMScanning as Scanning<VM>>::scan_object(fake_tls, object, &mut f);
168 }
169}