Skip to main content

qanglang_core/memory/
upvalue_overflow_arena.rs

1use crate::arena::{Arena, Index};
2use crate::memory::ClosureHandle;
3
4pub const OVERFLOW_CHUNK_SIZE: usize = 8;
5
6pub type UpvalueOverflowHandle = Index;
7
8#[derive(Debug, Clone)]
9pub struct UpvalueOverflowChunk {
10    pub entries: [(ClosureHandle, usize); OVERFLOW_CHUNK_SIZE],
11    pub count: usize,
12    pub is_marked: bool,
13    pub next: Option<UpvalueOverflowHandle>,
14}
15
16impl Default for UpvalueOverflowChunk {
17    fn default() -> Self {
18        Self {
19            entries: [(ClosureHandle::default(), 0); OVERFLOW_CHUNK_SIZE],
20            count: 0,
21            is_marked: false,
22            next: None,
23        }
24    }
25}
26
27#[derive(Debug, Default, Clone)]
28pub struct UpvalueOverflowArena {
29    chunks: Arena<UpvalueOverflowChunk>,
30}
31
32impl UpvalueOverflowArena {
33    pub fn new() -> Self {
34        Self::with_capacity(32)
35    }
36
37    pub fn with_capacity(capacity: usize) -> Self {
38        Self {
39            chunks: Arena::with_capacity(capacity),
40        }
41    }
42
43    pub fn allocate_chunk(&mut self) -> UpvalueOverflowHandle {
44        self.chunks.insert(UpvalueOverflowChunk::default())
45    }
46
47    pub fn get_chunk(&self, handle: UpvalueOverflowHandle) -> &UpvalueOverflowChunk {
48        &self.chunks[handle]
49    }
50
51    pub fn get_chunk_mut(&mut self, handle: UpvalueOverflowHandle) -> &mut UpvalueOverflowChunk {
52        &mut self.chunks[handle]
53    }
54
55    pub fn mark_chunk(&mut self, handle: UpvalueOverflowHandle) {
56        if let Some(chunk) = self.chunks.get_mut(handle) {
57            chunk.is_marked = true;
58        }
59    }
60
61    pub fn collect_garbage(&mut self) {
62        let estimated_deletions = (self.chunks.len() / 4).max(8);
63        let mut handles_to_remove = Vec::with_capacity(estimated_deletions);
64
65        for (handle, chunk) in self.chunks.iter_mut() {
66            if chunk.is_marked {
67                chunk.is_marked = false;
68            } else {
69                handles_to_remove.push(handle);
70            }
71        }
72
73        for handle in handles_to_remove {
74            self.chunks.remove(handle);
75        }
76    }
77
78    pub fn get_allocated_bytes(&self) -> usize {
79        self.chunks.len() * std::mem::size_of::<UpvalueOverflowChunk>()
80    }
81}