From d00294e9f01a205ad53b9e1fe89f910a2f31d614 Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 11:37:41 +0800 Subject: [PATCH 1/7] use stkid --- crates/luars/src/gc/mod.rs | 2 +- .../src/lua_value/lua_table/native_table.rs | 6 +- crates/luars/src/lua_value/mod.rs | 95 +- crates/luars/src/lua_vm/call_info.rs | 14 +- crates/luars/src/lua_vm/execute/call.rs | 7 +- .../luars/src/lua_vm/execute/execute_loop.rs | 844 ++++++++---------- crates/luars/src/lua_vm/execute/helper.rs | 151 +--- crates/luars/src/lua_vm/execute/metamethod.rs | 8 +- crates/luars/src/lua_vm/lua_state.rs | 51 +- crates/luars/src/lua_vm/mod.rs | 10 +- crates/luars/src/lua_vm/stk_id.rs | 192 ++++ 11 files changed, 697 insertions(+), 683 deletions(-) create mode 100644 crates/luars/src/lua_vm/stk_id.rs diff --git a/crates/luars/src/gc/mod.rs b/crates/luars/src/gc/mod.rs index 4594854c..510596d1 100644 --- a/crates/luars/src/gc/mod.rs +++ b/crates/luars/src/gc/mod.rs @@ -399,7 +399,7 @@ impl GC { #[inline] fn prepare_object_for_release(obj: &mut GcObjectOwner) { if let Some(thread) = obj.as_thread_mut() { - thread.release(); + thread.release_ci(); } } diff --git a/crates/luars/src/lua_value/lua_table/native_table.rs b/crates/luars/src/lua_value/lua_table/native_table.rs index a882c194..2c4b5f08 100644 --- a/crates/luars/src/lua_value/lua_table/native_table.rs +++ b/crates/luars/src/lua_value/lua_table/native_table.rs @@ -265,7 +265,7 @@ impl NativeTable { /// Zero-copy short string lookup — writes directly to destination pointer. /// Assumes hash is non-empty and key is short string. /// Returns true if found and written. - pub unsafe fn get_shortstr_into(&self, key: &LuaValue, dest: *mut LuaValue) -> bool { + pub(crate) fn get_shortstr_into(&self, key: &LuaValue, dest: *mut LuaValue) -> bool { let mut node = self.mainposition_string(key); let key_ptr = key.string_ptr_raw(); @@ -1160,7 +1160,7 @@ impl NativeTable { /// Returns true if a non-nil/non-empty value was found and written. /// CRITICAL: #[inline(always)] — this is the hot path for t[i] reads. #[inline(always)] - pub unsafe fn fast_geti_into(&self, key: i64, dest: *mut LuaValue) -> bool { + pub(crate) fn fast_geti_into(&self, key: i64, dest: *mut LuaValue) -> bool { unsafe { let u = (key as u64).wrapping_sub(1); if u < self.asize as u64 { @@ -1181,7 +1181,7 @@ impl NativeTable { /// Used as fallback when fast_geti_into misses (key not in array range). /// Mirrors C Lua's getintfromhash() + finishnodeget(). #[inline(always)] - pub unsafe fn get_int_from_hash_into(&self, key: i64, dest: *mut LuaValue) -> bool { + pub(crate) fn get_int_from_hash_into(&self, key: i64, dest: *mut LuaValue) -> bool { if self.node.is_null() { return false; } diff --git a/crates/luars/src/lua_value/mod.rs b/crates/luars/src/lua_value/mod.rs index 64f9b421..588ae9ee 100644 --- a/crates/luars/src/lua_value/mod.rs +++ b/crates/luars/src/lua_value/mod.rs @@ -30,12 +30,7 @@ pub(crate) type LuaInnerValue = Value; // For internal use within LuaValue imple use crate::Instruction; use crate::gc::{ProtoPtr, UpvaluePtr}; -use crate::lua_vm::CFunction; - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct LuaValuePtr { - pub ptr: *mut LuaValue, -} +use crate::lua_vm::{CFunction, StkId}; /// Runtime upvalue — pointer-based design matching C Lua's UpVal. /// @@ -48,7 +43,7 @@ pub struct LuaValuePtr { pub struct LuaUpvalue { /// Always-valid pointer to the upvalue's current value. /// Open → stack slot, Closed → &self.closed_value - v: *mut LuaValue, + v: StkId, /// Storage for the closed value. When closed, `v` points here. closed_value: LuaValue, /// Stack index (only meaningful when open) @@ -59,9 +54,9 @@ impl LuaUpvalue { /// Create an open upvalue pointing to a stack location (absolute index). /// `stack_ptr` must remain valid until the upvalue is closed or the pointer is updated. #[inline(always)] - pub fn new_open(stack_index: usize, stack_ptr: LuaValuePtr) -> Self { + pub fn new_open(stack_index: usize, stk_id: StkId) -> Self { LuaUpvalue { - v: stack_ptr.ptr, + v: stk_id, closed_value: LuaValue::nil(), stack_index, } @@ -73,7 +68,7 @@ impl LuaUpvalue { #[inline(always)] pub fn new_closed(value: LuaValue) -> Self { LuaUpvalue { - v: std::ptr::null_mut(), + v: StkId::null(), closed_value: value, stack_index: 0, } @@ -84,8 +79,8 @@ impl LuaUpvalue { /// No-op for open upvalues (where v is already a valid stack pointer). #[inline(always)] pub fn fix_closed_ptr(&mut self) { - if self.v.is_null() { - self.v = &mut self.closed_value as *mut LuaValue; + if !self.v.is_valid() { + self.v = StkId::from_mut_ptr(&mut self.closed_value as *mut LuaValue); } } @@ -93,7 +88,7 @@ impl LuaUpvalue { /// Open ⟺ `v` does NOT point to our own `closed_value` field. #[inline(always)] pub fn is_open(&self) -> bool { - !std::ptr::eq(self.v, &self.closed_value) + !std::ptr::eq(self.v.as_ptr(), &self.closed_value) } /// Get the stack index (only meaningful when open). @@ -107,101 +102,43 @@ impl LuaUpvalue { #[inline(always)] pub fn close(&mut self, stack_value: LuaValue) { self.closed_value = stack_value; - self.v = &mut self.closed_value as *mut LuaValue; + self.v = StkId::from_mut_ptr(&mut self.closed_value as *mut LuaValue); } /// Update the cached stack pointer (called after stack reallocation). #[inline(always)] - pub fn update_stack_ptr(&mut self, ptr: *mut LuaValue) { - self.v = ptr; + pub fn update_stack_ptr(&mut self, stk_id: StkId) { + self.v = stk_id; } /// Get the raw v pointer (for caching in the execute loop). #[inline(always)] - pub fn get_v_ptr(&self) -> *mut LuaValue { + pub fn get_v_stk_id(&self) -> StkId { self.v } /// Get the value with **zero branching** — single pointer dereference. #[inline(always)] pub fn get_value(&self) -> LuaValue { - debug_assert!(!self.v.is_null(), "upvalue get_value: null pointer"); - debug_assert!( - (self.v as usize) > 0x10000, - "upvalue get_value: suspiciously low pointer {:p} (stack_index={})", - self.v, - self.stack_index - ); - let val = unsafe { *self.v }; - debug_assert!( - Self::is_valid_tt(val.tt()), - "upvalue get_value: INVALID type tag 0x{:02X} read from {:p} (stack_index={}, is_open={}). Likely dangling pointer!", - val.tt(), - self.v, - self.stack_index, - self.is_open() - ); - val + self.v.get() } /// Get reference to the value with **zero branching**. #[inline(always)] pub fn get_value_ref(&self) -> &LuaValue { - debug_assert!(!self.v.is_null(), "upvalue get_value_ref: null pointer"); - unsafe { &*self.v } + self.v.get_ref() } /// Set the value with **zero branching** — single pointer write. #[inline(always)] pub fn set_value(&mut self, val: LuaValue) { - debug_assert!(!self.v.is_null(), "upvalue set_value: null pointer"); - debug_assert!( - (self.v as usize) > 0x10000, - "upvalue set_value: suspiciously low pointer {:p} (stack_index={})", - self.v, - self.stack_index - ); - unsafe { *self.v = val } + self.v.write(&val); } /// Set the value by raw parts to avoid constructing a temporary LuaValue. #[inline(always)] pub fn set_value_parts(&mut self, value: Value, tt: u8) { - debug_assert!(!self.v.is_null(), "upvalue set_value_parts: null pointer"); - debug_assert!( - (self.v as usize) > 0x10000, - "upvalue set_value_parts: suspiciously low pointer {:p} (stack_index={})", - self.v, - self.stack_index - ); - unsafe { - (*self.v).value = value; - (*self.v).tt = tt; - } - } - - /// Check if a type tag is valid (used for dangling pointer detection) - fn is_valid_tt(tt: u8) -> bool { - use crate::lua_value::lua_value::*; - matches!( - tt, - LUA_VNIL - | LUA_VEMPTY - | LUA_VABSTKEY - | LUA_VFALSE - | LUA_VTRUE - | LUA_VNUMINT - | LUA_VNUMFLT - | LUA_VSHRSTR - | LUA_VLNGSTR - | LUA_VTABLE - | LUA_VFUNCTION - | LUA_CCLOSURE - | LUA_VLCF - | LUA_VLIGHTUSERDATA - | LUA_VUSERDATA - | LUA_VTHREAD - ) + self.v.write_parts(tt, value); } pub fn get_closed_value(&self) -> Option<&LuaValue> { diff --git a/crates/luars/src/lua_vm/call_info.rs b/crates/luars/src/lua_vm/call_info.rs index 88e9518f..3b3745f8 100644 --- a/crates/luars/src/lua_vm/call_info.rs +++ b/crates/luars/src/lua_vm/call_info.rs @@ -1,8 +1,10 @@ // CallInfo - Information about a single function call // Equivalent to CallInfo structure in Lua C API (lstate.h) +use crate::LuaValue; use crate::gc::UpvaluePtr; use crate::lua_value::LuaProto; +use crate::lua_vm::StkId; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; @@ -91,6 +93,11 @@ pub struct CallInfo { /// NOTE: This may be updated by VARARGPREP after stack rearrangement pub base: usize, + /// Cached raw pointer to this frame's base register (base + stack ptr). + /// Eliminates `stack_mut().as_mut_ptr().add(base)` in hot opcodes. + /// Updated on stack reallocation via `LuaState::fix_call_info_base_stk`. + pub base_stk: StkId, + /// Offset from original base to func position (for vararg functions after buildhiddenargs) /// When nextraargs > 0 and buildhiddenargs was called: /// - func_offset = totalargs + 1 (the shift amount) @@ -177,9 +184,10 @@ impl DerefMut for CallInfoPtr { impl CallInfo { /// Create a new call frame for a Lua function - pub fn new_lua(base: usize, nparams: usize) -> Self { + pub fn new_lua(sp: *mut LuaValue, base: usize, nparams: usize) -> Self { Self { base, + base_stk: StkId::from_stack(sp, base), chunk_ptr: std::ptr::null(), upvalue_ptrs: std::ptr::null(), func_offset: 1, // Initially base - 1 = func @@ -192,9 +200,10 @@ impl CallInfo { } /// Create a new call frame for a C function - pub fn new_c(base: usize, nparams: usize) -> Self { + pub fn new_c(sp: *mut crate::lua_value::LuaValue, base: usize, nparams: usize) -> Self { Self { base, + base_stk: StkId::from_stack(sp, base), chunk_ptr: std::ptr::null(), upvalue_ptrs: std::ptr::null(), func_offset: 1, @@ -275,6 +284,7 @@ impl Default for CallInfo { fn default() -> Self { Self { base: 0, + base_stk: StkId::null(), chunk_ptr: std::ptr::null(), upvalue_ptrs: std::ptr::null(), func_offset: 1, diff --git a/crates/luars/src/lua_vm/execute/call.rs b/crates/luars/src/lua_vm/execute/call.rs index 9f051132..88d7dc74 100644 --- a/crates/luars/src/lua_vm/execute/call.rs +++ b/crates/luars/src/lua_vm/execute/call.rs @@ -5,8 +5,9 @@ use crate::{ LUA_MASKCALL, LUA_MASKRET, LuaProto, LuaValue, gc::UpvaluePtr, lua_vm::{ - CFunction, LUA_HOOKCALL, LUA_HOOKRET, LuaResult, LuaState, TmKind, call_info::call_status, - execute::hook::hook_on_return, get_metamethod_event, lua_limits::EXTRA_STACK, + CFunction, LUA_HOOKCALL, LUA_HOOKRET, LuaResult, LuaState, StkId, TmKind, + call_info::call_status, execute::hook::hook_on_return, get_metamethod_event, + lua_limits::EXTRA_STACK, }, }; @@ -273,10 +274,12 @@ pub fn pretailcall_lua( // Batch update CI fields (reuse current frame, no push/pop) { + let sp = lua_state.stack_mut().as_mut_ptr(); let ci = lua_state .current_frame_mut() .expect("call update requires an active call frame"); ci.base = new_base; + ci.base_stk = StkId::from_stack(sp, new_base); ci.func_offset = 1; ci.top = frame_top as u32; ci.pc = 0; diff --git a/crates/luars/src/lua_vm/execute/execute_loop.rs b/crates/luars/src/lua_vm/execute/execute_loop.rs index 3a7fbb96..7d9914c0 100644 --- a/crates/luars/src/lua_vm/execute/execute_loop.rs +++ b/crates/luars/src/lua_vm/execute/execute_loop.rs @@ -22,9 +22,9 @@ use crate::{ Instruction, LUA_MASKCALL, LUA_MASKCOUNT, LUA_MASKLINE, LUA_MASKRET, LuaResult, LuaState, LuaValue, OpCode, gc::TablePtr, - lua_value::{BIT_ISCOLLECTABLE, LUA_VNUMINT, LuaProto}, + lua_value::{BIT_ISCOLLECTABLE, LuaProto}, lua_vm::{ - LuaError, TmKind, + LuaError, StkId, TmKind, call_info::call_status::{CIST_C, CIST_CLSRET, CIST_PENDING_FINISH}, execute::{ call::{poscall, precall, pretailcall}, @@ -34,12 +34,10 @@ use crate::{ bin_tm_fallback, eq_fallback, error_div_by_zero, error_global, error_mod_by_zero, finishget_fallback, finishset_fallback, float_for_loop, fltvalue, forprep, handle_pending_ops, instr_at, ivalue, k_val, lua_fmod, lua_idiv, lua_imod, - lua_shiftl, lua_shiftr, luai_numpow, objlen, order_tm_fallback, pfltvalue, pivalue, - psetfltvalue, psetivalue, ptonumberns, pttisfloat, pttisinteger, return0_with_hook, - return1_with_hook, self_shortstr_index_chain_fast, setbfvalue, setbtvalue, - setfltvalue, setivalue, setnilvalue, setobj2s, setobjs2s, stack_copy, - stack_mut_ptr, stack_mut_ref, stack_ptr, stack_ref, stack_val, stack_val_mut, - tointegerns, tonumberns, ttisfloat, ttisinteger, ttisstring, unary_tm_fallback, + lua_shiftl, lua_shiftr, luai_numpow, objlen, order_tm_fallback, pivalue, pk_val, + ptonumberns, pttisinteger, return0_with_hook, return1_with_hook, + self_shortstr_index_chain_fast, tointegerns, tonumberns, ttisfloat, ttisinteger, + ttisstring, unary_tm_fallback, }, hook::{hook_check_instruction, hook_on_call}, metamethod::call_newindex_tm_fast, @@ -77,219 +75,175 @@ fn current_trap(lua_state: &LuaState) -> bool { } macro_rules! op_arithI { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $iop:expr, $fop:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $iop:expr, $fop:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let sc = $instr.get_sc(); - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let ra_ptr = sp.add($base + a); - let v1_ptr = sp.add($base + b) as *const LuaValue; - - if pttisinteger(v1_ptr) { - let iv1 = pivalue(v1_ptr); - $pc += 1; - psetivalue(ra_ptr, $iop(iv1, sc)); - } else if pttisfloat(v1_ptr) { - let nb = pfltvalue(v1_ptr); - let fimm = sc as f64; - $pc += 1; - psetfltvalue(ra_ptr, $fop(nb, fimm)); - } + let v1 = $base_stk.offset(b); + if v1.is_integer() { + $pc += 1; + $base_stk.offset(a).set_integer($iop(v1.ivalue(), sc)); + } else if v1.is_float() { + $pc += 1; + $base_stk + .offset(a) + .set_float($fop(v1.fltvalue(), sc as f64)); } }}; } macro_rules! op_arithf_aux { - ($ra_ptr:expr, $pc:expr, $v1_ptr:expr, $v2_ptr:expr, $fop:expr) => {{ + ($ra_stk:expr, $pc:expr, $v1_stk:expr, $v2_stk:expr, $fop:expr) => {{ let mut n1 = 0.0; let mut n2 = 0.0; - if ptonumberns($v1_ptr, &mut n1) && ptonumberns($v2_ptr, &mut n2) { + if unsafe { + ptonumberns($v1_stk.as_const_ptr(), &mut n1) + && ptonumberns($v2_stk.as_const_ptr(), &mut n2) + } { $pc += 1; - psetfltvalue($ra_ptr, $fop(n1, n2)); + $ra_stk.set_float($fop(n1, n2)); } }}; } macro_rules! op_arith { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $iop:expr, $fop:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $iop:expr, $fop:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = sp.add($base + c) as *const LuaValue; - let ra_ptr = sp.add($base + a); - - if pttisinteger(v1_ptr) && pttisinteger(v2_ptr) { - let i1 = pivalue(v1_ptr); - let i2 = pivalue(v2_ptr); - $pc += 1; - psetivalue(ra_ptr, $iop(i1, i2)); - } else { - op_arithf_aux!(ra_ptr, $pc, v1_ptr, v2_ptr, $fop); - } + let v1 = $base_stk.offset(b); + let v2 = $base_stk.offset(c); + if v1.is_integer() && v2.is_integer() { + $pc += 1; + $base_stk + .offset(a) + .set_integer($iop(v1.ivalue(), v2.ivalue())); + } else { + op_arithf_aux!($base_stk.offset(a), $pc, v1, v2, $fop); } }}; } macro_rules! op_arithf { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $fop:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $fop:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = sp.add($base + c) as *const LuaValue; - let ra_ptr = sp.add($base + a); - op_arithf_aux!(ra_ptr, $pc, v1_ptr, v2_ptr, $fop); - } + op_arithf_aux!( + $base_stk.offset(a), + $pc, + $base_stk.offset(b), + $base_stk.offset(c), + $fop + ); }}; } macro_rules! op_arithK { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $constants:expr, $iop:expr, $fop:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $constants:expr, $iop:expr, $fop:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = $constants.as_ptr().add(c); - let ra_ptr = sp.add($base + a); - - if pttisinteger(v1_ptr) && pttisinteger(v2_ptr) { - let i1 = pivalue(v1_ptr); - let i2 = pivalue(v2_ptr); - $pc += 1; - psetivalue(ra_ptr, $iop(i1, i2)); - } else { - op_arithf_aux!(ra_ptr, $pc, v1_ptr, v2_ptr, $fop); - } + let v1 = $base_stk.offset(b); + let v2 = pk_val($constants, c); + if v1.is_integer() && v2.is_integer() { + $pc += 1; + $base_stk + .offset(a) + .set_integer($iop(v1.ivalue(), v2.ivalue())); + } else { + op_arithf_aux!($base_stk.offset(a), $pc, v1, v2, $fop); } }}; } macro_rules! op_arithfK { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $constants:expr, $fop:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $constants:expr, $fop:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = $constants.as_ptr().add(c); - let ra_ptr = sp.add($base + a); - op_arithf_aux!(ra_ptr, $pc, v1_ptr, v2_ptr, $fop); - } + op_arithf_aux!( + $base_stk.offset(a), + $pc, + $base_stk.offset(b), + pk_val($constants, c), + $fop + ); }}; } macro_rules! op_arith_check_zero { - ($instr:expr, $lua_state:expr, $ci:expr, $base:expr, $pc:expr, $iop:expr, $fop:expr, $err_fn:expr) => {{ + ($instr:expr, $lua_state:expr, $ci:expr, $base_stk:expr, $pc:expr, $iop:expr, $fop:expr, $err_fn:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = sp.add($base + c) as *const LuaValue; - let ra_ptr = sp.add($base + a); - - if pttisinteger(v1_ptr) && pttisinteger(v2_ptr) { - let i1 = pivalue(v1_ptr); - let i2 = pivalue(v2_ptr); - if i2 != 0 { - $pc += 1; - psetivalue(ra_ptr, $iop(i1, i2)); - } else { - $ci.save_pc($pc); - return Err($err_fn($lua_state)); - } + let v1 = $base_stk.offset(b); + let v2 = $base_stk.offset(c); + if v1.is_integer() && v2.is_integer() { + let i1 = v1.ivalue(); + let i2 = v2.ivalue(); + if i2 != 0 { + $pc += 1; + $base_stk.offset(a).set_integer($iop(i1, i2)); } else { - op_arithf_aux!(ra_ptr, $pc, v1_ptr, v2_ptr, $fop); + $ci.save_pc($pc); + return Err($err_fn($lua_state)); } + } else { + op_arithf_aux!($base_stk.offset(a), $pc, v1, v2, $fop); } }}; } macro_rules! op_arithK_check_zero { - ($instr:expr, $lua_state:expr, $ci:expr, $base:expr, $pc:expr, $constants:expr, $iop:expr, $fop:expr, $err_fn:expr) => {{ + ($instr:expr, $lua_state:expr, $ci:expr, $base_stk:expr, $pc:expr, $constants:expr, $iop:expr, $fop:expr, $err_fn:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = $constants.as_ptr().add(c); - let ra_ptr = sp.add($base + a); - - if pttisinteger(v1_ptr) && pttisinteger(v2_ptr) { - let i1 = pivalue(v1_ptr); - let i2 = pivalue(v2_ptr); - if i2 != 0 { - $pc += 1; - psetivalue(ra_ptr, $iop(i1, i2)); - } else { - $ci.save_pc($pc); - return Err($err_fn($lua_state)); - } + let v1 = $base_stk.offset(b); + let v2 = pk_val($constants, c); + if v1.is_integer() && v2.is_integer() { + let i1 = v1.ivalue(); + let i2 = v2.ivalue(); + if i2 != 0 { + $pc += 1; + $base_stk.offset(a).set_integer($iop(i1, i2)); } else { - op_arithf_aux!(ra_ptr, $pc, v1_ptr, v2_ptr, $fop); + $ci.save_pc($pc); + return Err($err_fn($lua_state)); } + } else { + op_arithf_aux!($base_stk.offset(a), $pc, v1, v2, $fop); } }}; } macro_rules! op_bitwise { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $op:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $op:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = sp.add($base + c) as *const LuaValue; - - let mut i1 = 0i64; - let mut i2 = 0i64; - if tointegerns(&*v1_ptr, &mut i1) && tointegerns(&*v2_ptr, &mut i2) { - let ra_ptr = sp.add($base + a); - $pc += 1; - psetivalue(ra_ptr, $op(i1, i2)); - } + let mut i1 = 0i64; + let mut i2 = 0i64; + if tointegerns($base_stk.offset(b).get_ref(), &mut i1) + && tointegerns($base_stk.offset(c).get_ref(), &mut i2) + { + $pc += 1; + $base_stk.offset(a).set_integer($op(i1, i2)); } }}; } macro_rules! op_bitwiseK { - ($instr:expr, $lua_state:expr, $base:expr, $pc:expr, $constants:expr, $op:expr) => {{ + ($instr:expr, $base_stk:expr, $pc:expr, $constants:expr, $op:expr) => {{ let a = $instr.get_a() as usize; let b = $instr.get_b() as usize; let c = $instr.get_c() as usize; - - unsafe { - let sp = $lua_state.stack_mut().as_mut_ptr(); - let v1_ptr = sp.add($base + b) as *const LuaValue; - let v2_ptr = $constants.as_ptr().add(c); - - let mut i1 = 0i64; - let i2 = pivalue(v2_ptr); - if tointegerns(&*v1_ptr, &mut i1) { - let ra_ptr = sp.add($base + a); - $pc += 1; - psetivalue(ra_ptr, $op(i1, i2)); - } + let mut i1 = 0i64; + let i2 = pk_val($constants, c).ivalue(); + if tointegerns($base_stk.offset(b).get_ref(), &mut i1) { + $pc += 1; + $base_stk.offset(a).set_integer($op(i1, i2)); } }}; } @@ -318,10 +272,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( continue; } - let mut base = ci.base; + let mut base_stk = ci.base_stk; let mut pc = ci.pc as usize; let mut chunk = unsafe { &*ci.chunk_ptr }; - debug_assert!(lua_state.stack_len() >= base + chunk.max_stack_size + EXTRA_STACK); + debug_assert!(lua_state.stack_len() >= ci.base + chunk.max_stack_size + EXTRA_STACK); let mut code: &[Instruction] = &chunk.code; let mut constants: &[LuaValue] = &chunk.constants; @@ -355,7 +309,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if ci.call_status & (CIST_C | CIST_PENDING_FINISH) != 0 { break; } - base = ci.base; + base_stk = ci.base_stk; pc = ci.pc as usize; chunk = unsafe { &*ci.chunk_ptr }; code = &chunk.code; @@ -373,7 +327,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let frame_idx = lua_state.call_depth() - 1; let ci_ptr = lua_state.get_call_info_ptr(frame_idx); ci = unsafe { &mut *ci_ptr }; - base = ci.base; + base_stk = ci.base_stk; pc = 0; chunk = unsafe { &*ci.chunk_ptr }; code = &chunk.code; @@ -393,12 +347,6 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; } - macro_rules! stack_id { - ($a:expr) => { - base + $a as usize - }; - } - macro_rules! updatetrap { () => { #[cfg(not(feature = "sandbox"))] @@ -415,7 +363,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( macro_rules! updatebase { () => { - base = ci.base; + base_stk = ci.base_stk; }; } @@ -441,27 +389,28 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( match instr.get_opcode() { OpCode::Move => { // R[A] := R[B] - let a = instr.get_a(); - let b = instr.get_b(); - setobjs2s(lua_state, stack_id!(a), stack_id!(b)); + let a = instr.get_a() as usize; + let b = instr.get_b() as usize; + base_stk.offset(a).set(base_stk.offset(b)); } OpCode::LoadI => { // R[A] := sBx - let a = instr.get_a(); - let sbx = instr.get_sbx(); - setivalue(stack_val_mut(lua_state.stack_mut(), base, a), sbx as i64); + let a = instr.get_a() as usize; + base_stk.offset(a).set_integer(instr.get_sbx() as i64); } OpCode::LoadF => { // R[A] := (float)sBx let a = instr.get_a(); let sbx = instr.get_sbx(); - setfltvalue(stack_val_mut(lua_state.stack_mut(), base, a), sbx as f64); + base_stk.offset(a as usize).set_float(sbx as f64); } OpCode::LoadK => { // R[A] := K[Bx] let a = instr.get_a(); let bx = instr.get_bx(); - setobj2s(lua_state, stack_id!(a), k_val(constants, bx)); + base_stk + .offset(a as usize) + .set(pk_val(constants, bx as usize)); } OpCode::LoadKX => { // R[A] := K[extra arg] @@ -470,30 +419,32 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( debug_assert_eq!(next_instr.get_opcode(), OpCode::ExtraArg); let rb = next_instr.get_ax(); pc += 1; - setobj2s(lua_state, stack_id!(a), k_val(constants, rb)); + base_stk + .offset(a as usize) + .set(pk_val(constants, rb as usize)); } OpCode::LoadFalse => { // R[A] := false let a = instr.get_a(); - setbfvalue(stack_val_mut(lua_state.stack_mut(), base, a)); + base_stk.offset(a as usize).set_bool(false); } OpCode::LFalseSkip => { // R[A] := false; pc++ let a = instr.get_a(); - setbfvalue(stack_val_mut(lua_state.stack_mut(), base, a)); + base_stk.offset(a as usize).set_bool(false); pc += 1; // Skip next instruction } OpCode::LoadTrue => { // R[A] := true let a = instr.get_a(); - setbtvalue(stack_val_mut(lua_state.stack_mut(), base, a)); + base_stk.offset(a as usize).set_bool(true); } OpCode::LoadNil => { // R[A], R[A+1], ..., R[A+B] := nil let mut a = instr.get_a(); let mut b = instr.get_b(); loop { - setnilvalue(stack_val_mut(lua_state.stack_mut(), base, a)); + base_stk.offset(a as usize).set_nil(); if b == 0 { break; } @@ -507,9 +458,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); unsafe { let upvalue_ptr = *ci.upvalue_ptrs.add(b as usize); - let src = &*upvalue_ptr.as_ref().data.get_v_ptr(); - let dest = stack_mut_ptr(lua_state.stack_mut(), stack_id!(a)); - *dest = *src; + let src = upvalue_ptr.as_ref().data.get_v_stk_id(); + base_stk.offset(a as usize).set(src); } } OpCode::SetUpval => { @@ -518,7 +468,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); unsafe { let upvalue_ptr = *ci.upvalue_ptrs.add(b as usize); - let value = stack_ref(lua_state.stack(), stack_id!(a)); + let value = base_stk.offset(a as usize).get(); upvalue_ptr .as_mut_ref() .data @@ -538,6 +488,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let upvalue_ptr = unsafe { *ci.upvalue_ptrs.add(instr.get_b() as usize) }; let upval_value = upvalue_ptr.as_ref().data.get_value_ref(); let key = k_val(constants, instr.get_c()); + let dest = base_stk.offset(a as usize); debug_assert!( key.is_short_string(), "GetTabUp key must be short string for fast path" @@ -559,35 +510,31 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if outer.is_table() { let inner_table = outer.hvalue(); if inner_table.impl_table.has_hash() { - let dest = - stack_mut_ptr(lua_state.stack_mut(), stack_id!(a)); - if unsafe { - inner_table - .impl_table - .get_shortstr_into(next_key, dest) - } { + if inner_table + .impl_table + .get_shortstr_into(next_key, dest.as_ptr()) + { pc += 1; continue; } } } - setobj2s(lua_state, stack_id!(a), &outer); + base_stk.offset(a as usize).write(&outer); continue; } } } if table.impl_table.has_hash() { - let dest = stack_mut_ptr(lua_state.stack_mut(), stack_id!(a)); - if unsafe { table.impl_table.get_shortstr_into(key, dest) } { + if table.impl_table.get_shortstr_into(key, dest.as_ptr()) { continue; } } } savestate!(); let upval_value = *upval_value; - finishget_fallback(lua_state, ci, &upval_value, key, stack_id!(a))?; + finishget_fallback(lua_state, ci, &upval_value, key, dest)?; updatetrap!(); } OpCode::GetTable => { @@ -596,51 +543,46 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); let c = instr.get_c(); - let rb_ptr = stack_ptr(lua_state.stack(), stack_id!(b)); + let rb = base_stk.offset(b as usize); + let rc = base_stk.offset(c as usize); + let dest = base_stk.offset(a as usize); + if rb.is_table() { + let table = rb.hvalue(); - if unsafe { (*rb_ptr).is_table() } { - let table = unsafe { (*rb_ptr).hvalue() }; - let rc_idx = stack_id!(c); - let rc_ptr = stack_ptr(lua_state.stack(), rc_idx); - let rc_tt = unsafe { (*rc_ptr).tt }; - let dest = stack_mut_ptr(lua_state.stack_mut(), stack_id!(a)); // Hot path 1: integer key → array fast path - if rc_tt == LUA_VNUMINT { - let key = unsafe { (*rc_ptr).value.i }; - if unsafe { table.impl_table.fast_geti_into(key, dest) } { + if rc.is_integer() { + let key = rc.ivalue(); + if table.impl_table.fast_geti_into(key, dest.as_ptr()) { continue; } - if unsafe { table.impl_table.get_int_from_hash_into(key, dest) } { + if table.impl_table.get_int_from_hash_into(key, dest.as_ptr()) { continue; } } // Hot path 2: short string key → hash fast path (zero-copy) - else if unsafe { (*rc_ptr).is_short_string() } + else if rc.is_short_string() && table.impl_table.has_hash() - && unsafe { table.impl_table.get_shortstr_into(&*rc_ptr, dest) } + && table + .impl_table + .get_shortstr_into(rc.get_ref(), dest.as_ptr()) { continue; } - let rc = unsafe { *rc_ptr }; // Cold path: other key types, hash fallback for integers - if let Some(val) = table.impl_table.raw_get(&rc) { - setobj2s(lua_state, stack_id!(a), &val); + if let Some(val) = table.impl_table.raw_get(rc.get_ref()) { + dest.write(&val); continue; } savestate!(); - let rb = unsafe { *rb_ptr }; - finishget_fallback(lua_state, ci, &rb, &rc, stack_id!(a))?; + finishget_fallback(lua_state, ci, rb.get_ref(), rc.get_ref(), dest)?; updatetrap!(); continue; } - let rb = unsafe { *rb_ptr }; - let rc = stack_copy(lua_state.stack(), stack_id!(c)); - // Metamethod / non-table fallback savestate!(); - finishget_fallback(lua_state, ci, &rb, &rc, stack_id!(a))?; + finishget_fallback(lua_state, ci, rb.get_ref(), rc.get_ref(), dest)?; updatetrap!(); } OpCode::GetI => { @@ -648,47 +590,53 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); let rc = instr.get_c() as i64; - let rb = *stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b as usize); + let dest = base_stk.offset(a as usize); if rb.is_table() { let table = rb.hvalue(); - let dest = stack_mut_ptr(lua_state.stack_mut(), stack_id!(a)); + // fast_geti: try array part first - let found = unsafe { table.impl_table.fast_geti_into(rc, dest) }; + let found = table.impl_table.fast_geti_into(rc, dest.as_ptr()); if found { continue; } // fallback: direct integer hash lookup (no float/array re-check) - let found = unsafe { table.impl_table.get_int_from_hash_into(rc, dest) }; + let found = table.impl_table.get_int_from_hash_into(rc, dest.as_ptr()); if found { continue; } } savestate!(); - finishget_fallback(lua_state, ci, &rb, &LuaValue::integer(rc), stack_id!(a))?; + finishget_fallback(lua_state, ci, rb.get_ref(), &LuaValue::integer(rc), dest)?; updatetrap!(); } OpCode::GetField => { // GETFIELD: R[A] := R[B][K[C]:string] - let rb_ptr = stack_ptr(lua_state.stack(), stack_id!(instr.get_b())); + let rb = base_stk.offset(instr.get_b() as usize); let key = k_val(constants, instr.get_c()); debug_assert!( key.is_short_string(), "GetField key must be short string for fast path" ); - if unsafe { (*rb_ptr).is_table() } { - let table = unsafe { (*rb_ptr).hvalue() }; + if rb.is_table() { + let table = rb.hvalue(); if table.impl_table.has_hash() { - let dest = - stack_mut_ptr(lua_state.stack_mut(), stack_id!(instr.get_a())); - if unsafe { table.impl_table.get_shortstr_into(key, dest) } { + let dest = base_stk.offset(instr.get_a() as usize); + if table.impl_table.get_shortstr_into(key, dest.as_ptr()) { continue; } } } savestate!(); - let rb = unsafe { *rb_ptr }; - finishget_fallback(lua_state, ci, &rb, key, stack_id!(instr.get_a()))?; + let rb = rb.get(); + finishget_fallback( + lua_state, + ci, + &rb, + key, + base_stk.offset(instr.get_a() as usize), + )?; updatetrap!(); } OpCode::SetTabUp => { @@ -722,9 +670,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( table.impl_table.finish_shortstr_set(key, rc, pset_result); (new_key, delta, rc.tt) } else { - let rc_ptr = stack_ptr(lua_state.stack(), stack_id!(c)); - let rc_tt = unsafe { (*rc_ptr).tt }; - let rc_value = unsafe { (*rc_ptr).value }; + let rc = base_stk.offset(c as usize); + let rc_tt = rc.get().tt; + let rc_value = rc.get().value; let pset_result = table.impl_table.pset_shortstr_parts(key, rc_value, rc_tt); let (new_key, delta) = table.impl_table.finish_shortstr_set_parts( @@ -749,7 +697,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - stack_copy(lua_state.stack(), stack_id!(c)) + base_stk.offset(c as usize).get() }; if table.impl_table.set_existing_shortstr(key, rc) { if rc.is_collectable() { @@ -765,7 +713,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - stack_copy(lua_state.stack(), stack_id!(c)) + base_stk.offset(c as usize).get() }; savestate!(); if known_newindex_miss { @@ -784,11 +732,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); let c = instr.get_c(); - // why use pointer here? - // because we have tryed to use stack_copy for table access in the past, - // but is too slow, and we want to avoid unnecessary copying of table values. - let ra_ptr = stack_ptr(lua_state.stack(), stack_id!(a)); - let rb_ptr = stack_ptr(lua_state.stack(), stack_id!(b)); + // Use StkId-derived raw pointers for fast table access + let ra_stk = base_stk.offset(a as usize); + let rb_stk = base_stk.offset(b as usize); + let ra_ptr = ra_stk.as_const_ptr(); + let rb_ptr = rb_stk.as_const_ptr(); + let ra_val = unsafe { *ra_ptr }; // Hot path: table + integer key in array range, no __newindex // Deferred computation: table_ptr and gc barrier only when needed @@ -798,13 +747,13 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { if !instr.get_k() { - let rc_ptr = stack_ptr(lua_state.stack(), stack_id!(c)); - let rc_tt = unsafe { (*rc_ptr).tt }; - let rc_value = unsafe { (*rc_ptr).value }; + let rc_stk = base_stk.offset(c as usize); + let rc_tt = rc_stk.get().tt; + let rc_value = rc_stk.get().value; if table.impl_table.fast_seti_parts(key, rc_value, rc_tt) { if rc_tt & BIT_ISCOLLECTABLE != 0 { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetTable fast path requires table"), ); @@ -812,11 +761,11 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( continue; } - let rc = unsafe { *rc_ptr }; + let rc = rc_stk.get(); let delta = table.impl_table.set_int_slow(key, rc); if delta != 0 { lua_state.gc_track_table_resize( - unsafe { *ra_ptr } + ra_val .as_table_ptr() .expect("SetTable fast path requires table"), delta, @@ -824,7 +773,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if rc_tt & BIT_ISCOLLECTABLE != 0 { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetTable fast path requires table"), ); @@ -836,7 +785,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if table.impl_table.fast_seti(key, rc) { if rc.is_collectable() { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetTable fast path requires table"), ); @@ -847,7 +796,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let delta = table.impl_table.set_int_slow(key, rc); if delta != 0 { lua_state.gc_track_table_resize( - unsafe { *ra_ptr } + ra_val .as_table_ptr() .expect("SetTable fast path requires table"), delta, @@ -855,7 +804,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if rc.is_collectable() { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetTable fast path requires table"), ); @@ -865,12 +814,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; if table.impl_table.set_existing_int(key, rc) { if rc.is_collectable() { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetTable fast path requires table"), ); @@ -883,7 +832,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; savestate!(); if call_newindex_tm_fast(lua_state, ci, ra, meta, rb, rc)? { @@ -911,9 +860,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( table.impl_table.finish_shortstr_set(key, rc, pset_result); (new_key, delta, rc.is_collectable() || key.is_collectable()) } else { - let rc_ptr = stack_ptr(lua_state.stack(), stack_id!(c)); - let rc_tt = unsafe { (*rc_ptr).tt }; - let rc_value = unsafe { (*rc_ptr).value }; + let rc_stk = base_stk.offset(c as usize); + let rc_tt = rc_stk.get().tt; + let rc_value = rc_stk.get().value; let pset_result = table.impl_table.pset_shortstr_parts(key, rc_value, rc_tt); let (new_key, delta) = table.impl_table.finish_shortstr_set_parts( @@ -934,7 +883,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if delta != 0 { lua_state.gc_track_table_resize( - unsafe { *ra_ptr } + ra_val .as_table_ptr() .expect("SetTable fast path requires table"), delta, @@ -942,7 +891,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if needs_barrier { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetTable fast path requires table"), ); @@ -956,7 +905,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; if ra.is_table() { let table = ra.hvalue_mut(); @@ -1003,7 +952,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::SetI => { // SETI: R[A][B] := RK(C) (integer key) - let ra = stack_val(lua_state.stack(), base, instr.get_a()); + let ra = base_stk.offset(instr.get_a() as usize).get(); let b = instr.get_b() as i64; let c = instr.get_c(); @@ -1011,7 +960,6 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if ra.is_table() { let table = ra.hvalue_mut(); // Pre-extract table/gc pointers as Copy values to break borrow chain - // (ra is a reference into the stack which borrows lua_state) let table_ptr = ra.as_table_ptr().expect("SetI fast path requires table"); let gc_ptr = ra .as_gc_ptr() @@ -1019,9 +967,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { if !instr.get_k() { - let rc_ptr = stack_ptr(lua_state.stack(), stack_id!(c)); - let rc_tt = unsafe { (*rc_ptr).tt }; - let rc_value = unsafe { (*rc_ptr).value }; + let rc_stk = base_stk.offset(c as usize); + let rc_tt = rc_stk.get().tt; + let rc_value = rc_stk.get().value; if table.impl_table.fast_seti_parts(b, rc_value, rc_tt) { if rc_tt & BIT_ISCOLLECTABLE != 0 { lua_state.gc_barrier_back(gc_ptr); @@ -1029,7 +977,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( continue; } - let rc = unsafe { *rc_ptr }; + let rc = rc_stk.get(); let delta = table.impl_table.set_int_slow(b, rc); if delta != 0 { lua_state.gc_track_table_resize(table_ptr, delta); @@ -1060,7 +1008,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; if table.impl_table.set_existing_int(b, rc) { if rc.is_collectable() { @@ -1069,7 +1017,6 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( continue; } // Fall through to finishset fallback (known miss) - let ra = *ra; let rb = LuaValue::integer(b); savestate!(); if call_newindex_tm_fast(lua_state, ci, ra, meta, rb, rc)? { @@ -1084,9 +1031,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; - let ra = *ra; let rb = LuaValue::integer(b); savestate!(); finishset_fallback(lua_state, ci, &ra, &rb, rc, false)?; @@ -1097,7 +1043,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); let c = instr.get_c(); - let ra_ptr = stack_ptr(lua_state.stack(), stack_id!(a)); + let ra_stk = base_stk.offset(a as usize); + let ra_ptr = ra_stk.as_const_ptr(); + let ra_val = unsafe { *ra_ptr }; let key = k_val(constants, b); debug_assert!( key.is_short_string(), @@ -1116,9 +1064,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( table.impl_table.finish_shortstr_set(key, rc, pset_result); (new_key, delta, rc.tt) } else { - let rc_ptr = stack_ptr(lua_state.stack(), stack_id!(c)); - let rc_tt = unsafe { (*rc_ptr).tt }; - let rc_value = unsafe { (*rc_ptr).value }; + let rc_stk = base_stk.offset(c as usize); + let rc_tt = rc_stk.get().tt; + let rc_value = rc_stk.get().value; let pset_result = table.impl_table.pset_shortstr_parts(key, rc_value, rc_tt); let (new_key, delta) = table.impl_table.finish_shortstr_set_parts( @@ -1134,7 +1082,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if delta != 0 { lua_state.gc_track_table_resize( - unsafe { *ra_ptr } + ra_val .as_table_ptr() .expect("SetField fast path requires table"), delta, @@ -1142,7 +1090,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if rc_tt & BIT_ISCOLLECTABLE != 0 { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetField fast path requires table"), ); @@ -1152,12 +1100,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; if table.impl_table.set_existing_shortstr(key, rc) { if rc.is_collectable() { lua_state.gc_barrier_back( - unsafe { *ra_ptr } + ra_val .as_gc_ptr() .expect("SetField fast path requires table"), ); @@ -1171,7 +1119,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = if instr.get_k() { *k_val(constants, c) } else { - *stack_val(lua_state.stack(), base, c) + base_stk.offset(c as usize).get() }; let rb = *key; savestate!(); @@ -1209,9 +1157,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( pc += 1; // skip EXTRAARG let value = lua_state.create_table(vc as usize, vb as usize)?; - setobj2s(lua_state, stack_id!(a), &value); + base_stk.offset(a as usize).write(&value); - let new_top = base + a as usize + 1; + let new_top = ci.base + a as usize + 1; // ci.save_pc(pc); // lua_state.set_top_raw(new_top); // lua_state.check_gc()?; @@ -1222,89 +1170,88 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( OpCode::Self_ => { // SELF: R[A+1] := R[B]; R[A] := R[B][K[C]:string] let a = instr.get_a(); - let rb = *stack_val(lua_state.stack(), base, instr.get_b()); + let rb = base_stk.offset(instr.get_b() as usize).get(); let key = k_val(constants, instr.get_c()); debug_assert!( key.is_short_string(), "Self key must be short string for fast path" ); - setobj2s(lua_state, stack_id!(a + 1), &rb); + base_stk.offset(a as usize + 1).write(&rb); // Fast path: rb is a table with hash part if rb.ttistable() { let table = rb.hvalue(); if table.impl_table.has_hash() { - let dest = stack_mut_ptr(lua_state.stack_mut(), stack_id!(a)); - if unsafe { table.impl_table.get_shortstr_into(key, dest) } { + let dest = base_stk.offset(a as usize); + if table.impl_table.get_shortstr_into(key, dest.as_ptr()) { continue; } } - if self_shortstr_index_chain_fast(lua_state, &rb, key, stack_id!(a)) { + if self_shortstr_index_chain_fast( + lua_state, + &rb, + key, + base_stk.offset(a as usize), + ) { continue; } } savestate!(); - finishget_fallback(lua_state, ci, &rb, key, stack_id!(a))?; + finishget_fallback(lua_state, ci, &rb, key, base_stk.offset(a as usize))?; updatetrap!(); } OpCode::Add => { - // op_arith(L, l_addi, luai_numadd) // R[A] := R[B] + R[C] op_arith!( instr, - lua_state, - base, + base_stk, pc, |i1: i64, i2: i64| i1.wrapping_add(i2), |n1: f64, n2: f64| n1 + n2 ); } OpCode::AddI => { - // op_arithI(L, l_addi, luai_numadd) // R[A] := R[B] + sC op_arithI!( instr, - lua_state, - base, + base_stk, pc, |iv1: i64, sc: i32| iv1.wrapping_add(sc as i64), |nb: f64, fimm: f64| nb + fimm ); } OpCode::Sub => { - // op_arith(L, l_subi, luai_numsub) + // R[A] := R[B] - R[C] op_arith!( instr, - lua_state, - base, + base_stk, pc, |i1: i64, i2: i64| i1.wrapping_sub(i2), |n1: f64, n2: f64| n1 - n2 ); } OpCode::Mul => { - // op_arith(L, l_muli, luai_nummul) + // R[A] := R[B] * R[C] op_arith!( instr, - lua_state, - base, + base_stk, pc, |i1: i64, i2: i64| i1.wrapping_mul(i2), |n1: f64, n2: f64| n1 * n2 ); } OpCode::Div => { - // op_arithf(L, luai_numdiv) - 浮点除法 - op_arithf!(instr, lua_state, base, pc, |n1: f64, n2: f64| n1 / n2); + // R[A] := R[B] / R[C] (float) + op_arithf!(instr, base_stk, pc, |n1: f64, n2: f64| n1 / n2); } OpCode::IDiv => { - // op_arith(L, luaV_idiv, luai_numidiv) - 整数除法 + // R[A] := R[B] // R[C] (floor division) op_arith_check_zero!( instr, lua_state, ci, - base, + base_stk, pc, |i1: i64, i2: i64| lua_idiv(i1, i2), |n1: f64, n2: f64| (n1 / n2).floor(), @@ -1312,12 +1259,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ); } OpCode::Mod => { - // op_arith(L, luaV_mod, luaV_modf) + // R[A] := R[B] % R[C] op_arith_check_zero!( instr, lua_state, ci, - base, + base_stk, pc, |i1: i64, i2: i64| lua_imod(i1, i2), |n1: f64, n2: f64| lua_fmod(n1, n2), @@ -1325,18 +1272,14 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ); } OpCode::Pow => { - // op_arithf(L, luai_numpow) - op_arithf!(instr, lua_state, base, pc, |n1: f64, n2: f64| luai_numpow( - n1, n2 - )); + // R[A] := R[B] ^ R[C] + op_arithf!(instr, base_stk, pc, |n1: f64, n2: f64| luai_numpow(n1, n2)); } OpCode::AddK => { - // op_arithK(L, l_addi, luai_numadd) // R[A] := R[B] + K[C] op_arithK!( instr, - lua_state, - base, + base_stk, pc, constants, |i1: i64, i2: i64| i1.wrapping_add(i2), @@ -1347,8 +1290,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // R[A] := R[B] - K[C] op_arithK!( instr, - lua_state, - base, + base_stk, pc, constants, |i1: i64, i2: i64| i1.wrapping_sub(i2), @@ -1359,8 +1301,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // R[A] := R[B] * K[C] op_arithK!( instr, - lua_state, - base, + base_stk, pc, constants, |i1: i64, i2: i64| i1.wrapping_mul(i2), @@ -1373,7 +1314,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( instr, lua_state, ci, - base, + base_stk, pc, constants, |i1: i64, i2: i64| lua_imod(i1, i2), @@ -1383,14 +1324,13 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::PowK => { // R[A] := R[B] ^ K[C] (always float) - op_arithfK!(instr, lua_state, base, pc, constants, |n1: f64, n2: f64| { + op_arithfK!(instr, base_stk, pc, constants, |n1: f64, n2: f64| { luai_numpow(n1, n2) }); } OpCode::DivK => { // R[A] := R[B] / K[C] (float division) - op_arithfK!(instr, lua_state, base, pc, constants, |n1: f64, n2: f64| n1 - / n2); + op_arithfK!(instr, base_stk, pc, constants, |n1: f64, n2: f64| n1 / n2); } OpCode::IDivK => { // R[A] := R[B] // K[C] (floor division) @@ -1398,7 +1338,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( instr, lua_state, ci, - base, + base_stk, pc, constants, |i1: i64, i2: i64| lua_idiv(i1, i2), @@ -1408,80 +1348,63 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::BAndK => { // R[A] := R[B] & K[C] - op_bitwiseK!(instr, lua_state, base, pc, constants, |i1: i64, i2: i64| i1 - & i2); + op_bitwiseK!(instr, base_stk, pc, constants, |i1: i64, i2: i64| i1 & i2); } OpCode::BOrK => { // R[A] := R[B] | K[C] - op_bitwiseK!(instr, lua_state, base, pc, constants, |i1: i64, i2: i64| i1 - | i2); + op_bitwiseK!(instr, base_stk, pc, constants, |i1: i64, i2: i64| i1 | i2); } OpCode::BXorK => { // R[A] := R[B] ^ K[C] (bitwise xor) - op_bitwiseK!(instr, lua_state, base, pc, constants, |i1: i64, i2: i64| i1 - ^ i2); + op_bitwiseK!(instr, base_stk, pc, constants, |i1: i64, i2: i64| i1 ^ i2); } OpCode::BAnd => { - // op_bitwise(L, l_band) - op_bitwise!(instr, lua_state, base, pc, |i1: i64, i2: i64| i1 & i2); + // R[A] := R[B] & R[C] + op_bitwise!(instr, base_stk, pc, |i1: i64, i2: i64| i1 & i2); } OpCode::BOr => { - // op_bitwise(L, l_bor) - op_bitwise!(instr, lua_state, base, pc, |i1: i64, i2: i64| i1 | i2); + // R[A] := R[B] | R[C] + op_bitwise!(instr, base_stk, pc, |i1: i64, i2: i64| i1 | i2); } OpCode::BXor => { - // op_bitwise(L, l_bxor) - op_bitwise!(instr, lua_state, base, pc, |i1: i64, i2: i64| i1 ^ i2); + // R[A] := R[B] ^ R[C] + op_bitwise!(instr, base_stk, pc, |i1: i64, i2: i64| i1 ^ i2); } OpCode::Shl => { - // op_bitwise(L, luaV_shiftl) - op_bitwise!(instr, lua_state, base, pc, |i1: i64, i2: i64| lua_shiftl( - i1, i2 - )); + // R[A] := R[B] << R[C] + op_bitwise!(instr, base_stk, pc, |i1: i64, i2: i64| lua_shiftl(i1, i2)); } OpCode::Shr => { - // op_bitwise(L, luaV_shiftr) - op_bitwise!(instr, lua_state, base, pc, |i1: i64, i2: i64| lua_shiftr( - i1, i2 - )); + // R[A] := R[B] >> R[C] + op_bitwise!(instr, base_stk, pc, |i1: i64, i2: i64| lua_shiftr(i1, i2)); } OpCode::ShlI => { // R[A] := sC << R[B] - // Note: In Lua 5.5, SHLI is immediate << register (not register << immediate) let a = instr.get_a() as usize; let b = instr.get_b() as usize; - let ic = instr.get_sc(); // shift amount from immediate + let ic = instr.get_sc(); - let rb = stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b); let mut ib = 0i64; - if tointegerns(rb, &mut ib) { + if tointegerns(rb.get_ref(), &mut ib) { pc += 1; - // luaV_shiftl(ic, ib): shift ic left by ib - setivalue( - stack_val_mut(lua_state.stack_mut(), base, a), - lua_shiftl(ic as i64, ib), - ); + base_stk.offset(a).set_integer(lua_shiftl(ic as i64, ib)); } // else: metamethod } OpCode::ShrI => { // R[A] := R[B] >> sC - // Logical right shift (Lua 5.5: luaV_shiftr) let a = instr.get_a() as usize; let b = instr.get_b() as usize; - let ic = instr.get_sc(); // shift amount + let ic = instr.get_sc(); - let rb = stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b); let mut ib = 0i64; - if tointegerns(rb, &mut ib) { + if tointegerns(rb.get_ref(), &mut ib) { pc += 1; - // luaV_shiftr(ib, ic) = luaV_shiftl(ib, -ic) - setivalue( - stack_val_mut(lua_state.stack_mut(), base, a), - lua_shiftr(ib, ic as i64), - ); + base_stk.offset(a).set_integer(lua_shiftr(ib, ic as i64)); } // else: metamethod } @@ -1489,10 +1412,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a() as usize; let b = instr.get_b() as usize; - let ra = *stack_val(lua_state.stack(), base, a); - let rb = *stack_val(lua_state.stack(), base, b); + let ra = base_stk.offset(a).get(); + let rb = base_stk.offset(b).get(); let pi = instr_at(code, pc - 2); - let result_reg = (base + pi.get_a() as usize) as u32; + let result_reg = (ci.base + pi.get_a() as usize) as u32; let tm = TmKind::from_u8(instr.get_c() as u8); @@ -1505,24 +1428,25 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let imm = instr.get_sb(); let flip = instr.get_k(); - let ra = stack_val(lua_state.stack(), base, a); + let ra = base_stk.offset(a).get(); let pi = instr_at(code, pc - 2); - let result_reg = (base + pi.get_a() as usize) as u32; + let result_reg = (ci.base + pi.get_a() as usize) as u32; let tm = TmKind::from_u8(instr.get_c() as u8); let rb = LuaValue::integer(imm as i64); - let r = if flip { (rb, *ra) } else { (*ra, rb) }; + let r = if flip { (rb, ra) } else { (ra, rb) }; savestate!(); bin_tm_fallback(lua_state, ci, r.0, r.1, result_reg, a as u32, a as u32, tm)?; updatetrap!(); } OpCode::MmBinK => { - let ra = *stack_val(lua_state.stack(), base, instr.get_a()); + let a = instr.get_a(); + let ra = base_stk.offset(a as usize).get(); let pi = instr_at(code, pc - 2); let imm = *k_val(constants, instr.get_b()); let tm = TmKind::from_u8(instr.get_c() as u8); let flip = instr.get_k(); - let result_reg = (base + pi.get_a() as usize) as u32; + let result_reg = (ci.base + pi.get_a() as usize) as u32; let a_reg = instr.get_a(); savestate!(); @@ -1534,22 +1458,24 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); - let rb = *stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b as usize).get(); if ttisinteger(&rb) { let ib = ivalue(&rb); - setivalue( - stack_val_mut(lua_state.stack_mut(), base, a), - ib.wrapping_neg(), - ); + base_stk.offset(a as usize).set_integer(ib.wrapping_neg()); } else { let mut nb = 0.0; if tonumberns(&rb, &mut nb) { - setfltvalue(stack_val_mut(lua_state.stack_mut(), base, a), -nb); + base_stk.offset(a as usize).set_float(-nb); } else { savestate!(); - let result_reg = stack_id!(a); - unary_tm_fallback(lua_state, ci, rb, result_reg, TmKind::Unm)?; + unary_tm_fallback( + lua_state, + ci, + rb, + ci.base + a as usize, + TmKind::Unm, + )?; updatetrap!(); } } @@ -1558,15 +1484,14 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); - let rb = *stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b as usize).get(); let mut ib = 0i64; if tointegerns(&rb, &mut ib) { - setivalue(stack_val_mut(lua_state.stack_mut(), base, a), !ib); + base_stk.offset(a as usize).set_integer(!ib); } else { savestate!(); - let result_reg = stack_id!(a); - unary_tm_fallback(lua_state, ci, rb, result_reg, TmKind::Bnot)?; + unary_tm_fallback(lua_state, ci, rb, ci.base + a as usize, TmKind::Bnot)?; updatetrap!(); } } @@ -1575,34 +1500,34 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); - let rb = stack_val(lua_state.stack(), base, b); - if rb.ttisfalse() || rb.is_nil() { - setbtvalue(stack_val_mut(lua_state.stack_mut(), base, a)); + let rb = base_stk.offset(b as usize); + if rb.is_false_or_nil() { + base_stk.offset(a as usize).set_bool(true); } else { - setbfvalue(stack_val_mut(lua_state.stack_mut(), base, a)); + base_stk.offset(a as usize).set_bool(false); } } OpCode::Len => { // HOT PATH: inline table length for no-metatable case let a = instr.get_a(); let b = instr.get_b(); - let rb = *stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b as usize).get(); savestate!(); - objlen(lua_state, ci, stack_id!(a), rb)?; + objlen(lua_state, ci, base_stk.offset(a as usize), rb)?; } OpCode::Concat => { let a = instr.get_a(); let n = instr.get_b(); if n == 2 { - let concat_top = base + (a + n) as usize; + let concat_top = ci.base + (a + n) as usize; lua_state.set_top_raw(concat_top); - let left = *stack_val(lua_state.stack(), base, a); - let right = *stack_val(lua_state.stack(), base, a + 1); + let left = base_stk.offset(a as usize).get(); + let right = base_stk.offset(a as usize + 1).get(); ci.save_pc(pc); if let Some(result) = try_concat_pair_utf8(lua_state, left, right)? { - *stack_val_mut(lua_state.stack_mut(), base, a) = result; + base_stk.offset(a as usize).write(&result); lua_state.set_top_raw(concat_top - 1); updatetrap!(); @@ -1612,7 +1537,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } } - let concat_top = base + (a + n) as usize; + let concat_top = ci.base + (a + n) as usize; lua_state.set_top_raw(concat_top); // ProtectNT @@ -1632,7 +1557,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::Close => { let a = instr.get_a(); - let close_from = stack_id!(a); + let close_from = ci.base + a as usize; ci.save_pc(pc); match lua_state.close_all(close_from) { @@ -1648,7 +1573,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Mark variable as to-be-closed let a = instr.get_a(); ci.save_pc(pc); // save PC so get_local_var_name finds the variable name - lua_state.mark_tbc(stack_id!(a))?; + lua_state.mark_tbc(ci.base + a as usize)?; } OpCode::Jmp => { let sj = instr.get_sj(); @@ -1658,8 +1583,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( OpCode::Eq => { let a = instr.get_a(); let b = instr.get_b(); - let ra = *stack_val(lua_state.stack(), base, a); - let rb = *stack_val(lua_state.stack(), base, b); + let ra = base_stk.offset(a as usize).get(); + let rb = base_stk.offset(b as usize).get(); savestate!(); let cond = eq_fallback(lua_state, ci, ra, rb)?; updatetrap!(); @@ -1677,9 +1602,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); let cond = { - let stack = lua_state.stack_mut(); - let ra = stack_ref(stack, stack_id!(a)); - let rb = stack_ref(stack, stack_id!(b)); + let ra = base_stk.offset(a as usize).get_ref(); + let rb = base_stk.offset(b as usize).get_ref(); if ttisinteger(ra) && ttisinteger(rb) { ivalue(ra) < ivalue(rb) @@ -1718,9 +1642,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); let cond = { - let stack = lua_state.stack_mut(); - let ra = stack_ref(stack, stack_id!(a)); - let rb = stack_ref(stack, stack_id!(b)); + let ra = base_stk.offset(a as usize).get_ref(); + let rb = base_stk.offset(b as usize).get_ref(); if ttisinteger(ra) && ttisinteger(rb) { ivalue(ra) <= ivalue(rb) @@ -1759,7 +1682,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); let k = instr.get_k(); - let ra = stack_val(lua_state.stack(), base, a); + let ra = base_stk.offset(a as usize).get_ref(); let rb = k_val(constants, b); // Raw equality (no metamethods for constants) let cond = ra == rb; @@ -1774,7 +1697,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( OpCode::EqI => { let a = instr.get_a(); let im = instr.get_sb(); - let ra = stack_val(lua_state.stack(), base, a); + let ra = base_stk.offset(a as usize).get_ref(); let cond = if ttisinteger(ra) { ivalue(ra) == im as i64 } else if ttisfloat(ra) { @@ -1796,15 +1719,15 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a() as usize; let im = instr.get_sb(); - let cond = unsafe { - let ra_ptr = stack_mut_ptr(lua_state.stack_mut(), base + a); + let cond = { + let ra = base_stk.offset(a); - if pttisinteger(ra_ptr) { - pivalue(ra_ptr) < im as i64 - } else if pttisfloat(ra_ptr) { - pfltvalue(ra_ptr) < im as f64 + if ra.is_integer() { + ra.ivalue() < im as i64 + } else if ra.is_float() { + ra.fltvalue() < im as f64 } else { - let va = *ra_ptr; + let va = ra.get(); let isf = instr.get_c() != 0; let vb = if isf { LuaValue::float(im as f64) @@ -1831,15 +1754,15 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a() as usize; let im = instr.get_sb(); - let cond = unsafe { - let ra_ptr = stack_mut_ptr(lua_state.stack_mut(), base + a); + let cond = { + let ra = base_stk.offset(a); - if pttisinteger(ra_ptr) { - pivalue(ra_ptr) <= im as i64 - } else if pttisfloat(ra_ptr) { - pfltvalue(ra_ptr) <= im as f64 + if ra.is_integer() { + ra.ivalue() <= im as i64 + } else if ra.is_float() { + ra.fltvalue() <= im as f64 } else { - let va = *ra_ptr; + let va = ra.get(); let isf = instr.get_c() != 0; let vb = if isf { LuaValue::float(im as f64) @@ -1866,15 +1789,15 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a() as usize; let im = instr.get_sb(); - let cond = unsafe { - let ra_ptr = stack_mut_ptr(lua_state.stack_mut(), base + a); + let cond = { + let ra = base_stk.offset(a); - if pttisinteger(ra_ptr) { - pivalue(ra_ptr) > im as i64 - } else if pttisfloat(ra_ptr) { - pfltvalue(ra_ptr) > im as f64 + if ra.is_integer() { + ra.ivalue() > im as i64 + } else if ra.is_float() { + ra.fltvalue() > im as f64 } else { - let va = *ra_ptr; + let va = ra.get(); let isf = instr.get_c() != 0; let vb = if isf { LuaValue::float(im as f64) @@ -1902,15 +1825,15 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a() as usize; let im = instr.get_sb(); - let cond = unsafe { - let ra_ptr = stack_mut_ptr(lua_state.stack_mut(), base + a); + let cond = { + let ra = base_stk.offset(a); - if pttisinteger(ra_ptr) { - pivalue(ra_ptr) >= im as i64 - } else if pttisfloat(ra_ptr) { - pfltvalue(ra_ptr) >= im as f64 + if ra.is_integer() { + ra.ivalue() >= im as i64 + } else if ra.is_float() { + ra.fltvalue() >= im as f64 } else { - let va = *ra_ptr; + let va = ra.get(); let isf = instr.get_c() != 0; let vb = if isf { LuaValue::float(im as f64) @@ -1936,7 +1859,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::Test => { let a = instr.get_a(); - let ra = stack_val(lua_state.stack(), base, a); + let ra = base_stk.offset(a as usize).get_ref(); // l_isfalse: nil or false => truthy = !nil && !false let cond = !ra.is_nil() && !ra.ttisfalse(); @@ -1955,13 +1878,13 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); let k = instr.get_k(); - let rb = *stack_val(lua_state.stack(), base, b); + let rb = base_stk.offset(b as usize).get(); let cond = rb.is_nil() || rb.ttisfalse(); if cond == k { pc += 1; // Condition failed - skip next instruction (JMP) } else { // Condition succeeded - copy value and EXECUTE next instruction (must be JMP) - setobj2s(lua_state, stack_id!(a), &rb); + base_stk.offset(a as usize).write(&rb); // donextjump: fetch and execute next JMP instruction let next_instr = instr_at(code, pc); debug_assert!(next_instr.get_opcode() == OpCode::Jmp); @@ -1975,7 +1898,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b() as usize; let nresults = instr.get_c() as i32 - 1; - let func_idx = stack_id!(a); + let func_idx = ci.base + a as usize; let nargs = if b != 0 { lua_state.set_top_raw(func_idx + b); b - 1 @@ -2012,7 +1935,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ci.save_pc(pc); // Set locals directly — no CallInfo read-back needed chunk = unsafe { &*chunk_ptr }; - base = new_base; + base_stk = + StkId::from_stack(lua_state.stack_mut().as_mut_ptr(), new_base); pc = 0; code = &chunk.code; constants = &chunk.constants; @@ -2064,7 +1988,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( OpCode::TailCall => { let a = instr.get_a(); let mut b = instr.get_b() as usize; - let func_idx = stack_id!(a); + let func_idx = ci.base + a as usize; // let nparams1 = instr.get_c() as usize; if b != 0 { lua_state.set_top_raw(func_idx + b); @@ -2073,7 +1997,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } ci.save_pc(pc); if instr.get_k() { - lua_state.close_upvalues(base); + lua_state.close_upvalues(ci.base); } if pretailcall(lua_state, func_idx, b)? { // Lua tail call: reload callee frame, continue dispatch directly @@ -2089,7 +2013,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::Return => { // return R[A], ..., R[A+B-2] (lvm.c:1763-1783) - let a_pos = stack_id!(instr.get_a()); + let a_pos = ci.base + instr.get_a() as usize; let mut n; // Check if resuming after a yield inside __close during return @@ -2103,7 +2027,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ci.save_pc(pc); // Continue closing remaining TBC variables (if any) - match lua_state.close_all(base) { + match lua_state.close_all(ci.base) { Ok(()) => {} Err(LuaError::Yield) => { ci.call_status |= CIST_CLSRET; @@ -2126,7 +2050,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if lua_state.get_top() < ci_top { lua_state.set_top_raw(ci_top); } - match lua_state.close_all(base) { + match lua_state.close_all(ci.base) { Ok(()) => {} Err(LuaError::Yield) => { ci.call_status |= CIST_CLSRET; @@ -2149,7 +2073,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // return (no values) if lua_state.hook_mask & (LUA_MASKRET | LUA_MASKLINE) != 0 { ci.save_pc(pc); - return0_with_hook(lua_state, stack_id!(instr.get_a()), pc)?; + return0_with_hook(lua_state, ci.base + instr.get_a() as usize, pc)?; break; } @@ -2177,7 +2101,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // return R[A] (single value) if lua_state.hook_mask & (LUA_MASKRET | LUA_MASKLINE) != 0 { ci.save_pc(pc); - return1_with_hook(lua_state, stack_id!(instr.get_a()), pc)?; + return1_with_hook(lua_state, ci.base + instr.get_a() as usize, pc)?; break; } @@ -2190,10 +2114,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Caller wants no results lua_state.set_top_raw(res); } else { - // Copy the single result value using raw pointer + // Copy the single result value using StkId + let val = base_stk.offset(instr.get_a() as usize).get(); unsafe { let sp = lua_state.stack_mut().as_mut_ptr(); - let val = *sp.add(base + instr.get_a() as usize); *sp.add(res) = val; } lua_state.set_top_raw(res + 1); @@ -2217,7 +2141,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let bx = instr.get_bx() as usize; unsafe { - let ra = stack_mut_ptr(lua_state.stack_mut(), base + a); + let ra = base_stk.offset(a).as_ptr(); // Check if integer loop (tag of step at ra+1) if pttisinteger(ra.add(1)) { // Integer loop (most common for numeric loops) @@ -2239,7 +2163,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( pc -= bx; } // else: counter expired, exit loop - } else if float_for_loop(lua_state, base + a) { + } else if float_for_loop(lua_state, ci.base + a) { // Float loop with non-integer step // Jump back if loop continues pc -= bx; @@ -2251,7 +2175,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( OpCode::ForPrep => { let a = instr.get_a(); savestate!(); - if forprep(lua_state, stack_id!(a))? { + if forprep(lua_state, ci.base + a as usize)? { // Skip the loop body: jump forward past FORLOOP pc += instr.get_bx() as usize + 1; } @@ -2261,13 +2185,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a() as usize; let bx = instr.get_bx() as usize; - let stack = lua_state.stack_mut(); - let ra = base + a; + let ra = ci.base + a; // Swap control and closing variables - stack.swap(ra + 3, ra + 2); + lua_state.stack_mut().swap(ra + 3, ra + 2); - // Mark ra+2 as to-be-closed if not nil + // Mark ra+2 as to-be-closed if not nil (regardless — mark_tbc handles it) lua_state.mark_tbc(ra + 2)?; pc += bx; @@ -2277,12 +2200,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Copy iterator+state+control to ra+3..ra+5, then precall. let a = instr.get_a() as usize; let c = instr.get_c() as usize; - let ra = base + a; - let func_idx = ra + 3; - let stack = lua_state.stack_mut(); - *stack_mut_ref(stack, ra + 5) = stack_copy(stack, ra + 3); - *stack_mut_ref(stack, ra + 4) = stack_copy(stack, ra + 1); - *stack_mut_ref(stack, ra + 3) = stack_copy(stack, ra); + let func_idx = ci.base + a + 3; + base_stk.offset(a + 5).set(base_stk.offset(a + 3)); + base_stk.offset(a + 4).set(base_stk.offset(a + 1)); + base_stk.offset(a + 3).set(base_stk.offset(a)); lua_state.set_top_raw(func_idx + 3); // func + 2 args ci.save_pc(pc); if precall(lua_state, func_idx, 2, c as i32)? { @@ -2299,10 +2220,11 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( OpCode::TForLoop => { // Generic for loop test // If ra+3 (control variable) != nil then continue loop (jump back) - // After TForPrep swap: ra+2=closing(TBC), ra+3=control - // TFORCALL places first result at ra+3, automatically updating control - // Check if ra+3 (control value from iterator) is not nil - if !stack_val(lua_state.stack(), base, instr.get_a() + 3).is_nil() { + if !base_stk + .offset(instr.get_a() as usize + 3) + .get_ref() + .is_nil() + { // Continue loop: jump back pc -= instr.get_bx() as usize; } @@ -2313,8 +2235,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let mut n = instr.get_vb() as usize; let stack_idx = instr.get_vc() as usize; let mut last = stack_idx; + let a_pos = ci.base + a as usize; if n == 0 { - n = lua_state.get_top() - stack_id!(a) - 1; // adjust n based on top if vb=0 + n = lua_state.get_top() - a_pos - 1; // adjust n based on top if vb=0 } else { lua_state.set_top_raw(ci.top as usize); } @@ -2327,21 +2250,21 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Add extra to starting index last += extra * (1 << Instruction::SIZE_V_C); } - let ra = *stack_val(lua_state.stack(), base, a); + let ra = base_stk.offset(a as usize).get(); let h = ra.hvalue_mut(); if last > h.impl_table.asize as usize { h.impl_table.resize_array(last as u32); } let impl_table = &mut h.impl_table; - let stack_ptr = lua_state.stack().as_ptr(); + let stack_base = lua_state.stack().as_ptr(); let mut is_collectable = false; // Port of C Lua's SETLIST loop (lvm.c): // for (; n > 0; n--) { val = s2v(ra+n); obj2arr(h, last, val); last--; } // Reads n values from stack[ra+n..ra+1], writes to table[last..last-n+1] let mut write_idx = last; for i in (1..=n).rev() { - let val = unsafe { *stack_ptr.add(stack_id!(a) + i) }; + let val = unsafe { *stack_base.add(a_pos + i) }; if val.iscollectable() { is_collectable = true; } @@ -2364,9 +2287,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); let upvalue_ptrs = unsafe { std::slice::from_raw_parts(ci.upvalue_ptrs, chunk.upvalue_count) }; - push_closure(lua_state, base, a, proto_idx, chunk, upvalue_ptrs)?; + push_closure(lua_state, ci.base, a, proto_idx, chunk, upvalue_ptrs)?; - lua_state.check_gc_in_loop(pc, base + a + 1, &mut trap); + lua_state.check_gc_in_loop(pc, ci.base + a + 1, &mut trap); } OpCode::Vararg => { let a = instr.get_a() as usize; @@ -2375,7 +2298,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let vatab = if instr.get_k() { b as i32 } else { -1 }; savestate!(); - match get_varargs(lua_state, base, a, b, vatab, n, chunk) { + match get_varargs(lua_state, ci.base, a, b, vatab, n, chunk) { Ok(()) => { updatetrap!(); } @@ -2388,13 +2311,13 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } } OpCode::GetVarg => { - let a = stack_id!(instr.get_a()); - let c = stack_id!(instr.get_c()); - get_vararg(lua_state, base, a, c)?; + let a = ci.base + instr.get_a() as usize; + let c = ci.base + instr.get_c() as usize; + get_vararg(lua_state, ci.base, a, c)?; } OpCode::ErrNNil => { let a = instr.get_a(); - let ra = stack_val(lua_state.stack(), base, a); + let ra = base_stk.offset(a as usize).get_ref(); if !ra.is_nil() { let bx = instr.get_bx() as usize; @@ -2414,7 +2337,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } OpCode::VarargPrep => { ci.save_pc(pc); + let mut base = ci.base; exec_varargprep(lua_state, chunk, &mut base)?; + // Re-sync base_stk after potential base change + base_stk = StkId::from_stack(lua_state.stack_mut().as_mut_ptr(), base); // After varargprep, hook call if hooks are active let hook_mask = lua_state.hook_mask; diff --git a/crates/luars/src/lua_vm/execute/helper.rs b/crates/luars/src/lua_vm/execute/helper.rs index da52149f..e7f65d48 100644 --- a/crates/luars/src/lua_vm/execute/helper.rs +++ b/crates/luars/src/lua_vm/execute/helper.rs @@ -1,4 +1,4 @@ -use crate::lua_value::{LUA_VFALSE, LUA_VNIL, LUA_VNUMFLT, LUA_VNUMINT, LUA_VTRUE, LuaInnerValue}; +use crate::lua_value::{LUA_VNIL, LUA_VNUMFLT, LUA_VNUMINT, LuaInnerValue}; use crate::stdlib::basic::parse_number::parse_lua_number; use crate::stdlib::debug::{objtypename, ordererror, typeerror}; use crate::{ @@ -6,7 +6,7 @@ use crate::{ gc::TablePtr, lua_value::{lua_value_to_udvalue, udvalue_to_lua_value, udvalue_to_lua_value_with_token}, lua_vm::{ - LuaError, LuaState, TmKind, + LuaError, LuaState, StkId, TmKind, call_info::{ CallInfo, call_status::{ @@ -67,10 +67,12 @@ pub fn buildhiddenargs( } { + let sp = lua_state.stack_mut().as_mut_ptr(); let ci = lua_state .current_frame_mut() .expect("stack frame update requires an active call frame"); ci.base = new_base; + ci.base_stk = StkId::from_stack(sp, new_base); ci.top = (new_base + chunk.max_stack_size) as u32; ci.func_offset = (new_base - func_pos) as u32; // Distance from new_base to original func } @@ -149,16 +151,6 @@ pub fn chgfltvalue(v: &mut LuaValue, n: f64) { v.value.n = n; } -/// setivalue - 设置整数值 -/// OPTIMIZATION: Direct field access matching Lua 5.5's setivalue macro -#[inline(always)] -pub unsafe fn psetivalue(v: *mut LuaValue, i: i64) { - unsafe { - (*v).tt = LUA_VNUMINT; - (*v).value.i = i; - } -} - /// setivalue_ref - 引用版本(保留兼容性) #[inline(always)] pub fn setivalue(v: &mut LuaValue, i: i64) { @@ -191,16 +183,6 @@ pub fn luai_numpow(a: f64, b: f64) -> f64 { } } -/// setfltvalue - 设置浮点值 -/// OPTIMIZATION: Direct field access matching Lua 5.5's setfltvalue macro -#[inline(always)] -pub unsafe fn psetfltvalue(v: *mut LuaValue, n: f64) { - unsafe { - (*v).tt = LUA_VNUMFLT; // Lua 5.5's LUA_TNUMFLT is one more than LUA_VNUMINT - (*v).value.n = n; - } -} - /// setfltvalue_ref - 引用版本(保留兼容性) #[inline(always)] pub fn setfltvalue(v: &mut LuaValue, n: f64) { @@ -208,22 +190,6 @@ pub fn setfltvalue(v: &mut LuaValue, n: f64) { v.value.n = n; } -/// setbfvalue_ref - 引用版本(保留兼容性) -#[inline(always)] -pub fn setbfvalue(v: &mut LuaValue) { - // *v = LuaValue::boolean(false); - v.tt = LUA_VFALSE; - v.value = LuaInnerValue::NIL; -} - -/// setbtvalue_ref - 引用版本(保留兼容性) -#[inline(always)] -pub fn setbtvalue(v: &mut LuaValue) { - // *v = LuaValue::boolean(true); - v.tt = LUA_VTRUE; - v.value = LuaInnerValue::NIL; -} - /// setnilvalue_ref - 引用版本(保留兼容性) #[inline(always)] pub fn setnilvalue(v: &mut LuaValue) { @@ -240,14 +206,6 @@ pub fn setobjs2s(l: &mut LuaState, a: usize, b: usize) { } } -#[inline(always)] -pub fn setobj2s(l: &mut LuaState, a: usize, b: &LuaValue) { - let stack = l.stack_mut(); - unsafe { - *stack.get_unchecked_mut(a) = *b; - } -} - /// luaV_shiftl - Shift integer x left by y positions. /// If y is negative, shifts right (LOGICAL/unsigned shift). /// Matches Lua 5.5's luaV_shiftl from lvm.c. @@ -1104,33 +1062,28 @@ pub fn handle_pending_ops(lua_state: &mut LuaState, ci: &mut CallInfo) -> LuaRes pub fn objlen( l: &mut LuaState, ci: &mut CallInfo, - result_reg: usize, + dest_stk_id: StkId, value: LuaValue, ) -> LuaResult<()> { if let Some(bytes) = value.as_bytes() { let len = bytes.len(); - setivalue( - unsafe { l.stack_mut().get_unchecked_mut(result_reg) }, - len as i64, - ); + dest_stk_id.set_integer(len as i64); return Ok(()); } else if value.ttistable() { if let Some(tm) = get_metamethod_event(l, &value, TmKind::Len) { - return match call_tm_res_into(l, tm, value, value, result_reg) { + return match call_tm_res_into(l, tm, value, value, dest_stk_id) { Ok(()) => Ok(()), Err(LuaError::Yield) => { - mark_pending_finish(ci, result_reg as i32); + let aux = l.offset_of_stk_id(dest_stk_id); + mark_pending_finish(ci, aux); Err(LuaError::Yield) } Err(e) => Err(e), }; } - let len = value.as_table().unwrap().len(); - setivalue( - unsafe { l.stack_mut().get_unchecked_mut(result_reg) }, - len as i64, - ); + let len = value.hvalue().len(); + dest_stk_id.set_integer(len as i64); return Ok(()); } else { // Try trait-based __len for userdata first @@ -1140,10 +1093,7 @@ pub fn objlen( let trait_obj = ud.get_trait()?; if let Some(udv) = trait_obj.lua_len() { let result = udvalue_to_lua_value(l, udv)?; - setivalue( - unsafe { l.stack_mut().get_unchecked_mut(result_reg) }, - result.as_integer().unwrap_or(0), - ); + dest_stk_id.set_integer(result.as_integer().unwrap_or(0)); return Ok(()); } } @@ -1151,10 +1101,11 @@ pub fn objlen( let tm = get_metamethod_event(l, &value, TmKind::Len); if let Some(tm) = tm { - match call_tm_res_into(l, tm, value, value, result_reg) { + match call_tm_res_into(l, tm, value, value, dest_stk_id) { Ok(()) => {} Err(LuaError::Yield) => { - mark_pending_finish(ci, result_reg as i32); + let aux = l.offset_of_stk_id(dest_stk_id); + mark_pending_finish(ci, aux); return Err(LuaError::Yield); } Err(e) => return Err(e), @@ -1493,12 +1444,13 @@ pub fn finishget_fallback( ci: &mut CallInfo, obj: &LuaValue, key: &LuaValue, - dest_reg: usize, + dest_stk_id: StkId, ) -> LuaResult<()> { - match finishget_to_reg_known_miss(lua_state, obj, key, dest_reg) { + match finishget_to_reg_known_miss(lua_state, obj, key, dest_stk_id) { Ok(()) => Ok(()), Err(LuaError::Yield) => { - mark_pending_finish(ci, dest_reg as i32); + let aux = lua_state.offset_of_stk_id(dest_stk_id); + mark_pending_finish(ci, aux); Err(LuaError::Yield) } Err(e) => Err(e), @@ -1507,13 +1459,13 @@ pub fn finishget_fallback( /// Fast path for OOP-style `SELF_` lookups where the miss is resolved by a /// table-only `__index` chain and the key is a short string. -/// Returns true if a value was found and written directly to `dest_reg`. +/// Returns true if a value was found and written directly to `dest_stk_id`. #[inline(never)] pub fn self_shortstr_index_chain_fast( lua_state: &mut LuaState, obj: &LuaValue, key: &LuaValue, - dest_reg: usize, + dest_stk_id: StkId, ) -> bool { const TM_INDEX_BIT: u8 = TmKind::Index as u8; @@ -1531,7 +1483,7 @@ pub fn self_shortstr_index_chain_fast( }; if let Some(value) = table.impl_table.get_shortstr_fast(key) { - setobj2s(lua_state, dest_reg, &value); + dest_stk_id.write(&value); return true; } @@ -1564,7 +1516,7 @@ fn finishget_to_reg_inner( lua_state: &mut LuaState, obj: &LuaValue, key: &LuaValue, - dest_reg: usize, + dest_stk_id: StkId, skip_first_raw_lookup: bool, ) -> LuaResult<()> { const TM_INDEX_BIT: u8 = TmKind::Index as u8; @@ -1576,7 +1528,7 @@ fn finishget_to_reg_inner( let tm = if let Some(table) = t.as_table_mut() { if !skip_raw_lookup { if let Some(val) = table.raw_get(key) { - setobj2s(lua_state, dest_reg, &val); + dest_stk_id.write(&val); return Ok(()); } } else { @@ -1585,12 +1537,12 @@ fn finishget_to_reg_inner( let meta = table.meta_ptr(); if meta.is_null() { - setobj2s(lua_state, dest_reg, &LuaValue::nil()); + dest_stk_id.set_nil(); return Ok(()); } let mt = unsafe { &mut (*meta.as_mut_ptr()).data }; if mt.no_tm(TM_INDEX_BIT) { - setobj2s(lua_state, dest_reg, &LuaValue::nil()); + dest_stk_id.set_nil(); return Ok(()); } let vm = lua_state.global_state_mut(); @@ -1599,7 +1551,7 @@ fn finishget_to_reg_inner( Some(v) => v, None => { mt.set_tm_absent(TM_INDEX_BIT); - setobj2s(lua_state, dest_reg, &LuaValue::nil()); + dest_stk_id.set_nil(); return Ok(()); } } @@ -1613,7 +1565,7 @@ fn finishget_to_reg_inner( && let Some(udv) = trait_obj.get_field(key_str) { let result = udvalue_to_lua_value_with_token(lua_state, udv, token)?; - setobj2s(lua_state, dest_reg, &result); + dest_stk_id.write(&result); return Ok(()); } } @@ -1627,7 +1579,7 @@ fn finishget_to_reg_inner( }; if tm.is_function() { - return call_tm_res_into(lua_state, tm, t, *key, dest_reg); + return call_tm_res_into(lua_state, tm, t, *key, dest_stk_id); } t = tm; @@ -1640,7 +1592,7 @@ fn finishget_to_reg_inner( table.raw_get(key) }; if let Some(value) = value { - setobj2s(lua_state, dest_reg, &value); + dest_stk_id.write(&value); return Ok(()); } skip_raw_lookup = true; @@ -1654,9 +1606,9 @@ fn finishget_to_reg_known_miss( lua_state: &mut LuaState, obj: &LuaValue, key: &LuaValue, - dest_reg: usize, + dest_stk_id: StkId, ) -> LuaResult<()> { - finishget_to_reg_inner(lua_state, obj, key, dest_reg, true) + finishget_to_reg_inner(lua_state, obj, key, dest_stk_id, true) } /// finishset wrapper for SetTabUp/SetTable/SetI/SetField @@ -1770,42 +1722,11 @@ pub fn const_ref(constants: &[LuaValue], index: I) -> &LuaValue { unsafe { constants.get_unchecked(index.to_usize()) } } -#[inline(always)] -pub fn stack_ref(stack: &[LuaValue], index: usize) -> &LuaValue { - unsafe { stack.get_unchecked(index) } -} - -#[inline(always)] -pub fn stack_mut_ref(stack: &mut [LuaValue], index: usize) -> &mut LuaValue { - unsafe { stack.get_unchecked_mut(index) } -} - -#[inline(always)] -pub fn stack_copy(stack: &[LuaValue], index: usize) -> LuaValue { - *stack_ref(stack, index) -} - -#[inline(always)] -pub fn stack_ptr(stack: &[LuaValue], index: usize) -> *const LuaValue { - unsafe { stack.as_ptr().add(index) } -} - -#[inline(always)] -pub fn stack_mut_ptr(stack: &mut [LuaValue], index: usize) -> *mut LuaValue { - unsafe { stack.as_mut_ptr().add(index) } -} - -#[inline(always)] -pub fn stack_val(stack: &[LuaValue], base: usize, reg: I) -> &LuaValue { - stack_ref(stack, base + reg.to_usize()) -} - -#[inline(always)] -pub fn stack_val_mut(stack: &mut [LuaValue], base: usize, reg: I) -> &mut LuaValue { - stack_mut_ref(stack, base + reg.to_usize()) -} - #[inline(always)] pub fn k_val(constants: &[LuaValue], index: I) -> &LuaValue { const_ref(constants, index) } + +pub fn pk_val(constants: &[LuaValue], index: usize) -> StkId { + StkId::from_const_ptr(const_ref(constants, index) as *const LuaValue) +} diff --git a/crates/luars/src/lua_vm/execute/metamethod.rs b/crates/luars/src/lua_vm/execute/metamethod.rs index dda08781..04b9e34d 100644 --- a/crates/luars/src/lua_vm/execute/metamethod.rs +++ b/crates/luars/src/lua_vm/execute/metamethod.rs @@ -9,7 +9,7 @@ use crate::lua_vm::execute::helper::{get_binop_metamethod, get_metamethod_from_m /// /// Implements MMBIN, MMBINI, MMBINK opcodes /// Based on Lua 5.5 ltm.c -use crate::lua_vm::{LuaError, LuaResult, LuaState, get_metamethod_event}; +use crate::lua_vm::{LuaError, LuaResult, LuaState, StkId, get_metamethod_event}; use crate::stdlib::debug; /// Try unary metamethod (for __unm, __bnot) @@ -383,7 +383,7 @@ pub fn call_tm_res_into( metamethod: LuaValue, arg1: LuaValue, arg2: LuaValue, - dest_reg: usize, + dest_stk_id: StkId, ) -> LuaResult<()> { let func_pos = { let ci_top = lua_state @@ -441,11 +441,11 @@ pub fn call_tm_res_into( } else if metamethod.is_cfunction() { call_c_function(lua_state, func_pos, 2, 1)?; } else { - return Err(crate::stdlib::debug::callerror(lua_state, &metamethod)); + return Err(debug::callerror(lua_state, &metamethod)); } let result = lua_state.stack()[func_pos]; - lua_state.stack_mut()[dest_reg] = result; + dest_stk_id.write(&result); lua_state.set_top_raw(func_pos); Ok(()) } diff --git a/crates/luars/src/lua_vm/lua_state.rs b/crates/luars/src/lua_vm/lua_state.rs index 6bb9efdb..dd371b49 100644 --- a/crates/luars/src/lua_vm/lua_state.rs +++ b/crates/luars/src/lua_vm/lua_state.rs @@ -7,7 +7,7 @@ use crate::gc::{ CreateResult, GcKind, GcObjectPtr, Pooled, ProtoPtr, StringPtr, TablePtr, ThreadPtr, UpvaluePtr, }; use crate::lua_value::userdata_trait::UserDataTrait; -use crate::lua_value::{LuaUserdata, LuaValue, LuaValueKind, LuaValuePtr, UpvalueStore}; +use crate::lua_value::{LuaUserdata, LuaValue, LuaValueKind, UpvalueStore}; use crate::lua_vm::async_thread::AsyncFuture; use crate::lua_vm::call_info::call_status::{ self, CIST_C, CIST_HOOKED, CIST_RECST, CIST_XPCALL, CIST_YPCALL, @@ -21,7 +21,7 @@ use crate::lua_vm::safe_option::{LuaSafeState, SafeOption}; use crate::lua_vm::sandbox::{SANDBOX_TIMEOUT_CHECK_INTERVAL, SandboxConfig, SandboxRuntimeLimits}; use crate::lua_vm::{ CallInfo, CallInfoPtr, GlobalState, GlobalStateHandle, LuaError, LuaResult, - LuaTypedAsyncCallback, LuaTypedCallback, TmKind, get_metamethod_event, + LuaTypedAsyncCallback, LuaTypedCallback, StkId, TmKind, get_metamethod_event, }; use crate::lua_vm::{ LUA_HOOKCALL, LUA_HOOKCOUNT, LUA_HOOKLINE, LUA_HOOKRET, LUA_HOOKTAILCALL, async_thread, @@ -237,7 +237,7 @@ impl LuaState { } #[inline] - pub(crate) fn release(&mut self) { + pub(crate) fn release_ci(&mut self) { self.call_depth = 0; self.call_stack.clear(); self.call_stack_storage.clear(); @@ -348,6 +348,7 @@ impl LuaState { let ci = unsafe { self.call_stack[self.call_depth].as_mut() }; *ci = CallInfo { base, + base_stk: self.ci_base_stk(base), func_offset: 1, top: frame_top as u32, pc: 0, @@ -361,6 +362,7 @@ impl LuaState { // Slow path: allocate new stable CallInfo slot (first time reaching this depth) self.alloc_call_info_slot(CallInfo { base, + base_stk: self.ci_base_stk(base), func_offset: 1, top: frame_top as u32, pc: 0, @@ -412,6 +414,7 @@ impl LuaState { let ci = unsafe { self.call_stack.get_unchecked(self.call_depth).as_mut() }; *ci = CallInfo { base, + base_stk: self.ci_base_stk(base), func_offset: 1, top: frame_top as u32, pc: 0, @@ -460,6 +463,7 @@ impl LuaState { let ci = unsafe { self.call_stack.get_unchecked(self.call_depth).as_mut() }; *ci = CallInfo { base, + base_stk: self.ci_base_stk(base), func_offset: 1, top: frame_top as u32, pc: 0, @@ -554,6 +558,7 @@ impl LuaState { let ci = unsafe { self.call_stack.get_unchecked(self.call_depth).as_mut() }; *ci = CallInfo { base, + base_stk: self.ci_base_stk(base), func_offset: 1, top: frame_top as u32, pc: 0, @@ -566,6 +571,7 @@ impl LuaState { } else { self.alloc_call_info_slot(CallInfo { base, + base_stk: self.ci_base_stk(base), func_offset: 1, top: frame_top as u32, pc: 0, @@ -618,6 +624,7 @@ impl LuaState { let ci = unsafe { self.call_stack.get_unchecked(self.call_depth).as_mut() }; *ci = CallInfo { base, + base_stk: self.ci_base_stk(base), chunk_ptr: std::ptr::null(), upvalue_ptrs: std::ptr::null(), func_offset: 1, @@ -630,6 +637,7 @@ impl LuaState { } else { self.alloc_call_info_slot(CallInfo { base, + base_stk: self.ci_base_stk(base), chunk_ptr: std::ptr::null(), upvalue_ptrs: std::ptr::null(), func_offset: 1, @@ -765,8 +773,9 @@ impl LuaState { let capacity = self.stack.capacity(); self.stack.resize(new_size, LuaValue::nil()); if self.stack.capacity() > capacity { - // If the vector had to reallocate, we need to update all open upvalue pointers + // If the vector had to reallocate, we need to update all cached stack pointers self.fix_open_upvalue_pointers(); + self.fix_call_info_base_stk(); } Ok(()) @@ -776,19 +785,37 @@ impl LuaState { /// Must be called whenever the stack Vec's internal buffer moves /// (e.g., after Vec::push triggers a reallocation). pub fn fix_open_upvalue_pointers(&mut self) { + let sp = self.stack.as_mut_ptr(); for upval_ptr in &self.open_upvalues_list { let data = &mut upval_ptr.as_mut_ref().data; // All entries in open_upvalues_list must be open debug_assert!(data.is_open()); let stack_index = data.get_stack_index(); if stack_index < self.stack.len() { - data.update_stack_ptr( - (&self.stack[stack_index]) as *const LuaValue as *mut LuaValue, - ); + data.update_stack_ptr(StkId::from_mut_ptr(unsafe { sp.add(stack_index) })); } } } + #[inline(always)] + fn ci_base_stk(&self, base: usize) -> StkId { + StkId::from_stack(self.stack.as_ptr() as *mut LuaValue, base) + } + + fn fix_call_info_base_stk(&mut self) { + let sp = self.stack.as_mut_ptr(); + for ci_ptr in self.call_stack.iter() { + let ci = unsafe { &mut *ci_ptr.as_ptr() }; + ci.base_stk = StkId::from_stack(sp, ci.base); + } + } + + pub(crate) fn offset_of_stk_id(&self, stk_id: StkId) -> i32 { + let sp = self.stack.as_ptr() as *const LuaValue; + let offset = (stk_id.as_ptr() as usize).wrapping_sub(sp as usize); + (offset / std::mem::size_of::()) as i32 + } + /// Get register relative to current frame base #[inline(always)] pub fn reg_get(&self, reg: u8) -> Option { @@ -1533,11 +1560,9 @@ impl LuaState { // Not found, create a new one let upval_ptr = { - let ptr = LuaValuePtr { - ptr: unsafe { self.stack.as_mut_ptr().add(stack_index) }, - }; + let stk_id = StkId::from_mut_ptr(unsafe { self.stack.as_mut_ptr().add(stack_index) }); let vm = self.global_state_mut(); - vm.create_upvalue_open(stack_index, ptr)? + vm.create_upvalue_open(stack_index, stk_id)? }; self.open_upvalues_list.insert(insert_pos, upval_ptr); @@ -2103,10 +2128,10 @@ impl LuaState { pub fn create_upvalue_open( &mut self, stack_index: usize, - stack_ptr: LuaValuePtr, + stk_id: StkId, ) -> LuaResult { self.global_state_mut() - .create_upvalue_open(stack_index, stack_ptr) + .create_upvalue_open(stack_index, stk_id) } /// Create a raw string value. diff --git a/crates/luars/src/lua_vm/mod.rs b/crates/luars/src/lua_vm/mod.rs index aa2714c3..c47d675a 100644 --- a/crates/luars/src/lua_vm/mod.rs +++ b/crates/luars/src/lua_vm/mod.rs @@ -21,6 +21,7 @@ mod safe_option; mod sandbox; #[cfg(feature = "shared-proto")] mod shared_proto; +pub(crate) mod stk_id; mod string_arth; use crate::compiler::{LuaLanguageLevel, compile_code, compile_code_with_name}; @@ -29,9 +30,7 @@ use crate::gc::{ }; use crate::gc::{GC, ProtoPtr}; use crate::lua_value::lua_convert::{FromLua, IntoLua}; -use crate::lua_value::{ - LuaProto, LuaUpvalue, LuaUserdata, LuaValue, LuaValueKind, LuaValuePtr, UpvalueStore, -}; +use crate::lua_value::{LuaProto, LuaUpvalue, LuaUserdata, LuaValue, LuaValueKind, UpvalueStore}; pub use crate::lua_vm::call_info::{CallInfo, CallInfoPtr}; use crate::lua_vm::const_string::ConstString; pub use crate::lua_vm::debug_info::DebugInfo; @@ -44,6 +43,7 @@ pub use crate::lua_vm::lua_ref::{ LUA_REFNIL, LuaAnyRef, LuaFunctionRef, LuaRefValue, LuaStringRef, LuaTableRef, RefId, UserDataRef, }; +pub(crate) use crate::lua_vm::stk_id::StkId; type ArithMetaFn = fn(&mut LuaState) -> LuaResult; pub use crate::lua_vm::lua_state::LuaState; @@ -1247,9 +1247,9 @@ impl GlobalState { pub fn create_upvalue_open( &mut self, stack_index: usize, - ptr: LuaValuePtr, + stk_id: StkId, ) -> LuaResult { - let upval = LuaUpvalue::new_open(stack_index, ptr); + let upval = LuaUpvalue::new_open(stack_index, stk_id); self.object_allocator.create_upvalue(&mut self.gc, upval) } diff --git a/crates/luars/src/lua_vm/stk_id.rs b/crates/luars/src/lua_vm/stk_id.rs new file mode 100644 index 00000000..d09c5846 --- /dev/null +++ b/crates/luars/src/lua_vm/stk_id.rs @@ -0,0 +1,192 @@ +// StkId — Stack slot identifier, equivalent to C Lua's StkId (TValue*) +// +// Encapsulates a raw *mut LuaValue pointer to a stack slot. All methods are +// #[inline(always)]: internally unsafe, externally safe. Eliminates scattered +// `unsafe` blocks and repeated `lua_state.stack_mut().as_mut_ptr()` calls +// in opcode handlers. +// +// # Safety Invariant +// The pointer must point to a valid LuaValue within the Lua stack. + +use crate::{ + LuaRawTable, + lua_value::{ + LUA_VFALSE, LUA_VNIL, LUA_VNUMFLT, LUA_VNUMINT, LUA_VTRUE, LuaInnerValue, LuaValue, + }, +}; + +/// Stack slot handle — a raw pointer wrapped for safe(er) access. +#[derive(Clone, Copy)] +pub struct StkId(*mut LuaValue); + +impl StkId { + // ===== Construction / Addressing ===== + + /// Construct from a raw pointer (used once per frame at outer loop init). + #[inline(always)] + pub fn from_mut_ptr(ptr: *mut LuaValue) -> Self { + Self(ptr) + } + + pub fn from_const_ptr(ptr: *const LuaValue) -> Self { + Self(ptr as *mut LuaValue) + } + + /// Null StkId (used for uninitialized CallInfo). + #[inline(always)] + pub fn null() -> Self { + Self(std::ptr::null_mut()) + } + + /// Compute StkId from stack base pointer + absolute index. + #[inline(always)] + pub fn from_stack(sp: *mut LuaValue, idx: usize) -> Self { + Self(unsafe { sp.add(idx) }) + } + + /// Register-relative offset: `base.offset(reg)` = &stack[base + reg]. + #[inline(always)] + pub fn offset(self, reg: usize) -> Self { + unsafe { Self(self.0.add(reg)) } + } + + // ===== Type Checks ===== + + #[inline(always)] + pub fn is_integer(self) -> bool { + unsafe { (*self.0).tt == LUA_VNUMINT } + } + + #[inline(always)] + pub fn is_float(self) -> bool { + unsafe { (*self.0).tt == LUA_VNUMFLT } + } + + #[inline(always)] + pub fn is_table(self) -> bool { + unsafe { (*self.0).is_table() } + } + + #[inline(always)] + pub fn is_false_or_nil(self) -> bool { + unsafe { + let tt = (*self.0).tt; + tt == LUA_VFALSE || tt == LUA_VNIL + } + } + + #[inline(always)] + pub fn is_short_string(self) -> bool { + unsafe { (*self.0).is_short_string() } + } + + // ===== Value Reads ===== + + #[inline(always)] + pub fn ivalue(self) -> i64 { + unsafe { (*self.0).value.i } + } + + #[inline(always)] + pub fn fltvalue(self) -> f64 { + unsafe { (*self.0).value.n } + } + + #[inline(always)] + pub fn hvalue(self) -> &'static LuaRawTable { + unsafe { (*self.0).hvalue() } + } + + // ===== Value Writes ===== + + /// Copy 16 bytes from another stack slot (equivalent to C Lua's setobjs2s). + #[inline(always)] + pub fn set(self, src: StkId) { + unsafe { + *self.0 = *src.0; + } + } + + /// Copy a LuaValue from an arbitrary reference (constants table etc.). + #[inline(always)] + pub fn write(self, v: &LuaValue) { + unsafe { + *self.0 = *v; + } + } + + #[inline(always)] + pub fn write_parts(self, tt: u8, value: LuaInnerValue) { + unsafe { + (*self.0).tt = tt; + (*self.0).value = value; + } + } + + #[inline(always)] + pub fn set_integer(self, i: i64) { + unsafe { + (*self.0).tt = LUA_VNUMINT; + (*self.0).value.i = i; + } + } + + #[inline(always)] + pub fn set_float(self, n: f64) { + unsafe { + (*self.0).tt = LUA_VNUMFLT; + (*self.0).value.n = n; + } + } + + #[inline(always)] + pub fn set_bool(self, b: bool) { + unsafe { + (*self.0).tt = if b { LUA_VTRUE } else { LUA_VFALSE }; + (*self.0).value = LuaInnerValue::NIL; + } + } + + #[inline(always)] + pub fn set_nil(self) { + unsafe { + (*self.0).tt = LUA_VNIL; + (*self.0).value = LuaInnerValue::NIL; + } + } + + /// Write only the integer value field without touching the type tag. + /// Used by FORLOOP for in-place counter/idx updates. + #[inline(always)] + pub fn set_raw_i(self, i: i64) { + unsafe { + (*self.0).value.i = i; + } + } + + // ===== Raw Pointer Access (for helper functions expecting pointers) ===== + + #[inline(always)] + pub fn as_ptr(self) -> *mut LuaValue { + self.0 + } + + #[inline(always)] + pub fn as_const_ptr(self) -> *const LuaValue { + self.0 as *const LuaValue + } + + #[inline(always)] + pub fn is_valid(self) -> bool { + !self.0.is_null() + } + + #[inline(always)] + pub fn get(self) -> LuaValue { + unsafe { *self.0 } + } + + pub fn get_ref(self) -> &'static LuaValue { + unsafe { &*self.0 } + } +} From 0dcf420d99ed14f873b4ccea83126f5c0c58a844 Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 13:39:21 +0800 Subject: [PATCH 2/7] clean warning --- .../luars/src/lua_vm/execute/execute_loop.rs | 62 +++++++++++++------ crates/luars/src/lua_vm/lua_state.rs | 2 +- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/crates/luars/src/lua_vm/execute/execute_loop.rs b/crates/luars/src/lua_vm/execute/execute_loop.rs index 7d9914c0..1f525627 100644 --- a/crates/luars/src/lua_vm/execute/execute_loop.rs +++ b/crates/luars/src/lua_vm/execute/execute_loop.rs @@ -349,6 +349,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( macro_rules! updatetrap { () => { + // Always reload base_stk — the stack may have been reallocated + // by a metamethod call or other operation since our last reload. + base_stk = ci.base_stk; + #[cfg(not(feature = "sandbox"))] { trap = lua_state.hook_mask != 0; @@ -361,12 +365,6 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; } - macro_rules! updatebase { - () => { - base_stk = ci.base_stk; - }; - } - macro_rules! savestate { () => { ci.save_pc(pc); @@ -383,7 +381,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ci.save_pc(pc); trap = hook_check_instruction(lua_state, pc, chunk)?; - updatebase!(); + base_stk = ci.base_stk; } match instr.get_opcode() { @@ -509,14 +507,13 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if let Some(outer) = table.impl_table.get_shortstr_fast(key) { if outer.is_table() { let inner_table = outer.hvalue(); - if inner_table.impl_table.has_hash() { - if inner_table + if inner_table.impl_table.has_hash() + && inner_table .impl_table .get_shortstr_into(next_key, dest.as_ptr()) - { - pc += 1; - continue; - } + { + pc += 1; + continue; } } @@ -526,10 +523,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } } - if table.impl_table.has_hash() { - if table.impl_table.get_shortstr_into(key, dest.as_ptr()) { - continue; - } + if table.impl_table.has_hash() + && table.impl_table.get_shortstr_into(key, dest.as_ptr()) + { + continue; } } savestate!(); @@ -1193,6 +1190,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( key, base_stk.offset(a as usize), ) { + updatetrap!(); continue; } } @@ -1514,6 +1512,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rb = base_stk.offset(b as usize).get(); savestate!(); objlen(lua_state, ci, base_stk.offset(a as usize), rb)?; + updatetrap!(); } OpCode::Concat => { let a = instr.get_a(); @@ -1561,7 +1560,9 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ci.save_pc(pc); match lua_state.close_all(close_from) { - Ok(()) => {} + Ok(()) => { + updatetrap!(); + } Err(LuaError::Yield) => { ci.pc -= 1; return Err(LuaError::Yield); @@ -2028,7 +2029,17 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Continue closing remaining TBC variables (if any) match lua_state.close_all(ci.base) { - Ok(()) => {} + Ok(()) => { + #[cfg(not(feature = "sandbox"))] + { + trap = lua_state.hook_mask != 0; + } + + #[cfg(feature = "sandbox")] + { + trap = lua_state.has_active_instruction_watch(); + } + } Err(LuaError::Yield) => { ci.call_status |= CIST_CLSRET; ci.save_pc(pc - 1); @@ -2051,7 +2062,17 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( lua_state.set_top_raw(ci_top); } match lua_state.close_all(ci.base) { - Ok(()) => {} + Ok(()) => { + #[cfg(not(feature = "sandbox"))] + { + trap = lua_state.hook_mask != 0; + } + + #[cfg(feature = "sandbox")] + { + trap = lua_state.has_active_instruction_watch(); + } + } Err(LuaError::Yield) => { ci.call_status |= CIST_CLSRET; ci.save_pc(pc - 1); @@ -2179,6 +2200,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Skip the loop body: jump forward past FORLOOP pc += instr.get_bx() as usize + 1; } + updatetrap!(); } OpCode::TForPrep => { // Prepare generic for loop — inline (for loop related) diff --git a/crates/luars/src/lua_vm/lua_state.rs b/crates/luars/src/lua_vm/lua_state.rs index dd371b49..c00eaf4c 100644 --- a/crates/luars/src/lua_vm/lua_state.rs +++ b/crates/luars/src/lua_vm/lua_state.rs @@ -811,7 +811,7 @@ impl LuaState { } pub(crate) fn offset_of_stk_id(&self, stk_id: StkId) -> i32 { - let sp = self.stack.as_ptr() as *const LuaValue; + let sp = self.stack.as_ptr(); let offset = (stk_id.as_ptr() as usize).wrapping_sub(sp as usize); (offset / std::mem::size_of::()) as i32 } From 92fd55053fd0c262f47a6683102fa45fb85e5888 Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 14:33:39 +0800 Subject: [PATCH 3/7] clean many unsafe --- crates/luars/src/gc/gc_object.rs | 27 +- .../src/lua_value/lua_table/native_table.rs | 27 +- crates/luars/src/lua_value/lua_value.rs | 17 + .../luars/src/lua_vm/execute/execute_loop.rs | 298 +++++++----------- crates/luars/src/lua_vm/stk_id.rs | 26 ++ crates/luars/src/stdlib/table.rs | 5 +- 6 files changed, 172 insertions(+), 228 deletions(-) diff --git a/crates/luars/src/gc/gc_object.rs b/crates/luars/src/gc/gc_object.rs index c1b8f011..5e203a96 100644 --- a/crates/luars/src/gc/gc_object.rs +++ b/crates/luars/src/gc/gc_object.rs @@ -483,17 +483,17 @@ impl GcObjectPtr { const PTR_MASK: u64 = (1u64 << 48) - 1; // low 48 bits // Tag values — must match GcObjectKind repr(u8) - const TAG_STRING: u64 = 0; - const TAG_TABLE: u64 = 1; - const TAG_FUNCTION: u64 = 2; - const TAG_CCLOSURE: u64 = 3; - const TAG_RCLOSURE: u64 = 4; - const TAG_UPVALUE: u64 = 5; - const TAG_THREAD: u64 = 6; - const TAG_USERDATA: u64 = 7; - const TAG_PROTO: u64 = 8; - #[inline(always)] - fn new_tagged(ptr: u64, tag: u64) -> Self { + pub const TAG_STRING: u64 = 0; + pub const TAG_TABLE: u64 = 1; + pub const TAG_FUNCTION: u64 = 2; + pub const TAG_CCLOSURE: u64 = 3; + pub const TAG_RCLOSURE: u64 = 4; + pub const TAG_UPVALUE: u64 = 5; + pub const TAG_THREAD: u64 = 6; + pub const TAG_USERDATA: u64 = 7; + pub const TAG_PROTO: u64 = 8; + #[inline(always)] + pub fn new_tagged(ptr: u64, tag: u64) -> Self { debug_assert!( ptr & !Self::PTR_MASK == 0, "pointer exceeds 48 bits: 0x{ptr:016x}" @@ -501,6 +501,11 @@ impl GcObjectPtr { Self(ptr | (tag << Self::TAG_SHIFT)) } + #[inline(always)] + pub fn null() -> Self { + Self(0) + } + #[inline(always)] fn tag(&self) -> u8 { (self.0 >> Self::TAG_SHIFT) as u8 diff --git a/crates/luars/src/lua_value/lua_table/native_table.rs b/crates/luars/src/lua_value/lua_table/native_table.rs index 2c4b5f08..bdc0a9b8 100644 --- a/crates/luars/src/lua_value/lua_table/native_table.rs +++ b/crates/luars/src/lua_value/lua_table/native_table.rs @@ -538,19 +538,6 @@ impl NativeTable { } } - pub fn finish_shortstr_set_parts( - &mut self, - key: &LuaValue, - value: Value, - tt: u8, - result: ShortStrSetResult, - ) -> (bool, isize) { - match result { - ShortStrSetResult::Done { new_key, mem_delta } => (new_key, mem_delta), - other => self.finish_shortstr_set(key, LuaValue::from_raw(value, tt), other), - } - } - fn insert_new_shortstr(&mut self, key: &LuaValue, value: LuaValue) -> (bool, isize) { debug_assert!(key.is_short_string()); debug_assert!(!value.is_nil()); @@ -673,7 +660,7 @@ impl NativeTable { /// Write value to array at Lua index (1-based) #[inline(always)] - pub unsafe fn write_array(&mut self, lua_index: i64, luaval: LuaValue) { + pub(crate) fn write_array(&mut self, lua_index: i64, luaval: LuaValue) { if lua_index < 1 || lua_index > self.asize as i64 { return; } @@ -1431,9 +1418,7 @@ impl NativeTable { } // Move each key: write to array, remove from hash for (k, v) in to_migrate { - unsafe { - self.write_array(k, v); - } + self.write_array(k, v); let key_val = LuaValue::integer(k); self.set_node(key_val, LuaValue::nil()); // mark dead in hash } @@ -1678,9 +1663,7 @@ impl NativeTable { if i >= 1 && i <= self.asize as i64 { // Key is in array range - set in array part ONLY let was_nil = unsafe { self.read_array(i).is_none() }; - unsafe { - self.write_array(i, value); - } + self.write_array(i, value); // DEFENSIVE: If setting to nil, also clear any stale hash entry // for this integer key. This can happen when GC clearing corrupted // lenhint and a key was placed in both array and hash parts. @@ -1700,9 +1683,7 @@ impl NativeTable { if i == current_len + 1 { let new_size = ((i as u32).next_power_of_two()).max(4); let delta = self.resize_array(new_size); - unsafe { - self.write_array(i, value); - } + self.write_array(i, value); self.migrate_hash_int_keys_to_array(); return (true, delta); } diff --git a/crates/luars/src/lua_value/lua_value.rs b/crates/luars/src/lua_value/lua_value.rs index 7ac5111f..ae41f7fd 100644 --- a/crates/luars/src/lua_value/lua_value.rs +++ b/crates/luars/src/lua_value/lua_value.rs @@ -1032,6 +1032,23 @@ impl LuaValue { } } + #[inline(always)] + pub(crate) fn as_gc_ptr_unchecked(&self) -> GcObjectPtr { + // Unsafe version for internal use when caller already knows it's a GC object + let tag = match self.tt { + LUA_VTABLE => GcObjectPtr::TAG_TABLE, + LUA_VFUNCTION => GcObjectPtr::TAG_FUNCTION, + LUA_CCLOSURE => GcObjectPtr::TAG_CCLOSURE, + LUA_VRCLOSURE => GcObjectPtr::TAG_RCLOSURE, + LUA_VSHRSTR | LUA_VLNGSTR => GcObjectPtr::TAG_STRING, + LUA_VTHREAD => GcObjectPtr::TAG_THREAD, + LUA_VUSERDATA => GcObjectPtr::TAG_USERDATA, + // interal use only: caller must ensure it's a valid GC object type + _ => panic!("Invalid GC object type tag: {}", self.tt), + }; + GcObjectPtr::new_tagged(self.raw_ptr() as u64, tag) + } + // ============ Truthiness (Lua semantics) ============ /// l_isfalse - Lua truthiness: only nil and false are falsy diff --git a/crates/luars/src/lua_vm/execute/execute_loop.rs b/crates/luars/src/lua_vm/execute/execute_loop.rs index 1f525627..7356663d 100644 --- a/crates/luars/src/lua_vm/execute/execute_loop.rs +++ b/crates/luars/src/lua_vm/execute/execute_loop.rs @@ -454,30 +454,28 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // R[A] := UpValue[B] let a = instr.get_a(); let b = instr.get_b(); - unsafe { - let upvalue_ptr = *ci.upvalue_ptrs.add(b as usize); - let src = upvalue_ptr.as_ref().data.get_v_stk_id(); - base_stk.offset(a as usize).set(src); - } + + let upvalue_ptr = unsafe { *ci.upvalue_ptrs.add(b as usize) }; + let src = upvalue_ptr.as_ref().data.get_v_stk_id(); + base_stk.offset(a as usize).set(src); } OpCode::SetUpval => { // UpValue[B] := R[A] let a = instr.get_a(); let b = instr.get_b(); - unsafe { - let upvalue_ptr = *ci.upvalue_ptrs.add(b as usize); - let value = base_stk.offset(a as usize).get(); - upvalue_ptr - .as_mut_ref() - .data - .set_value_parts(value.value, value.tt); - - // GC barrier (only for collectable values) - if value.tt & BIT_ISCOLLECTABLE != 0 - && let Some(gc_ptr) = value.as_gc_ptr() - { - lua_state.gc_barrier(upvalue_ptr, gc_ptr); - } + + let upvalue_ptr = unsafe { *ci.upvalue_ptrs.add(b as usize) }; + let value = base_stk.offset(a as usize).get(); + upvalue_ptr + .as_mut_ref() + .data + .set_value_parts(value.value, value.tt); + + // GC barrier (only for collectable values) + if value.tt & BIT_ISCOLLECTABLE != 0 + && let Some(gc_ptr) = value.as_gc_ptr() + { + lua_state.gc_barrier(upvalue_ptr, gc_ptr); } } OpCode::GetTabUp => { @@ -660,25 +658,21 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( .expect("SetTabUp fast path requires collectable table"); meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { - let (new_key, delta, rc_tt) = if instr.get_k() { + let (new_key, delta, is_collectable) = if instr.get_k() { let rc = *k_val(constants, c); let pset_result = table.impl_table.pset_shortstr(key, rc); let (new_key, delta) = table.impl_table.finish_shortstr_set(key, rc, pset_result); - (new_key, delta, rc.tt) + (new_key, delta, rc.is_collectable()) } else { let rc = base_stk.offset(c as usize); - let rc_tt = rc.get().tt; - let rc_value = rc.get().value; - let pset_result = - table.impl_table.pset_shortstr_parts(key, rc_value, rc_tt); - let (new_key, delta) = table.impl_table.finish_shortstr_set_parts( + let pset_result = table.impl_table.pset_shortstr(key, rc.get()); + let (new_key, delta) = table.impl_table.finish_shortstr_set( key, - rc_value, - rc_tt, + rc.get(), pset_result, ); - (new_key, delta, rc_tt) + (new_key, delta, rc.is_collectable()) }; if new_key { table.invalidate_tm_cache(); @@ -686,7 +680,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if delta != 0 { lua_state.gc_track_table_resize(table_ptr, delta); } - if rc_tt & BIT_ISCOLLECTABLE != 0 { + if is_collectable { lua_state.gc_barrier_back(gc_ptr); } continue; @@ -730,50 +724,32 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let b = instr.get_b(); let c = instr.get_c(); // Use StkId-derived raw pointers for fast table access - let ra_stk = base_stk.offset(a as usize); - let rb_stk = base_stk.offset(b as usize); - let ra_ptr = ra_stk.as_const_ptr(); - let rb_ptr = rb_stk.as_const_ptr(); - let ra_val = unsafe { *ra_ptr }; + let ra = base_stk.offset(a as usize); + let rb = base_stk.offset(b as usize); // Hot path: table + integer key in array range, no __newindex // Deferred computation: table_ptr and gc barrier only when needed - if unsafe { (*ra_ptr).is_table() && (*rb_ptr).ttisinteger() } { - let table = unsafe { (*ra_ptr).hvalue_mut() }; - let key = unsafe { (*rb_ptr).ivalue() }; + if ra.is_table() && rb.is_integer() { + let table = ra.hvalue_mut(); + let key = rb.ivalue(); let meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { if !instr.get_k() { - let rc_stk = base_stk.offset(c as usize); - let rc_tt = rc_stk.get().tt; - let rc_value = rc_stk.get().value; - if table.impl_table.fast_seti_parts(key, rc_value, rc_tt) { - if rc_tt & BIT_ISCOLLECTABLE != 0 { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetTable fast path requires table"), - ); + let rc = base_stk.offset(c as usize); + if table.impl_table.fast_seti(key, rc.get()) { + if rc.is_collectable() { + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } - let rc = rc_stk.get(); + let rc = rc.get(); let delta = table.impl_table.set_int_slow(key, rc); if delta != 0 { - lua_state.gc_track_table_resize( - ra_val - .as_table_ptr() - .expect("SetTable fast path requires table"), - delta, - ); + lua_state.gc_track_table_resize(ra.as_table_ptr(), delta); } - if rc_tt & BIT_ISCOLLECTABLE != 0 { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetTable fast path requires table"), - ); + if rc.is_collectable() { + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } @@ -781,30 +757,17 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rc = *k_val(constants, c); if table.impl_table.fast_seti(key, rc) { if rc.is_collectable() { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetTable fast path requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } let delta = table.impl_table.set_int_slow(key, rc); if delta != 0 { - lua_state.gc_track_table_resize( - ra_val - .as_table_ptr() - .expect("SetTable fast path requires table"), - delta, - ); + lua_state.gc_track_table_resize(ra.as_table_ptr(), delta); } if rc.is_collectable() { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetTable fast path requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } else { @@ -815,41 +778,42 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; if table.impl_table.set_existing_int(key, rc) { if rc.is_collectable() { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetTable fast path requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } // Fall through to finishset fallback (known miss) - let ra = unsafe { *ra_ptr }; - let rb = unsafe { *rb_ptr }; let rc = if instr.get_k() { *k_val(constants, c) } else { base_stk.offset(c as usize).get() }; savestate!(); - if call_newindex_tm_fast(lua_state, ci, ra, meta, rb, rc)? { + if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, rb.get(), rc)? { updatetrap!(); continue; } - finishset_fallback(lua_state, ci, &ra, &rb, rc, true)?; + finishset_fallback( + lua_state, + ci, + ra.get_ref(), + rb.get_ref(), + rc, + true, + )?; updatetrap!(); continue; } } // Slow path: shortstr, generic key, non-table, or metamethod - if unsafe { (*ra_ptr).is_table() } { - let table = unsafe { (*ra_ptr).hvalue_mut() }; + if ra.is_table() { + let table = ra.hvalue_mut(); let meta = table.meta_ptr(); if (meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into())) - && unsafe { (*rb_ptr).is_short_string() } + && rb.is_short_string() { - let key = unsafe { &*rb_ptr }; + let key = rb.get_ref(); let (new_key, delta, needs_barrier) = if instr.get_k() { let rc = *k_val(constants, c); let pset_result = table.impl_table.pset_shortstr(key, rc); @@ -857,48 +821,28 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( table.impl_table.finish_shortstr_set(key, rc, pset_result); (new_key, delta, rc.is_collectable() || key.is_collectable()) } else { - let rc_stk = base_stk.offset(c as usize); - let rc_tt = rc_stk.get().tt; - let rc_value = rc_stk.get().value; - let pset_result = - table.impl_table.pset_shortstr_parts(key, rc_value, rc_tt); - let (new_key, delta) = table.impl_table.finish_shortstr_set_parts( + let rc = base_stk.offset(c as usize); + let pset_result = table.impl_table.pset_shortstr(key, rc.get()); + let (new_key, delta) = table.impl_table.finish_shortstr_set( key, - rc_value, - rc_tt, + rc.get(), pset_result, ); - ( - new_key, - delta, - (rc_tt & BIT_ISCOLLECTABLE != 0) - || (unsafe { (*rb_ptr).tt } & BIT_ISCOLLECTABLE != 0), - ) + (new_key, delta, (rc.is_collectable() || rb.is_collectable())) }; if new_key { table.invalidate_tm_cache(); } if delta != 0 { - lua_state.gc_track_table_resize( - ra_val - .as_table_ptr() - .expect("SetTable fast path requires table"), - delta, - ); + lua_state.gc_track_table_resize(ra.as_table_ptr(), delta); } if needs_barrier { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetTable fast path requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } } - let ra = unsafe { *ra_ptr }; - let rb = unsafe { *rb_ptr }; let rc = if instr.get_k() { *k_val(constants, c) } else { @@ -908,48 +852,47 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let table = ra.hvalue_mut(); let meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { - if !rb.is_nil() && !rb.ttisinteger() { - let (_new_key, delta) = table.impl_table.raw_set(&rb, rc); + if !rb.is_nil() && !rb.is_integer() { + let (_new_key, delta) = table.impl_table.raw_set(rb.get_ref(), rc); if delta != 0 { - lua_state.gc_track_table_resize( - ra.as_table_ptr() - .expect("SetTable fallback requires table"), - delta, - ); + lua_state.gc_track_table_resize(ra.as_table_ptr(), delta); } if rc.is_collectable() || rb.is_collectable() { - lua_state.gc_barrier_back( - ra.as_gc_ptr().expect("SetTable fallback requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } } else if rb.is_short_string() { - if table.impl_table.set_existing_shortstr(&rb, rc) { + if table.impl_table.set_existing_shortstr(rb.get_ref(), rc) { if rc.is_collectable() || rb.is_collectable() { - lua_state.gc_barrier_back( - ra.as_gc_ptr().expect("SetTable fallback requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } savestate!(); - if call_newindex_tm_fast(lua_state, ci, ra, meta, rb, rc)? { + if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, rb.get(), rc)? { updatetrap!(); continue; } - finishset_fallback(lua_state, ci, &ra, &rb, rc, true)?; + finishset_fallback( + lua_state, + ci, + ra.get_ref(), + rb.get_ref(), + rc, + true, + )?; updatetrap!(); continue; } } savestate!(); - finishset_fallback(lua_state, ci, &ra, &rb, rc, false)?; + finishset_fallback(lua_state, ci, ra.get_ref(), rb.get_ref(), rc, false)?; updatetrap!(); } OpCode::SetI => { // SETI: R[A][B] := RK(C) (integer key) - let ra = base_stk.offset(instr.get_a() as usize).get(); + let ra = base_stk.offset(instr.get_a() as usize); let b = instr.get_b() as i64; let c = instr.get_c(); @@ -957,29 +900,24 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if ra.is_table() { let table = ra.hvalue_mut(); // Pre-extract table/gc pointers as Copy values to break borrow chain - let table_ptr = ra.as_table_ptr().expect("SetI fast path requires table"); - let gc_ptr = ra - .as_gc_ptr() - .expect("SetI fast path requires collectable table"); + let table_ptr = ra.as_table_ptr(); + let gc_ptr = ra.as_gc_ptr(); let meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { if !instr.get_k() { - let rc_stk = base_stk.offset(c as usize); - let rc_tt = rc_stk.get().tt; - let rc_value = rc_stk.get().value; - if table.impl_table.fast_seti_parts(b, rc_value, rc_tt) { - if rc_tt & BIT_ISCOLLECTABLE != 0 { + let rc = base_stk.offset(c as usize); + if table.impl_table.fast_seti(b, rc.get()) { + if rc.is_collectable() { lua_state.gc_barrier_back(gc_ptr); } continue; } - let rc = rc_stk.get(); - let delta = table.impl_table.set_int_slow(b, rc); + let delta = table.impl_table.set_int_slow(b, rc.get()); if delta != 0 { lua_state.gc_track_table_resize(table_ptr, delta); } - if rc_tt & BIT_ISCOLLECTABLE != 0 { + if rc.is_collectable() { lua_state.gc_barrier_back(gc_ptr); } continue; @@ -1016,11 +954,11 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Fall through to finishset fallback (known miss) let rb = LuaValue::integer(b); savestate!(); - if call_newindex_tm_fast(lua_state, ci, ra, meta, rb, rc)? { + if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, rb, rc)? { updatetrap!(); continue; } - finishset_fallback(lua_state, ci, &ra, &rb, rc, true)?; + finishset_fallback(lua_state, ci, ra.get_ref(), &rb, rc, true)?; updatetrap!(); continue; } @@ -1032,7 +970,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; let rb = LuaValue::integer(b); savestate!(); - finishset_fallback(lua_state, ci, &ra, &rb, rc, false)?; + finishset_fallback(lua_state, ci, ra.get_ref(), &rb, rc, false)?; updatetrap!(); } OpCode::SetField => { @@ -1040,9 +978,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let a = instr.get_a(); let b = instr.get_b(); let c = instr.get_c(); - let ra_stk = base_stk.offset(a as usize); - let ra_ptr = ra_stk.as_const_ptr(); - let ra_val = unsafe { *ra_ptr }; + let ra = base_stk.offset(a as usize); let key = k_val(constants, b); debug_assert!( key.is_short_string(), @@ -1050,47 +986,34 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ); let mut known_newindex_miss = false; let mut meta = TablePtr::null(); - if unsafe { (*ra_ptr).is_table() } { - let table = unsafe { (*ra_ptr).hvalue_mut() }; + if ra.is_table() { + let table = ra.hvalue_mut(); meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { - let (new_key, delta, rc_tt) = if instr.get_k() { + let (new_key, delta, is_collectable) = if instr.get_k() { let rc = *k_val(constants, c); let pset_result = table.impl_table.pset_shortstr(key, rc); let (new_key, delta) = table.impl_table.finish_shortstr_set(key, rc, pset_result); - (new_key, delta, rc.tt) + (new_key, delta, rc.is_collectable()) } else { - let rc_stk = base_stk.offset(c as usize); - let rc_tt = rc_stk.get().tt; - let rc_value = rc_stk.get().value; - let pset_result = - table.impl_table.pset_shortstr_parts(key, rc_value, rc_tt); - let (new_key, delta) = table.impl_table.finish_shortstr_set_parts( + let rc = base_stk.offset(c as usize); + let pset_result = table.impl_table.pset_shortstr(key, rc.get()); + let (new_key, delta) = table.impl_table.finish_shortstr_set( key, - rc_value, - rc_tt, + rc.get(), pset_result, ); - (new_key, delta, rc_tt) + (new_key, delta, rc.is_collectable()) }; if new_key { table.invalidate_tm_cache(); } if delta != 0 { - lua_state.gc_track_table_resize( - ra_val - .as_table_ptr() - .expect("SetField fast path requires table"), - delta, - ); + lua_state.gc_track_table_resize(ra.as_table_ptr(), delta); } - if rc_tt & BIT_ISCOLLECTABLE != 0 { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetField fast path requires table"), - ); + if is_collectable { + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } else { @@ -1101,33 +1024,27 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; if table.impl_table.set_existing_shortstr(key, rc) { if rc.is_collectable() { - lua_state.gc_barrier_back( - ra_val - .as_gc_ptr() - .expect("SetField fast path requires table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr()); } continue; } known_newindex_miss = true; } } - let ra = unsafe { *ra_ptr }; let rc = if instr.get_k() { *k_val(constants, c) } else { base_stk.offset(c as usize).get() }; - let rb = *key; savestate!(); if known_newindex_miss { - if call_newindex_tm_fast(lua_state, ci, ra, meta, rb, rc)? { + if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, *key, rc)? { updatetrap!(); continue; } - finishset_fallback(lua_state, ci, &ra, &rb, rc, true)?; + finishset_fallback(lua_state, ci, ra.get_ref(), key, rc, true)?; } else { - finishset_fallback(lua_state, ci, &ra, &rb, rc, false)?; + finishset_fallback(lua_state, ci, ra.get_ref(), key, rc, false)?; } updatetrap!(); } @@ -2290,9 +2207,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if val.iscollectable() { is_collectable = true; } - unsafe { - impl_table.write_array(write_idx as i64, val); - } + + impl_table.write_array(write_idx as i64, val); write_idx -= 1; } diff --git a/crates/luars/src/lua_vm/stk_id.rs b/crates/luars/src/lua_vm/stk_id.rs index d09c5846..dd5ff462 100644 --- a/crates/luars/src/lua_vm/stk_id.rs +++ b/crates/luars/src/lua_vm/stk_id.rs @@ -10,6 +10,7 @@ use crate::{ LuaRawTable, + gc::{GcObjectPtr, TablePtr}, lua_value::{ LUA_VFALSE, LUA_VNIL, LUA_VNUMFLT, LUA_VNUMINT, LUA_VTRUE, LuaInnerValue, LuaValue, }, @@ -67,6 +68,11 @@ impl StkId { unsafe { (*self.0).is_table() } } + #[inline(always)] + pub fn is_nil(self) -> bool { + unsafe { (*self.0).tt == LUA_VNIL } + } + #[inline(always)] pub fn is_false_or_nil(self) -> bool { unsafe { @@ -97,6 +103,26 @@ impl StkId { unsafe { (*self.0).hvalue() } } + #[inline(always)] + pub fn hvalue_mut(self) -> &'static mut LuaRawTable { + unsafe { (*self.0).hvalue_mut() } + } + + #[inline(always)] + pub fn as_gc_ptr(self) -> GcObjectPtr { + unsafe { (*self.0).as_gc_ptr_unchecked() } + } + + #[inline(always)] + pub fn as_table_ptr(self) -> TablePtr { + unsafe { (*self.0).as_table_ptr().expect("Table pointer expected") } + } + + #[inline(always)] + pub fn is_collectable(self) -> bool { + unsafe { (*self.0).is_collectable() } + } + // ===== Value Writes ===== /// Copy 16 bytes from another stack slot (equivalent to C Lua's setobjs2s). diff --git a/crates/luars/src/stdlib/table.rs b/crates/luars/src/stdlib/table.rs index 245ebf58..7f6c24fd 100644 --- a/crates/luars/src/stdlib/table.rs +++ b/crates/luars/src/stdlib/table.rs @@ -563,9 +563,8 @@ fn table_pack(l: &mut LuaState) -> LuaResult { } // Direct array write — table was created with array size = n, // so indices 1..n are guaranteed in-bounds - unsafe { - impl_table.write_array((i + 1) as i64, arg); - } + + impl_table.write_array((i + 1) as i64, arg); } // Set "n" field through the LuaTable (needs to invalidate TM cache) From 3dc25346efcef47f69794fe09ca84429b1a98987 Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 15:48:03 +0800 Subject: [PATCH 4/7] clean code --- crates/luars/src/gc/gc_object.rs | 1 + .../luars/src/lua_value/lua_table/native_table.rs | 2 +- crates/luars/src/lua_value/lua_value.rs | 3 +-- crates/luars/src/lua_vm/execute/execute_loop.rs | 13 +++---------- crates/luars/src/lua_vm/stk_id.rs | 2 +- 5 files changed, 7 insertions(+), 14 deletions(-) diff --git a/crates/luars/src/gc/gc_object.rs b/crates/luars/src/gc/gc_object.rs index 5e203a96..8a3291f8 100644 --- a/crates/luars/src/gc/gc_object.rs +++ b/crates/luars/src/gc/gc_object.rs @@ -492,6 +492,7 @@ impl GcObjectPtr { pub const TAG_THREAD: u64 = 6; pub const TAG_USERDATA: u64 = 7; pub const TAG_PROTO: u64 = 8; + pub const TAG_NONE: u64 = 9; #[inline(always)] pub fn new_tagged(ptr: u64, tag: u64) -> Self { debug_assert!( diff --git a/crates/luars/src/lua_value/lua_table/native_table.rs b/crates/luars/src/lua_value/lua_table/native_table.rs index bdc0a9b8..6751952d 100644 --- a/crates/luars/src/lua_value/lua_table/native_table.rs +++ b/crates/luars/src/lua_value/lua_table/native_table.rs @@ -388,7 +388,7 @@ impl NativeTable { self.pset_shortstr_parts(key, value.value, value.tt) } - pub fn pset_shortstr_parts( + pub(crate) fn pset_shortstr_parts( &mut self, key: &LuaValue, value: Value, diff --git a/crates/luars/src/lua_value/lua_value.rs b/crates/luars/src/lua_value/lua_value.rs index ae41f7fd..f5ff6db5 100644 --- a/crates/luars/src/lua_value/lua_value.rs +++ b/crates/luars/src/lua_value/lua_value.rs @@ -1043,8 +1043,7 @@ impl LuaValue { LUA_VSHRSTR | LUA_VLNGSTR => GcObjectPtr::TAG_STRING, LUA_VTHREAD => GcObjectPtr::TAG_THREAD, LUA_VUSERDATA => GcObjectPtr::TAG_USERDATA, - // interal use only: caller must ensure it's a valid GC object type - _ => panic!("Invalid GC object type tag: {}", self.tt), + _ => GcObjectPtr::TAG_NONE, }; GcObjectPtr::new_tagged(self.raw_ptr() as u64, tag) } diff --git a/crates/luars/src/lua_vm/execute/execute_loop.rs b/crates/luars/src/lua_vm/execute/execute_loop.rs index 7356663d..58afb3b5 100644 --- a/crates/luars/src/lua_vm/execute/execute_loop.rs +++ b/crates/luars/src/lua_vm/execute/execute_loop.rs @@ -650,12 +650,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let mut meta = TablePtr::null(); if upval_value.is_table() { let table = upval_value.hvalue_mut(); - let table_ptr = upval_value - .as_table_ptr() - .expect("SetTabUp fast path requires table"); - let gc_ptr = upval_value - .as_gc_ptr() - .expect("SetTabUp fast path requires collectable table"); + let table_ptr = upval_value.table_ptr_raw(); + let gc_ptr = upval_value.as_gc_ptr_unchecked(); meta = table.meta_ptr(); if meta.is_null() || meta.as_mut_ref().data.no_tm(TmKind::NewIndex.into()) { let (new_key, delta, is_collectable) = if instr.get_k() { @@ -2213,10 +2209,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } if is_collectable { - lua_state.gc_barrier_back( - ra.as_gc_ptr() - .expect("SetList fast path requires collectable table"), - ); + lua_state.gc_barrier_back(ra.as_gc_ptr_unchecked()); } } OpCode::Closure => { diff --git a/crates/luars/src/lua_vm/stk_id.rs b/crates/luars/src/lua_vm/stk_id.rs index dd5ff462..c4884f47 100644 --- a/crates/luars/src/lua_vm/stk_id.rs +++ b/crates/luars/src/lua_vm/stk_id.rs @@ -115,7 +115,7 @@ impl StkId { #[inline(always)] pub fn as_table_ptr(self) -> TablePtr { - unsafe { (*self.0).as_table_ptr().expect("Table pointer expected") } + unsafe { (*self.0).table_ptr_raw() } } #[inline(always)] From 7c48d5a1fe16e97a99c6cdd404f5f90a2f8dbb9b Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 16:52:10 +0800 Subject: [PATCH 5/7] optimize performance --- .../luars/src/lua_vm/execute/execute_loop.rs | 60 ++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/crates/luars/src/lua_vm/execute/execute_loop.rs b/crates/luars/src/lua_vm/execute/execute_loop.rs index 58afb3b5..a7f985d2 100644 --- a/crates/luars/src/lua_vm/execute/execute_loop.rs +++ b/crates/luars/src/lua_vm/execute/execute_loop.rs @@ -349,10 +349,6 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( macro_rules! updatetrap { () => { - // Always reload base_stk — the stack may have been reallocated - // by a metamethod call or other operation since our last reload. - base_stk = ci.base_stk; - #[cfg(not(feature = "sandbox"))] { trap = lua_state.hook_mask != 0; @@ -365,6 +361,15 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; } + // Re-sync base_stk after any operation that might have reallocated + // the stack (metamethod calls, concat, close_all, etc.). + // Unlike updatetrap!, this is NOT on the arithmetic / comparison hot path. + macro_rules! syncbase { + () => { + base_stk = ci.base_stk; + }; + } + macro_rules! savestate { () => { ci.save_pc(pc); @@ -530,6 +535,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); let upval_value = *upval_value; finishget_fallback(lua_state, ci, &upval_value, key, dest)?; + syncbase!(); updatetrap!(); } OpCode::GetTable => { @@ -571,6 +577,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); finishget_fallback(lua_state, ci, rb.get_ref(), rc.get_ref(), dest)?; + syncbase!(); updatetrap!(); continue; } @@ -578,6 +585,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Metamethod / non-table fallback savestate!(); finishget_fallback(lua_state, ci, rb.get_ref(), rc.get_ref(), dest)?; + syncbase!(); updatetrap!(); } OpCode::GetI => { @@ -604,6 +612,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); finishget_fallback(lua_state, ci, rb.get_ref(), &LuaValue::integer(rc), dest)?; + syncbase!(); updatetrap!(); } OpCode::GetField => { @@ -632,6 +641,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( key, base_stk.offset(instr.get_a() as usize), )?; + syncbase!(); updatetrap!(); } OpCode::SetTabUp => { @@ -705,6 +715,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); if known_newindex_miss { if call_newindex_tm_fast(lua_state, ci, upval_value, meta, *key, rc)? { + syncbase!(); updatetrap!(); continue; } @@ -712,6 +723,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } else { finishset_fallback(lua_state, ci, &upval_value, key, rc, false)?; } + syncbase!(); updatetrap!(); } OpCode::SetTable => { @@ -786,6 +798,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; savestate!(); if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, rb.get(), rc)? { + syncbase!(); updatetrap!(); continue; } @@ -797,6 +810,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( rc, true, )?; + syncbase!(); updatetrap!(); continue; } @@ -867,6 +881,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } savestate!(); if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, rb.get(), rc)? { + syncbase!(); updatetrap!(); continue; } @@ -878,12 +893,14 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( rc, true, )?; + syncbase!(); updatetrap!(); continue; } } savestate!(); finishset_fallback(lua_state, ci, ra.get_ref(), rb.get_ref(), rc, false)?; + syncbase!(); updatetrap!(); } OpCode::SetI => { @@ -951,10 +968,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rb = LuaValue::integer(b); savestate!(); if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, rb, rc)? { + syncbase!(); updatetrap!(); continue; } finishset_fallback(lua_state, ci, ra.get_ref(), &rb, rc, true)?; + syncbase!(); updatetrap!(); continue; } @@ -967,6 +986,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rb = LuaValue::integer(b); savestate!(); finishset_fallback(lua_state, ci, ra.get_ref(), &rb, rc, false)?; + syncbase!(); updatetrap!(); } OpCode::SetField => { @@ -1035,6 +1055,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); if known_newindex_miss { if call_newindex_tm_fast(lua_state, ci, ra.get(), meta, *key, rc)? { + syncbase!(); updatetrap!(); continue; } @@ -1042,6 +1063,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } else { finishset_fallback(lua_state, ci, ra.get_ref(), key, rc, false)?; } + syncbase!(); updatetrap!(); } OpCode::NewTable => { @@ -1070,12 +1092,8 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( base_stk.offset(a as usize).write(&value); let new_top = ci.base + a as usize + 1; - // ci.save_pc(pc); - // lua_state.set_top_raw(new_top); - // lua_state.check_gc()?; - // let frame_top = ci.top; - // lua_state.set_top_raw(frame_top as usize); lua_state.check_gc_in_loop(pc, new_top, &mut trap); + syncbase!(); } OpCode::Self_ => { // SELF: R[A+1] := R[B]; R[A] := R[B][K[C]:string] @@ -1103,6 +1121,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( key, base_stk.offset(a as usize), ) { + syncbase!(); updatetrap!(); continue; } @@ -1110,6 +1129,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); finishget_fallback(lua_state, ci, &rb, key, base_stk.offset(a as usize))?; + syncbase!(); updatetrap!(); } OpCode::Add => { @@ -1332,6 +1352,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); bin_tm_fallback(lua_state, ci, ra, rb, result_reg, a as u32, b as u32, tm)?; + syncbase!(); updatetrap!(); } OpCode::MmBinI => { @@ -1348,6 +1369,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let r = if flip { (rb, ra) } else { (ra, rb) }; savestate!(); bin_tm_fallback(lua_state, ci, r.0, r.1, result_reg, a as u32, a as u32, tm)?; + syncbase!(); updatetrap!(); } OpCode::MmBinK => { @@ -1363,6 +1385,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); let r = if flip { (imm, ra) } else { (ra, imm) }; bin_tm_fallback(lua_state, ci, r.0, r.1, result_reg, a_reg, a_reg, tm)?; + syncbase!(); updatetrap!(); } OpCode::Unm => { @@ -1387,6 +1410,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ci.base + a as usize, TmKind::Unm, )?; + syncbase!(); updatetrap!(); } } @@ -1403,6 +1427,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } else { savestate!(); unary_tm_fallback(lua_state, ci, rb, ci.base + a as usize, TmKind::Bnot)?; + syncbase!(); updatetrap!(); } } @@ -1425,6 +1450,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rb = base_stk.offset(b as usize).get(); savestate!(); objlen(lua_state, ci, base_stk.offset(a as usize), rb)?; + syncbase!(); updatetrap!(); } OpCode::Concat => { @@ -1445,6 +1471,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let top = lua_state.get_top(); lua_state.check_gc_in_loop(pc, top, &mut trap); + syncbase!(); continue; } } @@ -1466,6 +1493,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let top = lua_state.get_top(); lua_state.check_gc_in_loop(pc, top, &mut trap); + syncbase!(); } OpCode::Close => { let a = instr.get_a(); @@ -1474,6 +1502,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( ci.save_pc(pc); match lua_state.close_all(close_from) { Ok(()) => { + syncbase!(); updatetrap!(); } Err(LuaError::Yield) => { @@ -1501,6 +1530,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let rb = base_stk.offset(b as usize).get(); savestate!(); let cond = eq_fallback(lua_state, ci, ra, rb)?; + syncbase!(); updatetrap!(); let k = instr.get_k(); if cond != k { @@ -1508,6 +1538,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( } else { let jmp = instr_at(code, pc); pc = ((pc + 1) as isize + jmp.get_sj() as isize) as usize; + syncbase!(); updatetrap!(); } } @@ -1537,6 +1568,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let vb = *rb; savestate!(); let result = order_tm_fallback(lua_state, ci, va, vb, TmKind::Lt)?; + syncbase!(); updatetrap!(); result } @@ -1577,6 +1609,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( let vb = *rb; savestate!(); let result = order_tm_fallback(lua_state, ci, va, vb, TmKind::Le)?; + syncbase!(); updatetrap!(); result } @@ -1650,6 +1683,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; savestate!(); let result = order_tm_fallback(lua_state, ci, va, vb, TmKind::Lt)?; + syncbase!(); updatetrap!(); result } @@ -1685,6 +1719,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( }; savestate!(); let result = order_tm_fallback(lua_state, ci, va, vb, TmKind::Le)?; + syncbase!(); updatetrap!(); result } @@ -1721,6 +1756,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); // GtI: a > b ≡ b < a → swap args, use Lt let result = order_tm_fallback(lua_state, ci, vb, va, TmKind::Lt)?; + syncbase!(); updatetrap!(); result } @@ -1757,6 +1793,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); // GeI: a >= b ≡ b <= a → swap args, use Le let result = order_tm_fallback(lua_state, ci, vb, va, TmKind::Le)?; + syncbase!(); updatetrap!(); result } @@ -1897,6 +1934,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if lua_state.hook_mask & LUA_MASKLINE != 0 { lua_state.oldpc = (pc - 1) as u32; } + syncbase!(); updatetrap!(); } OpCode::TailCall => { @@ -1923,6 +1961,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( if lua_state.hook_mask & LUA_MASKLINE != 0 { lua_state.oldpc = (pc - 1) as u32; } + syncbase!(); updatetrap!(); } OpCode::Return => { @@ -2113,6 +2152,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( // Skip the loop body: jump forward past FORLOOP pc += instr.get_bx() as usize + 1; } + syncbase!(); updatetrap!(); } OpCode::TForPrep => { @@ -2221,6 +2261,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( push_closure(lua_state, ci.base, a, proto_idx, chunk, upvalue_ptrs)?; lua_state.check_gc_in_loop(pc, ci.base + a + 1, &mut trap); + syncbase!(); } OpCode::Vararg => { let a = instr.get_a() as usize; @@ -2231,6 +2272,7 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<( savestate!(); match get_varargs(lua_state, ci.base, a, b, vatab, n, chunk) { Ok(()) => { + syncbase!(); updatetrap!(); } Err(LuaError::Yield) => { From c080ccd3d028eb259e60e0712276b491ab53b254 Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 17:38:48 +0800 Subject: [PATCH 6/7] better performance --- crates/luars/src/lua_vm/stk_id.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/luars/src/lua_vm/stk_id.rs b/crates/luars/src/lua_vm/stk_id.rs index c4884f47..51679906 100644 --- a/crates/luars/src/lua_vm/stk_id.rs +++ b/crates/luars/src/lua_vm/stk_id.rs @@ -129,7 +129,10 @@ impl StkId { #[inline(always)] pub fn set(self, src: StkId) { unsafe { - *self.0 = *src.0; + // this is effectively a memcpy of the entire LuaValue (16 bytes), including the type tag and value fields + let src = *src.0; + (*self.0).tt = src.tt; + (*self.0).value = src.value; } } @@ -137,7 +140,8 @@ impl StkId { #[inline(always)] pub fn write(self, v: &LuaValue) { unsafe { - *self.0 = *v; + (*self.0).tt = v.tt; + (*self.0).value = v.value; } } @@ -215,4 +219,8 @@ impl StkId { pub fn get_ref(self) -> &'static LuaValue { unsafe { &*self.0 } } + + pub fn get_parts(self) -> (u8, LuaInnerValue) { + unsafe { ((*self.0).tt, (*self.0).value) } + } } From d10abacdec07bba1f4a5ec6683043b27630c806f Mon Sep 17 00:00:00 2001 From: CppCXY <812125110@qq.com> Date: Fri, 5 Jun 2026 19:02:54 +0800 Subject: [PATCH 7/7] optimize instruction --- crates/luars/src/lua_vm/opcode/instruction.rs | 94 ++++++++++--------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/crates/luars/src/lua_vm/opcode/instruction.rs b/crates/luars/src/lua_vm/opcode/instruction.rs index efb86f15..28c7d139 100644 --- a/crates/luars/src/lua_vm/opcode/instruction.rs +++ b/crates/luars/src/lua_vm/opcode/instruction.rs @@ -67,6 +67,7 @@ impl Instruction { pub const POS_SJ: u32 = Self::POS_A; // Maximum values + pub const MAX_OP: u32 = (1 << Self::SIZE_OP) - 1; pub const MAX_A: u32 = (1 << Self::SIZE_A) - 1; pub const MAX_B: u32 = (1 << Self::SIZE_B) - 1; pub const MAX_C: u32 = (1 << Self::SIZE_C) - 1; @@ -82,7 +83,7 @@ impl Instruction { pub const OFFSET_SBX: i32 = (Self::MAX_BX >> 1) as i32; pub const OFFSET_SJ: i32 = (Self::MAX_SJ >> 1) as i32; - // Create masks + // Generic mask helpers (used by setters and uncommon getters) #[inline(always)] fn mask1(n: u32, p: u32) -> u32 { (!((!0u32) << n)) << p @@ -93,110 +94,115 @@ impl Instruction { !Self::mask1(n, p) } - // Get/Set opcode + // ── Hot getters — direct const-folded shift+mask (endian-agnostic) ── + // + // Each method expands to a single `(word >> CONST) & CONST` that LLVM + // folds into the optimal 1–2 instruction sequence on any architecture. + // No function call to `get_arg`, no runtime `mask1` computation. + #[inline(always)] pub fn get_opcode(self) -> OpCode { - let op_byte = ((self.0 >> Self::POS_OP) & Self::mask1(Self::SIZE_OP, 0)) as u8; - OpCode::from_u8(op_byte) + OpCode::from_u8((self.0 & Self::MAX_OP) as u8) } #[inline(always)] - pub fn set_opcode(&mut self, op: OpCode) { - self.0 = (self.0 & Self::mask0(Self::SIZE_OP, Self::POS_OP)) - | (((op as u32) << Self::POS_OP) & Self::mask1(Self::SIZE_OP, Self::POS_OP)); + pub fn get_a(self) -> u32 { + (self.0 >> Self::POS_A) & Self::MAX_A } - // Generic argument getter #[inline(always)] - fn get_arg(&self, pos: u32, size: u32) -> u32 { - (self.0 >> pos) & Self::mask1(size, 0) + pub fn get_b(self) -> u32 { + (self.0 >> Self::POS_B) & Self::MAX_B } - // Generic argument setter #[inline(always)] - fn set_arg(&mut self, v: u32, pos: u32, size: u32) { - self.0 = (self.0 & Self::mask0(size, pos)) | ((v << pos) & Self::mask1(size, pos)); + pub fn get_c(self) -> u32 { + (self.0 >> Self::POS_C) & Self::MAX_C } - // Field accessors #[inline(always)] - pub fn get_a(self) -> u32 { - self.get_arg(Self::POS_A, Self::SIZE_A) + pub fn get_k(self) -> bool { + (self.0 >> Self::POS_K) & 1 != 0 } #[inline(always)] - pub fn set_a(&mut self, v: u32) { - self.set_arg(v, Self::POS_A, Self::SIZE_A); + pub fn get_bx(self) -> u32 { + (self.0 >> Self::POS_BX) & Self::MAX_BX } #[inline(always)] - pub fn get_b(self) -> u32 { - self.get_arg(Self::POS_B, Self::SIZE_B) + pub fn get_ax(self) -> u32 { + (self.0 >> Self::POS_AX) & Self::MAX_AX } + // ── Derived signed getters ── + #[inline(always)] pub fn get_sb(self) -> i32 { self.get_b() as i32 - Self::OFFSET_SB } #[inline(always)] - pub fn set_b(&mut self, v: u32) { - self.set_arg(v, Self::POS_B, Self::SIZE_B); + pub fn get_sc(self) -> i32 { + self.get_c() as i32 - Self::OFFSET_SC } #[inline(always)] - pub fn get_c(self) -> u32 { - self.get_arg(Self::POS_C, Self::SIZE_C) + pub fn get_sbx(self) -> i32 { + self.get_bx() as i32 - Self::OFFSET_SBX } #[inline(always)] - pub fn get_sc(self) -> i32 { - self.get_c() as i32 - Self::OFFSET_SC + pub fn get_sj(self) -> i32 { + self.get_ax() as i32 - Self::OFFSET_SJ } + // ── Setters and rare getters (keep generic shift/mask) ── + #[inline(always)] - pub fn set_c(&mut self, v: u32) { - self.set_arg(v, Self::POS_C, Self::SIZE_C); + pub fn set_opcode(&mut self, op: OpCode) { + self.0 = (self.0 & Self::mask0(Self::SIZE_OP, Self::POS_OP)) + | (((op as u32) << Self::POS_OP) & Self::mask1(Self::SIZE_OP, Self::POS_OP)); } #[inline(always)] - pub fn get_k(self) -> bool { - self.get_arg(Self::POS_K, Self::SIZE_K) != 0 + fn get_arg(&self, pos: u32, size: u32) -> u32 { + (self.0 >> pos) & Self::mask1(size, 0) } #[inline(always)] - pub fn set_k(&mut self, v: bool) { - self.set_arg(if v { 1 } else { 0 }, Self::POS_K, Self::SIZE_K); + fn set_arg(&mut self, v: u32, pos: u32, size: u32) { + self.0 = (self.0 & Self::mask0(size, pos)) | ((v << pos) & Self::mask1(size, pos)); } #[inline(always)] - pub fn get_bx(self) -> u32 { - self.get_arg(Self::POS_BX, Self::SIZE_BX) + pub fn set_a(&mut self, v: u32) { + self.set_arg(v, Self::POS_A, Self::SIZE_A); } #[inline(always)] - pub fn get_sbx(self) -> i32 { - self.get_bx() as i32 - Self::OFFSET_SBX + pub fn set_b(&mut self, v: u32) { + self.set_arg(v, Self::POS_B, Self::SIZE_B); } #[inline(always)] - pub fn set_bx(&mut self, v: u32) { - self.set_arg(v, Self::POS_BX, Self::SIZE_BX); + pub fn set_c(&mut self, v: u32) { + self.set_arg(v, Self::POS_C, Self::SIZE_C); } #[inline(always)] - pub fn get_ax(self) -> u32 { - self.get_arg(Self::POS_AX, Self::SIZE_AX) + pub fn set_k(&mut self, v: bool) { + self.set_arg(if v { 1 } else { 0 }, Self::POS_K, Self::SIZE_K); } #[inline(always)] - pub fn set_ax(&mut self, v: u32) { - self.set_arg(v, Self::POS_AX, Self::SIZE_AX); + pub fn set_bx(&mut self, v: u32) { + self.set_arg(v, Self::POS_BX, Self::SIZE_BX); } #[inline(always)] - pub fn get_sj(self) -> i32 { - self.get_arg(Self::POS_SJ, Self::SIZE_SJ) as i32 - Self::OFFSET_SJ + pub fn set_ax(&mut self, v: u32) { + self.set_arg(v, Self::POS_AX, Self::SIZE_AX); } #[inline(always)]