diff --git a/lunar_wave_cli/Cargo.toml b/lunar_wave_cli/Cargo.toml index 89e4d06..06afd01 100644 --- a/lunar_wave_cli/Cargo.toml +++ b/lunar_wave_cli/Cargo.toml @@ -8,6 +8,10 @@ authors = ["ReactorScram"] [dependencies] lunar_wave_vm = { path = "../lunar_wave_vm" } +[profile.release] +codegen-units = 1 +lto = "fat" + [target.x86_64-unknown-linux-gnu] linker = "/usr/bin/clang" # Recommended for flamegraph diff --git a/lunar_wave_vm/src/loader.rs b/lunar_wave_vm/src/loader.rs index 3969f6b..8320ed5 100644 --- a/lunar_wave_vm/src/loader.rs +++ b/lunar_wave_vm/src/loader.rs @@ -104,6 +104,68 @@ fn i_sc (buf: [u8; 4]) -> Option { i8::try_from (i32::try_from (c).ok ()? - 127).ok () } +pub trait DecodeInstruction { + fn opcode (self) -> u8; + + fn a (self) -> u8; + fn ax (self) -> u32; + fn b (self) -> u8; + fn bx (self) -> u32; + fn c (self) -> u8; + fn k (self) -> bool; + fn sb (self) -> i8; + fn sbx (self) -> i32; + fn sc (self) -> i8; + fn sj (self) -> i32; +} + +impl DecodeInstruction for u32 { + #[inline(always)] + fn opcode (self) -> u8 { + ((self >> 0) & 0x7f) as u8 + } + + fn a (self) -> u8 { + ((self >> 7) & 0xff) as u8 + } + + fn ax (self) -> u32 { + self >> 7 + } + + fn b (self) -> u8 { + ((self >> 16) & 0xff) as u8 + } + + fn bx (self) -> u32 { + (self >> 15) as u32 + } + + fn c (self) -> u8 { + (self >> 24) as u8 + } + + fn k (self) -> bool { + ((self >> 15) & 0x1) == 1 + } + + fn sb (self) -> i8 { + ((((self >> 16) & 0xff) as i16) - 127) as i8 + } + + fn sbx (self) -> i32 { + (self >> 15) as i32 - 65535 + } + + fn sc (self) -> i8 { + (((self >> 24) as i16) - 127) as i8 + } + + fn sj (self) -> i32 { + ((self >> 7) as i32) - 0xffffff + } +} + pub fn parse_inst (buf: [u8; 4]) -> Option { let opcode = buf [0] & 0x7f; @@ -151,9 +213,9 @@ pub fn parse_inst (buf: [u8; 4]) -> Option 0x33 => Inst::Not (a, b), 0x34 => Inst::Len (a, b), 0x35 => Inst::Concat (a, b), + 0x38 => Inst::Jmp (s_j), 0x3c => Inst::EqK (a, b, k), 0x3d => Inst::EqI (a, i_sb (buf)?, k), - 0x38 => Inst::Jmp (s_j), 0x42 => Inst::Test (a, k), 0x44 => Inst::Call (a, b, c), 0x45 => Inst::TailCall (a, b, c, k), @@ -264,9 +326,11 @@ pub fn parse_block (rdr: &mut R, si: &mut Interner, blocks: &mut Vec < for _ in 0..inst_count { let mut buf = [0u8; 4]; rdr.read_exact (&mut buf).ok ().unwrap (); - instructions.push (parse_inst (buf).expect (&format! ("{buf:?}"))); + instructions.push (u32::from_le_bytes (buf)); } + let instructions = Rc::from (instructions); + let constant_count = parse_int (rdr).unwrap (); let mut constants = Vec::with_capacity (constant_count as usize); diff --git a/lunar_wave_vm/src/state.rs b/lunar_wave_vm/src/state.rs index 9fe8b1c..f0bc26a 100644 --- a/lunar_wave_vm/src/state.rs +++ b/lunar_wave_vm/src/state.rs @@ -16,9 +16,9 @@ pub struct Upvalue { pub kind: u8, } -#[derive (Clone, Debug, Default)] +#[derive (Clone, Debug)] pub struct Block { - pub instructions: Vec , + pub instructions: Rc <[u32]>, pub constants: Vec , pub upvalues: Vec , } @@ -56,7 +56,7 @@ pub struct State { pub debug_print: bool, chunk: Chunk, - current_block: Rc , + current_instructions: Rc <[u32]>, pub upvalues: Vec , pub si: Interner, } @@ -183,7 +183,7 @@ pub enum StepError { impl State { pub fn new (chunk: Chunk, upvalues: Vec ) -> Self { - let current_block = Rc::clone (&chunk.blocks [0]); + let current_instructions = Rc::clone (&chunk.blocks [0].instructions); Self { // TODO: Stack is actually supposed to grow to a limit of @@ -194,7 +194,7 @@ impl State { stack_top: Default::default (), debug_print: false, chunk, - current_block, + current_instructions, upvalues, si: Default::default (), } @@ -202,9 +202,9 @@ impl State { pub fn new_with_args > (chunk: Chunk, mut si: Interner, args: I) -> Self { let upvalues = Self::upvalues_from_args (&mut si, args); - let current_block = match chunk.blocks.get (0) { - Some (x) => Rc::clone (&x), - None => Default::default (), + let current_instructions = match chunk.blocks.get (0) { + Some (x) => Rc::clone (&x.instructions), + None => Rc::from ([]), }; Self { @@ -216,7 +216,7 @@ impl State { stack_top: Default::default (), debug_print: false, chunk, - current_block, + current_instructions, upvalues, si, } @@ -403,7 +403,7 @@ impl State { } fn op_get_field (&mut self, a: u8, b: u8, c: u8) { - let block = &self.current_block; + let block = &self.chunk.blocks [self.stack_top.block_idx]; let constants = &block.constants; let key = match &constants [usize::from (c)] { @@ -441,6 +441,7 @@ impl State { // No need for metamethods } else { + dbg! (&self.stack_top); panic! ("Not sure how to implement OP_MMBIN for these 2 values {a:?}, {b:?}"); } } @@ -454,14 +455,17 @@ impl State { (Value::Integer (b), Value::Integer (c)) => Value::from (b * c), (Value::Integer (b), Value::Float (c)) => Value::from (*b as f64 * c), (Value::Float (b), Value::Integer (c)) => Value::from (b * *c as f64), - _ => return false, + (b, c) => { + panic! ("OP_MUL unimplemented for {b:?}, {c:?}"); + return false; + }, }; true } fn op_set_field (&mut self, a: u8, b: u8, c: u8, k: bool) { - let block = &self.current_block; + let block = &self.chunk.blocks [self.stack_top.block_idx]; let constants = &block.constants; let b = usize::try_from (b).unwrap (); @@ -500,25 +504,25 @@ impl State { } fn constants (&self) -> &[Value] { - &self.current_block.constants + &self.chunk.blocks [self.stack_top.block_idx].constants } fn set_block_idx (&mut self, block_idx: usize) { self.stack_top.block_idx = block_idx; - self.current_block = Rc::clone (&self.chunk.blocks [block_idx]); + self.current_instructions = Rc::clone (&self.chunk.blocks [block_idx].instructions); } fn set_stack_top (&mut self, frame: StackFrame) { self.stack_top = frame; - self.current_block = match self.chunk.blocks.get (frame.block_idx) { - Some (x) => Rc::clone (&x), - None => Default::default (), + self.current_instructions = match self.chunk.blocks.get (frame.block_idx) { + Some (x) => Rc::clone (&x.instructions), + None => Rc::from ([]), }; } - fn fetch (&self) -> &Instruction { - match self.current_block.instructions.get (self.stack_top.program_counter) { - Some (x) => x, + fn fetch (&self) -> u32 { + match self.current_instructions.get (self.stack_top.program_counter) { + Some (x) => *x, None => { dbg! (&self.stack, &self.stack_top); panic! ("program_counter went out of bounds"); @@ -532,35 +536,38 @@ impl State { pub fn step (&mut self) -> Result