Skip to main content

luaur_code_gen/functions/
execute_gettableks.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::enums::lua_type::lua_Type;
13use luaur_vm::functions::lua_h_getstr::luaH_getstr;
14use luaur_vm::functions::lua_v_call_tm::lua_v_call_tm;
15use luaur_vm::functions::lua_v_gettable::lua_v_gettable;
16use luaur_vm::macros::clvalue::clvalue;
17use luaur_vm::macros::fasttm::fasttm;
18use luaur_vm::macros::getstr::getstr;
19use luaur_vm::macros::gkey::{gkey, gval};
20use luaur_vm::macros::gval_2_slot::gval2slot;
21use luaur_vm::macros::hvalue::hvalue;
22use luaur_vm::macros::lua_o_nilobject::luaO_nilobject;
23use luaur_vm::macros::pvalue::pvalue;
24use luaur_vm::macros::setnvalue::setnvalue;
25use luaur_vm::macros::setobj_2_s::setobj_2_s as setobj2s;
26use luaur_vm::macros::tsvalue::tsvalue;
27use luaur_vm::macros::ttisfunction::ttisfunction;
28use luaur_vm::macros::ttisnil::ttisnil;
29use luaur_vm::macros::ttisstring::ttisstring;
30use luaur_vm::macros::ttistable::ttistable;
31use luaur_vm::macros::ttisuserdata::ttisuserdata;
32use luaur_vm::macros::ttisvector::ttisvector;
33use luaur_vm::macros::uvalue::uvalue;
34use luaur_vm::macros::vvalue::vvalue;
35use luaur_vm::type_aliases::stk_id::StkId;
36use luaur_vm::type_aliases::t_value::TValue;
37use luaur_vm::type_aliases::tms::TMS;
38
39#[inline]
40unsafe fn vm_kv(
41    i: u32,
42    cl: *mut luaur_vm::records::closure::Closure,
43    k: *mut TValue,
44) -> *mut TValue {
45    let p = {
46        let l = &(*cl).inner.l;
47        l.p
48    };
49    luaur_common::LUAU_ASSERT!(i < (*p).sizek as u32);
50    k.add(i as usize)
51}
52
53pub unsafe fn execute_gettableks(
54    L: *mut lua_State,
55    pc: *const Instruction,
56    mut base: StkId,
57    k: *mut TValue,
58) -> *const Instruction {
59    let cl = clvalue!((*(*L).ci).func);
60    let mut pc_ptr = pc;
61    let insn = *pc_ptr;
62    pc_ptr = pc_ptr.add(1);
63    let op = LUAU_INSN_OP(insn);
64    let ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
65    let rb = VM_REG!(LUAU_INSN_B(insn) as i32, L, base) as *mut TValue;
66    let aux = *pc_ptr;
67    pc_ptr = pc_ptr.add(1);
68    let kv = vm_kv(
69        if op == LuauOpcode::LOP_GETUDATAKS as u32 {
70            LUAU_INSN_AUX_KV16(aux)
71        } else {
72            aux
73        },
74        cl,
75        k,
76    );
77    luaur_common::LUAU_ASSERT!(ttisstring!(kv as *const TValue));
78
79    if ttistable!(rb as *const TValue) {
80        let h = hvalue!(rb as *const TValue);
81
82        if (*h).metatable.is_null() {
83            let res = luaH_getstr(h, tsvalue!(kv as *const TValue) as *mut _);
84
85            if res != luaO_nilobject {
86                VM_PATCH_C(pc_ptr.sub(2), gval2slot!(h, res));
87            }
88
89            setobj2s!(L, ra, res);
90            return pc_ptr;
91        }
92
93        let slot = (LUAU_INSN_C(insn) as i32) & (*h).nodemask8 as i32;
94        (*L).cachedslot = slot;
95        vm_protect!(L, pc_ptr, base, {
96            lua_v_gettable(L, rb as *const TValue, kv, ra);
97        });
98        VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);
99        return pc_ptr;
100    }
101
102    if luaur_common::FFlag::LuauDirectFieldGet.get() && ttisuserdata!(rb as *const TValue) {
103        let dispatch = {
104            let u = uvalue!(rb as *const TValue);
105            (*(*L).global).udatadirectfields[u.tag as usize]
106        };
107
108        if !dispatch.is_null() {
109            let slot = (LUAU_INSN_C(insn) as i32) & (*dispatch).nodemask8 as i32;
110            let n = (*dispatch).node.add(slot as usize);
111
112            if ttisstring!(gkey!(n) as *const TValue)
113                && tsvalue!(gkey!(n) as *const TValue) == tsvalue!(kv as *const TValue)
114                && !ttisnil!(gval!(n))
115            {
116                let f: unsafe extern "C" fn(*mut core::ffi::c_void, *mut core::ffi::c_void) =
117                    core::mem::transmute(pvalue!(gval!(n) as *const TValue));
118                let u = uvalue!(rb as *const TValue);
119                f(
120                    u.data.as_ptr() as *mut core::ffi::c_void,
121                    ra as *mut core::ffi::c_void,
122                );
123                return pc_ptr;
124            }
125
126            let fptr = luaH_getstr(dispatch, tsvalue!(kv as *const TValue) as *mut _);
127            if !ttisnil!(fptr) {
128                VM_PATCH_C(pc_ptr.sub(2), gval2slot!(dispatch, fptr));
129                let f: unsafe extern "C" fn(*mut core::ffi::c_void, *mut core::ffi::c_void) =
130                    core::mem::transmute(pvalue!(fptr));
131                let u = uvalue!(rb as *const TValue);
132                f(
133                    u.data.as_ptr() as *mut core::ffi::c_void,
134                    ra as *mut core::ffi::c_void,
135                );
136                return pc_ptr;
137            }
138        }
139    }
140
141    let mut fn_tm: *const TValue = core::ptr::null();
142    if ttisuserdata!(rb as *const TValue)
143        && {
144            fn_tm = fasttm(
145                L,
146                (*uvalue!(rb as *const TValue)).metatable,
147                TMS::TM_INDEX as i32,
148            );
149            !fn_tm.is_null()
150        }
151        && ttisfunction!(fn_tm)
152        && (*clvalue!(fn_tm)).isC != 0
153    {
154        luaur_common::LUAU_ASSERT!((*L).top.add(3) < (*L).stack.add((*L).stacksize as usize));
155        let top = (*L).top;
156        setobj2s!(L, top.add(0), fn_tm);
157        setobj2s!(L, top.add(1), rb as *const TValue);
158        setobj2s!(L, top.add(2), kv as *const TValue);
159        (*L).top = top.add(3);
160
161        (*L).cachedslot = LUAU_INSN_C(insn) as i32;
162        vm_protect!(L, pc_ptr, base, {
163            lua_v_call_tm(L, 2, LUAU_INSN_A(insn) as i32);
164        });
165        VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);
166        return pc_ptr;
167    } else if ttisvector!(rb as *const TValue) {
168        let name = getstr(tsvalue!(kv as *const TValue));
169        let ic = ((*name.add(0)) as u8 | b' ') as i32 - b'x' as i32;
170
171        if (ic as u32) < luaur_vm::macros::lua_vector_size::LUA_VECTOR_SIZE as u32
172            && *name.add(1) == 0
173        {
174            let v = vvalue!(rb as *const TValue).as_ptr();
175            setnvalue!(ra, *v.add(ic as usize) as f64);
176            return pc_ptr;
177        }
178
179        fn_tm = fasttm(
180            L,
181            (*(*L).global).mt[lua_Type::LUA_TVECTOR as usize],
182            TMS::TM_INDEX as i32,
183        );
184
185        if !fn_tm.is_null() && ttisfunction!(fn_tm) && (*clvalue!(fn_tm)).isC != 0 {
186            luaur_common::LUAU_ASSERT!((*L).top.add(3) < (*L).stack.add((*L).stacksize as usize));
187            let top = (*L).top;
188            setobj2s!(L, top.add(0), fn_tm);
189            setobj2s!(L, top.add(1), rb as *const TValue);
190            setobj2s!(L, top.add(2), kv as *const TValue);
191            (*L).top = top.add(3);
192
193            (*L).cachedslot = LUAU_INSN_C(insn) as i32;
194            vm_protect!(L, pc_ptr, base, {
195                lua_v_call_tm(L, 2, LUAU_INSN_A(insn) as i32);
196            });
197            VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);
198            return pc_ptr;
199        }
200    }
201
202    vm_protect!(L, pc_ptr, base, {
203        lua_v_gettable(L, rb as *const TValue, kv, ra);
204    });
205    pc_ptr
206}
207
208#[no_mangle]
209pub unsafe extern "C" fn executeGETTABLEKS(
210    L: *mut lua_State,
211    pc: *const Instruction,
212    base: StkId,
213    k: *mut TValue,
214) -> *const Instruction {
215    execute_gettableks(L, pc, base, k)
216}