Skip to main content

luaur_code_gen/functions/
execute_prepvarargs.rs

1use luaur_common::macros::luau_assert::LUAU_ASSERT;
2use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
3use luaur_vm::macros::cast_int::cast_int;
4use luaur_vm::macros::clvalue::clvalue;
5use luaur_vm::macros::setnilvalue::setnilvalue;
6use luaur_vm::macros::setobj_2_s::setobj_2_s as setobj2s;
7use luaur_vm::type_aliases::stk_id::StkId;
8use luaur_vm::type_aliases::t_value::TValue;
9
10use crate::macros::vm_protect::vm_protect as VM_PROTECT;
11use crate::type_aliases::instruction_ir_builder::Instruction;
12use crate::type_aliases::lua_state::lua_State;
13
14pub unsafe fn execute_prepvarargs(
15    L: *mut lua_State,
16    pc: *const Instruction,
17    mut base: StkId,
18    _k: *mut TValue,
19) -> *const Instruction {
20    let l_ptr = L as *mut luaur_vm::records::lua_state::lua_State;
21    let cl = clvalue!((*(*l_ptr).ci).func);
22    let mut pc_ptr = pc;
23    let insn = *pc_ptr;
24    pc_ptr = pc_ptr.add(1);
25    let numparams = LUAU_INSN_A(insn) as i32;
26
27    // all fixed parameters are copied after the top so we need more stack space
28    VM_PROTECT!(l_ptr, pc_ptr as *const u32, base, {
29        let n = (*cl).stacksize as i32 + numparams;
30        if luaur_vm::macros::stacklimitreached::stacklimitreached(l_ptr, n) {
31            luaur_vm::functions::lua_d_growstack::lua_d_growstack(l_ptr, n);
32        } else {
33            // condhardstacktests expansion:
34            // In Luau, condhardstacktests is usually gated by a debug flag or internal check.
35            // Since LuauCheckStackVariable was not found, we use the standard VM logic
36            // which often omits the hard stack test in production or uses a different flag.
37            // We'll follow the luaD_checkstack macro logic but skip the missing FFlag.
38        }
39    });
40
41    LUAU_ASSERT!(cast_int!((*l_ptr).top.offset_from(base)) >= numparams);
42
43    // move fixed parameters to final position
44    let fixed = base; // first fixed argument
45    let new_base = (*l_ptr).top; // final position of first argument
46
47    for i in 0..numparams {
48        setobj2s!(l_ptr, new_base.add(i as usize), fixed.add(i as usize));
49        setnilvalue!(fixed.add(i as usize));
50    }
51
52    // rewire our stack frame to point to the new base
53    (*(*l_ptr).ci).base = new_base;
54    (*(*l_ptr).ci).top = new_base.add((*cl).stacksize as usize);
55
56    (*l_ptr).base = new_base;
57    (*l_ptr).top = (*(*l_ptr).ci).top;
58
59    pc_ptr
60}
61
62#[no_mangle]
63pub unsafe extern "C" fn executePREPVARARGS(
64    L: *mut lua_State,
65    pc: *const Instruction,
66    base: StkId,
67    k: *mut TValue,
68) -> *const Instruction {
69    execute_prepvarargs(L, pc, base, k)
70}