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