1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use crate::{
    gc_info_table::GC_TABLE,
    gc_size,
    global_allocator::GlobalAllocator,
    header::CellState,
    header::HeapObjectHeader,
    heap::Heap,
    internal::{gc_info::GCInfoIndex, trace_trait::TraceDescriptor},
    visitor::{Visitor, VisitorTrait},
};

pub struct MarkingVisitor {
    worklist: Vec<TraceDescriptor>,
    heap: *mut GlobalAllocator,
    h: *mut Heap,
    bytes_visited: usize,
}
#[inline]
unsafe fn trace_desc(ptr: *mut HeapObjectHeader) -> TraceDescriptor {
    TraceDescriptor {
        base_object_payload: (*ptr).payload(),
        callback: GC_TABLE.get_gc_info((*ptr).get_gc_info_index()).trace,
    }
}
impl VisitorTrait for MarkingVisitor {
    fn heap(&self) -> *mut Heap {
        self.h
    }
    fn visit(
        &mut self,
        this: *const u8,
        descriptor: crate::internal::trace_trait::TraceDescriptor,
    ) {
        unsafe {
            let header = HeapObjectHeader::from_object(this);
            let res = (*self.h).test_and_set_marked(header);

            if !res {
                (*header).force_set_state(CellState::PossiblyGrey);
                self.bytes_visited += gc_size(header);
                self.worklist.push(descriptor);
            }
        }
    }

    fn visit_conservative(&mut self, from: *const *const u8, to: *const *const u8) {
        let mut scan = from;
        let end = to;

        while scan < end {
            unsafe {
                let pointer = scan.read();

                if (*self.heap).block_allocator.is_in_space(pointer) {
                    let cell = pointer;
                    if cell as usize % 8 == 0 && (*self.heap).live_bitmap.has_address(cell) {
                        if (*self.heap).live_bitmap.test(cell)
                            && (*cell.cast::<HeapObjectHeader>()).get_gc_info_index()
                                != GCInfoIndex(0)
                        {
                            let hdr = cell.cast::<HeapObjectHeader>();

                            self.visit((*hdr).payload(), trace_desc(hdr as _));
                        }
                    }
                } else {
                    let hdr = (*self.heap).large_space.contains(pointer);

                    if !hdr.is_null() {
                        self.visit((*hdr).payload(), trace_desc(hdr));
                    }
                }
                scan = scan.add(1);
            }
        }
    }
}

pub struct SynchronousMarking<'a> {
    heap: &'a mut Heap,
}

impl<'a> SynchronousMarking<'a> {
    pub fn new(heap: &'a mut Heap) -> Self {
        Self { heap }
    }
    pub fn run(&mut self) -> usize {
        let mut vis = MarkingVisitor {
            worklist: vec![],
            heap: &mut self.heap.global,
            bytes_visited: 0,
            h: self.heap as *mut _,
        };

        let mut constraints = std::mem::replace(&mut self.heap.constraints, vec![]);
        for c in constraints.iter_mut() {
            c.execute(&mut Visitor { vis: &mut vis })
        }
        self.heap.constraints = constraints;
        while let Some(desc) = vis.worklist.pop() {
            unsafe {
                let hdr = HeapObjectHeader::from_object(desc.base_object_payload);

                assert!((*hdr).set_state(CellState::PossiblyGrey, CellState::PossiblyBlack));
                (desc.callback)(&mut Visitor { vis: &mut vis }, desc.base_object_payload);
            }
        }
        vis.bytes_visited
    }
}