use crate::value::Value; pub const NUM_LOCALS: usize = 256; #[derive(Debug)] pub struct Heap { pub buf: Vec, first_active: bool, free_ptr: usize, last_live: usize, pub locals: [Value; NUM_LOCALS], } impl Heap { pub fn new() -> Heap { Heap { buf: Vec::new(), first_active: true, free_ptr: 0, last_live: 0, locals: [Value(0); NUM_LOCALS], } } fn forwarded(&self, p: usize) -> bool { let Some(q) = Value(self.buf[p]).to_pointer() else { return false; }; self.first_active == (q < self.buf.len() / 2) } fn alloc_size(&self, p: usize) -> usize { usize::try_from(self.buf[p - 1] >> 1).expect("using 32 bits in 2024 LULW") } fn simple_alloc(&mut self, size: usize) -> usize { self.buf[self.free_ptr] = u64::try_from(size).expect("how even??") << 1; let p = self.free_ptr + 1; self.free_ptr += size + 1; p } fn process_gc_value(&mut self, val: Value) -> Value { let Some(p) = val.to_pointer() else { return val; }; if self.forwarded(p) { return Value(self.buf[p]); } let size = self.alloc_size(p); // Allocate space in the new buffer. let q = self.simple_alloc(size); // Write forwarding pointer. let first_val = Value(self.buf[p]); self.buf[p] = Value::from_pointer(q).repr(); // Copy values, recursively modifying pointers. self.buf[q] = self.process_gc_value(first_val).repr(); for i in 1..size { self.buf[q + i] = self.process_gc_value(Value(self.buf[p + i])).repr(); } Value::from_pointer(q) } fn size(&self) -> usize { if self.first_active { self.free_ptr } else { self.free_ptr - self.buf.len() / 2 } } fn collect_garbage(&mut self) { if self.size() < 2 * self.last_live { return; } // Swap the heaps. if self.first_active { self.first_active = false; self.free_ptr = self.buf.len() / 2; } else { self.first_active = true; self.free_ptr = 0; } for i in 0..self.locals.len() { self.locals[i] = self.process_gc_value(self.locals[i]); } self.last_live = self.size(); } fn more_space(&mut self, size_hint: usize) { let mut new_size = self.buf.len() / 2; if new_size == 0 { new_size = 1; } while new_size < self.free_ptr + size_hint { new_size *= 2; } self.first_active = true; self.buf.resize(new_size * 2, 0); } pub fn alloc(&mut self, size: i64) -> Result { if size <= 0 { return Err(String::from("alloc of zero size")); } let usize = usize::try_from(size).expect("32 bits in 2024 LULW"); self.collect_garbage(); if self.size() + usize + 1 > self.buf.len() / 2 { self.more_space(usize + 1); } let p = self.simple_alloc(usize::try_from(size).expect("using 32 bits in 2024 LULW")); for i in 0..usize { self.buf[p + i] = 0; } Ok(p) } pub fn peek(&self, p: usize) -> Result { if p >= self.buf.len() { return Err(String::from("peek: out of range")); } Ok(Value(self.buf[p])) } pub fn poke(&mut self, p: usize, val: Value) -> Result<(), String> { if p >= self.buf.len() { return Err(String::from("poke: out of range")); } self.buf[p] = val.repr(); Ok(()) } }