luaur_code_gen/functions/
execute_dupclosure.rs1use 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}