1use crate::barrier::SatbBuffer;
24use crate::header::{GcColor, GcHeader};
25use std::collections::HashSet;
26use std::sync::atomic::{AtomicBool, Ordering};
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum MarkPhase {
31 Idle,
33 Marking,
35 Terminating,
37 Complete,
39}
40
41pub struct Marker {
43 worklist: Vec<*mut u8>,
45 live_set: HashSet<usize>,
47 is_marking: AtomicBool,
52 phase: MarkPhase,
54}
55
56unsafe impl Send for Marker {}
58
59impl Marker {
60 pub fn new() -> Self {
61 Self {
62 worklist: Vec::with_capacity(1024),
63 live_set: HashSet::with_capacity(4096),
64 is_marking: AtomicBool::new(false),
65 phase: MarkPhase::Idle,
66 }
67 }
68
69 pub fn reset(&mut self) {
71 self.worklist.clear();
72 self.live_set.clear();
73 self.is_marking.store(false, Ordering::Release);
74 self.phase = MarkPhase::Idle;
75 }
76
77 pub fn start_marking(&mut self) {
84 self.worklist.clear();
85 self.live_set.clear();
86 self.is_marking.store(true, Ordering::Release);
87 self.phase = MarkPhase::Marking;
88 }
89
90 pub fn finish_marking(&mut self) {
92 self.is_marking.store(false, Ordering::Release);
93 self.phase = MarkPhase::Idle;
94 }
95
96 #[inline(always)]
100 pub fn is_marking(&self) -> bool {
101 self.is_marking.load(Ordering::Acquire)
102 }
103
104 pub fn phase(&self) -> MarkPhase {
106 self.phase
107 }
108
109 pub fn mark_root(&mut self, ptr: *mut u8) {
113 if ptr.is_null() {
114 return;
115 }
116 let header = Self::header_of(ptr);
117 if header.color() == GcColor::White {
118 header.set_color(GcColor::Gray);
119 self.worklist.push(ptr);
120 self.live_set.insert(ptr as usize);
121 }
122 }
123
124 pub fn mark_gray(&mut self, ptr: *mut u8) {
128 if ptr.is_null() {
129 return;
130 }
131 if self.live_set.insert(ptr as usize) {
133 let header = Self::header_of(ptr);
134 header.set_color(GcColor::Gray);
135 self.worklist.push(ptr);
136 } else {
137 let header = Self::header_of(ptr);
140 if header.color() == GcColor::White {
141 header.set_color(GcColor::Gray);
142 self.worklist.push(ptr);
143 }
144 }
145 }
146
147 pub fn mark_child(&mut self, ptr: *mut u8) {
150 if ptr.is_null() {
151 return;
152 }
153 let header = Self::header_of(ptr);
154 if header.color() == GcColor::White {
155 header.set_color(GcColor::Gray);
156 self.worklist.push(ptr);
157 self.live_set.insert(ptr as usize);
158 }
159 }
160
161 pub fn mark_step(&mut self, budget: usize) -> bool {
173 let mut processed = 0;
174 while processed < budget {
175 let Some(ptr) = self.worklist.pop() else {
176 return true;
177 };
178
179 let header = Self::header_of(ptr);
180
181 if header.color() == GcColor::Black {
183 continue;
184 }
185
186 header.set_color(GcColor::Black);
191 processed += 1;
192 }
193 self.worklist.is_empty()
194 }
195
196 pub fn mark_all(&mut self) {
198 while !self.mark_step(256) {}
199 }
200
201 pub fn terminate_marking(&mut self, satb: &mut SatbBuffer) -> bool {
212 self.phase = MarkPhase::Terminating;
213
214 for ptr in satb.drain() {
217 if !self.is_marked(ptr) {
218 self.mark_gray(ptr);
219 }
220 }
221
222 while let Some(obj) = self.worklist.pop() {
224 let header = Self::header_of(obj);
225 if header.color() != GcColor::Black {
226 header.set_color(GcColor::Black);
227 }
228 }
230
231 let terminated = self.worklist.is_empty() && satb.is_empty();
232 if terminated {
233 self.phase = MarkPhase::Complete;
234 }
235 terminated
236 }
237
238 pub fn is_marked(&self, ptr: *const u8) -> bool {
242 self.live_set.contains(&(ptr as usize))
243 }
244
245 pub fn is_live(&self, ptr: *const u8) -> bool {
247 self.is_marked(ptr)
248 }
249
250 pub fn gray_count(&self) -> usize {
252 self.worklist.len()
253 }
254
255 pub fn live_count(&self) -> usize {
257 self.live_set.len()
258 }
259
260 pub fn clear_mark(&self, ptr: *mut u8) {
264 let header = Self::header_of(ptr);
265 header.set_color(GcColor::White);
266 }
267
268 fn header_of(ptr: *mut u8) -> &'static mut GcHeader {
275 unsafe {
276 let header_ptr = ptr.sub(std::mem::size_of::<GcHeader>()) as *mut GcHeader;
277 &mut *header_ptr
278 }
279 }
280}
281
282impl Default for Marker {
283 fn default() -> Self {
284 Self::new()
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291 use crate::header::GcHeader;
292
293 fn make_fake_object() -> Vec<u8> {
294 let mut buf = vec![0u8; 16]; let header_ptr = buf.as_mut_ptr() as *mut GcHeader;
296 unsafe {
297 header_ptr.write(GcHeader::new(0, 8));
298 }
299 buf
300 }
301
302 #[test]
303 fn test_mark_root_colors_gray() {
304 let mut buf = make_fake_object();
305 let obj_ptr = unsafe { buf.as_mut_ptr().add(8) };
306
307 let mut marker = Marker::new();
308 marker.mark_root(obj_ptr);
309
310 let header = unsafe { &*(buf.as_ptr() as *const GcHeader) };
311 assert_eq!(header.color(), GcColor::Gray);
312 assert_eq!(marker.gray_count(), 1);
313 }
314
315 #[test]
316 fn test_mark_step_colors_black() {
317 let mut buf = make_fake_object();
318 let obj_ptr = unsafe { buf.as_mut_ptr().add(8) };
319
320 let mut marker = Marker::new();
321 marker.mark_root(obj_ptr);
322 let done = marker.mark_step(10);
323 assert!(done);
324
325 let header = unsafe { &*(buf.as_ptr() as *const GcHeader) };
326 assert_eq!(header.color(), GcColor::Black);
327 assert_eq!(marker.gray_count(), 0);
328 }
329
330 #[test]
331 fn test_null_root_ignored() {
332 let mut marker = Marker::new();
333 marker.mark_root(std::ptr::null_mut());
334 assert_eq!(marker.gray_count(), 0);
335 }
336
337 #[test]
338 fn test_is_marking_flag() {
339 let mut marker = Marker::new();
340 assert!(!marker.is_marking());
341
342 marker.start_marking();
343 assert!(marker.is_marking());
344 assert_eq!(marker.phase(), MarkPhase::Marking);
345
346 marker.finish_marking();
347 assert!(!marker.is_marking());
348 assert_eq!(marker.phase(), MarkPhase::Idle);
349 }
350
351 #[test]
352 fn test_mark_gray_adds_to_worklist() {
353 let mut buf = make_fake_object();
354 let obj_ptr = unsafe { buf.as_mut_ptr().add(8) };
355
356 let mut marker = Marker::new();
357 marker.start_marking();
358 marker.mark_gray(obj_ptr);
359
360 assert_eq!(marker.gray_count(), 1);
361 assert!(marker.is_marked(obj_ptr));
362 }
363
364 #[test]
365 fn test_mark_gray_idempotent() {
366 let mut buf = make_fake_object();
367 let obj_ptr = unsafe { buf.as_mut_ptr().add(8) };
368
369 let mut marker = Marker::new();
370 marker.start_marking();
371 marker.mark_gray(obj_ptr);
372 marker.mark_gray(obj_ptr); assert_eq!(marker.live_count(), 1);
375 }
376
377 #[test]
378 fn test_incremental_mark_step_budget() {
379 let mut bufs: Vec<Vec<u8>> = (0..5).map(|_| make_fake_object()).collect();
381 let ptrs: Vec<*mut u8> = bufs
382 .iter_mut()
383 .map(|b| unsafe { b.as_mut_ptr().add(8) })
384 .collect();
385
386 let mut marker = Marker::new();
387 marker.start_marking();
388 for &ptr in &ptrs {
389 marker.mark_root(ptr);
390 }
391 assert_eq!(marker.gray_count(), 5);
392
393 let done = marker.mark_step(2);
395 assert!(!done);
396 assert_eq!(marker.gray_count(), 3);
398
399 let done = marker.mark_step(10);
401 assert!(done);
402 assert_eq!(marker.gray_count(), 0);
403 }
404
405 #[test]
406 fn test_terminate_marking_empty_satb() {
407 let mut buf = make_fake_object();
408 let obj_ptr = unsafe { buf.as_mut_ptr().add(8) };
409
410 let mut marker = Marker::new();
411 marker.start_marking();
412 marker.mark_root(obj_ptr);
413 marker.mark_all();
414
415 let mut satb = SatbBuffer::new(64);
416 let terminated = marker.terminate_marking(&mut satb);
417 assert!(terminated);
418 assert_eq!(marker.phase(), MarkPhase::Complete);
419 }
420
421 #[test]
422 fn test_terminate_marking_with_satb_entries() {
423 let mut buf1 = make_fake_object();
424 let mut buf2 = make_fake_object();
425 let ptr1 = unsafe { buf1.as_mut_ptr().add(8) };
426 let ptr2 = unsafe { buf2.as_mut_ptr().add(8) };
427
428 let mut marker = Marker::new();
429 marker.start_marking();
430 marker.mark_root(ptr1);
431 marker.mark_all();
432
433 let mut satb = SatbBuffer::new(64);
435 satb.enqueue(ptr2);
436
437 let terminated = marker.terminate_marking(&mut satb);
438 assert!(terminated);
439 assert!(marker.is_marked(ptr2));
441 }
442
443 #[test]
444 fn test_clear_mark() {
445 let mut buf = make_fake_object();
446 let obj_ptr = unsafe { buf.as_mut_ptr().add(8) };
447
448 let mut marker = Marker::new();
449 marker.mark_root(obj_ptr);
450 marker.mark_all();
451
452 let header = unsafe { &*(buf.as_ptr() as *const GcHeader) };
453 assert_eq!(header.color(), GcColor::Black);
454
455 marker.clear_mark(obj_ptr);
456 assert_eq!(header.color(), GcColor::White);
457 }
458
459 #[test]
460 fn test_full_incremental_cycle() {
461 let mut bufs: Vec<Vec<u8>> = (0..10).map(|_| make_fake_object()).collect();
463 let ptrs: Vec<*mut u8> = bufs
464 .iter_mut()
465 .map(|b| unsafe { b.as_mut_ptr().add(8) })
466 .collect();
467
468 let mut marker = Marker::new();
469 marker.start_marking();
470
471 for &ptr in &ptrs {
473 marker.mark_root(ptr);
474 }
475
476 let mut steps = 0;
478 while !marker.mark_step(3) {
479 steps += 1;
480 }
481 assert!(steps >= 1);
483
484 let mut satb = SatbBuffer::new(64);
486 let terminated = marker.terminate_marking(&mut satb);
487 assert!(terminated);
488 assert_eq!(marker.phase(), MarkPhase::Complete);
489
490 for &ptr in &ptrs {
492 assert!(marker.is_marked(ptr));
493 }
494
495 marker.finish_marking();
496 assert!(!marker.is_marking());
497 assert_eq!(marker.phase(), MarkPhase::Idle);
498 }
499}