mmtk/plan/lxr/gc_work/
mature_sweeping.rs1use 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
16pub 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 #[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 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 continue;
69 } else {
70 std::sync::atomic::fence(Ordering::SeqCst);
72 if self.rc.count(o) == 0 {
73 continue;
74 }
75 }
76 }
77 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}