1use std::collections::HashSet;
2use std::mem::swap;
3use std::sync::Mutex;
4
5use crate::util::ObjectReference;
6
7use super::object_enum::ObjectEnumerator;
8
9pub struct TreadMill {
13 sync: Mutex<TreadMillSync>,
14}
15
16#[derive(Default)]
18struct TreadMillSync {
19 from_space: HashSet<ObjectReference>,
21 to_space: HashSet<ObjectReference>,
24 collect_nursery: HashSet<ObjectReference>,
26 alloc_nursery: HashSet<ObjectReference>,
29}
30
31impl std::fmt::Debug for TreadMill {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 let sync = self.sync.lock().unwrap();
34 f.debug_struct("TreadMill")
35 .field("from_space", &sync.from_space)
36 .field("to_space", &sync.to_space)
37 .field("collect_nursery", &sync.collect_nursery)
38 .field("alloc_nursery", &sync.alloc_nursery)
39 .finish()
40 }
41}
42
43impl TreadMill {
44 pub fn new() -> Self {
45 TreadMill {
46 sync: Mutex::new(Default::default()),
47 }
48 }
49
50 pub fn add_to_treadmill(&self, object: ObjectReference, nursery: bool) {
55 let mut sync = self.sync.lock().unwrap();
56 if nursery {
57 trace!("Adding {} to alloc_nursery", object);
58 sync.alloc_nursery.insert(object);
59 } else {
60 trace!("Adding {} to to_space", object);
61 sync.to_space.insert(object);
62 }
63 }
64
65 pub fn collect_nursery(&self) -> impl IntoIterator<Item = ObjectReference> {
68 let mut sync = self.sync.lock().unwrap();
69 std::mem::take(&mut sync.collect_nursery)
70 }
71
72 pub fn collect_mature(&self) -> impl IntoIterator<Item = ObjectReference> {
75 let mut sync = self.sync.lock().unwrap();
76 std::mem::take(&mut sync.from_space)
77 }
78
79 pub fn copy(&self, object: ObjectReference, is_in_nursery: bool) {
81 let mut sync = self.sync.lock().unwrap();
82 if is_in_nursery {
83 debug_assert!(
84 sync.collect_nursery.contains(&object),
85 "copy source object ({}) must be in collect_nursery",
86 object
87 );
88 sync.collect_nursery.remove(&object);
89 } else {
90 debug_assert!(
91 sync.from_space.contains(&object),
92 "copy source object ({}) must be in from_space",
93 object
94 );
95 sync.from_space.remove(&object);
96 }
97 sync.to_space.insert(object);
98 }
99
100 pub fn is_to_space_empty(&self) -> bool {
102 let sync = self.sync.lock().unwrap();
103 sync.to_space.is_empty()
104 }
105
106 pub fn is_from_space_empty(&self) -> bool {
108 let sync = self.sync.lock().unwrap();
109 sync.from_space.is_empty()
110 }
111
112 pub fn is_alloc_nursery_empty(&self) -> bool {
114 let sync = self.sync.lock().unwrap();
115 sync.alloc_nursery.is_empty()
116 }
117
118 pub fn is_collect_nursery_empty(&self) -> bool {
120 let sync = self.sync.lock().unwrap();
121 sync.collect_nursery.is_empty()
122 }
123
124 pub fn flip(&mut self, full_heap: bool) {
130 let sync = self.sync.get_mut().unwrap();
131 swap(&mut sync.alloc_nursery, &mut sync.collect_nursery);
132 trace!("Flipped alloc_nursery and collect_nursery");
133 if full_heap {
134 swap(&mut sync.from_space, &mut sync.to_space);
135 trace!("Flipped from_space and to_space");
136 }
137 }
138
139 pub(crate) fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator, all: bool) {
146 let sync = self.sync.lock().unwrap();
147 let mut enumerated = 0usize;
148 let mut visit_objects = |set: &HashSet<ObjectReference>| {
149 for object in set.iter() {
150 enumerator.visit_object(*object);
151 enumerated += 1;
152 }
153 };
154 visit_objects(&sync.alloc_nursery);
155 visit_objects(&sync.to_space);
156
157 if all {
158 visit_objects(&sync.collect_nursery);
159 visit_objects(&sync.from_space);
160 }
161
162 debug!("Enumerated {enumerated} objects in LOS. all: {all}. from_space: {fs}, to_space: {ts}, collect_nursery: {cn}, alloc_nursery: {an}",
163 fs=sync.from_space.len(),
164 ts=sync.to_space.len(),
165 cn=sync.collect_nursery.len(),
166 an=sync.alloc_nursery.len(),
167 );
168 }
169}
170
171impl Default for TreadMill {
172 fn default() -> Self {
173 Self::new()
174 }
175}