diff --git a/src/vstc/virtual_machine/bytecode_decoder.rs b/src/vstc/virtual_machine/bytecode_decoder.rs index 90704a7..df8f490 100644 --- a/src/vstc/virtual_machine/bytecode_decoder.rs +++ b/src/vstc/virtual_machine/bytecode_decoder.rs @@ -16,6 +16,7 @@ pub struct BytecodeDecoder { #[repr(u8)] #[derive(PartialEq)] pub enum BytecodeType { + End = 0x00, Undefined = 0x02, Null = 0x03, False = 0x04, @@ -31,17 +32,12 @@ pub enum BytecodeType { Register = 0x0e, } -impl BytecodeDecoder { - pub fn decode_byte(&mut self) -> u8 { - let byte = self.data[self.pos]; - self.pos += 1; - return byte; - } - - pub fn decode_type(&mut self) -> BytecodeType { +impl BytecodeType { + fn from_byte(byte: u8) -> BytecodeType { use BytecodeType::*; - return match self.decode_byte() { + return match byte { + 0x00 => End, 0x02 => Undefined, 0x03 => Null, 0x04 => False, @@ -59,11 +55,32 @@ impl BytecodeDecoder { _ => std::panic!("Unrecognized BytecodeType"), }; } +} + +impl BytecodeDecoder { + pub fn decode_byte(&mut self) -> u8 { + let byte = self.data[self.pos]; + self.pos += 1; + return byte; + } + + pub fn peek_byte(&self) -> u8 { + return self.data[self.pos]; + } + + pub fn decode_type(&mut self) -> BytecodeType { + return BytecodeType::from_byte(self.decode_byte()); + } + + pub fn peek_type(&self) -> BytecodeType { + return BytecodeType::from_byte(self.peek_byte()); + } pub fn decode_val(&mut self, registers: &Vec) -> Val { use BytecodeType::*; return match self.decode_type() { + End => std::panic!("Cannot decode end"), Undefined => std::panic!("Not implemented"), Null => std::panic!("Not implemented"), False => std::panic!("Not implemented"), @@ -184,6 +201,7 @@ impl BytecodeDecoder { 0x06 => OpMul, 0x08 => OpMod, 0x11 => OpLess, + 0x21 => Call, 0x27 => Jmp, 0x28 => JmpIf, diff --git a/src/vstc/virtual_machine/virtual_machine.rs b/src/vstc/virtual_machine/virtual_machine.rs index afd78c9..8f925d5 100644 --- a/src/vstc/virtual_machine/virtual_machine.rs +++ b/src/vstc/virtual_machine/virtual_machine.rs @@ -5,6 +5,7 @@ use super::vs_undefined::VsUndefined; use super::vs_number::VsNumber; use super::operations; use super::bytecode_decoder::BytecodeDecoder; +use super::bytecode_decoder::BytecodeType; use super::instruction::Instruction; pub struct VirtualMachine { @@ -14,8 +15,8 @@ pub struct VirtualMachine { pub struct StackFrame { pub decoder: BytecodeDecoder, pub registers: Vec, - pub this_target: usize, - pub return_target: usize, + pub this_target: Option, + pub return_target: Option, } impl VirtualMachine { @@ -26,11 +27,14 @@ impl VirtualMachine { }; let main_fn = bd.decode_val(&Vec::new()); + let frame = main_fn.make_frame(); - if !main_fn.push_frame(self) { + if !frame.is_some() { std::panic!("bytecode does start with function") } + self.stack.push(frame.unwrap()); + while self.stack.len() > 1 { self.step(); } @@ -53,8 +57,8 @@ impl VirtualMachine { pos: 0, }, registers: registers, - return_target: 0, - this_target: 1, + return_target: Some(0), + this_target: Some(1), }; vm.stack.push(frame); @@ -65,8 +69,8 @@ impl VirtualMachine { pub fn step(&mut self) { use Instruction::*; - let frame = self.stack.last_mut().unwrap(); - + let mut frame = self.stack.last_mut().unwrap(); + match frame.decoder.decode_instruction() { End => { self.pop(); @@ -132,6 +136,46 @@ impl VirtualMachine { } } + Call => { + let fn_ = frame.decoder.decode_val(&frame.registers); + let maybe_new_frame = fn_.make_frame(); + + if maybe_new_frame.is_none() { + std::panic!("Not implemented: throw exception (fn_ is not a function)"); + } + + let mut new_frame = maybe_new_frame.unwrap(); + + let bytecode_type = frame.decoder.decode_type(); + + if bytecode_type != BytecodeType::Array { + std::panic!("Not implemented: call instruction not using inline array"); + } + + // Params start at 2 since 0:return, 1:this + let mut reg_i = 2; + + while frame.decoder.peek_type() != BytecodeType::End { + let val = frame.decoder.decode_val(&frame.registers); + + if reg_i < new_frame.registers.len() { + // TODO: We should also stop writing into registers when hitting the + // parameter count. This won't matter for correctly constructed + // bytecode but hand-written assembly/bytecode may violate + // optimization assumptions. + new_frame.registers[reg_i] = val; + reg_i += 1; + } + } + + frame.decoder.decode_type(); // End (TODO: assert) + + frame.return_target = frame.decoder.decode_register_index(); + frame.this_target = None; + + self.stack.push(new_frame); + } + Jmp => { let dst = frame.decoder.decode_pos(); frame.decoder.pos = dst; @@ -154,7 +198,12 @@ impl VirtualMachine { let old_frame = self.stack.pop().unwrap(); let frame = self.stack.last_mut().unwrap(); - frame.registers[frame.return_target] = old_frame.registers[0].clone(); - frame.registers[frame.this_target] = old_frame.registers[1].clone(); + if frame.return_target.is_some() { + frame.registers[frame.return_target.unwrap()] = old_frame.registers[0].clone(); + } + + if frame.this_target.is_some() { + frame.registers[frame.this_target.unwrap()] = old_frame.registers[1].clone(); + } } } diff --git a/src/vstc/virtual_machine/vs_bool.rs b/src/vstc/virtual_machine/vs_bool.rs index 4521b01..0158815 100644 --- a/src/vstc/virtual_machine/vs_bool.rs +++ b/src/vstc/virtual_machine/vs_bool.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use super::vs_value::Val; use super::vs_value::VsType; use super::vs_value::VsValue; -use super::virtual_machine::VirtualMachine; +use super::virtual_machine::StackFrame; pub struct VsBool { value: bool, @@ -32,8 +32,8 @@ impl VsValue for VsBool { return true; } - fn push_frame(&self, vm: &mut VirtualMachine) -> bool { - return false; + fn make_frame(&self) -> Option { + return None; } fn is_truthy(&self) -> bool { diff --git a/src/vstc/virtual_machine/vs_function.rs b/src/vstc/virtual_machine/vs_function.rs index 8df5852..6651254 100644 --- a/src/vstc/virtual_machine/vs_function.rs +++ b/src/vstc/virtual_machine/vs_function.rs @@ -4,7 +4,6 @@ use super::vs_value::VsType; use super::vs_value::VsValue; use super::vs_value::Val; use super::vs_undefined::VsUndefined; -use super::virtual_machine::VirtualMachine; use super::virtual_machine::StackFrame; use super::bytecode_decoder::BytecodeDecoder; @@ -32,24 +31,22 @@ impl VsValue for VsFunction { return false; } - fn push_frame(&self, vm: &mut VirtualMachine) -> bool { + fn make_frame(&self) -> Option { let mut registers: Vec = Vec::with_capacity(self.register_count - 1); for _ in 0..(self.register_count - 1) { registers.push(VsUndefined::new()); } - vm.stack.push(StackFrame { + return Some(StackFrame { decoder: BytecodeDecoder { data: self.bytecode.clone(), pos: self.start, }, registers: registers, - this_target: 0, - return_target: 0, + this_target: None, + return_target: None, }); - - return true; } fn is_truthy(&self) -> bool { diff --git a/src/vstc/virtual_machine/vs_number.rs b/src/vstc/virtual_machine/vs_number.rs index 1263831..a095902 100644 --- a/src/vstc/virtual_machine/vs_number.rs +++ b/src/vstc/virtual_machine/vs_number.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use super::vs_value::Val; use super::vs_value::VsType; use super::vs_value::VsValue; -use super::virtual_machine::VirtualMachine; +use super::virtual_machine::StackFrame; pub struct VsNumber { value: f64, @@ -32,8 +32,8 @@ impl VsValue for VsNumber { return true; } - fn push_frame(&self, vm: &mut VirtualMachine) -> bool { - return false; + fn make_frame(&self) -> Option { + return None; } fn is_truthy(&self) -> bool { diff --git a/src/vstc/virtual_machine/vs_pointer.rs b/src/vstc/virtual_machine/vs_pointer.rs index 53c4f86..e94d340 100644 --- a/src/vstc/virtual_machine/vs_pointer.rs +++ b/src/vstc/virtual_machine/vs_pointer.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use super::vs_value::Val; use super::vs_value::VsValue; use super::vs_value::VsType; -use super::virtual_machine::VirtualMachine; +use super::virtual_machine::StackFrame; use super::bytecode_decoder::BytecodeDecoder; use super::bytecode_decoder::BytecodeType; @@ -53,6 +53,7 @@ impl VsValue for VsPointer { }; return match bd.decode_type() { + BytecodeType::End => std::panic!("Invalid: pointer to end"), BytecodeType::Undefined => VsType::Undefined, BytecodeType::Null => VsType::Null, BytecodeType::False => VsType::Bool, @@ -90,8 +91,8 @@ impl VsValue for VsPointer { } } - fn push_frame(&self, vm: &mut VirtualMachine) -> bool { - return self.decode().push_frame(vm); + fn make_frame(&self) -> Option { + return self.decode().make_frame(); } fn is_truthy(&self) -> bool { diff --git a/src/vstc/virtual_machine/vs_string.rs b/src/vstc/virtual_machine/vs_string.rs index 9df8a1f..68615c0 100644 --- a/src/vstc/virtual_machine/vs_string.rs +++ b/src/vstc/virtual_machine/vs_string.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use super::vs_value::Val; use super::vs_value::VsType; use super::vs_value::VsValue; -use super::virtual_machine::VirtualMachine; +use super::virtual_machine::StackFrame; pub struct VsString { value: String, @@ -36,8 +36,8 @@ impl VsValue for VsString { return true; } - fn push_frame(&self, vm: &mut VirtualMachine) -> bool { - return false; + fn make_frame(&self) -> Option { + return None; } fn is_truthy(&self) -> bool { diff --git a/src/vstc/virtual_machine/vs_undefined.rs b/src/vstc/virtual_machine/vs_undefined.rs index 364de19..594f0cb 100644 --- a/src/vstc/virtual_machine/vs_undefined.rs +++ b/src/vstc/virtual_machine/vs_undefined.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use super::vs_value::Val; use super::vs_value::VsType; use super::vs_value::VsValue; -use super::virtual_machine::VirtualMachine; +use super::virtual_machine::StackFrame; pub struct VsUndefined {} @@ -30,8 +30,8 @@ impl VsValue for VsUndefined { return true; } - fn push_frame(&self, vm: &mut VirtualMachine) -> bool { - return false; + fn make_frame(&self) -> Option { + return None; } fn is_truthy(&self) -> bool { diff --git a/src/vstc/virtual_machine/vs_value.rs b/src/vstc/virtual_machine/vs_value.rs index 96e07c7..6a5e9b0 100644 --- a/src/vstc/virtual_machine/vs_value.rs +++ b/src/vstc/virtual_machine/vs_value.rs @@ -1,7 +1,7 @@ use std::rc::Rc; use super::vs_string::VsString; -use super::virtual_machine::VirtualMachine; +use super::virtual_machine::StackFrame; pub type Val = Rc; @@ -39,7 +39,7 @@ pub trait VsValue { fn is_primitive(&self) -> bool; fn is_truthy(&self) -> bool; - fn push_frame(&self, vm: &mut VirtualMachine) -> bool; + fn make_frame(&self) -> Option; } pub trait ValTrait {