diff options
Diffstat (limited to 'bytecode')
| -rw-r--r-- | bytecode/src/heap.rs | 105 |
1 files changed, 48 insertions, 57 deletions
diff --git a/bytecode/src/heap.rs b/bytecode/src/heap.rs index fc70a23..1706d10 100644 --- a/bytecode/src/heap.rs +++ b/bytecode/src/heap.rs @@ -2,28 +2,6 @@ use crate::data::{Pointer, Value}; use std::collections::HashMap; use std::iter::Iterator; -fn transmute(p: &u8) -> Result<&u64, String> { - let u8_p = p as *const u8; - let u64_p = u8_p as *const u64; - if u64_p as usize % 8 != 0 { - return Err(String::from("not aligned")); - } - unsafe { - return Ok(&*u64_p); - } -} - -fn transmute_mut(p: &mut u8) -> Result<&mut u64, String> { - let u8_p = p as *mut u8; - let u64_p = u8_p as *mut u64; - if u64_p as usize % 8 != 0 { - return Err(String::from("not aligned")); - } - unsafe { - return Ok(&mut *u64_p); - } -} - fn rewrite_pointers( stack: &mut [Value], rewrites: &HashMap<Pointer, Pointer>, @@ -45,35 +23,41 @@ fn rewrite_pointers( return Ok(()); } +fn open_ptr(p: Pointer) -> (usize, usize) { + let Pointer(u) = p; + return (u / 8, u % 8); +} + pub struct Heap { - heap: Vec<u8>, + heap: Vec<u64>, free_pointer: usize, - spare_heap: Vec<u8>, + spare_heap: Vec<u64>, } impl Heap { pub fn new() -> Self { Heap { - heap: vec![0; 1024], // 1 kB + heap: vec![0; 512], // 4 kB free_pointer: 0, - spare_heap: Vec::new(), + spare_heap: vec![0; 512], } } fn alloc_size(&mut self, p: Pointer) -> Result<usize, String> { - let Pointer(u) = p; + let (u, _) = open_ptr(p); + if u == 0 { + return Err("cannot get the size of a nil pointer"); + } // Alloc size is stored just below the pointer. - let u8_p = &self.heap[u - 8]; - let u64_p = transmute(u8_p)?; - return Ok(usize::try_from(*u64_p).unwrap() >> 1); + let size = self.heap[u - 1]; + return Ok(usize::try_from(size).unwrap() >> 1); } fn is_bytevector(&mut self, p: Pointer) -> Result<bool, String> { - let Pointer(u) = p; - let u8_p = &self.heap[u - 8]; - let u64_p = transmute(u8_p)?; + let (u, _) = open_ptr(p); + let size = self.heap[u - 1]; // Low bit 1 means bytevector. - return Ok(*u64_p & 1 != 0); + return Ok(size & 1 != 0); } fn gc_process_value( @@ -187,21 +171,19 @@ impl Heap { locals: &mut [Value], bytevector_p: bool, ) -> Result<Pointer, String> { - if self.heap.len() - self.free_pointer < n { + let n_cells = (n + 7) / 8; + if self.heap.len() - self.free_pointer < n_cells { self.collect_garbage(n, stack, locals)?; - if self.heap.len() - self.free_pointer < n { - return Err(String::from("out of space")); - } } - let len_p = transmute_mut(&mut self.heap[self.free_pointer])?; + let len_p = &mut self.heap[self.free_pointer]?; *len_p = u64::try_from(n).unwrap() << 1; if bytevector_p { *len_p |= 1; } - self.free_pointer += 8; - let p = Pointer(self.free_pointer); + self.free_pointer += 1; + let p = Pointer(self.free_pointer * 8); + let n_cells = n / 8; self.heap[self.free_pointer..self.free_pointer + n].fill(0); - self.free_pointer += n; return Ok(p); } @@ -224,28 +206,37 @@ impl Heap { } pub fn peek(&self, p: Pointer) -> Result<Value, String> { - let Pointer(x) = p; - let u8_p = &self.heap[x]; - let u64_p = transmute(u8_p)?; - return Ok(Value(*u64_p)); + let (u, _) = open_ptr(p); + if u >= self.heap.len() { + return Err(format!("invalid pointer {:x}", p)); + } + return Ok(Value(self.heap[u])); } pub fn poke(&mut self, v: Value, p: Pointer) -> Result<(), String> { - let Pointer(x) = p; - let Value(u) = v; - let u8_p = &mut self.heap[x]; - let u64_p = transmute_mut(u8_p)?; - *u64_p = u; + let (u, _) = open_ptr(p); + let Value(x) = v; + if u >= self.heap.len() { + return Err(format!("invalid pointer {:x}", p)); + self.heap[u] = x; return Ok(()); } - pub fn peek_byte(&self, p: Pointer) -> u8 { - let Pointer(x) = p; - return self.heap[x]; + fn peek_byte(&self, p: Pointer) -> Result<u8, String> { + let (word_cnt, word_offset) = open_ptr(p); + if word_cnt >= self.heap.len() { + return Err(format!("invalid pointer {:x}", p)); + } + return (self.heap[word_cnt] >> word_offset * 8) as u8; } - pub fn poke_byte(&mut self, u: u8, p: Pointer) { - let Pointer(x) = p; - self.heap[x] = u; + pub fn poke_byte(&mut self, u: u8, p: Pointer) -> Result<(), String> { + let (word_cnt, word_offset) = open_ptr(p); + if word_cnt >= self.heap.len() { + return Err(format!("invalid pointer {:x}", p)); + } + let surrounding_word = self.heap[word_cnt]; + let mask = !(0xff << word_offset * 8); + self.heap[word_cnt] = surrounding_word & mask | u << word_offset * 8; } } |
