Implement call instruction

This commit is contained in:
Andrew Morris
2022-05-03 12:28:36 +10:00
parent 5d40ed552b
commit 1509f7f9fb
9 changed files with 107 additions and 42 deletions

View File

@@ -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>) -> 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,

View File

@@ -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<Val>,
pub this_target: usize,
pub return_target: usize,
pub this_target: Option<usize>,
pub return_target: Option<usize>,
}
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();
}
}
}

View File

@@ -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<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {

View File

@@ -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<StackFrame> {
let mut registers: Vec<Val> = 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 {

View File

@@ -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<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {

View File

@@ -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<StackFrame> {
return self.decode().make_frame();
}
fn is_truthy(&self) -> bool {

View File

@@ -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<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {

View File

@@ -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<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {

View File

@@ -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<dyn VsValue>;
@@ -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<StackFrame>;
}
pub trait ValTrait {