aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vm.rs176
1 files changed, 109 insertions, 67 deletions
diff --git a/src/vm.rs b/src/vm.rs
index e5c7b2e..3215797 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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);
}