Skip to main content

luaur_vm/functions/
lua_v_call_tm.rs

1use crate::macros::clvalue::clvalue;
2use crate::macros::incr_ci::incr_ci;
3use crate::macros::lua_d_checkstack::luaD_checkstack;
4use crate::macros::lua_minstack::LUA_MINSTACK;
5use crate::macros::luai_maxccalls::LUAI_MAXCCALLS;
6use crate::macros::setnilvalue::setnilvalue;
7use crate::macros::setobj_2_s::setobj2s;
8use crate::macros::ttisfunction::ttisfunction;
9use crate::records::call_info::CallInfo;
10use crate::records::closure::Closure;
11use crate::records::lua_state::lua_State;
12use crate::type_aliases::lua_c_function::lua_CFunction;
13use crate::type_aliases::stk_id::StkId;
14use crate::type_aliases::t_value::TValue;
15use luaur_common::macros::luau_assert::LUAU_ASSERT;
16use luaur_common::FFlag;
17
18/// C++ `LUAU_NOINLINE void luaV_callTM(lua_State* L, int nparams, int res)`.
19#[allow(non_snake_case)]
20pub unsafe fn lua_v_call_tm(L: *mut lua_State, nparams: i32, res: i32) {
21    // LUAU_NOINLINE is handled by the attribute on the function
22    (*L).nCcalls += 1;
23
24    if (*L).nCcalls >= LUAI_MAXCCALLS as u16 {
25        crate::functions::lua_d_check_cstack::luaD_checkCstack(L);
26    }
27
28    luaD_checkstack!(L, LUA_MINSTACK);
29
30    let top = (*L).top;
31    let fun = top.sub(nparams as usize).sub(1);
32
33    let ci = incr_ci!(L);
34    (*ci).func = fun;
35    (*ci).base = fun.add(1);
36    (*ci).top = top.add(LUA_MINSTACK as usize);
37    (*ci).savedpc = std::ptr::null_mut();
38    (*ci).flags = 0;
39    (*ci).nresults = if res >= 0 { 1 } else { 0 };
40    LUAU_ASSERT!((*ci).top <= (*L).stack_last);
41
42    let mut ccl: *mut Closure = std::ptr::null_mut();
43    if FFlag::LuauClosureUsageCounter.get() {
44        ccl = clvalue!(fun) as *mut Closure;
45        (*ccl).usage += 1;
46    }
47
48    LUAU_ASSERT!(ttisfunction!((*ci).func));
49    LUAU_ASSERT!((clvalue!((*ci).func) as *mut Closure).is_null() == false);
50    LUAU_ASSERT!((clvalue!((*ci).func) as *mut Closure).is_null() == false);
51    LUAU_ASSERT!((*clvalue!((*ci).func)).isC != 0);
52
53    (*L).base = fun.add(1);
54    LUAU_ASSERT!((*L).top == (*L).base.add(nparams as usize));
55
56    let cl = clvalue!(fun);
57    let c = core::ptr::addr_of!((*cl).inner.c).cast::<crate::records::closure::CClosure>();
58    let func = (*c).f;
59    let n = func.unwrap()(L);
60    LUAU_ASSERT!(n >= 0); // yields should have been blocked by nCcalls
61
62    // ci is our callinfo, cip is our parent
63    // note that we read L->ci again since it may have been reallocated by the call
64    let cip = (*L).ci.sub(1);
65
66    if FFlag::LuauClosureUsageCounter.get() {
67        LUAU_ASSERT!((*ccl).usage > 0);
68        (*ccl).usage -= 1;
69    }
70
71    // copy return value into parent stack
72    if res >= 0 {
73        if n > 0 {
74            setobj2s!(
75                L,
76                (*cip).base.add(res as usize),
77                (*L).top.sub(n as usize) as *const TValue
78            );
79        } else {
80            setnilvalue!((*cip).base.add(res as usize));
81        }
82    }
83
84    (*L).ci = cip;
85    (*L).base = (*cip).base;
86    (*L).top = (*cip).top;
87
88    (*L).nCcalls -= 1;
89}