diff --git a/crates/luars/src/lua_vm/execute/arithmetic_instructions.rs b/crates/luars/src/lua_vm/execute/arithmetic_instructions.rs index 028cd681..135e102f 100644 --- a/crates/luars/src/lua_vm/execute/arithmetic_instructions.rs +++ b/crates/luars/src/lua_vm/execute/arithmetic_instructions.rs @@ -7,45 +7,15 @@ use crate::{ lua_vm::{Instruction, LuaCallFrame, LuaResult, LuaVM}, }; -/// Slow path for ADD - separate function to hint branch predictor -#[cold] -#[inline(never)] -fn exec_add_slow( - reg_base: *mut LuaValue, - a: usize, - left: LuaValue, - right: LuaValue, - frame_ptr: *mut LuaCallFrame, -) { - unsafe { - let left_tag = left.primary & TYPE_MASK; - let right_tag = right.primary & TYPE_MASK; - - let result = if left_tag == TAG_FLOAT && right_tag == TAG_FLOAT { - LuaValue::number(f64::from_bits(left.secondary) + f64::from_bits(right.secondary)) - } else if left_tag == TAG_INTEGER && right_tag == TAG_FLOAT { - LuaValue::number((left.secondary as i64) as f64 + f64::from_bits(right.secondary)) - } else if left_tag == TAG_FLOAT && right_tag == TAG_INTEGER { - LuaValue::number(f64::from_bits(left.secondary) + (right.secondary as i64) as f64) - } else { - return; - }; - - *reg_base.add(a) = result; - (*frame_ptr).pc += 1; - } -} - /// ADD: R[A] = R[B] + R[C] /// OPTIMIZED: Matches Lua C's setivalue behavior - always write both fields #[inline(always)] -pub fn exec_add(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_add(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr); let left = *reg_base.add(b); let right = *reg_base.add(c); @@ -60,54 +30,37 @@ pub fn exec_add(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: result as u64, }; - (*frame_ptr).pc += 1; // Skip MMBIN + *pc += 1; // Skip MMBIN return; } - // Slow path: Float operations - in separate cold function - exec_add_slow(reg_base, a, left, right, frame_ptr); - } -} - -/// Slow path for SUB -#[cold] -#[inline(never)] -fn exec_sub_slow( - reg_base: *mut LuaValue, - a: usize, - left: LuaValue, - right: LuaValue, - frame_ptr: *mut LuaCallFrame, -) { - unsafe { let left_tag = left.primary & TYPE_MASK; let right_tag = right.primary & TYPE_MASK; let result = if left_tag == TAG_FLOAT && right_tag == TAG_FLOAT { - LuaValue::number(f64::from_bits(left.secondary) - f64::from_bits(right.secondary)) + LuaValue::number(f64::from_bits(left.secondary) + f64::from_bits(right.secondary)) } else if left_tag == TAG_INTEGER && right_tag == TAG_FLOAT { - LuaValue::number((left.secondary as i64) as f64 - f64::from_bits(right.secondary)) + LuaValue::number((left.secondary as i64) as f64 + f64::from_bits(right.secondary)) } else if left_tag == TAG_FLOAT && right_tag == TAG_INTEGER { - LuaValue::number(f64::from_bits(left.secondary) - (right.secondary as i64) as f64) + LuaValue::number(f64::from_bits(left.secondary) + (right.secondary as i64) as f64) } else { return; }; *reg_base.add(a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } /// SUB: R[A] = R[B] - R[C] /// OPTIMIZED: Matches Lua C's setivalue behavior #[inline(always)] -pub fn exec_sub(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_sub(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr); let left = *reg_base.add(b); let right = *reg_base.add(c); @@ -120,53 +73,38 @@ pub fn exec_sub(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: result as u64, }; - (*frame_ptr).pc += 1; + *pc += 1; return; } - exec_sub_slow(reg_base, a, left, right, frame_ptr); - } -} - -/// Slow path for MUL -#[cold] -#[inline(never)] -fn exec_mul_slow( - reg_base: *mut LuaValue, - a: usize, - left: LuaValue, - right: LuaValue, - frame_ptr: *mut LuaCallFrame, -) { - unsafe { + // Slow path: mixed or float types let left_tag = left.primary & TYPE_MASK; let right_tag = right.primary & TYPE_MASK; let result = if left_tag == TAG_FLOAT && right_tag == TAG_FLOAT { - LuaValue::number(f64::from_bits(left.secondary) * f64::from_bits(right.secondary)) + LuaValue::number(f64::from_bits(left.secondary) - f64::from_bits(right.secondary)) } else if left_tag == TAG_INTEGER && right_tag == TAG_FLOAT { - LuaValue::number((left.secondary as i64) as f64 * f64::from_bits(right.secondary)) + LuaValue::number((left.secondary as i64) as f64 - f64::from_bits(right.secondary)) } else if left_tag == TAG_FLOAT && right_tag == TAG_INTEGER { - LuaValue::number(f64::from_bits(left.secondary) * (right.secondary as i64) as f64) + LuaValue::number(f64::from_bits(left.secondary) - (right.secondary as i64) as f64) } else { return; }; *reg_base.add(a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } /// MUL: R[A] = R[B] * R[C] /// OPTIMIZED: Matches Lua C's setivalue behavior #[inline(always)] -pub fn exec_mul(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_mul(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr); let left = *reg_base.add(b); let right = *reg_base.add(c); @@ -179,23 +117,36 @@ pub fn exec_mul(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: result as u64, }; - (*frame_ptr).pc += 1; + *pc += 1; return; } - exec_mul_slow(reg_base, a, left, right, frame_ptr); + let left_tag = left.primary & TYPE_MASK; + let right_tag = right.primary & TYPE_MASK; + + let result = if left_tag == TAG_FLOAT && right_tag == TAG_FLOAT { + LuaValue::number(f64::from_bits(left.secondary) * f64::from_bits(right.secondary)) + } else if left_tag == TAG_INTEGER && right_tag == TAG_FLOAT { + LuaValue::number((left.secondary as i64) as f64 * f64::from_bits(right.secondary)) + } else if left_tag == TAG_FLOAT && right_tag == TAG_INTEGER { + LuaValue::number(f64::from_bits(left.secondary) * (right.secondary as i64) as f64) + } else { + return; + }; + + *reg_base.add(a) = result; + *pc += 1; } } /// DIV: R[A] = R[B] / R[C] /// Division always returns float in Lua -pub fn exec_div(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_div(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_ptr().add(base_ptr); let left = *reg_base.add(b); let right = *reg_base.add(c); @@ -220,18 +171,17 @@ pub fn exec_div(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(l_float / r_float); - (*frame_ptr).pc += 1; + *pc += 1; } } /// IDIV: R[A] = R[B] // R[C] (floor division) -pub fn exec_idiv(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_idiv(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_ptr().add(base_ptr); let left = *reg_base.add(b); let right = *reg_base.add(c); @@ -269,18 +219,17 @@ pub fn exec_idiv(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } /// MOD: R[A] = R[B] % R[C] -pub fn exec_mod(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_mod(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_ptr().add(base_ptr); let left = *reg_base.add(b); let right = *reg_base.add(c); @@ -319,18 +268,17 @@ pub fn exec_mod(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } /// POW: R[A] = R[B] ^ R[C] -pub fn exec_pow(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_pow(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); let right = *vm.register_stack.as_ptr().add(base_ptr + c); @@ -344,16 +292,15 @@ pub fn exec_pow(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(l_float.powf(r_float)); - (*frame_ptr).pc += 1; + *pc += 1; } } /// UNM: R[A] = -R[B] (unary minus) -pub fn exec_unm(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_unm(vm: &mut LuaVM, instr: u32, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; - let base_ptr = unsafe { (*frame_ptr).base_ptr }; let value = vm.register_stack[base_ptr + b]; let result = if let Some(i) = value.as_integer() { @@ -393,13 +340,12 @@ pub fn exec_unm(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua /// ADDI: R[A] = R[B] + sC /// OPTIMIZED: Minimal branches, inline integer path #[inline(always)] -pub fn exec_addi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_addi(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let sc = Instruction::get_sc(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr); let left = *reg_base.add(b); @@ -409,14 +355,14 @@ pub fn exec_addi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { let dest = reg_base.add(a); (*dest).primary = TAG_INTEGER; (*dest).secondary = result as u64; - (*frame_ptr).pc += 1; // Skip MMBINI + *pc += 1; // Skip MMBINI return; } if left.primary == TAG_FLOAT { let l = f64::from_bits(left.secondary); *reg_base.add(a) = LuaValue::float(l + sc as f64); - (*frame_ptr).pc += 1; + *pc += 1; return; } } @@ -425,13 +371,18 @@ pub fn exec_addi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// ADDK: R[A] = R[B] + K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_addk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_addk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -444,7 +395,7 @@ pub fn exec_addk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: result as u64, }; - (*frame_ptr).pc += 1; + *pc += 1; return; } @@ -455,14 +406,14 @@ pub fn exec_addk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_FLOAT, secondary: result.to_bits(), }; - (*frame_ptr).pc += 1; + *pc += 1; return; } // Mixed types if let (Some(l), Some(r)) = (left.as_number(), constant.as_number()) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(l + r); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -470,13 +421,18 @@ pub fn exec_addk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// SUBK: R[A] = R[B] - K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_subk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_subk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -489,7 +445,7 @@ pub fn exec_subk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: result as u64, }; - (*frame_ptr).pc += 1; + *pc += 1; return; } @@ -500,14 +456,14 @@ pub fn exec_subk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_FLOAT, secondary: result.to_bits(), }; - (*frame_ptr).pc += 1; + *pc += 1; return; } // Mixed types if let (Some(l), Some(r)) = (left.as_number(), constant.as_number()) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(l - r); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -515,13 +471,18 @@ pub fn exec_subk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// MULK: R[A] = R[B] * K[C] /// OPTIMIZED: Direct field writes, minimal branching #[inline(always)] -pub fn exec_mulk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_mulk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -533,7 +494,7 @@ pub fn exec_mulk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { let dest = vm.register_stack.as_mut_ptr().add(base_ptr + a); (*dest).primary = TAG_INTEGER; (*dest).secondary = result as u64; - (*frame_ptr).pc += 1; + *pc += 1; return; } @@ -543,7 +504,7 @@ pub fn exec_mulk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { let dest = vm.register_stack.as_mut_ptr().add(base_ptr + a); (*dest).primary = TAG_FLOAT; (*dest).secondary = result.to_bits(); - (*frame_ptr).pc += 1; + *pc += 1; return; } @@ -551,14 +512,14 @@ pub fn exec_mulk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { if left.primary == TAG_INTEGER && constant.primary == TAG_FLOAT { let result = (left.secondary as i64) as f64 * f64::from_bits(constant.secondary); *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::float(result); - (*frame_ptr).pc += 1; + *pc += 1; return; } if left.primary == TAG_FLOAT && constant.primary == TAG_INTEGER { let result = f64::from_bits(left.secondary) * (constant.secondary as i64) as f64; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::float(result); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -566,13 +527,18 @@ pub fn exec_mulk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// MODK: R[A] = R[B] % K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_modk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_modk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -589,7 +555,7 @@ pub fn exec_modk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: l.rem_euclid(r) as u64, }; - (*frame_ptr).pc += 1; + *pc += 1; return; } @@ -597,7 +563,7 @@ pub fn exec_modk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { if let (Some(l), Some(r)) = (left.as_number(), constant.as_number()) { let result = l - (l / r).floor() * r; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(result); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -605,13 +571,18 @@ pub fn exec_modk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// POWK: R[A] = R[B] ^ K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_powk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_powk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -627,20 +598,25 @@ pub fn exec_powk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(l_float.powf(r_float)); - (*frame_ptr).pc += 1; + *pc += 1; } } /// DIVK: R[A] = R[B] / K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_divk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_divk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -656,20 +632,25 @@ pub fn exec_divk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(l_float / r_float); - (*frame_ptr).pc += 1; + *pc += 1; } } /// IDIVK: R[A] = R[B] // K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_idivk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_idivk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -686,14 +667,14 @@ pub fn exec_idivk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { primary: TAG_INTEGER, secondary: l.div_euclid(r) as u64, }; - (*frame_ptr).pc += 1; + *pc += 1; return; } // Float // Float if let (Some(l), Some(r)) = (left.as_number(), constant.as_number()) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number((l / r).floor()); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -702,70 +683,66 @@ pub fn exec_idivk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// BAND: R[A] = R[B] & R[C] #[inline(always)] -pub fn exec_band(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_band(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); let right = *vm.register_stack.as_ptr().add(base_ptr + c); if let (Some(l), Some(r)) = (left.as_integer(), right.as_integer()) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(l & r); - (*frame_ptr).pc += 1; + *pc += 1; } } } /// BOR: R[A] = R[B] | R[C] #[inline(always)] -pub fn exec_bor(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_bor(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); let right = *vm.register_stack.as_ptr().add(base_ptr + c); if let (Some(l), Some(r)) = (left.as_integer(), right.as_integer()) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(l | r); - (*frame_ptr).pc += 1; + *pc += 1; } } } /// BXOR: R[A] = R[B] ~ R[C] #[inline(always)] -pub fn exec_bxor(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_bxor(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); let right = *vm.register_stack.as_ptr().add(base_ptr + c); if let (Some(l), Some(r)) = (left.as_integer(), right.as_integer()) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(l ^ r); - (*frame_ptr).pc += 1; + *pc += 1; } } } /// SHL: R[A] = R[B] << R[C] #[inline(always)] -pub fn exec_shl(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_shl(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); let right = *vm.register_stack.as_ptr().add(base_ptr + c); @@ -776,20 +753,19 @@ pub fn exec_shl(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { LuaValue::integer(l >> ((-r) & 63)) }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } } /// SHR: R[A] = R[B] >> R[C] #[inline(always)] -pub fn exec_shr(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_shr(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); let right = *vm.register_stack.as_ptr().add(base_ptr + c); @@ -800,7 +776,7 @@ pub fn exec_shr(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { LuaValue::integer(l << ((-r) & 63)) }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -808,13 +784,18 @@ pub fn exec_shr(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// BANDK: R[A] = R[B] & K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_bandk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_bandk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -841,7 +822,7 @@ pub fn exec_bandk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { if let (Some(l), Some(r)) = (l_int, r_int) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(l & r); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -849,13 +830,18 @@ pub fn exec_bandk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// BORK: R[A] = R[B] | K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_bork(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_bork( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -882,7 +868,7 @@ pub fn exec_bork(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { if let (Some(l), Some(r)) = (l_int, r_int) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(l | r); - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -890,13 +876,18 @@ pub fn exec_bork(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// BXORK: R[A] = R[B] ~ K[C] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_bxork(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_bxork( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); // FAST PATH: Direct constant access via cached pointer @@ -923,20 +914,19 @@ pub fn exec_bxork(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { if let (Some(l), Some(r)) = (l_int, r_int) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(l ^ r); - (*frame_ptr).pc += 1; + *pc += 1; } } } /// SHRI: R[A] = R[B] >> sC #[inline(always)] -pub fn exec_shri(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_shri(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let sc = Instruction::get_sc(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + b); if let Some(l) = left.as_integer() { @@ -946,20 +936,19 @@ pub fn exec_shri(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { LuaValue::integer(l << ((-sc) & 63)) }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } } /// SHLI: R[A] = sC << R[B] #[inline(always)] -pub fn exec_shli(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_shli(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let sc = Instruction::get_sc(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let right = *vm.register_stack.as_ptr().add(base_ptr + b); if let Some(r) = right.as_integer() { @@ -969,18 +958,17 @@ pub fn exec_shli(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { LuaValue::integer((sc as i64) >> ((-r) & 63)) }; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = result; - (*frame_ptr).pc += 1; + *pc += 1; } } } /// BNOT: R[A] = ~R[B] #[inline(always)] -pub fn exec_bnot(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_bnot(vm: &mut LuaVM, instr: u32, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; - let base_ptr = unsafe { (*frame_ptr).base_ptr }; let value = vm.register_stack[base_ptr + b]; if let Some(int_val) = value.as_integer() { @@ -1008,14 +996,14 @@ pub fn exec_bnot(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lu ))) } +#[allow(dead_code)] /// NOT: R[A] = not R[B] #[inline(always)] -pub fn exec_not(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_not(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let value = *vm.register_stack.as_ptr().add(base_ptr + b); // In Lua, only nil and false are falsy @@ -1027,11 +1015,10 @@ pub fn exec_not(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// LEN: R[A] = #R[B] #[inline(always)] -pub fn exec_len(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_len(vm: &mut LuaVM, instr: u32, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; - let base_ptr = unsafe { (*frame_ptr).base_ptr }; let value = vm.register_stack[base_ptr + b]; // Check for __len metamethod first (for tables) @@ -1074,22 +1061,28 @@ pub fn exec_len(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua } /// MmBin: Metamethod binary operation (register, register) +/// OPTIMIZED: Uses passed code_ptr instead of dereferencing frame_ptr #[inline(always)] -pub fn exec_mmbin(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_mmbin( + vm: &mut LuaVM, + instr: u32, + code_ptr: *const u32, + pc: &mut usize, + base_ptr: usize, +) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let prev_pc = (*frame_ptr).pc - 1; + let prev_pc = *pc - 1; if prev_pc == 0 { return Ok(()); } // Get previous instruction to find destination register - let prev_instr = (*frame_ptr).code_ptr.add(prev_pc - 1).read(); + let prev_instr = code_ptr.add(prev_pc - 1).read(); let dest_reg = Instruction::get_a(prev_instr) as usize; let ra = *vm.register_stack.as_ptr().add(base_ptr + a); @@ -1119,22 +1112,28 @@ pub fn exec_mmbin(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> L } /// MmBinI: Metamethod binary operation (register, immediate) +/// OPTIMIZED: Uses passed code_ptr instead of dereferencing frame_ptr #[inline(always)] -pub fn exec_mmbini(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_mmbini( + vm: &mut LuaVM, + instr: u32, + code_ptr: *const u32, + pc: &mut usize, + base_ptr: usize, +) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let sb = Instruction::get_sb(instr); let c = Instruction::get_c(instr); let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let prev_pc = (*frame_ptr).pc - 1; + let prev_pc = *pc - 1; if prev_pc == 0 { return Ok(()); } - let prev_instr = (*frame_ptr).code_ptr.add(prev_pc - 1).read(); + let prev_instr = code_ptr.add(prev_pc - 1).read(); let dest_reg = Instruction::get_a(prev_instr) as usize; let rb = *vm.register_stack.as_ptr().add(base_ptr + a); @@ -1161,40 +1160,35 @@ pub fn exec_mmbini(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> } /// MmBinK: Metamethod binary operation (register, constant) +/// OPTIMIZED: Uses passed code_ptr and constants_ptr instead of dereferencing frame_ptr #[inline(always)] -pub fn exec_mmbink(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_mmbink( + vm: &mut LuaVM, + instr: u32, + code_ptr: *const u32, + constants_ptr: *const LuaValue, + pc: &mut usize, + base_ptr: usize, +) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let prev_pc = (*frame_ptr).pc - 1; + let prev_pc = *pc - 1; if prev_pc == 0 { return Ok(()); } - let prev_instr = (*frame_ptr).code_ptr.add(prev_pc - 1).read(); + let prev_instr = code_ptr.add(prev_pc - 1).read(); let dest_reg = Instruction::get_a(prev_instr) as usize; let ra = *vm.register_stack.as_ptr().add(base_ptr + a); - // Get constant - let kb = if let Some(func_id) = (*frame_ptr).function_value.as_function_id() { - if let Some(func_ref) = vm.object_pool.get_function(func_id) { - if let Some(&val) = func_ref.chunk.constants.get(b) { - val - } else { - return Ok(()); - } - } else { - return Ok(()); - } - } else { - return Ok(()); - }; + // Get constant via passed constants_ptr + let kb = *constants_ptr.add(b); // Use pre-cached metamethod StringId let mm_key = LuaValue::string(vm.object_pool.get_binop_tm(c as u8)); diff --git a/crates/luars/src/lua_vm/execute/control_instructions.rs b/crates/luars/src/lua_vm/execute/control_instructions.rs index 202e3bf3..d74fe679 100644 --- a/crates/luars/src/lua_vm/execute/control_instructions.rs +++ b/crates/luars/src/lua_vm/execute/control_instructions.rs @@ -138,14 +138,13 @@ pub fn exec_return( /// JMP sJ /// pc += sJ +#[allow(dead_code)] #[inline(always)] -pub fn exec_jmp(instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_jmp(instr: u32, pc: &mut usize) { let sj = Instruction::get_sj(instr); - unsafe { - // PC already incremented by dispatcher, so we add offset directly - (*frame_ptr).pc = ((*frame_ptr).pc as i32 + sj) as usize; - } + // PC already incremented by dispatcher, so we add offset directly + *pc = (*pc as i32 + sj) as usize; } // ============ Test Instructions ============ @@ -153,14 +152,13 @@ pub fn exec_jmp(instr: u32, frame_ptr: *mut LuaCallFrame) { /// TEST A k /// if (not R[A] == k) then pc++ /// ULTRA-OPTIMIZED: Direct type tag check, single branch +#[allow(dead_code)] #[inline(always)] -pub fn exec_test(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_test(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; - // OPTIMIZATION: Direct unsafe access and type tag comparison let value = *vm.register_stack.as_ptr().add(base_ptr + a); @@ -172,7 +170,7 @@ pub fn exec_test(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { // If (not value) == k, skip next instruction if !is_truthy == k { - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -181,14 +179,12 @@ pub fn exec_test(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// if (not R[B] == k) then R[A] := R[B] else pc++ /// ULTRA-OPTIMIZED: Direct type tag check, single branch #[inline(always)] -pub fn exec_testset(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_testset(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; - // OPTIMIZATION: Direct unsafe access let reg_ptr = vm.register_stack.as_ptr().add(base_ptr); let value = *reg_ptr.add(b); @@ -201,7 +197,7 @@ pub fn exec_testset(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { if is_truthy == k { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = value; } else { - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -212,13 +208,16 @@ pub fn exec_testset(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// if ((R[A] == R[B]) ~= k) then pc++ /// ULTRA-OPTIMIZED: Fast path for common types (integers, floats, strings) #[inline(always)] -pub fn exec_eq(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_eq( + vm: &mut LuaVM, + instr: u32, + pc: &mut usize, + base_ptr: usize, +) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let k = Instruction::get_k(instr); - let base_ptr = unsafe { (*frame_ptr).base_ptr }; - // OPTIMIZATION: Use unsafe for unchecked register access let (left, right) = unsafe { let reg_base = vm.register_stack.as_ptr().add(base_ptr); @@ -279,9 +278,7 @@ pub fn exec_eq(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR // If (left == right) != k, skip next instruction if is_equal != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } Ok(()) @@ -291,14 +288,13 @@ pub fn exec_eq(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR /// if ((R[A] < R[B]) ~= k) then pc++ /// ULTRA-OPTIMIZED: Direct integer fast path like Lua C #[inline(always)] -pub fn exec_lt(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_lt(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let reg_base = vm.register_stack.as_ptr().add(base_ptr); + let reg_base = vm.register_stack.as_ptr().add(*base_ptr); let left = *reg_base.add(a); let right = *reg_base.add(b); @@ -310,7 +306,7 @@ pub fn exec_lt(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR if left_tag == TAG_INTEGER && right_tag == TAG_INTEGER { let is_less = (left.secondary as i64) < (right.secondary as i64); if is_less != k { - (*frame_ptr).pc += 1; + *pc += 1; } return Ok(()); } @@ -319,7 +315,7 @@ pub fn exec_lt(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR if left_tag == TAG_FLOAT && right_tag == TAG_FLOAT { let is_less = f64::from_bits(left.secondary) < f64::from_bits(right.secondary); if is_less != k { - (*frame_ptr).pc += 1; + *pc += 1; } return Ok(()); } @@ -340,7 +336,7 @@ pub fn exec_lt(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR }; let is_less = left_f < right_f; if is_less != k { - (*frame_ptr).pc += 1; + *pc += 1; } return Ok(()); } @@ -350,13 +346,13 @@ pub fn exec_lt(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR if left_tag == TAG_STRING && right_tag == TAG_STRING { let is_less = left < right; if is_less != k { - (*frame_ptr).pc += 1; + *pc += 1; } return Ok(()); } // Slow path: metamethod - exec_lt_metamethod(vm, left, right, k, frame_ptr) + exec_lt_metamethod(vm, left, right, k, pc) } } @@ -368,7 +364,7 @@ fn exec_lt_metamethod( left: crate::LuaValue, right: crate::LuaValue, k: bool, - frame_ptr: *mut LuaCallFrame, + pc: &mut usize, ) -> LuaResult<()> { // Use pre-cached __lt StringId let mm_key = LuaValue::string(vm.object_pool.tm_lt); @@ -380,9 +376,7 @@ fn exec_lt_metamethod( if let Some(result) = vm.call_metamethod(&metamethod, &[left, right])? { let is_less_result = !result.is_nil() && result.as_bool().unwrap_or(true); if is_less_result != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } return Ok(()); } @@ -398,9 +392,7 @@ fn exec_lt_metamethod( if let Some(result) = vm.call_metamethod(&metamethod, &[left, right])? { let is_less_result = !result.is_nil() && result.as_bool().unwrap_or(true); if is_less_result != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } return Ok(()); } @@ -424,13 +416,16 @@ fn exec_lt_metamethod( /// if ((R[A] <= R[B]) ~= k) then pc++ /// ULTRA-OPTIMIZED: Use combined_tags for fast path like LT #[inline(always)] -pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_le( + vm: &mut LuaVM, + instr: u32, + pc: &mut usize, + base_ptr: usize, +) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let k = Instruction::get_k(instr); - let base_ptr = unsafe { (*frame_ptr).base_ptr }; - // OPTIMIZATION: Use unsafe for unchecked register access let (left, right) = unsafe { let reg_base = vm.register_stack.as_ptr().add(base_ptr); @@ -481,9 +476,7 @@ pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR if let Some(result) = vm.call_metamethod(&metamethod, &[left, right])? { let is_le_result = !result.is_nil() && result.as_bool().unwrap_or(true); if is_le_result != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } return Ok(()); } @@ -499,9 +492,7 @@ pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR if let Some(result) = vm.call_metamethod(&metamethod, &[left, right])? { let is_le_result = !result.is_nil() && result.as_bool().unwrap_or(true); if is_le_result != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } return Ok(()); } @@ -523,9 +514,7 @@ pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR let is_gt_result = !result.is_nil() && result.as_bool().unwrap_or(true); let is_le_result = !is_gt_result; // a <= b is !(b < a) if is_le_result != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } return Ok(()); } @@ -543,9 +532,7 @@ pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR !result.is_nil() && result.as_bool().unwrap_or(true); let is_le_result = !is_gt_result; if is_le_result != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } return Ok(()); } @@ -567,9 +554,7 @@ pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR }; if is_less_or_equal != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } Ok(()) @@ -578,12 +563,18 @@ pub fn exec_le(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaR /// EQK A B k /// if ((R[A] == K[B]) ~= k) then pc++ #[inline(always)] -pub fn exec_eqk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_eqk( + vm: &mut LuaVM, + instr: u32, + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + base_ptr: usize, +) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let k = Instruction::get_k(instr); - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; + let func_value = unsafe { (*frame_ptr).function_value }; // Get function using new ID-based API let Some(func_id) = func_value.as_function_id() else { @@ -601,9 +592,7 @@ pub fn exec_eqk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua let is_equal = left == constant; if is_equal != k { - unsafe { - (*frame_ptr).pc += 1; - } + *pc += 1; } Ok(()) @@ -612,13 +601,12 @@ pub fn exec_eqk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua /// EQI A sB k /// if ((R[A] == sB) ~= k) then pc++ #[inline(always)] -pub fn exec_eqi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_eqi(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let sb = Instruction::get_sb(instr); let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + a); use crate::lua_value::{TAG_INTEGER, TYPE_MASK}; @@ -631,7 +619,7 @@ pub fn exec_eqi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { }; if is_equal != k { - (*frame_ptr).pc += 1; + *pc += 1; } } } @@ -639,13 +627,12 @@ pub fn exec_eqi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// LTI A sB k /// if ((R[A] < sB) ~= k) then pc++ #[inline(always)] -pub fn exec_lti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_lti(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let sb = Instruction::get_sb(instr); let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + a); // OPTIMIZATION: Direct type tag comparison @@ -663,7 +650,7 @@ pub fn exec_lti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua }; if is_less != k { - (*frame_ptr).pc += 1; + *pc += 1; } } @@ -673,13 +660,12 @@ pub fn exec_lti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua /// LEI A sB k /// if ((R[A] <= sB) ~= k) then pc++ #[inline(always)] -pub fn exec_lei(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_lei(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let sb = Instruction::get_sb(instr); let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + a); use crate::lua_value::{TAG_INTEGER, TYPE_MASK}; @@ -695,7 +681,7 @@ pub fn exec_lei(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua }; if is_less_equal != k { - (*frame_ptr).pc += 1; + *pc += 1; } } @@ -705,13 +691,12 @@ pub fn exec_lei(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua /// GTI A sB k /// if ((R[A] > sB) ~= k) then pc++ #[inline(always)] -pub fn exec_gti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_gti(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let sb = Instruction::get_sb(instr); let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + a); use crate::lua_value::{TAG_INTEGER, TYPE_MASK}; @@ -727,7 +712,7 @@ pub fn exec_gti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua }; if is_greater != k { - (*frame_ptr).pc += 1; + *pc += 1; } } @@ -737,13 +722,12 @@ pub fn exec_gti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua /// GEI A sB k /// if ((R[A] >= sB) ~= k) then pc++ #[inline(always)] -pub fn exec_gei(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_gei(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let sb = Instruction::get_sb(instr); let k = Instruction::get_k(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; let left = *vm.register_stack.as_ptr().add(base_ptr + a); use crate::lua_value::{TAG_INTEGER, TYPE_MASK}; @@ -759,7 +743,7 @@ pub fn exec_gei(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lua }; if is_greater_equal != k { - (*frame_ptr).pc += 1; + *pc += 1; } } diff --git a/crates/luars/src/lua_vm/execute/load_instructions.rs b/crates/luars/src/lua_vm/execute/load_instructions.rs index 94ef7b13..821b8c79 100644 --- a/crates/luars/src/lua_vm/execute/load_instructions.rs +++ b/crates/luars/src/lua_vm/execute/load_instructions.rs @@ -10,11 +10,11 @@ use crate::lua_vm::{Instruction, LuaCallFrame, LuaVM}; /// /// This instruction moves vararg arguments to a safe location after max_stack_size, /// so they won't be overwritten by local variable operations. -pub fn exec_varargprep(vm: &mut LuaVM, instr: u32, _frame_ptr: *mut LuaCallFrame) { +pub fn exec_varargprep(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) { let a = Instruction::get_a(instr) as usize; // number of fixed params let frame = vm.current_frame(); - let base_ptr = frame.base_ptr; + let frame_base = frame.base_ptr; let top = frame.top; // Get max_stack_size from the function using new ObjectPool API @@ -26,24 +26,24 @@ pub fn exec_varargprep(vm: &mut LuaVM, instr: u32, _frame_ptr: *mut LuaCallFrame }; let max_stack_size = func_ref.chunk.max_stack_size; - // Arguments were placed starting at base_ptr by CALL instruction - // Fixed parameters are at base_ptr + 0 to base_ptr + a - 1 - // Extra arguments (varargs) are at base_ptr + a to base_ptr + top - 1 - // We need to move the varargs to base_ptr + max_stack_size to protect them + // Arguments were placed starting at frame_base by CALL instruction + // Fixed parameters are at frame_base + 0 to frame_base + a - 1 + // Extra arguments (varargs) are at frame_base + a to frame_base + top - 1 + // We need to move the varargs to frame_base + max_stack_size to protect them // from being overwritten by local variable operations if top > a { let vararg_count = top - a; - let vararg_dest = base_ptr + max_stack_size; + let vararg_dest = frame_base + max_stack_size; // Ensure we have enough space for the varargs let required_size = vararg_dest + vararg_count; vm.ensure_stack_capacity(required_size); - // Move varargs from base_ptr + a to base_ptr + max_stack_size + // Move varargs from frame_base + a to frame_base + max_stack_size // Copy in reverse order in case source and destination overlap for i in (0..vararg_count).rev() { - vm.register_stack[vararg_dest + i] = vm.register_stack[base_ptr + a + i]; + vm.register_stack[vararg_dest + i] = vm.register_stack[frame_base + a + i]; } // Set vararg info in frame @@ -51,27 +51,30 @@ pub fn exec_varargprep(vm: &mut LuaVM, instr: u32, _frame_ptr: *mut LuaCallFrame } else { // No varargs passed vm.current_frame_mut() - .set_vararg(base_ptr + max_stack_size, 0); + .set_vararg(frame_base + max_stack_size, 0); } // Initialize local variables (registers from 0 to max_stack_size) with nil // But preserve fixed parameters (0..a) for i in a..max_stack_size { - if base_ptr + i < vm.register_stack.len() { - vm.register_stack[base_ptr + i] = LuaValue::nil(); + if frame_base + i < vm.register_stack.len() { + vm.register_stack[frame_base + i] = LuaValue::nil(); } } + + // updatebase - frame operations may change base_ptr + unsafe { *base_ptr = (*frame_ptr).base_ptr; } } /// LOADNIL A B /// R[A], R[A+1], ..., R[A+B] := nil #[inline(always)] -pub fn exec_loadnil(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_loadnil(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let nil_val = LuaValue::nil(); let reg_ptr = vm.register_stack.as_mut_ptr().add(base_ptr); for i in 0..=b { @@ -83,11 +86,11 @@ pub fn exec_loadnil(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// LOADFALSE A /// R[A] := false #[inline(always)] -pub fn exec_loadfalse(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_loadfalse(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(false); } } @@ -95,25 +98,25 @@ pub fn exec_loadfalse(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) /// LFALSESKIP A /// R[A] := false; pc++ #[inline(always)] -pub fn exec_lfalseskip(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_lfalseskip(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(false); // Skip next instruction - (*frame_ptr).pc += 1; + *pc += 1; } } /// LOADTRUE A /// R[A] := true #[inline(always)] -pub fn exec_loadtrue(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_loadtrue(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(true); } } @@ -121,12 +124,13 @@ pub fn exec_loadtrue(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// LOADI A sBx /// R[A] := sBx (signed integer) #[inline(always)] -pub fn exec_loadi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +#[allow(dead_code)] +pub fn exec_loadi(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let sbx = Instruction::get_sbx(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::integer(sbx as i64); } } @@ -134,12 +138,12 @@ pub fn exec_loadi(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// LOADF A sBx /// R[A] := (lua_Number)sBx #[inline(always)] -pub fn exec_loadf(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_loadf(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let sbx = Instruction::get_sbx(instr); unsafe { - let base_ptr = (*frame_ptr).base_ptr; *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::number(sbx as f64); } } @@ -148,12 +152,12 @@ pub fn exec_loadf(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// R[A] := K[Bx] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_loadk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_loadk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let bx = Instruction::get_bx(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; // FAST PATH: Direct constant access via cached pointer let constant = *(*frame_ptr).constants_ptr.add(bx); *vm.register_stack.as_mut_ptr().add(base_ptr + a) = constant; @@ -163,18 +167,18 @@ pub fn exec_loadk(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// LOADKX A /// R[A] := K[extra arg] #[inline(always)] -pub fn exec_loadkx(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_loadkx(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; unsafe { - let pc = (*frame_ptr).pc; - (*frame_ptr).pc += 1; // Skip the extra arg instruction - let base_ptr = (*frame_ptr).base_ptr; + let pc_val = (*frame_ptr).pc; + (*frame_ptr).pc = pc_val + 1; // Skip the extra arg instruction let func_id = (*frame_ptr).function_value.as_function_id(); if let Some(fid) = func_id { if let Some(func_ref) = vm.object_pool.get_function(fid) { - if let Some(&extra_instr) = func_ref.chunk.code.get(pc) { + if let Some(&extra_instr) = func_ref.chunk.code.get(pc_val) { let bx = Instruction::get_ax(extra_instr) as usize; if let Some(&constant) = func_ref.chunk.constants.get(bx) { *vm.register_stack.as_mut_ptr().add(base_ptr + a) = constant; @@ -188,12 +192,12 @@ pub fn exec_loadkx(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// MOVE A B /// R[A] := R[B] #[inline(always)] -pub fn exec_move(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +#[allow(dead_code)] +pub fn exec_move(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_ptr = vm.register_stack.as_mut_ptr().add(base_ptr); *reg_ptr.add(a) = *reg_ptr.add(b); } diff --git a/crates/luars/src/lua_vm/execute/loop_instructions.rs b/crates/luars/src/lua_vm/execute/loop_instructions.rs index 39512ae0..82da7d81 100644 --- a/crates/luars/src/lua_vm/execute/loop_instructions.rs +++ b/crates/luars/src/lua_vm/execute/loop_instructions.rs @@ -13,12 +13,11 @@ use crate::{ /// Prepare numeric for loop: R[A]-=R[A+2]; R[A+3]=R[A]; if (skip) pc+=Bx+1 /// OPTIMIZED: Uses frame_ptr directly, no i128, unsafe register access #[inline(always)] -pub fn exec_forprep(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_forprep(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let bx = Instruction::get_bx(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr + a); let init = *reg_base; @@ -67,7 +66,7 @@ pub fn exec_forprep(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> if count == 0 { // Skip the entire loop body and FORLOOP - (*frame_ptr).pc += bx; + *pc += bx; } else { // Store count-1 in R[A+1] (we'll execute count times, counter starts at count-1) // because we already set R[A+3] = init for the first iteration @@ -116,7 +115,7 @@ pub fn exec_forprep(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> }; if should_skip { - (*frame_ptr).pc += bx; + *pc += bx; } else { // Prepare internal index *reg_base = LuaValue::number(init_f - step_f); @@ -133,12 +132,12 @@ pub fn exec_forprep(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> /// /// ULTRA-OPTIMIZED: Only check step type (like Lua C), use chgivalue pattern #[inline(always)] -pub fn exec_forloop(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +#[allow(dead_code)] +pub fn exec_forloop(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let bx = Instruction::get_bx(instr) as usize; unsafe { - let base_ptr = (*frame_ptr).base_ptr; let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr + a); // Only check step type - like Lua C's ttisinteger(s2v(ra + 2)) @@ -158,25 +157,25 @@ pub fn exec_forloop(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> (*reg_base).secondary = new_idx as u64; // idx += step (*reg_base.add(3)).secondary = new_idx as u64; // control = idx - (*frame_ptr).pc -= bx; + *pc -= bx; } // count == 0: loop ended, fall through return Ok(()); } // Float loop - slower path - exec_forloop_float(vm, reg_base, bx, frame_ptr) + exec_forloop_float(vm, reg_base, bx, pc) } } /// Float loop - separate cold function #[cold] #[inline(never)] -fn exec_forloop_float( +pub fn exec_forloop_float( vm: &mut LuaVM, reg_base: *mut LuaValue, bx: usize, - frame_ptr: *mut LuaCallFrame, + pc: &mut usize, ) -> LuaResult<()> { unsafe { let idx = *reg_base; @@ -221,7 +220,7 @@ fn exec_forloop_float( if should_continue { *reg_base = LuaValue::number(new_idx_f); *reg_base.add(3) = LuaValue::number(new_idx_f); - (*frame_ptr).pc -= bx; + *pc -= bx; } } @@ -232,38 +231,27 @@ fn exec_forloop_float( /// create upvalue for R[A + 3]; pc+=Bx /// In Lua 5.4, this creates a to-be-closed variable for the state #[inline(always)] -pub fn exec_tforprep(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_tforprep(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let bx = Instruction::get_bx(instr) as usize; - unsafe { - let base_ptr = (*frame_ptr).base_ptr; - - // In Lua 5.4, R[A+3] is the to-be-closed variable for the state - // For now, we just copy the state value to ensure it's preserved - let state = vm.register_stack[base_ptr + a + 1]; - vm.register_stack[base_ptr + a + 3] = state; + // In Lua 5.4, R[A+3] is the to-be-closed variable for the state + // For now, we just copy the state value to ensure it's preserved + let state = vm.register_stack[base_ptr + a + 1]; + vm.register_stack[base_ptr + a + 3] = state; - // Jump to loop start - (*frame_ptr).pc += bx; - } + // Jump to loop start + *pc += bx; } /// TFORCALL A C /// R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); +/// Returns true if a Lua function was called and frame changed (needs updatestate) #[inline(always)] -pub fn exec_tforcall(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_tforcall(vm: &mut LuaVM, instr: u32, frame_ptr: &mut *mut LuaCallFrame, base_ptr: usize) -> LuaResult { let a = Instruction::get_a(instr) as usize; let c = Instruction::get_c(instr) as usize; - let (base_ptr, _func_value, _current_pc) = unsafe { - ( - (*frame_ptr).base_ptr, - (*frame_ptr).function_value, - (*frame_ptr).pc, - ) - }; - // Get iterator function and state let func = vm.register_stack[base_ptr + a]; let state = vm.register_stack[base_ptr + a + 1]; @@ -301,6 +289,7 @@ pub fn exec_tforcall(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - for i in values.len()..=c { vm.register_stack[base_ptr + a + 3 + i] = LuaValue::nil(); } + Ok(false) // No frame change for C functions } LuaValueKind::Function => { // For Lua functions, we need to use CALL instruction logic @@ -348,31 +337,28 @@ pub fn exec_tforcall(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - ); vm.push_frame(new_frame); - // Execution will continue in the new frame + // Update frame_ptr to point to new frame + *frame_ptr = vm.current_frame_ptr(); + Ok(true) // Frame changed, need updatestate } _ => { - return Err(vm.error("attempt to call a non-function value in for loop".to_string())); + Err(vm.error("attempt to call a non-function value in for loop".to_string())) } } - - Ok(()) } /// TFORLOOP A Bx /// if R[A+1] ~= nil then { R[A]=R[A+1]; pc -= Bx } #[inline(always)] -pub fn exec_tforloop(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_tforloop(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let bx = Instruction::get_bx(instr) as usize; - unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let value = vm.register_stack[base_ptr + a + 1]; + let value = vm.register_stack[base_ptr + a + 1]; - if !value.is_nil() { - // Continue loop - vm.register_stack[base_ptr + a] = value; - (*frame_ptr).pc -= bx; - } + if !value.is_nil() { + // Continue loop + vm.register_stack[base_ptr + a] = value; + *pc -= bx; } } diff --git a/crates/luars/src/lua_vm/execute/mod.rs b/crates/luars/src/lua_vm/execute/mod.rs index 6a809bc5..fd3bcdd6 100644 --- a/crates/luars/src/lua_vm/execute/mod.rs +++ b/crates/luars/src/lua_vm/execute/mod.rs @@ -18,13 +18,42 @@ pub use upvalue_instructions::*; use super::{Instruction, LuaError, LuaResult, LuaVM, OpCode}; use crate::LuaValue; +use crate::lua_value::TAG_INTEGER; +use crate::lua_vm::LuaCallFrame; + +/// Save current pc to frame (like Lua C's savepc macro) +/// Called before operations that may call Lua functions (CALL, metamethods, etc.) +macro_rules! savepc { + ($frame_ptr:expr, $pc:expr) => { + unsafe { + (*$frame_ptr).pc = $pc; + } + }; +} + +/// Update pc, code_ptr and base_ptr from frame (like Lua C's updatestate) +/// Used after CALL/RETURN instructions when frame changes +#[inline(always)] +unsafe fn updatestate( + frame_ptr: *mut LuaCallFrame, + pc: &mut usize, + code_ptr: &mut *const u32, + base_ptr: &mut usize, +) { + unsafe { + *pc = (*frame_ptr).pc; + *code_ptr = (*frame_ptr).code_ptr; + *base_ptr = (*frame_ptr).base_ptr; + } +} /// Ultra-optimized main execution loop /// -/// Key optimizations: -/// 1. Instructions that never fail don't return Result - just continue -/// 2. frame_ptr is passed by mutable reference so CALL/RETURN can update it -/// 3. Minimal branching on the fast path +/// Key optimizations (like Lua C): +/// 1. Local variables: pc, code_ptr, base_ptr cached locally (like Lua C's luaV_execute) +/// 2. Hot path instructions inlined directly in match +/// 3. State reload only when frame changes (CALL/RETURN) +/// 4. Pass mutable references to avoid frequent frame_ptr writes /// /// Returns: Ok(LuaValue) on success, Err on runtime error #[inline(never)] // Don't inline this - it's the main loop, let it stay in cache @@ -37,275 +66,392 @@ pub fn luavm_execute(vm: &mut LuaVM) -> LuaResult { // Initialize frame pointer - Box ensures pointer stability across Vec reallocs let mut frame_ptr = vm.current_frame_ptr(); + // Like Lua C: cache hot variables as locals (register allocated) + // This avoids dereferencing frame_ptr on each instruction + let mut pc: usize; + let mut code_ptr: *const u32; + let mut base_ptr: usize; + + // Initial load from frame + unsafe { + pc = (*frame_ptr).pc; + code_ptr = (*frame_ptr).code_ptr; + base_ptr = (*frame_ptr).base_ptr; + } + 'mainloop: loop { - // Fetch and decode instruction - let instr = unsafe { (*frame_ptr).code_ptr.add((*frame_ptr).pc).read() }; - unsafe { - (*frame_ptr).pc += 1; - } + // Fetch instruction using local pc (like Lua C's vmfetch) + let instr = unsafe { *code_ptr.add(pc) }; + pc += 1; let opcode = Instruction::get_opcode(instr); match opcode { - // ============ Load Instructions (never fail) ============ + // ============ HOT PATH: Inline simple instructions (< 10 lines) ============ + + // MOVE - R[A] := R[B] OpCode::Move => { - exec_move(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + let b = Instruction::get_b(instr) as usize; + unsafe { + let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr); + *reg_base.add(a) = *reg_base.add(b); + } continue 'mainloop; } + + // LOADI - R[A] := sBx OpCode::LoadI => { - exec_loadi(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + let sbx = Instruction::get_sbx(instr); + unsafe { + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = + LuaValue::integer(sbx as i64); + } continue 'mainloop; } - OpCode::LoadNil => { - exec_loadnil(vm, instr, frame_ptr); + + // LOADF - R[A] := (float)sBx + OpCode::LoadF => { + let a = Instruction::get_a(instr) as usize; + let sbx = Instruction::get_sbx(instr); + unsafe { + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = + LuaValue::number(sbx as f64); + } continue 'mainloop; } - OpCode::LoadFalse => { - exec_loadfalse(vm, instr, frame_ptr); + + // LOADTRUE - R[A] := true + OpCode::LoadTrue => { + let a = Instruction::get_a(instr) as usize; + unsafe { + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(true); + } continue 'mainloop; } - OpCode::LoadTrue => { - exec_loadtrue(vm, instr, frame_ptr); + + // LOADFALSE - R[A] := false + OpCode::LoadFalse => { + let a = Instruction::get_a(instr) as usize; + unsafe { + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(false); + } continue 'mainloop; } + + // LFALSESKIP - R[A] := false; pc++ OpCode::LFalseSkip => { - exec_lfalseskip(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + unsafe { + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(false); + } + pc += 1; continue 'mainloop; } - OpCode::LoadF => { - exec_loadf(vm, instr, frame_ptr); + + // LOADNIL - R[A], ..., R[A+B] := nil + OpCode::LoadNil => { + let a = Instruction::get_a(instr) as usize; + let b = Instruction::get_b(instr) as usize; + unsafe { + let nil_val = LuaValue::nil(); + let reg_ptr = vm.register_stack.as_mut_ptr().add(base_ptr); + for i in 0..=b { + *reg_ptr.add(a + i) = nil_val; + } + } continue 'mainloop; } + + // LOADK - R[A] := K[Bx] OpCode::LoadK => { - exec_loadk(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + let bx = Instruction::get_bx(instr) as usize; + unsafe { + let constant = *(*frame_ptr).constants_ptr.add(bx); + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = constant; + } continue 'mainloop; } + + // LOADKX - R[A] := K[extra arg]; pc++ OpCode::LoadKX => { - exec_loadkx(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + unsafe { + let extra_instr = *code_ptr.add(pc); + pc += 1; + let bx = Instruction::get_ax(extra_instr) as usize; + let constant = *(*frame_ptr).constants_ptr.add(bx); + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = constant; + } continue 'mainloop; } + + // VARARGPREP - complex, call function OpCode::VarargPrep => { - exec_varargprep(vm, instr, frame_ptr); + exec_varargprep(vm, instr, frame_ptr, &mut base_ptr); continue 'mainloop; } - // ============ Arithmetic (integer fast path never fails) ============ + // ============ Arithmetic operations ============ OpCode::Add => { - exec_add(vm, instr, frame_ptr); + exec_add(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Sub => { - exec_sub(vm, instr, frame_ptr); + exec_sub(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Mul => { - exec_mul(vm, instr, frame_ptr); + exec_mul(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::AddI => { - exec_addi(vm, instr, frame_ptr); + exec_addi(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Div => { - exec_div(vm, instr, frame_ptr); + exec_div(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::IDiv => { - exec_idiv(vm, instr, frame_ptr); + exec_idiv(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Mod => { - exec_mod(vm, instr, frame_ptr); + exec_mod(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Pow => { - exec_pow(vm, instr, frame_ptr); + exec_pow(vm, instr, &mut pc, base_ptr); continue 'mainloop; } // Arithmetic with constants OpCode::AddK => { - exec_addk(vm, instr, frame_ptr); + exec_addk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::SubK => { - exec_subk(vm, instr, frame_ptr); + exec_subk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::MulK => { - exec_mulk(vm, instr, frame_ptr); + exec_mulk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::ModK => { - exec_modk(vm, instr, frame_ptr); + exec_modk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::PowK => { - exec_powk(vm, instr, frame_ptr); + exec_powk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::DivK => { - exec_divk(vm, instr, frame_ptr); + exec_divk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::IDivK => { - exec_idivk(vm, instr, frame_ptr); + exec_idivk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } - // ============ Bitwise (never fail for integers) ============ + // ============ Bitwise (inline simple ones) ============ OpCode::BAnd => { - exec_band(vm, instr, frame_ptr); + exec_band(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::BOr => { - exec_bor(vm, instr, frame_ptr); + exec_bor(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::BXor => { - exec_bxor(vm, instr, frame_ptr); + exec_bxor(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Shl => { - exec_shl(vm, instr, frame_ptr); + exec_shl(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::Shr => { - exec_shr(vm, instr, frame_ptr); + exec_shr(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::BAndK => { - exec_bandk(vm, instr, frame_ptr); + exec_bandk(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::BOrK => { - exec_bork(vm, instr, frame_ptr); + exec_bork(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::BXorK => { - exec_bxork(vm, instr, frame_ptr); + exec_bxork(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::ShrI => { - exec_shri(vm, instr, frame_ptr); + exec_shri(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::ShlI => { - exec_shli(vm, instr, frame_ptr); + exec_shli(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::BNot => { - if let Err(e) = exec_bnot(vm, instr, frame_ptr) { + if let Err(e) = exec_bnot(vm, instr, base_ptr) { return Err(e); } continue 'mainloop; } - // ============ Unary operations ============ + // ============ Unary operations (inline NOT) ============ OpCode::Not => { - exec_not(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + let b = Instruction::get_b(instr) as usize; + unsafe { + let value = *vm.register_stack.as_ptr().add(base_ptr + b); + let is_falsy = !value.is_truthy(); + *vm.register_stack.as_mut_ptr().add(base_ptr + a) = LuaValue::boolean(is_falsy); + } continue 'mainloop; } - // ============ Metamethod stubs (skip, handled by previous instruction) ============ + // ============ Metamethod stubs (save pc before calling) ============ OpCode::MmBin => { - if let Err(e) = exec_mmbin(vm, instr, frame_ptr) { + savepc!(frame_ptr, pc); + if let Err(e) = exec_mmbin(vm, instr, code_ptr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::MmBinI => { - if let Err(e) = exec_mmbini(vm, instr, frame_ptr) { + savepc!(frame_ptr, pc); + if let Err(e) = exec_mmbini(vm, instr, code_ptr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::MmBinK => { - if let Err(e) = exec_mmbink(vm, instr, frame_ptr) { + savepc!(frame_ptr, pc); + let constants_ptr = unsafe { (*frame_ptr).constants_ptr }; + if let Err(e) = exec_mmbink(vm, instr, code_ptr, constants_ptr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } - // ============ Comparisons (never fail for basic types) ============ + // ============ Comparisons (inline simple ones) ============ OpCode::LtI => { - if let Err(e) = exec_lti(vm, instr, frame_ptr) { + if let Err(e) = exec_lti(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::LeI => { - if let Err(e) = exec_lei(vm, instr, frame_ptr) { + if let Err(e) = exec_lei(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::GtI => { - if let Err(e) = exec_gti(vm, instr, frame_ptr) { + if let Err(e) = exec_gti(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::GeI => { - if let Err(e) = exec_gei(vm, instr, frame_ptr) { + if let Err(e) = exec_gei(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::EqI => { - exec_eqi(vm, instr, frame_ptr); + exec_eqi(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::EqK => { - if let Err(e) = exec_eqk(vm, instr, frame_ptr) { + if let Err(e) = exec_eqk(vm, instr, frame_ptr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } - // ============ Control Flow (never fail) ============ + // ============ Control Flow (inline JMP and TEST) ============ OpCode::Jmp => { - exec_jmp(instr, frame_ptr); + let sj = Instruction::get_sj(instr); + pc = (pc as i32 + sj) as usize; continue 'mainloop; } OpCode::Test => { - exec_test(vm, instr, frame_ptr); + let a = Instruction::get_a(instr) as usize; + let k = Instruction::get_k(instr); + unsafe { + let val = *vm.register_stack.as_ptr().add(base_ptr + a); + let is_truthy = val.is_truthy(); + if !is_truthy == k { + pc += 1; + } + } continue 'mainloop; } OpCode::TestSet => { - exec_testset(vm, instr, frame_ptr); + exec_testset(vm, instr, &mut pc, base_ptr); continue 'mainloop; } - // ============ Loop Instructions (never fail for integer loops) ============ + // ============ Loop Instructions (inline FORLOOP) ============ OpCode::ForPrep => { - if let Err(e) = exec_forprep(vm, instr, frame_ptr) { + if let Err(e) = exec_forprep(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::ForLoop => { - if let Err(e) = exec_forloop(vm, instr, frame_ptr) { - return Err(e); + let a = Instruction::get_a(instr) as usize; + let bx = Instruction::get_bx(instr) as usize; + unsafe { + let reg_base = vm.register_stack.as_mut_ptr().add(base_ptr + a); + let step = *reg_base.add(2); + + // Integer loop (like Lua C) + if step.primary == TAG_INTEGER { + let count = (*reg_base.add(1)).secondary; + if count > 0 { + let idx = (*reg_base).secondary as i64; + let step_i = step.secondary as i64; + let new_idx = idx.wrapping_add(step_i); + (*reg_base.add(1)).secondary = count - 1; + (*reg_base).secondary = new_idx as u64; + (*reg_base.add(3)).secondary = new_idx as u64; + pc -= bx; + } + continue 'mainloop; + } + // Float loop + if let Err(e) = exec_forloop_float(vm, reg_base, bx, &mut pc) { + return Err(e); + } } continue 'mainloop; } OpCode::TForPrep => { - exec_tforprep(vm, instr, frame_ptr); + exec_tforprep(vm, instr, &mut pc, base_ptr); continue 'mainloop; } OpCode::TForLoop => { - exec_tforloop(vm, instr, frame_ptr); + exec_tforloop(vm, instr, &mut pc, base_ptr); continue 'mainloop; } - // ============ Upvalue operations ============ + // ============ Upvalue operations (inline simple ones) ============ OpCode::GetUpval => { - exec_getupval(vm, instr, frame_ptr); + exec_getupval(vm, instr, frame_ptr, base_ptr); continue 'mainloop; } OpCode::SetUpval => { - exec_setupval(vm, instr, frame_ptr); + exec_setupval(vm, instr, frame_ptr, base_ptr); continue 'mainloop; } @@ -314,91 +460,124 @@ pub fn luavm_execute(vm: &mut LuaVM) -> LuaResult { continue 'mainloop; } - // ============ Return Instructions (special handling - can Exit) ============ - OpCode::Return0 => match exec_return0(vm, instr, &mut frame_ptr) { - Ok(()) => continue 'mainloop, - Err(LuaError::Exit) => return Err(LuaError::Exit), - Err(e) => return Err(e), - }, + // ============ Return Instructions (update state after frame change) ============ + OpCode::Return0 => { + match exec_return0(vm, instr, &mut frame_ptr) { + Ok(()) => { + // Reload state from new frame (like Lua C) + unsafe { + updatestate(frame_ptr, &mut pc, &mut code_ptr, &mut base_ptr); + } + continue 'mainloop; + } + Err(LuaError::Exit) => return Err(LuaError::Exit), + Err(e) => return Err(e), + } + } OpCode::Return1 => match exec_return1(vm, instr, &mut frame_ptr) { - Ok(()) => continue 'mainloop, + Ok(()) => { + unsafe { + updatestate(frame_ptr, &mut pc, &mut code_ptr, &mut base_ptr); + } + continue 'mainloop; + } Err(LuaError::Exit) => return Err(LuaError::Exit), Err(e) => return Err(e), }, OpCode::Return => match exec_return(vm, instr, &mut frame_ptr) { - Ok(()) => continue 'mainloop, + Ok(()) => { + unsafe { + updatestate(frame_ptr, &mut pc, &mut code_ptr, &mut base_ptr); + } + continue 'mainloop; + } Err(LuaError::Exit) => return Err(LuaError::Exit), Err(e) => return Err(e), }, - // ============ Function calls (update frame_ptr) ============ + // ============ Function calls (update state after frame change) ============ OpCode::Call => { + // Save current pc to frame before call (so return knows where to resume) + savepc!(frame_ptr, pc); if let Err(e) = exec_call(vm, instr, &mut frame_ptr) { return Err(e); } + // Reload state from new frame + unsafe { + updatestate(frame_ptr, &mut pc, &mut code_ptr, &mut base_ptr); + } continue 'mainloop; } - OpCode::TailCall => match exec_tailcall(vm, instr, &mut frame_ptr) { - Ok(()) => continue 'mainloop, - Err(LuaError::Exit) => return Err(LuaError::Exit), - Err(e) => return Err(e), - }, + OpCode::TailCall => { + // Save current pc before tail call + savepc!(frame_ptr, pc); + match exec_tailcall(vm, instr, &mut frame_ptr) { + Ok(()) => { + unsafe { + updatestate(frame_ptr, &mut pc, &mut code_ptr, &mut base_ptr); + } + continue 'mainloop; + } + Err(LuaError::Exit) => return Err(LuaError::Exit), + Err(e) => return Err(e), + } + } - // ============ Table operations (can trigger metamethods) ============ + // ============ Table operations ============ OpCode::NewTable => { - exec_newtable(vm, instr, frame_ptr); + exec_newtable(vm, instr, frame_ptr, &mut pc, base_ptr); continue 'mainloop; } OpCode::GetTable => { - if let Err(e) = exec_gettable(vm, instr, frame_ptr) { + if let Err(e) = exec_gettable(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::SetTable => { - if let Err(e) = exec_settable(vm, instr, frame_ptr) { + if let Err(e) = exec_settable(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::GetI => { - if let Err(e) = exec_geti(vm, instr, frame_ptr) { + if let Err(e) = exec_geti(vm, instr, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::SetI => { - if let Err(e) = exec_seti(vm, instr, frame_ptr) { + if let Err(e) = exec_seti(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::GetField => { - if let Err(e) = exec_getfield(vm, instr, frame_ptr) { + if let Err(e) = exec_getfield(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::SetField => { - if let Err(e) = exec_setfield(vm, instr, frame_ptr) { + if let Err(e) = exec_setfield(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::GetTabUp => { - if let Err(e) = exec_gettabup(vm, instr, frame_ptr) { + if let Err(e) = exec_gettabup(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::SetTabUp => { - if let Err(e) = exec_settabup(vm, instr, frame_ptr) { + if let Err(e) = exec_settabup(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Self_ => { - if let Err(e) = exec_self(vm, instr, frame_ptr) { + if let Err(e) = exec_self(vm, instr, frame_ptr, &mut base_ptr) { return Err(e); } continue 'mainloop; @@ -406,37 +585,37 @@ pub fn luavm_execute(vm: &mut LuaVM) -> LuaResult { // ============ Operations that can trigger metamethods ============ OpCode::Unm => { - if let Err(e) = exec_unm(vm, instr, frame_ptr) { + if let Err(e) = exec_unm(vm, instr, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Len => { - if let Err(e) = exec_len(vm, instr, frame_ptr) { + if let Err(e) = exec_len(vm, instr, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Concat => { - if let Err(e) = exec_concat(vm, instr, frame_ptr) { + if let Err(e) = exec_concat(vm, instr, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Eq => { - if let Err(e) = exec_eq(vm, instr, frame_ptr) { + if let Err(e) = exec_eq(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Lt => { - if let Err(e) = exec_lt(vm, instr, frame_ptr) { + if let Err(e) = exec_lt(vm, instr, &mut pc, &mut base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Le => { - if let Err(e) = exec_le(vm, instr, frame_ptr) { + if let Err(e) = exec_le(vm, instr, &mut pc, base_ptr) { return Err(e); } continue 'mainloop; @@ -444,35 +623,45 @@ pub fn luavm_execute(vm: &mut LuaVM) -> LuaResult { // ============ TForCall ============ OpCode::TForCall => { - if let Err(e) = exec_tforcall(vm, instr, frame_ptr) { - return Err(e); + savepc!(frame_ptr, pc); + match exec_tforcall(vm, instr, &mut frame_ptr, base_ptr) { + Ok(true) => { + // Lua function called, need to update state + unsafe { + updatestate(frame_ptr, &mut pc, &mut code_ptr, &mut base_ptr); + } + } + Ok(false) => { + // C function called, no state change needed + } + Err(e) => return Err(e), } continue 'mainloop; } // ============ Closure and special ============ OpCode::Closure => { - if let Err(e) = exec_closure(vm, instr, frame_ptr) { + if let Err(e) = exec_closure(vm, instr, frame_ptr, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::Vararg => { - if let Err(e) = exec_vararg(vm, instr, frame_ptr) { + if let Err(e) = exec_vararg(vm, instr, frame_ptr, base_ptr) { return Err(e); } continue 'mainloop; } OpCode::SetList => { - exec_setlist(vm, instr, frame_ptr); + exec_setlist(vm, instr, frame_ptr, base_ptr); continue 'mainloop; } OpCode::Close => { - exec_close(vm, instr, frame_ptr); + exec_close(vm, instr, base_ptr); continue 'mainloop; } OpCode::Tbc => { - exec_tbc(vm, instr, frame_ptr); + exec_tbc(vm, instr, base_ptr); continue 'mainloop; } } diff --git a/crates/luars/src/lua_vm/execute/table_instructions.rs b/crates/luars/src/lua_vm/execute/table_instructions.rs index 7717fc89..68146eb1 100644 --- a/crates/luars/src/lua_vm/execute/table_instructions.rs +++ b/crates/luars/src/lua_vm/execute/table_instructions.rs @@ -11,7 +11,7 @@ use crate::lua_vm::{Instruction, LuaCallFrame, LuaResult, LuaVM}; /// k = 1 means EXTRAARG follows with array_size / 256 /// OPTIMIZED: Fast path for common empty/small table case #[inline(always)] -pub fn exec_newtable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_newtable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, pc: &mut usize, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr); // log2(hash_size) + 1 let c = Instruction::get_c(instr); // array_size % 256 @@ -20,20 +20,20 @@ pub fn exec_newtable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { // Decode hash size: if b > 0, hash_size = 2^(b-1) let hash_size = if b > 0 { 1usize << (b - 1) } else { 0 }; - let (base_ptr, func_value) = unsafe { - (*frame_ptr).pc += 1; // Skip EXTRAARG - ((*frame_ptr).base_ptr, (*frame_ptr).function_value) + let func_value = unsafe { + *pc += 1; // Skip EXTRAARG + (*frame_ptr).function_value }; // Calculate array size - C is low bits, EXTRAARG has high bits when k=1 let array_size = if k { // Need to read EXTRAARG for large arrays - let pc = unsafe { (*frame_ptr).pc - 1 }; // We already incremented pc + let prev_pc = *pc - 1; // We already incremented pc // Use new ID-based API to get function and read EXTRAARG if let Some(func_id) = func_value.as_function_id() { if let Some(func_ref) = vm.object_pool.get_function(func_id) { - if pc < func_ref.chunk.code.len() { - let extra = Instruction::get_ax(func_ref.chunk.code[pc]) as usize; + if prev_pc < func_ref.chunk.code.len() { + let extra = Instruction::get_ax(func_ref.chunk.code[prev_pc]) as usize; extra * 256 + c as usize // MAXARG_C + 1 = 256 } else { c as usize @@ -63,17 +63,16 @@ pub fn exec_newtable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// R[A] := R[B][R[C]] /// OPTIMIZED: Fast path for integer keys and tables without metatable #[inline(always)] -pub fn exec_gettable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_gettable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; // Read values using unchecked access - let (table_value, key_value, base_ptr) = unsafe { - let bp = (*frame_ptr).base_ptr; - let table = *vm.register_stack.get_unchecked(bp + b); - let key = *vm.register_stack.get_unchecked(bp + c); - (table, key, bp) + let (table_value, key_value) = unsafe { + let table = *vm.register_stack.get_unchecked(*base_ptr + b); + let key = *vm.register_stack.get_unchecked(*base_ptr + c); + (table, key) }; // FAST PATH: Direct table access for common case (integer key, no metatable) @@ -84,7 +83,7 @@ pub fn exec_gettable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - // Try integer key fast path first if let Some(i) = key_value.as_integer() { if let Some(val) = lua_table.get_int(i) { - unsafe { *vm.register_stack.get_unchecked_mut(base_ptr + a) = val }; + unsafe { *vm.register_stack.get_unchecked_mut(*base_ptr + a) = val }; return Ok(()); } } @@ -92,14 +91,14 @@ pub fn exec_gettable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - // Try hash lookup if let Some(val) = lua_table.get_from_hash(&key_value) { if !val.is_nil() { - unsafe { *vm.register_stack.get_unchecked_mut(base_ptr + a) = val }; + unsafe { *vm.register_stack.get_unchecked_mut(*base_ptr + a) = val }; return Ok(()); } } // Key not found - check if no metatable to skip metamethod handling if lua_table.get_metatable().is_none() { - unsafe { *vm.register_stack.get_unchecked_mut(base_ptr + a) = LuaValue::nil() }; + unsafe { *vm.register_stack.get_unchecked_mut(*base_ptr + a) = LuaValue::nil() }; return Ok(()); } } @@ -110,8 +109,8 @@ pub fn exec_gettable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - .unwrap_or(LuaValue::nil()); // Re-read base_ptr after metamethod call - let new_base_ptr = unsafe { (*frame_ptr).base_ptr }; - vm.register_stack[new_base_ptr + a] = value; + *base_ptr = unsafe { (*frame_ptr).base_ptr }; + vm.register_stack[*base_ptr + a] = value; Ok(()) } @@ -120,7 +119,7 @@ pub fn exec_gettable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - /// R[A][R[B]] := RK(C) /// OPTIMIZED: Fast path for integer keys and tables without metatable #[inline(always)] -pub fn exec_settable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_settable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; @@ -128,16 +127,15 @@ pub fn exec_settable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - // Read all values using unchecked access let (table_value, key_value, set_value) = unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let table = *vm.register_stack.get_unchecked(base_ptr + a); - let key = *vm.register_stack.get_unchecked(base_ptr + b); + let table = *vm.register_stack.get_unchecked(*base_ptr + a); + let key = *vm.register_stack.get_unchecked(*base_ptr + b); let value = if k { // Get constant via cached pointer *(*frame_ptr).constants_ptr.add(c) } else { - *vm.register_stack.get_unchecked(base_ptr + c) + *vm.register_stack.get_unchecked(*base_ptr + c) }; (table, key, value) @@ -174,12 +172,11 @@ pub fn exec_settable(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - /// R[A] := R[B][C:integer] /// OPTIMIZED: Direct integer access using get_int_full() without creating LuaValue key #[inline(always)] -pub fn exec_geti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_geti(vm: &mut LuaVM, instr: u32, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as i64; // C is unsigned integer index - let base_ptr = unsafe { (*frame_ptr).base_ptr }; let table = unsafe { *vm.register_stack.get_unchecked(base_ptr + b) }; // FAST PATH: Direct integer access for tables using unchecked access @@ -211,11 +208,11 @@ pub fn exec_geti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lu Ok(()) } -/// SETI A B C k +/// SETI A B C /// R[A][B] := RK(C) /// OPTIMIZED: Direct integer key access using set_int() #[inline(always)] -pub fn exec_seti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_seti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as i64; // B is unsigned integer key let c = Instruction::get_c(instr) as usize; @@ -223,15 +220,14 @@ pub fn exec_seti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lu // CRITICAL: Read all values BEFORE any metamethod calls let (table_value, set_value) = unsafe { - let base_ptr = (*frame_ptr).base_ptr; - let table = *vm.register_stack.get_unchecked(base_ptr + a); + let table = *vm.register_stack.get_unchecked(*base_ptr + a); let value = if k { // Get constant via cached pointer for speed *(*frame_ptr).constants_ptr.add(c) } else { - *vm.register_stack.get_unchecked(base_ptr + c) + *vm.register_stack.get_unchecked(*base_ptr + c) }; (table, value) @@ -264,12 +260,12 @@ pub fn exec_seti(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lu /// GETFIELD A B C /// R[A] := R[B][K[C]:string] #[inline(always)] -pub fn exec_getfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_getfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; + let func_value = unsafe { (*frame_ptr).function_value }; // Get key constant using new API let Some(func_id) = func_value.as_function_id() else { @@ -282,7 +278,7 @@ pub fn exec_getfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - return Err(vm.error(format!("Invalid constant index: {}", c))); }; - let table_value = vm.register_stack[base_ptr + b]; + let table_value = vm.register_stack[*base_ptr + b]; // FAST PATH: Direct hash access for tables without metatable if let Some(table_id) = table_value.as_table_id() { @@ -290,14 +286,14 @@ pub fn exec_getfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - // Use optimized hash-only lookup (GETFIELD always uses string keys, never integers) if let Some(val) = table_ref.get_from_hash(&key_value) { if !val.is_nil() { - vm.register_stack[base_ptr + a] = val; + vm.register_stack[*base_ptr + a] = val; return Ok(()); } } // Check if no metatable - can return nil directly if table_ref.get_metatable().is_none() { - vm.register_stack[base_ptr + a] = LuaValue::nil(); + vm.register_stack[*base_ptr + a] = LuaValue::nil(); return Ok(()); } } @@ -309,8 +305,8 @@ pub fn exec_getfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - .unwrap_or(LuaValue::nil()); // IMPORTANT: Re-read base_ptr after metamethod call in case frames changed - let new_base_ptr = unsafe { (*frame_ptr).base_ptr }; - vm.register_stack[new_base_ptr + a] = value; + *base_ptr = unsafe { (*frame_ptr).base_ptr }; + vm.register_stack[*base_ptr + a] = value; Ok(()) } @@ -318,7 +314,7 @@ pub fn exec_getfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - /// SETFIELD A B C k /// R[A][K[B]:string] := RK(C) #[inline(always)] -pub fn exec_setfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_setfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; @@ -327,7 +323,6 @@ pub fn exec_setfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - // CRITICAL: Read all values BEFORE any metamethod calls // because metamethods can modify the register stack let (table_value, key_value, set_value) = unsafe { - let base_ptr = (*frame_ptr).base_ptr; let func_value = (*frame_ptr).function_value; // Get key constant using new API @@ -341,7 +336,7 @@ pub fn exec_setfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - return Err(vm.error(format!("Invalid constant index: {}", b))); }; - let table = vm.register_stack[base_ptr + a]; + let table = vm.register_stack[*base_ptr + a]; let value = if k { let Some(constant) = func_ref.chunk.constants.get(c).copied() else { @@ -349,7 +344,7 @@ pub fn exec_setfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - }; constant } else { - vm.register_stack[base_ptr + c] + vm.register_stack[*base_ptr + c] }; (table, key, value) @@ -379,12 +374,12 @@ pub fn exec_setfield(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - /// R[A] := UpValue[B][K[C]:string] /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_gettabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_gettabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; + let func_value = unsafe { (*frame_ptr).function_value }; // FAST PATH: Direct constant access via cached pointer let key_value = unsafe { *(*frame_ptr).constants_ptr.add(c) }; @@ -410,14 +405,14 @@ pub fn exec_gettabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - // Try direct access if let Some(val) = table_ref.raw_get(&key_value) { if !val.is_nil() { - vm.register_stack[base_ptr + a] = val; + vm.register_stack[*base_ptr + a] = val; return Ok(()); } } // Check if no metatable - can return nil directly if table_ref.get_metatable().is_none() { - vm.register_stack[base_ptr + a] = LuaValue::nil(); + vm.register_stack[*base_ptr + a] = LuaValue::nil(); return Ok(()); } } @@ -428,7 +423,7 @@ pub fn exec_gettabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - .table_get_with_meta(&table_value, &key_value) .unwrap_or(LuaValue::nil()); - vm.register_stack[base_ptr + a] = value; + vm.register_stack[*base_ptr + a] = value; Ok(()) } @@ -437,13 +432,13 @@ pub fn exec_gettabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - /// UpValue[A][K[B]:string] := RK(C) /// OPTIMIZED: Uses cached constants_ptr for direct constant access #[inline(always)] -pub fn exec_settabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_settabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; let k = Instruction::get_k(instr); - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; + let func_value = unsafe { (*frame_ptr).function_value }; // FAST PATH: Direct constant access via cached pointer let key_value = unsafe { *(*frame_ptr).constants_ptr.add(b) }; @@ -452,7 +447,7 @@ pub fn exec_settabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - let set_value = if k { unsafe { *(*frame_ptr).constants_ptr.add(c) } } else { - vm.register_stack[base_ptr + c] + vm.register_stack[*base_ptr + c] }; // Get function for upvalues access (still needed) @@ -493,13 +488,13 @@ pub fn exec_settabup(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) - /// SELF A B C /// R[A+1] := R[B]; R[A] := R[B][RK(C):string] #[inline(always)] -pub fn exec_self(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_self(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: &mut usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; - let table = vm.register_stack[base_ptr + b]; + let func_value = unsafe { (*frame_ptr).function_value }; + let table = vm.register_stack[*base_ptr + b]; // Get method key from constant using new API let Some(func_id) = func_value.as_function_id() else { @@ -513,7 +508,7 @@ pub fn exec_self(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lu }; // R[A+1] := R[B] (self parameter) - vm.register_stack[base_ptr + a + 1] = table; + vm.register_stack[*base_ptr + a + 1] = table; // R[A] := R[B][K[C]] (method) // Support both tables and userdata @@ -524,7 +519,7 @@ pub fn exec_self(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> Lu vm.table_get_with_meta(&table, &key) .unwrap_or(crate::LuaValue::nil()) }; - vm.register_stack[base_ptr + a] = method; + vm.register_stack[*base_ptr + a] = method; Ok(()) } diff --git a/crates/luars/src/lua_vm/execute/upvalue_instructions.rs b/crates/luars/src/lua_vm/execute/upvalue_instructions.rs index 5eabb352..9c90d95f 100644 --- a/crates/luars/src/lua_vm/execute/upvalue_instructions.rs +++ b/crates/luars/src/lua_vm/execute/upvalue_instructions.rs @@ -9,11 +9,11 @@ use crate::{ /// GETUPVAL A B /// R[A] := UpValue[B] #[inline(always)] -pub fn exec_getupval(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_getupval(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; + let func_value = unsafe { (*frame_ptr).function_value }; // OPTIMIZED: Use unchecked access since we know the function is valid let func_id = unsafe { func_value.as_function_id().unwrap_unchecked() }; @@ -31,11 +31,11 @@ pub fn exec_getupval(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// SETUPVAL A B /// UpValue[B] := R[A] #[inline(always)] -pub fn exec_setupval(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_setupval(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; + let func_value = unsafe { (*frame_ptr).function_value }; // OPTIMIZED: Use unchecked access since we know the function is valid let func_id = unsafe { func_value.as_function_id().unwrap_unchecked() }; @@ -51,9 +51,8 @@ pub fn exec_setupval(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// CLOSE A /// close all upvalues >= R[A] #[inline(always)] -pub fn exec_close(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_close(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; - let base_ptr = unsafe { (*frame_ptr).base_ptr }; let close_from = base_ptr + a; vm.close_upvalues_from(close_from); @@ -63,14 +62,14 @@ pub fn exec_close(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// R[A] := closure(KPROTO[Bx]) /// OPTIMIZED: Fast path for closures without upvalues #[inline(always)] -pub fn exec_closure(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_closure(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) -> LuaResult<()> { use crate::gc::UpvalueId; + let a = Instruction::get_a(instr) as usize; let bx = Instruction::get_bx(instr) as usize; - let (base_ptr, func_value) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).function_value) }; - + let func_value = unsafe { (*frame_ptr).function_value }; // Get current function using ID-based lookup let func_id = func_value .as_function_id() @@ -157,14 +156,13 @@ pub fn exec_closure(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> /// Vararg arguments are stored at frame.vararg_start (set by VARARGPREP). /// This instruction copies them to the target registers. #[inline(always)] -pub fn exec_vararg(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_vararg(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let c = Instruction::get_c(instr) as usize; - let (base_ptr, vararg_start, vararg_count, top) = unsafe { + let (vararg_start, vararg_count, top) = unsafe { let frame = &*frame_ptr; ( - frame.base_ptr, frame.get_vararg_start(), frame.get_vararg_count(), frame.top, @@ -207,12 +205,10 @@ pub fn exec_vararg(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> /// R[A] := R[A].. ... ..R[A+B] /// OPTIMIZED: Pre-allocation for string/number combinations #[inline(always)] -pub fn exec_concat(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> LuaResult<()> { +pub fn exec_concat(vm: &mut LuaVM, instr: u32, base_ptr: usize) -> LuaResult<()> { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; - let base_ptr = unsafe { (*frame_ptr).base_ptr }; - // ULTRA-OPTIMIZED: Build result string directly without intermediate allocations // Estimate total capacity and format numbers inline with itoa let mut total_capacity = 0usize; @@ -356,12 +352,12 @@ pub fn exec_concat(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -> /// SETLIST A B C k /// R[A][C+i] := R[A+i], 1 <= i <= B #[inline(always)] -pub fn exec_setlist(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_setlist(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; let b = Instruction::get_b(instr) as usize; let c = Instruction::get_c(instr) as usize; - let (base_ptr, top) = unsafe { ((*frame_ptr).base_ptr, (*frame_ptr).top) }; + let top = unsafe { (*frame_ptr).top }; let table = vm.register_stack[base_ptr + a]; let start_idx = c * 50; // 0-based for array indexing @@ -400,9 +396,8 @@ pub fn exec_setlist(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { /// mark variable A as to-be-closed /// This marks a variable to have its __close metamethod called when it goes out of scope #[inline(always)] -pub fn exec_tbc(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) { +pub fn exec_tbc(vm: &mut LuaVM, instr: u32, base_ptr: usize) { let a = Instruction::get_a(instr) as usize; - let base_ptr = unsafe { (*frame_ptr).base_ptr }; let reg_idx = base_ptr + a; // Get the value to be marked as to-be-closed