Skip to content

Commit

Permalink
Refactoring Virtual Machine
Browse files Browse the repository at this point in the history
  • Loading branch information
vangroan committed May 4, 2024
1 parent df67fa2 commit b4338c6
Show file tree
Hide file tree
Showing 10 changed files with 643 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = [
"crates/vuur_lexer",
"crates/vuur_parse",
"crates/vuur_compile",
"crates/vuur_compiler",
# "crates/vuur_compiler",
"crates/vuur_vm",
"crates/vuur",
]
1 change: 1 addition & 0 deletions crates/vuur_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num = "0.4"
vuur_compile = { path = "../vuur_compile" }
vuur_parse = { path = "../vuur_parse" }

Expand Down
45 changes: 45 additions & 0 deletions crates/vuur_vm/src/func_def.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::instruction_set::Op;
use std::rc::Rc;

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct FuncId(pub(crate) u32);

impl FuncId {
#[inline(always)]
pub(crate) fn new(id: u32) -> Self {
Self(id)
}

#[inline(always)]
pub fn to_usize(self) -> usize {
self.0 as usize
}

#[inline(always)]
pub fn to_u32(self) -> u32 {
self.0
}
}

#[derive(Debug)]
pub struct Closure {
pub func_id: FuncId,
pub func: Rc<ScriptFunc>,
pub up_values: Vec<()>,
}

#[derive(Debug)]
pub struct ScriptFunc {
pub id: FuncId,
pub constants: Vec<u32>,
pub code: Box<[Op]>,
}

pub type NativeFuncPtr = fn() -> ();

#[derive(Debug)]
pub struct NativeFunc {
pub id: FuncId,
pub ptr: NativeFuncPtr,
}
120 changes: 120 additions & 0 deletions crates/vuur_vm/src/instruction_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use std::fmt;
use std::fmt::Formatter;

/// Instruction set.
#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum Op {
/// Does nothing. The program counter will be incremented.
NoOp,

/// Remove the top values from the operand stack and discard it.
Pop,

// ------------------------------------------------------------------------
// Arithmetic
I32_Add,
I32_Sub,
I32_Mul,
I32_Div,
I32_Neg,
I32_Eq,
I32_Cmp,

/// Push a constant int32 value onto the operand stack.
I32_Const {
constant_id: ConstantId,
},
I32_Const_Inline {
arg: Arg24,
},

// ------------------------------------------------------------------------
// Variables
Store_Local {
local_id: Arg24,
},
Load_Local {
local_id: Arg24,
},

// ------------------------------------------------------------------------
// Up-values
/// "Close" the up-value, copying its inner value into its heap slot.
Upvalue_Close,

// ------------------------------------------------------------------------
// Callables
/// Statically call a function identified by `func_id`.
Call_Func {
func_id: Arg24,
},
Return,
/// Create a closure instance.
Closure_Create,

// ------------------------------------------------------------------------
// Control Flow
/// Unconditionally jump.
Jump,
/// Conditionally jump if the top of the operand stack is value 0, type int32.
Jump_False,
/// Ends the current block.
End,
/// Unconditionally error.
Abort,
}

pub type ConstantId = u16;

/// Bytecode argument packed into 24 bits, encoded in little-endian.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Arg24([u8; 3]);

impl Arg24 {
#[inline(always)]
pub fn from_i32(value: i32) -> Self {
// Shift left so sign will be preserved later when decoding.
let [_, a, b, c] = (value << 8).to_le_bytes();
Self([a, b, c])
}

#[inline(always)]
pub fn to_i32(self) -> i32 {
let [a, b, c] = self.0;
// Shift right to extend to cover up the least-significant bit,
// and preserve the sign.
i32::from_le_bytes([0, a, b, c]) >> 8
}

#[inline(always)]
pub fn to_u32(self) -> u32 {
let [a, b, c] = self.0;
u32::from_le_bytes([a, b, c, 0])
}
}

impl fmt::Debug for Arg24 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:06x}", self.to_u32())
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_instruction_size() {
assert!(
std::mem::size_of::<Op>() <= 4,
"bytecode instruction must be at most 32-bits (4 bytes)"
)
}

#[test]
fn test_arg24() {
assert_eq!(Arg24::from_i32(0b00000100_00000010_00000001), Arg24([1, 2, 4]));
assert_eq!(Arg24::from_i32(-1).to_i32(), -1, "negative values must be preserved");
}
}
17 changes: 15 additions & 2 deletions crates/vuur_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ use vuur_compile::bytecode::{decode_arg_a, decode_arg_k, decode_opcode, opcodes
use vuur_compile::Chunk;

pub mod error;
mod func_def;
mod instruction_set;
mod module;
pub mod obj;
pub mod vm_v2;
mod value;
#[doc(hidden)] pub mod symbol_table;

use self::error::{ErrorKind, Result, RuntimeError};

Expand All @@ -33,6 +39,9 @@ pub struct Fiber {
pub(crate) error: Option<String>,
}

/// Operand stack slot, which encodes an untyped value.
struct Slot(usize);

#[derive(Debug)]
struct FrameInfo {
/// Offset in the stack where this call frame's
Expand Down Expand Up @@ -135,6 +144,10 @@ impl Fiber {
}
}

pub fn run_v2(&mut self, chunk: &Chunk) {
todo!()
}

pub fn run(&mut self, chunk: &Chunk) {
println!("running...");
'eval: loop {
Expand All @@ -161,7 +174,7 @@ impl Fiber {

match op {
ops::NOOP => {
println!("");
println!("noop");
self.ip += 1
}
ops::POP => {
Expand Down Expand Up @@ -353,7 +366,7 @@ impl Fiber {

self.calls.push(FrameInfo {
base: stack_base,
// after this insrtuction
// after this instruction
return_addr: self.ip + 1,
});
}
Expand Down
16 changes: 16 additions & 0 deletions crates/vuur_vm/src/module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::func_def::{NativeFunc, ScriptFunc};
use std::rc::Rc;

#[derive(Debug)]
pub struct Module {
pub name: String,
pub func_defs: Vec<Rc<Func>>,
/// Module level global variables.
pub vars: Vec<()>,
}

#[derive(Debug)]
pub enum Func {
Script(ScriptFunc),
Native(NativeFunc),
}
Loading

0 comments on commit b4338c6

Please sign in to comment.