aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rhogenson@posteo.net>2022-06-30 20:12:48 -0700
committerRose Hogenson <rhogenson@posteo.net>2022-06-30 20:12:48 -0700
commit0ea60c64b3af71e505d452dc368b645b35dc2ae6 (patch)
tree1aeac8ec9fef31f22b83991303fe7438f2e37683
parentAdd a function for getting the gensym ID. (diff)
downloadchromatopelma-0ea60c64b3af71e505d452dc368b645b35dc2ae6.tar.zst
Remove unsafe code.
I'm partially doing it because I'm not sure if what I had was really safe, but also it just looks much cleaner this way.
-rw-r--r--bytecode/src/heap.rs105
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;
}
}