From e11026a5531ed85eecf427968ad92b5790e42ada Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Mon, 2 Oct 2023 17:39:33 -0500 Subject: [PATCH] :chart_with_upwards_trend: performance: down to 800 ms / 3.3x by changing PC handling --- lunar_wave_vm/src/state.rs | 297 ++++++++++++++++++++----------------- 1 file changed, 162 insertions(+), 135 deletions(-) diff --git a/lunar_wave_vm/src/state.rs b/lunar_wave_vm/src/state.rs index 2850dd4..0b7d176 100644 --- a/lunar_wave_vm/src/state.rs +++ b/lunar_wave_vm/src/state.rs @@ -28,10 +28,9 @@ pub struct Chunk { #[derive (Clone, Debug, Default)] pub struct StackFrame { - // i32 makes it a little easier to implement jumps // Starts at 0 right after OP_CALL - program_counter: i32, + program_counter: usize, // Starts from 0 for main and 1 for the first closure block_idx: usize, @@ -42,7 +41,7 @@ pub struct StackFrame { #[derive (Debug)] pub struct Breakpoint { pub block_idx: usize, - pub program_counter: i32, + pub program_counter: usize, } #[derive (Debug)] @@ -59,6 +58,7 @@ pub struct State { pub si: Interner, register_offset: usize, block_idx: usize, + next_pc: usize, } fn lw_io_write (l: &mut State, num_args: usize) -> usize { @@ -198,6 +198,7 @@ impl State { si: Default::default (), register_offset: 0, block_idx: 0, + next_pc: 0, } } @@ -219,6 +220,7 @@ impl State { si, register_offset: 0, block_idx: 0, + next_pc: 0, } } @@ -308,6 +310,101 @@ impl State { true } + fn op_call (&mut self, a: u8, b: u8, c: u8) -> bool { + let b = usize::from (b); + + // Take arguments from registers [a + 1, a + b) + // Call the function in register [a] + // Return values in registers [a, a + c - 1) + // + // That is, call a with b - 1 arguments and expect c returns + // + // e.g. CALL 0 2 1 mean "Call 0 with 1 argument, return 1 value", like for printing a constant + + // Do a clone here to avoid a borow problem. + // Should be fixable with more clever code. + + let v_a = self.reg (a).clone (); + + match v_a { + Value::BogusClosure (rc) => { + let idx = rc.borrow ().idx; + + let target_block = idx; + + let new_frame = StackFrame { + program_counter: 0, + block_idx: target_block, + register_offset: self.register_offset + a as usize + 1, + }; + + self.next_pc = 0; + self.block_idx = target_block; + self.register_offset = new_frame.register_offset; + + self.stack.push (new_frame); + + // Skip the PC increment at the bottom of the loop + return true; + }, + Value::RsFunc (x) => { + let old_offset = self.register_offset; + self.register_offset = old_offset + usize::from (a) + 1; + + // Trash the stack frame so it doesn't point to a + // valid Lua function + self.stack.push (StackFrame { + program_counter: 65535, // Bogus for native functions + block_idx: 65535, // Bogus + register_offset: self.register_offset, + }); + + let num_args = if b == 0 { + self.top - self.register_offset + } + else { + b - 1 + }; + + // Call + let num_results = x (self, num_args); + + let popped_frame = self.stack.pop ().unwrap (); + self.register_offset = old_offset; + let offset = old_offset + usize::from (a); + + for i in (offset)..(offset + usize::try_from (num_results).unwrap ()) { + self.registers [i] = self.registers [i + 1].take (); + } + + // Set up top for the next call + if c == 0 { + self.top = popped_frame.register_offset - 1 + num_results; + } + }, + x => { + panic! ("Cannot call value {x:?}"); + }, + } + + false + } + + fn op_div (&mut self, a: u8, b: u8, c: u8) -> bool { + let v_b = self.reg (b); + let v_c = self.reg (c); + + *self.reg_mut (a) = match (v_b, v_c) { + (Value::Float (b), Value::Float (c)) => Value::from (b / c), + (Value::Integer (b), Value::Integer (c)) => Value::from (*b as f64 / *c as f64), + (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, + }; + + true + } + fn op_get_field (&mut self, a: u8, b: u8, c: u8) { let block = self.chunk.blocks.get (self.block_idx).unwrap (); let constants = &block.constants; @@ -392,19 +489,28 @@ impl State { dst.insert_str (key, value); } + fn op_sub (&mut self, a: u8, b: u8, c: u8) -> bool { + let v_b = self.reg (b); + let v_c = self.reg (c); + + *self.reg_mut (a) = match (v_b, v_c) { + (Value::Float (b), Value::Float (c)) => Value::from (b - c), + (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, + }; + + true + } + pub fn step (&mut self) -> Result