Skip to main content

luaur_code_gen/functions/
execute_namecall.rs

1use crate::macros::vm_patch_c::VM_PATCH_C;
2use crate::macros::vm_protect::vm_protect;
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_opcode::LuauOpcode;
7use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
8use luaur_common::macros::luau_insn_aux_kv_16::LUAU_INSN_AUX_KV16;
9use luaur_common::macros::luau_insn_b::LUAU_INSN_B;
10use luaur_common::macros::luau_insn_c::LUAU_INSN_C;
11use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
12use luaur_vm::functions::lua_g_methoderror::luaG_methoderror;
13use luaur_vm::functions::lua_v_gettable::lua_v_gettable;
14use luaur_vm::macros::clvalue::clvalue;
15use luaur_vm::macros::fasttm::fasttm;
16use luaur_vm::macros::gkey::{gkey, gval};
17use luaur_vm::macros::hvalue::hvalue;
18use luaur_vm::macros::setobj_2_s::setobj_2_s as setobj2s;
19use luaur_vm::macros::tsvalue::tsvalue;
20use luaur_vm::macros::ttisnil::ttisnil;
21use luaur_vm::macros::ttisstring::ttisstring;
22use luaur_vm::macros::ttistable::ttistable;
23use luaur_vm::macros::ttisuserdata::ttisuserdata;
24use luaur_vm::macros::ttype::ttype;
25use luaur_vm::macros::uvalue::uvalue;
26use luaur_vm::type_aliases::stk_id::StkId;
27use luaur_vm::type_aliases::t_value::TValue;
28use luaur_vm::type_aliases::tms::TMS;
29
30#[inline]
31unsafe fn vm_kv(
32    i: u32,
33    cl: *mut luaur_vm::records::closure::Closure,
34    k: *mut TValue,
35) -> *mut TValue {
36    let p = {
37        let l = &(*cl).inner.l;
38        l.p
39    };
40    luaur_common::LUAU_ASSERT!(i < (*p).sizek as u32);
41    k.add(i as usize)
42}
43
44pub unsafe fn execute_namecall(
45    L: *mut lua_State,
46    pc: *const Instruction,
47    mut base: StkId,
48    k: *mut TValue,
49) -> *const Instruction {
50    let cl = clvalue!((*(*L).ci).func);
51    let mut pc_ptr = pc;
52    let insn = *pc_ptr;
53    pc_ptr = pc_ptr.add(1);
54    let op = LUAU_INSN_OP(insn);
55    let mut ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
56    let rb = VM_REG!(LUAU_INSN_B(insn) as i32, L, base) as *mut TValue;
57    let aux = *pc_ptr;
58    pc_ptr = pc_ptr.add(1);
59    let kv = vm_kv(
60        if op == LuauOpcode::LOP_NAMECALLUDATA as u32 {
61            LUAU_INSN_AUX_KV16(aux)
62        } else {
63            aux
64        },
65        cl,
66        k,
67    );
68    luaur_common::LUAU_ASSERT!(ttisstring!(kv as *const TValue));
69
70    if ttistable!(rb as *const TValue) {
71        setobj2s!(L, ra.add(1), rb as *const TValue);
72        (*L).cachedslot = LUAU_INSN_C(insn) as i32;
73        vm_protect!(L, pc_ptr, base, {
74            lua_v_gettable(L, rb as *const TValue, kv, ra);
75        });
76        VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);
77
78        ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
79        if ttisnil!(ra as *const TValue) {
80            luaG_methoderror(L, ra.add(1) as *const TValue, tsvalue!(kv as *const TValue));
81        }
82    } else {
83        let mt = if ttisuserdata!(rb as *const TValue) {
84            (*uvalue!(rb as *const TValue)).metatable
85        } else {
86            (*(*L).global).mt[ttype!(rb as *const TValue) as usize]
87        };
88
89        let fn_nc = fasttm(L, mt, TMS::TM_NAMECALL as i32);
90        if !fn_nc.is_null() {
91            setobj2s!(L, ra.add(1), rb as *const TValue);
92            setobj2s!(L, ra, fn_nc);
93
94            (*L).namecall = tsvalue!(kv as *const TValue) as *mut _;
95        } else {
96            let tmi = fasttm(L, mt, TMS::TM_INDEX as i32);
97            if !tmi.is_null() && ttistable!(tmi) {
98                let h = hvalue!(tmi);
99                let slot = (LUAU_INSN_C(insn) as i32) & (*h).nodemask8 as i32;
100                let n = (*h).node.add(slot as usize);
101
102                if ttisstring!(gkey!(n) as *const TValue)
103                    && tsvalue!(gkey!(n) as *const TValue) == tsvalue!(kv as *const TValue)
104                    && !ttisnil!(gval!(n))
105                {
106                    setobj2s!(L, ra.add(1), rb as *const TValue);
107                    setobj2s!(L, ra, gval!(n));
108                } else {
109                    setobj2s!(L, ra.add(1), rb as *const TValue);
110                    (*L).cachedslot = slot;
111                    vm_protect!(L, pc_ptr, base, {
112                        lua_v_gettable(L, rb as *const TValue, kv, ra);
113                    });
114                    VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);
115
116                    ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
117                    if ttisnil!(ra as *const TValue) {
118                        luaG_methoderror(
119                            L,
120                            ra.add(1) as *const TValue,
121                            tsvalue!(kv as *const TValue),
122                        );
123                    }
124                }
125            } else {
126                setobj2s!(L, ra.add(1), rb as *const TValue);
127                vm_protect!(L, pc_ptr, base, {
128                    lua_v_gettable(L, rb as *const TValue, kv, ra);
129                });
130
131                ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
132                if ttisnil!(ra as *const TValue) {
133                    luaG_methoderror(L, ra.add(1) as *const TValue, tsvalue!(kv as *const TValue));
134                }
135            }
136        }
137    }
138
139    luaur_common::LUAU_ASSERT!(
140        LUAU_INSN_OP(*pc_ptr) == LuauOpcode::LOP_CALL as u32
141            || LUAU_INSN_OP(*pc_ptr) == LuauOpcode::LOP_CALLFB as u32
142    );
143    pc_ptr
144}
145
146#[no_mangle]
147pub unsafe extern "C" fn executeNAMECALL(
148    L: *mut lua_State,
149    pc: *const Instruction,
150    base: StkId,
151    k: *mut TValue,
152) -> *const Instruction {
153    execute_namecall(L, pc, base, k)
154}