Skip to main content

luaur_code_gen/functions/
call_fallback.rs

1use core::ffi::{c_int, c_void};
2
3use crate::macros::call_fallback_yield::CALL_FALLBACK_YIELD;
4use luaur_vm::functions::lua_v_tryfunc_tm::lua_v_tryfunc_tm;
5use luaur_vm::macros::clvalue::clvalue;
6use luaur_vm::macros::lua_callinfo_native::LUA_CALLINFO_NATIVE;
7use luaur_vm::macros::lua_multret::LUA_MULTRET;
8use luaur_vm::macros::setnilvalue::setnilvalue;
9use luaur_vm::macros::setobj_2_s::setobj2s;
10use luaur_vm::macros::ttisfunction::ttisfunction;
11use luaur_vm::records::call_info::CallInfo;
12use luaur_vm::records::closure::Closure;
13use luaur_vm::type_aliases::lua_state::lua_State;
14use luaur_vm::type_aliases::stk_id::StkId;
15use luaur_vm::type_aliases::t_value::TValue;
16
17pub unsafe fn call_fallback(
18    L: *mut lua_State,
19    ra: StkId,
20    mut argtop: StkId,
21    nresults: c_int,
22) -> *mut Closure {
23    if !ttisfunction!(ra as *const TValue) {
24        lua_v_tryfunc_tm(L, ra);
25        argtop = argtop.add(1);
26    }
27
28    let ccl = clvalue!(ra as *const TValue);
29
30    if luaur_common::FFlag::LuauClosureUsageCounter.get() {
31        (*ccl).usage += 1;
32    }
33
34    let ci = incr_ci_local(L);
35    (*ci).func = ra;
36    (*ci).base = ra.add(1);
37    (*ci).top = argtop.add((*ccl).stacksize as usize);
38    (*ci).savedpc = core::ptr::null();
39    (*ci).flags = 0;
40    (*ci).nresults = nresults;
41
42    (*L).base = (*ci).base;
43    (*L).top = argtop;
44
45    luaur_vm::macros::lua_d_checkstackfornewci::luaD_checkstackfornewci(
46        L,
47        (*ccl).stacksize as c_int,
48    );
49    luaur_common::LUAU_ASSERT!((*ci).top <= (*L).stack_last);
50
51    if (*ccl).isC == 0 {
52        let p = {
53            let l = &(*ccl).inner.l;
54            l.p
55        };
56
57        let mut argi = (*L).top;
58        let argend = (*L).base.add((*p).numparams as usize);
59        while argi < argend {
60            setnilvalue!(argi);
61            argi = argi.add(1);
62        }
63        (*L).top = if (*p).is_vararg != 0 { argi } else { (*ci).top };
64
65        (*ci).savedpc = (*p).code;
66
67        let has_native_target = if luaur_common::FFlag::LuauNativeCodeTargetCheck.get() {
68            (*p).exectarget != 0
69        } else {
70            !(*p).execdata.is_null()
71        };
72
73        if has_native_target {
74            (*ci).flags = LUA_CALLINFO_NATIVE as u32;
75        }
76
77        ccl
78    } else {
79        let func = {
80            let c = &(*ccl).inner.c;
81            c.f
82        };
83        let n = match func {
84            Some(f) => f(L),
85            None => 0,
86        };
87
88        if n < 0 {
89            return CALL_FALLBACK_YIELD as usize as *mut Closure;
90        }
91
92        let ci = (*L).ci;
93        let cip = ci.sub(1);
94
95        if luaur_common::FFlag::LuauClosureUsageCounter.get() {
96            luaur_common::LUAU_ASSERT!((*ccl).usage > 0);
97            (*ccl).usage -= 1;
98        }
99
100        let mut res = (*ci).func;
101        let mut vali = (*L).top.sub(n as usize);
102        let valend = (*L).top;
103
104        let mut i = nresults;
105        while i != 0 && vali < valend {
106            setobj2s!(L, res, vali as *const TValue);
107            res = res.add(1);
108            vali = vali.add(1);
109            i -= 1;
110        }
111        while i > 0 {
112            setnilvalue!(res);
113            res = res.add(1);
114            i -= 1;
115        }
116
117        (*L).ci = cip;
118        (*L).base = (*cip).base;
119        (*L).top = if nresults == LUA_MULTRET {
120            res
121        } else {
122            (*cip).top
123        };
124
125        core::ptr::null_mut()
126    }
127}
128
129unsafe fn incr_ci_local(L: *mut lua_State) -> *mut CallInfo {
130    if (*L).ci == (*L).end_ci {
131        luaur_vm::functions::lua_d_grow_ci::luaD_growCI(L);
132    } else {
133        (*L).ci = (*L).ci.add(1);
134    }
135
136    (*L).ci
137}
138
139#[no_mangle]
140pub unsafe extern "C" fn callFallback(
141    L: *mut lua_State,
142    ra: StkId,
143    argtop: StkId,
144    nresults: c_int,
145) -> *mut c_void {
146    call_fallback(L, ra, argtop, nresults).cast()
147}