mmtk/plan/lxr/gc_work/
mature_sweeping.rs

1use std::ops::Range;
2use std::sync::atomic::Ordering;
3
4use crate::plan::lxr::{LazySweepingJobsCounter, LXR};
5use crate::policy::immix::block::{Block, BlockState};
6use crate::policy::immix::line::Line;
7use crate::policy::immix::ImmixSpace;
8use crate::scheduler::{GCWork, GCWorker};
9use crate::util::heap::chunk_map::Chunk;
10use crate::util::linear_scan::Region;
11use crate::util::rc::{self, RefCountHelper};
12use crate::util::ObjectReference;
13use crate::vm::VMBinding;
14use crate::MMTK;
15
16/// Chunk sweeping work packet.
17pub struct SweepDeadCycles<VM: VMBinding> {
18    chunks: Range<Chunk>,
19    _counter: LazySweepingJobsCounter,
20    rc: RefCountHelper<VM>,
21}
22
23#[allow(unused)]
24impl<VM: VMBinding> SweepDeadCycles<VM> {
25    const CAPACITY: usize = 1024;
26
27    pub fn new(chunks: Range<Chunk>, counter: LazySweepingJobsCounter) -> Self {
28        Self {
29            chunks,
30            _counter: counter,
31            rc: RefCountHelper::NEW,
32        }
33    }
34
35    fn process_dead_object(&mut self, o: ObjectReference) {
36        if RefCountHelper::<VM>::SANITY {
37            unsafe {
38                o.to_raw_address().store(0xdeadusize);
39            }
40        }
41
42        // Clear the VO bit.
43        // Note that if the object is in the LOS,
44        // the VO bit will be cleared in `LargeObjectSpace::release_object`.
45        #[cfg(feature = "vo_bit")]
46        crate::util::metadata::vo_bit::unset_vo_bit(o);
47
48        self.rc.unmark_straddle_object(o);
49        self.rc.set(o, 0);
50    }
51
52    fn process_block(&mut self, block: Block, lxr: &LXR<VM>, immix_space: &ImmixSpace<VM>) {
53        let mut has_dead_object = false;
54        let mut has_live = false;
55        let mut cursor = block.start();
56        let limit = block.end();
57        while cursor < limit {
58            let cur_cursor = cursor;
59            cursor += rc::MIN_OBJECT_SIZE;
60            let c = self.rc.count_by_address(cur_cursor);
61            if c != 0 {
62                // Safety: cur_cursor is either a valid object reference, or a straddle line
63                let o = unsafe { ObjectReference::from_raw_address_unchecked(cur_cursor) };
64                if !immix_space.is_marked(o) {
65                    if Line::is_aligned(o.to_raw_address()) {
66                        if c == 1 && self.rc.object_is_in_straddle_line_no_rc_check(o) {
67                            // this is a straddle line, skip
68                            continue;
69                        } else {
70                            // Now o is a valid object reference
71                            std::sync::atomic::fence(Ordering::SeqCst);
72                            if self.rc.count(o) == 0 {
73                                continue;
74                            }
75                        }
76                    }
77                    // o is still a valid object here.
78                    self.process_dead_object(o);
79                    has_dead_object = true;
80                } else {
81                    has_live = true;
82                }
83            }
84        }
85        if has_dead_object || !has_live {
86            lxr.add_to_possibly_dead_mature_blocks(block, false);
87        }
88    }
89}
90
91impl<VM: VMBinding> GCWork<VM> for SweepDeadCycles<VM> {
92    fn do_work(&mut self, _worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
93        let lxr = mmtk.get_plan().downcast_ref::<LXR<VM>>().unwrap();
94        let immix_space = &lxr.immix_space;
95        let num_chunks = (self.chunks.end.start() - self.chunks.start.start()) >> Chunk::LOG_BYTES;
96        let ix_space = &mmtk
97            .get_plan()
98            .downcast_ref::<LXR<VM>>()
99            .unwrap()
100            .immix_space;
101        for i in 0..num_chunks {
102            let chunk = self.chunks.start.next_nth(i);
103            if !ix_space.chunk_map.is_allocated(chunk) {
104                continue;
105            }
106
107            for block in chunk
108                .iter_region::<Block>()
109                .filter(|block| block.get_state() != BlockState::Unallocated)
110            {
111                if block.is_defrag_source() || block.get_state() == BlockState::Nursery {
112                    continue;
113                } else {
114                    self.process_block(block, lxr, immix_space)
115                }
116            }
117        }
118    }
119}
120
121pub struct RCSweepMatureAfterSATBLOS {
122    _counter: LazySweepingJobsCounter,
123}
124
125impl RCSweepMatureAfterSATBLOS {
126    pub fn new(counter: LazySweepingJobsCounter) -> Self {
127        Self { _counter: counter }
128    }
129}
130
131impl<VM: VMBinding> GCWork<VM> for RCSweepMatureAfterSATBLOS {
132    fn do_work(&mut self, _worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
133        let los = mmtk.get_plan().common().get_los();
134        los.sweep_rc_mature_objects_after_satb(&|o| los.is_marked(o) || los.rc.count(o) == 0);
135    }
136}