diff options
| -rw-r--r-- | src/vm.rs | 176 |
1 files changed, 109 insertions, 67 deletions
@@ -1,8 +1,11 @@ -use std::cell::RefCell; +use std::{alloc::{alloc, Layout}, cell::RefCell}; use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::convert::TryInto; use std::fmt::Debug; +use std::ptr; use std::rc::Rc; +use std::slice; use owo_colors::OwoColorize; @@ -54,7 +57,8 @@ struct Frame { pub struct VM { upvalues: HashMap<usize, Rc<RefCell<UpValue>>>, - stack: Vec<Value>, + stack_len: usize, + stack: *mut Value, frames: Vec<Frame>, blobs: Vec<Rc<Blob>>, @@ -78,12 +82,21 @@ pub enum OpResult { Continue, } +unsafe fn unwrap_unchecked_o<T>(val: Option<T>) -> T { + val.unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() }) +} + +unsafe fn unwrap_unchecked_r<T, S>(val: Result<T, S>) -> T { + val.unwrap_or_else(|_| unsafe { std::hint::unreachable_unchecked() }) +} + impl VM { pub(crate) fn new() -> Self { Self { upvalues: HashMap::new(), - stack: Vec::new(), + stack_len: 0, + stack: unsafe { alloc(Layout::array::<Value>(10_000).unwrap()) as *mut Value }, //TODO fix max len frames: Vec::new(), blobs: Vec::new(), @@ -112,19 +125,45 @@ impl VM { } fn push(&mut self, value: Value) { - self.stack.push(value); + unsafe { + *self.stack.offset(self.stack_len as isize) = value; + } + self.stack_len += 1; } + #[inline(always)] + fn get(&self, slot: usize) -> &Value { + // &self.stack[slot] + // unsafe { self.stack.get_unchecked(slot) } + unsafe { + &*self.stack.offset(slot as isize) + } + } + + #[inline(always)] + fn get_mut(&mut self, slot: usize) -> &mut Value { + // &mut self.stack[slot] + // unsafe { self.stack.get_unchecked_mut(slot) } + unsafe { + &mut *self.stack.offset(slot as isize) + } + } + + #[inline(always)] fn pop(&mut self) -> Value { - match self.stack.pop() { - Some(x) => x, - None => self.crash_and_burn(), + // self.stack.pop().unwrap() + // self.stack.pop().unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() }) + self.stack_len -= 1; + unsafe { + ptr::replace(self.stack.offset(self.stack_len as isize), + Value::Nil) } } + #[inline(always)] fn poppop(&mut self) -> (Value, Value) { - let (a, b) = (self.stack.remove(self.stack.len() - 1), - self.stack.remove(self.stack.len() - 1)); + let a = self.pop(); + let b = self.pop(); (b, a) // this matches the order they were on the stack } @@ -159,7 +198,7 @@ impl VM { } /// Stop the program, violently - fn crash_and_burn(&self) -> ! { + fn _crash_and_burn(&self) -> ! { self.print_stack(); println!("\n"); self.frame().block.borrow().debug_print(); @@ -195,13 +234,13 @@ impl VM { } Op::Tuple(size) => { - let values = self.stack.split_off(self.stack.len() - size); - self.stack.push(Value::Tuple(Rc::new(values))); + //let values = self.stack.split_off(self.stack_len - size); + //self.push(Value::Tuple(Rc::new(values))); } Op::PopUpvalue => { let value = self.pop(); - let slot = self.stack.len(); + let slot = self.stack_len; self.drop_upvalue(slot, value); } @@ -224,7 +263,7 @@ impl VM { let mut ups = Vec::new(); for (slot, is_up, _) in block.borrow().upvalues.iter() { let up = if *is_up { - if let Value::Function(local_ups, _) = &self.stack[offset] { + if let Value::Function(local_ups, _) = self.get(offset) { Rc::clone(&local_ups[*slot]) } else { unreachable!() @@ -243,20 +282,18 @@ impl VM { } Op::Index => { - let slot = self.stack.pop().unwrap(); - let val = self.stack.pop().unwrap(); - match (val, slot) { + match self.poppop() { (Value::Tuple(v), Value::Int(slot)) => { let slot = slot as usize; if v.len() < slot { - self.stack.push(Value::Nil); + self.push(Value::Nil); let len = v.len(); error!(self, ErrorKind::IndexOutOfBounds(Value::Tuple(v), len, slot)); } - self.stack.push(v[slot].clone()); + self.push(v[slot].clone()); } (val, slot) => { - self.stack.push(Value::Nil); + self.push(Value::Nil); error!(self, ErrorKind::RuntimeTypeError(op, vec![val, slot]), String::from("Cannot index type")); } } @@ -327,9 +364,10 @@ impl VM { Op::ReadUpvalue(slot) => { let offset = self.frame().stack_offset; - let value = match &self.stack[offset] { + let value = match self.get(offset) { Value::Function(ups, _) => { - ups[slot].borrow().get(&self.stack) + let stack = unsafe { slice::from_raw_parts(self.stack, self.stack_len) }; + ups[slot].borrow().get(&stack) } _ => unreachable!(), }; @@ -337,30 +375,31 @@ impl VM { } Op::AssignUpvalue(slot) => { - let offset = self.frame().stack_offset; - let value = self.pop(); - let slot = match &self.stack[offset] { - Value::Function(ups, _) => Rc::clone(&ups[slot]), - _ => unreachable!(), - }; - slot.borrow_mut().set(&mut self.stack, value); + // let offset = self.frame().stack_offset; + // let value = self.pop(); + // let slot = match self.get(offset) { + // Value::Function(ups, _) => Rc::clone(&ups[slot]), + // _ => unreachable!(), + // }; + // let stack = unsafe { slice::from_raw_parts_mut(self.stack, self.stack_len) }; + // slot.borrow_mut().set(stack, value); } Op::ReadLocal(slot) => { let slot = self.frame().stack_offset + slot; - self.push(self.stack[slot].clone()); + self.push(self.get(slot).clone()); } Op::AssignLocal(slot) => { let slot = self.frame().stack_offset + slot; - self.stack[slot] = self.pop(); + *self.get_mut(slot) = self.pop(); } Op::Define(_) => {} Op::Call(num_args) => { - let new_base = self.stack.len() - 1 - num_args; - match self.stack[new_base].clone() { + let new_base = self.stack_len - 1 - num_args; + match self.get(new_base).clone() { Value::Blob(blob_id) => { let blob = &self.blobs[blob_id]; @@ -394,11 +433,12 @@ impl VM { } Value::ExternFunction(slot) => { let extern_func = self.extern_functions[slot]; - let res = match extern_func(&self.stack[new_base+1..], false) { + let stack = unsafe { slice::from_raw_parts(self.stack, self.stack_len) }; + let res = match extern_func(&stack[new_base+1..], false) { Ok(value) => value, Err(ek) => error!(self, ek, "Wrong arguments to external function".to_string()), }; - self.stack.truncate(new_base); + self.stack_len = new_base; self.push(res); } _ => { @@ -416,14 +456,14 @@ impl VM { if self.frames.is_empty() { return Ok(OpResult::Done); } else { - self.stack[last.stack_offset] = self.pop(); - for slot in last.stack_offset+1..self.stack.len() { + *self.get_mut(last.stack_offset) = self.pop(); + for slot in last.stack_offset+1..self.stack_len { if self.upvalues.contains_key(&slot) { - let value = self.stack[slot].clone(); + let value = self.get(slot).clone(); self.drop_upvalue(slot, value); } } - self.stack.truncate(last.stack_offset + 1); + self.stack_len = last.stack_offset + 1; } } } @@ -432,20 +472,20 @@ impl VM { } fn print_stack(&self) { - let start = self.frame().stack_offset; - print!(" {:3} [", start); - for (i, s) in self.stack.iter().skip(start).enumerate() { - if i != 0 { - print!(" "); - } - print!("{:?}", s.green()); - } - println!("]"); - - println!("{:5} {:05} {:?}", - self.frame().block.borrow().line(self.frame().ip).red(), - self.frame().ip.blue(), - self.frame().block.borrow().ops[self.frame().ip]); + // let start = self.frame().stack_offset; + // print!(" {:3} [", start); + // for (i, s) in self.stack.iter().skip(start).enumerate() { + // if i != 0 { + // print!(" "); + // } + // print!("{:?}", s.green()); + // } + // println!("]"); + + // println!("{:5} {:05} {:?}", + // self.frame().block.borrow().line(self.frame().ip).red(), + // self.frame().ip.blue(), + // self.frame().block.borrow().ops[self.frame().ip]); } // Initalizes the VM for running. Run cannot be called before this. @@ -456,7 +496,7 @@ impl VM { self.strings = prog.strings.clone(); self.extern_functions = prog.functions.clone(); - self.stack.clear(); + self.stack_len = 0; self.frames.clear(); self.push(Value::Function(Vec::new(), Rc::clone(&block))); @@ -506,7 +546,7 @@ impl VM { if *is_up { types.push(ty.clone()); } else { - types.push(Type::from(&self.stack[*slot])); + types.push(Type::from(self.get(*slot))); } } @@ -611,8 +651,8 @@ impl VM { } Op::Call(num_args) => { - let new_base = self.stack.len() - 1 - num_args; - match self.stack[new_base].clone() { + let new_base = self.stack_len - 1 - num_args; + match self.get(new_base).clone() { Value::Blob(blob_id) => { let blob = &self.blobs[blob_id]; @@ -638,7 +678,8 @@ impl VM { num_args, args.len())); } - let stack_args = &self.stack[self.stack.len() - args.len()..]; + let stack = unsafe { slice::from_raw_parts(self.stack, self.stack_len) }; + let stack_args = &stack[self.stack_len - args.len()..]; let stack_args: Vec<_> = stack_args.iter().map(|x| x.into()).collect(); if args != &stack_args { error!(self, @@ -647,27 +688,28 @@ impl VM { args, stack_args)); } - self.stack[new_base] = block.borrow().ret().into(); + *self.get_mut(new_base) = block.borrow().ret().into(); - self.stack.truncate(new_base + 1); + self.stack_len = new_base + 1; } Value::ExternFunction(slot) => { let extern_func = self.extern_functions[slot]; - let res = match extern_func(&self.stack[new_base+1..], false) { + let stack = unsafe { slice::from_raw_parts(self.stack, self.stack_len) }; + let res = match extern_func(&stack[new_base+1..], false) { Ok(value) => value, Err(ek) => { - self.stack.truncate(new_base); + self.stack_len = new_base; self.push(Value::Nil); error!(self, ek, "Wrong arguments to external function".to_string()) } }; - self.stack.truncate(new_base); + self.stack_len = new_base; self.push(res); } _ => { error!(self, - ErrorKind::TypeError(op, vec![Type::from(&self.stack[new_base])]), - format!("Tried to call non-function {:?}", self.stack[new_base])); + ErrorKind::TypeError(op, vec![Type::from(self.get(new_base))]), + format!("Tried to call non-function {:?}", self.get(new_base))); } } } @@ -688,7 +730,7 @@ impl VM { } fn typecheck_block(&mut self, block: Rc<RefCell<Block>>) -> Vec<Error> { - self.stack.clear(); + self.stack_len = 0; self.frames.clear(); self.push(Value::Function(Vec::new(), Rc::clone(&block))); @@ -723,7 +765,7 @@ impl VM { self.frame_mut().ip += 1; } - if !self.stack.is_empty() { + if self.stack_len > 0 { let ident = self.pop().identity(); self.push(ident); } |
