Skip to main content

luaur_code_gen/functions/
execute_dupclosure.rs

1use crate::macros::vm_protect::vm_protect;
2use crate::macros::vm_protect_pc::VM_PROTECT_PC;
3use crate::macros::vm_reg::VM_REG;
4use crate::type_aliases::instruction_ir_builder::Instruction;
5use crate::type_aliases::lua_state::lua_State;
6use luaur_common::enums::luau_capture_type::LuauCaptureType;
7use luaur_common::enums::luau_opcode::LuauOpcode;
8use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
9use luaur_common::macros::luau_insn_b::LUAU_INSN_B;
10use luaur_common::macros::luau_insn_d::LUAU_INSN_D;
11use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
12use luaur_vm::functions::lua_f_new_lclosure::lua_f_new_lclosure;
13use luaur_vm::functions::lua_o_rawequal_obj::luaO_rawequalObj;
14use luaur_vm::macros::clvalue::clvalue;
15use luaur_vm::macros::lua_c_barrier::luaC_barrier;
16use luaur_vm::macros::lua_c_check_gc::luaC_checkGC;
17use luaur_vm::macros::setclvalue::setclvalue;
18use luaur_vm::macros::setobj::setobj;
19use luaur_vm::type_aliases::stk_id::StkId;
20use luaur_vm::type_aliases::t_value::TValue;
21
22pub unsafe fn execute_dupclosure(
23    L: *mut lua_State,
24    pc: *const Instruction,
25    base: StkId,
26    k: *mut TValue,
27) -> *const Instruction {
28    let l_ptr = L as *mut luaur_vm::records::lua_state::lua_State;
29    let cl = clvalue!((*(*l_ptr).ci).func);
30
31    let mut pc_ptr = pc;
32    let insn = *pc_ptr;
33    pc_ptr = pc_ptr.add(1);
34    let ra = VM_REG!(LUAU_INSN_A(insn) as i32, l_ptr, base);
35    let kv = k.add(LUAU_INSN_D(insn) as usize);
36
37    let kcl = clvalue!(kv as *const TValue);
38
39    VM_PROTECT_PC(l_ptr, pc_ptr);
40
41    let mut ncl = if (*kcl).env == (*cl).env {
42        kcl
43    } else {
44        let kp = {
45            let l = &(*kcl).inner.l;
46            l.p
47        };
48        lua_f_new_lclosure(l_ptr, (*kcl).nupvalues as i32, (*cl).env, kp)
49    };
50    setclvalue!(l_ptr, ra, ncl);
51
52    let mut ui: i32 = 0;
53    while ui < (*kcl).nupvalues as i32 {
54        let uinsn = *pc_ptr.add(ui as usize);
55        luaur_common::LUAU_ASSERT!(LUAU_INSN_OP(uinsn) == LuauOpcode::LOP_CAPTURE as u32);
56        luaur_common::LUAU_ASSERT!(
57            LUAU_INSN_A(uinsn) == LuauCaptureType::LCT_VAL as u32
58                || LUAU_INSN_A(uinsn) == LuauCaptureType::LCT_UPVAL as u32
59        );
60
61        let uv: *mut TValue = if LUAU_INSN_A(uinsn) == LuauCaptureType::LCT_VAL as u32 {
62            VM_REG!(LUAU_INSN_B(uinsn), l_ptr, base) as *mut TValue
63        } else {
64            let l = &mut (*cl).inner.l;
65            l.uprefs.as_mut_ptr().add(LUAU_INSN_B(uinsn) as usize)
66        };
67
68        let uref = {
69            let l = &mut (*ncl).inner.l;
70            l.uprefs.as_mut_ptr().add(ui as usize)
71        };
72
73        if ncl == kcl && luaO_rawequalObj(uref as *const TValue, uv as *const TValue) != 0 {
74            ui += 1;
75            continue;
76        }
77
78        if ncl == kcl && (*kcl).preload == 0 {
79            let kp = {
80                let l = &(*kcl).inner.l;
81                l.p
82            };
83            ncl = lua_f_new_lclosure(l_ptr, (*kcl).nupvalues as i32, (*cl).env, kp);
84            setclvalue!(l_ptr, ra, ncl);
85
86            ui = 0;
87            continue;
88        }
89
90        setobj!(l_ptr, uref, uv as *const TValue);
91        luaC_barrier!(l_ptr, ncl, uv as *const TValue);
92        ui += 1;
93    }
94
95    (*ncl).preload = 0;
96
97    if kcl != ncl {
98        let mut current_base = base;
99        vm_protect!(l_ptr, pc_ptr, current_base, {
100            luaC_checkGC!(l_ptr);
101        });
102    }
103
104    pc_ptr.add((*kcl).nupvalues as usize)
105}
106
107#[no_mangle]
108pub unsafe extern "C" fn executeDUPCLOSURE(
109    L: *mut lua_State,
110    pc: *const Instruction,
111    base: StkId,
112    k: *mut TValue,
113) -> *const Instruction {
114    execute_dupclosure(L, pc, base, k)
115}