1use crate::util::metadata::vo_bit;
2use crate::util::Address;
3use crate::util::ObjectReference;
4use crate::vm::ObjectModel;
5use crate::vm::VMBinding;
6use std::marker::PhantomData;
7
8pub struct ObjectIterator<VM: VMBinding, S: LinearScanObjectSize, const ATOMIC_LOAD_VO_BIT: bool> {
17 start: Address,
18 end: Address,
19 cursor: Address,
20 _p: PhantomData<(VM, S)>,
21}
22
23impl<VM: VMBinding, S: LinearScanObjectSize, const ATOMIC_LOAD_VO_BIT: bool>
24 ObjectIterator<VM, S, ATOMIC_LOAD_VO_BIT>
25{
26 pub fn new(start: Address, end: Address) -> Self {
29 debug_assert!(start < end);
30 debug_assert!(
31 start.is_aligned_to(ObjectReference::ALIGNMENT),
32 "start is not word-aligned: {start}"
33 );
34 debug_assert!(
35 end.is_aligned_to(ObjectReference::ALIGNMENT),
36 "end is not word-aligned: {end}"
37 );
38 ObjectIterator {
39 start,
40 end,
41 cursor: start,
42 _p: PhantomData,
43 }
44 }
45}
46
47impl<VM: VMBinding, S: LinearScanObjectSize, const ATOMIC_LOAD_VO_BIT: bool> std::iter::Iterator
48 for ObjectIterator<VM, S, ATOMIC_LOAD_VO_BIT>
49{
50 type Item = ObjectReference;
51
52 fn next(&mut self) -> Option<<Self as Iterator>::Item> {
53 while self.cursor < self.end {
54 let is_object = if ATOMIC_LOAD_VO_BIT {
55 vo_bit::is_vo_bit_set_for_addr(self.cursor)
56 } else {
57 unsafe { vo_bit::is_vo_bit_set_unsafe(self.cursor) }
58 };
59
60 if let Some(object) = is_object {
62 self.cursor = (self.cursor + S::size(object)).align_up(ObjectReference::ALIGNMENT);
64 return Some(object);
65 } else {
66 self.cursor += ObjectReference::ALIGNMENT;
67 }
68 }
69
70 None
71 }
72}
73
74pub trait LinearScanObjectSize {
77 fn size(object: ObjectReference) -> usize;
79}
80
81pub struct DefaultObjectSize<VM: VMBinding>(PhantomData<VM>);
83impl<VM: VMBinding> LinearScanObjectSize for DefaultObjectSize<VM> {
84 fn size(object: ObjectReference) -> usize {
85 VM::VMObjectModel::get_current_size(object)
86 }
87}
88
89pub trait Region: Copy + PartialEq + PartialOrd {
92 const LOG_BYTES: usize;
94 const BYTES: usize = 1 << Self::LOG_BYTES;
96
97 fn from_aligned_address(address: Address) -> Self;
100 fn start(&self) -> Address;
102
103 fn from_unaligned_address(address: Address) -> Self {
105 Self::from_aligned_address(Self::align(address))
106 }
107
108 fn align(address: Address) -> Address {
110 address.align_down(Self::BYTES)
111 }
112 fn is_aligned(address: Address) -> bool {
114 address.is_aligned_to(Self::BYTES)
115 }
116
117 fn end(&self) -> Address {
119 self.start() + Self::BYTES
120 }
121 fn next(&self) -> Self {
123 self.next_nth(1)
124 }
125 fn next_nth(&self, n: usize) -> Self {
127 debug_assert!(self.start().as_usize() < usize::MAX - (n << Self::LOG_BYTES));
128 Self::from_aligned_address(self.start() + (n << Self::LOG_BYTES))
129 }
130 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
132 if start.start() > end.start() {
133 return None;
134 }
135 Some((end.start() - start.start()) >> Self::LOG_BYTES)
136 }
137 fn includes_address(&self, addr: Address) -> bool {
139 Self::align(addr) == self.start()
140 }
141}
142
143#[allow(rustdoc::private_intra_doc_links)]
160pub trait UnstraddlableRegion: Region {
161 fn containing(object: ObjectReference) -> Self {
163 Self::from_unaligned_address(object.to_raw_address())
164 }
165
166 fn contains(&self, object: ObjectReference) -> bool {
168 self.includes_address(object.to_raw_address())
169 }
170}
171
172pub struct RegionIterator<R: Region> {
174 current: R,
175 end: R,
176}
177
178impl<R: Region> RegionIterator<R> {
179 pub fn new(start: R, end: R) -> Self {
181 Self {
182 current: start,
183 end,
184 }
185 }
186}
187
188impl<R: Region> Iterator for RegionIterator<R> {
189 type Item = R;
190
191 fn next(&mut self) -> Option<R> {
192 if self.current < self.end {
193 let ret = self.current;
194 self.current = self.current.next();
195 Some(ret)
196 } else {
197 None
198 }
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::util::constants::LOG_BYTES_IN_PAGE;
206
207 const PAGE_SIZE: usize = 1 << LOG_BYTES_IN_PAGE;
208
209 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
210 struct Page(Address);
211
212 impl Region for Page {
213 const LOG_BYTES: usize = LOG_BYTES_IN_PAGE as usize;
214
215 fn from_aligned_address(address: Address) -> Self {
216 debug_assert!(address.is_aligned_to(Self::BYTES));
217 Self(address)
218 }
219
220 fn start(&self) -> Address {
221 self.0
222 }
223 }
224
225 #[test]
226 fn test_region_methods() {
227 let addr4k = unsafe { Address::from_usize(PAGE_SIZE) };
228 let addr4k1 = unsafe { Address::from_usize(PAGE_SIZE + 1) };
229
230 debug_assert_eq!(Page::align(addr4k), addr4k);
232 debug_assert_eq!(Page::align(addr4k1), addr4k);
233 debug_assert!(Page::is_aligned(addr4k));
234 debug_assert!(!Page::is_aligned(addr4k1));
235
236 let page = Page::from_aligned_address(addr4k);
237 debug_assert_eq!(page.start(), addr4k);
239 debug_assert_eq!(page.end(), addr4k + PAGE_SIZE);
240 debug_assert_eq!(page.next().start(), addr4k + PAGE_SIZE);
242 debug_assert_eq!(page.next_nth(1).start(), addr4k + PAGE_SIZE);
243 debug_assert_eq!(page.next_nth(2).start(), addr4k + 2 * PAGE_SIZE);
244 }
245
246 #[test]
247 fn test_region_iterator_normal() {
248 let addr4k = unsafe { Address::from_usize(PAGE_SIZE) };
249 let page = Page::from_aligned_address(addr4k);
250 let end_page = page.next_nth(5);
251
252 let mut results = vec![];
253 let iter = RegionIterator::new(page, end_page);
254 for p in iter {
255 results.push(p);
256 }
257 debug_assert_eq!(
258 results,
259 vec![
260 page,
261 page.next_nth(1),
262 page.next_nth(2),
263 page.next_nth(3),
264 page.next_nth(4)
265 ]
266 );
267 }
268
269 #[test]
270 fn test_region_iterator_same_start_end() {
271 let addr4k = unsafe { Address::from_usize(PAGE_SIZE) };
272 let page = Page::from_aligned_address(addr4k);
273
274 let mut results = vec![];
275 let iter = RegionIterator::new(page, page);
276 for p in iter {
277 results.push(p);
278 }
279 debug_assert_eq!(results, vec![]);
280 }
281
282 #[test]
283 fn test_region_iterator_smaller_end() {
284 let addr4k = unsafe { Address::from_usize(PAGE_SIZE) };
285 let page = Page::from_aligned_address(addr4k);
286 let end = Page::from_aligned_address(Address::ZERO);
287
288 let mut results = vec![];
289 let iter = RegionIterator::new(page, end);
290 for p in iter {
291 results.push(p);
292 }
293 debug_assert_eq!(results, vec![]);
294 }
295}