1#[allow(unused_imports)]
7use crate::prelude::*;
8use crate::zio::{LexBuffer, ZIO};
9use crate::{
10 func,
11 state::{CallInfoIdx, LuaState},
12 vm,
13};
14use lua_types::closure::LuaClosure;
15use lua_types::tagmethod::TagMethod;
16use lua_types::StackIdx;
17use lua_types::{error::LuaError, status::LuaStatus, value::LuaValue};
18
19struct DynDataStub;
21impl DynDataStub {
22 fn new() -> Self {
23 DynDataStub
24 }
25}
26
27fn parse_stub(
42 state: &mut LuaState,
43 z: &mut ZIO,
44 _buff: &mut LexBuffer,
45 _dyd: &mut DynDataStub,
46 name: &[u8],
47 c: i32,
48) -> Result<lua_types::GcRef<lua_types::closure::LuaLClosure>, LuaError> {
49 let hook = state.global().parser_hook;
50 if let Some(parse) = hook {
51 return parse(state, z, name, c);
52 }
53 Err(LuaError::syntax(format_args!(
54 "{}: Lua text parser not yet wired (phase-b: lua-parse::parse)",
55 core::str::from_utf8(name).unwrap_or("?"),
56 )))
57}
58
59const LUAI_MAXSTACK: usize = 1_000_000;
63const ERRORSTACKSIZE: usize = LUAI_MAXSTACK + 200;
64
65const LUAI_MAXSTACK_51: usize = 65500;
74
75#[inline]
79fn max_stack(state: &LuaState) -> usize {
80 if state.global().lua_version == lua_types::LuaVersion::V51 {
81 LUAI_MAXSTACK_51
82 } else {
83 LUAI_MAXSTACK
84 }
85}
86
87const EXTRA_STACK: i32 = 5;
88
89const LUA_MINSTACK: i32 = 20;
90
91const LUA_MULTRET: i32 = -1;
92
93const NYCI: u32 = 0x10001;
94
95use crate::state::LUAI_MAXCCALLS;
96
97const CIST_C: u16 = 1 << 1;
99const CIST_FRESH: u16 = 1 << 2;
100const CIST_HOOKED: u16 = 1 << 3;
101const CIST_YPCALL: u16 = 1 << 4;
102const CIST_TAIL: u16 = 1 << 5;
103const CIST_HOOKYIELD: u16 = 1 << 6;
104const CIST_TRAN: u16 = 1 << 8;
105const CIST_CLSRET: u16 = 1 << 9;
106const CIST_FIN: u16 = 1 << 7;
107
108const LUA_MASKCALL: u8 = 1 << 0;
110const LUA_MASKRET: u8 = 1 << 1;
111
112const LUA_HOOKCALL: i32 = 0;
113const LUA_HOOKRET: i32 = 1;
114const LUA_HOOKTAILCALL: i32 = 4;
115const LUA_HOOKTAILRET: i32 = 4;
120
121const CLOSE_K_TOP: i32 = -1;
124
125#[inline]
129fn error_status(s: LuaStatus) -> bool {
130 (s as i32) > (LuaStatus::Yield as i32)
131}
132
133fn run_message_handler(
134 state: &mut LuaState,
135 err_slot: StackIdx,
136 errfunc_idx: StackIdx,
137 original_status: LuaStatus,
138 recover_ci: CallInfoIdx,
139 recover_allowhook: bool,
140) -> LuaStatus {
141 let saved_n_ccalls = state.n_ccalls;
142 state.n_ccalls += NYCI;
145 loop {
146 let arg = state.get_at(err_slot).clone();
147 state.set_top(err_slot + 1);
148 state.push(arg);
149 let handler = state.get_at(errfunc_idx).clone();
150 let func_idx = state.top_idx() - 2;
151 state.set_at(func_idx, handler);
152
153 match state.call_no_yield(func_idx, 1) {
154 Ok(()) => {
155 state.n_ccalls = saved_n_ccalls;
156 return original_status;
157 }
158 Err(e) => {
159 let status = e.to_status();
160 let value = e.into_value();
161 state.ci = recover_ci;
162 state.allowhook = recover_allowhook;
163 state.set_top(err_slot + 1);
164 state.set_at(err_slot, value);
165
166 if status == LuaStatus::ErrRun {
167 continue;
168 }
169
170 state.n_ccalls = saved_n_ccalls;
171 return LuaStatus::ErrErr;
172 }
173 }
174 }
175}
176
177pub(crate) fn set_error_obj(state: &mut LuaState, errcode: LuaStatus, old_top: StackIdx) {
190 match errcode {
191 LuaStatus::ErrMem => {
192 let memerrmsg = state.global().memerrmsg.clone();
194 state.set_at(old_top, LuaValue::Str(memerrmsg));
195 }
196 LuaStatus::ErrErr => {
197 if let Ok(s) = state.intern_str(b"error in error handling") {
198 state.set_at(old_top, LuaValue::Str(s));
199 }
200 }
201 LuaStatus::Ok => {
202 state.set_at(old_top, LuaValue::Nil);
203 }
204 _ => {
205 debug_assert!(error_status(errcode));
206 let top = state.top_idx();
207 let err_val = state.get_at(top - 1).clone();
208 state.set_at(old_top, err_val);
209 }
210 }
211 state.set_top(old_top + 1);
212}
213
214pub(crate) fn raw_run_protected<F>(state: &mut LuaState, f: F) -> Result<(), LuaError>
223where
224 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
225{
226 let old_n_ccalls = state.n_ccalls;
227 let result = f(state);
229 state.n_ccalls = old_n_ccalls;
230 result
231}
232
233pub(crate) fn realloc_stack(
248 state: &mut LuaState,
249 new_size: usize,
250 raise_error: bool,
251) -> Result<bool, LuaError> {
252 let old_size = state.stack_size() as usize;
253 debug_assert!(new_size <= LUAI_MAXSTACK || new_size == ERRORSTACKSIZE);
254
255 let old_gcstop = state.global().gcstopem;
258 state.global_mut().gcstopem = true;
259
260 let new_extent = new_size as usize + EXTRA_STACK as usize;
262 let alloc_result = state.stack_resize(new_extent);
263
264 state.global_mut().gcstopem = old_gcstop;
265
266 if alloc_result.is_err() {
267 if raise_error {
268 return Err(LuaError::Memory);
269 } else {
270 return Ok(false);
271 }
272 }
273
274 state.stack_last = StackIdx(new_size as u32);
275
276 let old_extent = old_size + EXTRA_STACK as usize;
278 for i in old_extent..new_extent {
279 state.stack_set_nil(i);
280 }
281
282 Ok(true)
283}
284
285pub(crate) fn grow_stack(
291 state: &mut LuaState,
292 n: i32,
293 raise_error: bool,
294) -> Result<bool, LuaError> {
295 let size = state.stack_size();
296 let cap = max_stack(state);
297
298 if size > cap {
299 debug_assert!(state.stack_size() == ERRORSTACKSIZE);
301 if raise_error {
302 return Err(LuaError::with_status(LuaStatus::ErrErr));
303 }
304 return Ok(false);
305 } else if (n as usize) < cap {
306 let mut new_size = 2 * size;
307 let needed = (state.top_idx().0 as i32 + n) as usize;
308 if new_size > cap {
309 new_size = cap;
310 }
311 if new_size < needed {
312 new_size = needed;
313 }
314 if new_size <= cap {
315 return realloc_stack(state, new_size, raise_error);
316 }
317 }
318 realloc_stack(state, ERRORSTACKSIZE, raise_error)?;
320 if raise_error {
321 return Err(crate::debug::prefixed_runtime_pub(
322 state,
323 b"stack overflow".to_vec(),
324 ));
325 }
326 Ok(false)
327}
328
329fn stack_in_use(state: &LuaState) -> usize {
332 let mut lim = state.top_idx();
333 let mut ci_idx_opt = Some(state.ci);
335 while let Some(ci_idx) = ci_idx_opt {
336 let ci = state.get_ci(ci_idx);
337 if lim.0 < ci.top.0 {
338 lim = ci.top;
339 }
340 ci_idx_opt = ci.previous;
341 }
342 debug_assert!(true );
343 let res = lim.0 as usize + 1;
344 if res < LUA_MINSTACK as usize {
345 LUA_MINSTACK as usize
346 } else {
347 res
348 }
349}
350
351pub(crate) fn shrink_stack(state: &mut LuaState) {
354 let inuse = stack_in_use(state);
355 let max = if inuse > LUAI_MAXSTACK / 3 {
356 LUAI_MAXSTACK
357 } else {
358 inuse * 3
359 };
360 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
361 let nsize = if inuse > LUAI_MAXSTACK / 2 {
362 LUAI_MAXSTACK
363 } else {
364 inuse * 2
365 };
366 let _ = realloc_stack(state, nsize, false);
367 }
368 state.shrink_ci();
369}
370
371pub(crate) fn hook(
378 state: &mut LuaState,
379 event: i32,
380 line: i32,
381 ftransfer: i32,
382 ntransfer: i32,
383) -> Result<(), LuaError> {
384 if !state.has_hook() || !state.allowhook {
385 return Ok(());
386 }
387
388 let ci_idx = state.ci;
389
390 let saved_top = state.top_idx();
392 let saved_ci_top = state.get_ci(ci_idx).top;
393
394 let mut mask = CIST_HOOKED;
395
396 if ntransfer != 0 {
397 mask |= CIST_TRAN;
398 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
399 }
400
401 {
402 let ci = state.get_ci(ci_idx);
403 if ci.is_lua() {
404 let ci_top = ci.top;
405 if state.top_idx().0 < ci_top.0 {
406 state.set_top(ci_top);
407 }
408 }
409 }
410
411 state.check_stack(LUA_MINSTACK as i32)?;
412
413 {
414 let top = state.top_idx();
415 let ci = state.get_ci_mut(ci_idx);
416 if ci.top.0 < (top + LUA_MINSTACK).0 {
417 let new_top = top + LUA_MINSTACK;
418 ci.top = new_top;
419 state.clear_stack_range(top, new_top);
420 }
421 }
422
423 state.allowhook = false;
424 state.get_ci_mut(ci_idx).callstatus |= mask;
425
426 let mut ar = crate::debug::LuaDebug::default();
427 ar.event = event;
428 ar.currentline = line;
429 ar.ftransfer = ftransfer as u16;
430 ar.ntransfer = ntransfer as u16;
431 ar.i_ci = Some(ci_idx);
432 let hook_opt = state.hook.take();
433 if let Some(mut h) = hook_opt {
434 h(state, &ar);
435 if state.hook.is_none() {
436 state.hook = Some(h);
437 }
438 }
439
440 debug_assert!(!state.allowhook);
441 state.allowhook = true;
442
443 state.get_ci_mut(ci_idx).top = saved_ci_top;
445 state.set_top(saved_top);
446 state.get_ci_mut(ci_idx).callstatus &= !mask;
447
448 Ok(())
449}
450
451pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
454 state.oldpc = 0;
455 if state.hookmask & LUA_MASKCALL != 0 {
456 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
457 LUA_HOOKTAILCALL
458 } else {
459 LUA_HOOKCALL
460 };
461 let numparams = {
463 state.get_ci_lua_proto_numparams(ci_idx)
466 };
467 let pc = state.ci_savedpc(ci_idx);
468 state.set_ci_savedpc(ci_idx, pc + 1);
469 hook(state, event, -1, 1, numparams as i32)?;
470 state.set_ci_savedpc(ci_idx, pc);
471 }
472 Ok(())
473}
474
475fn fire_tail_returns(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
485 if !state.get_ci(ci_idx).is_lua() {
486 return Ok(());
487 }
488 while state.get_ci(ci_idx).tailcalls > 0 {
489 state.get_ci_mut(ci_idx).tailcalls -= 1;
490 hook(state, LUA_HOOKTAILRET, -1, 0, 0)?;
491 }
492 Ok(())
493}
494
495fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
498 if state.hookmask & LUA_MASKRET != 0 {
499 let first_res = state.top_idx().0 as i32 - nres;
500 let mut delta: i32 = 0;
501
502 if state.get_ci(ci_idx).is_lua() {
503 let (is_vararg, nextraargs, numparams) = state.get_ci_vararg_info(ci_idx);
505 if is_vararg {
506 delta = nextraargs + numparams as i32 + 1;
507 }
508 }
509
510 let original_func = state.get_ci(ci_idx).func;
512 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
513
514 let ci_func = state.get_ci(ci_idx).func;
515 let ftransfer = (first_res - ci_func.0 as i32) as u16;
516
517 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
518
519 state.get_ci_mut(ci_idx).func = original_func;
520
521 fire_tail_returns(state, ci_idx)?;
522 }
523
524 let previous = state.get_ci(ci_idx).previous;
526 if let Some(prev_idx) = previous {
527 if state.get_ci(prev_idx).is_lua() {
528 state.oldpc = state.get_ci_pcrel(prev_idx);
532 }
533 }
534
535 Ok(())
536}
537
538fn try_func_tm(
548 state: &mut LuaState,
549 func_idx: StackIdx,
550 call_metamethods: &mut u8,
551) -> Result<StackIdx, LuaError> {
552 let count_call_metamethods = state.global().lua_version == lua_types::LuaVersion::V55;
553 if count_call_metamethods && *call_metamethods == 15 {
554 return Err(LuaError::runtime(format_args!("'__call' chain too long")));
555 }
556 state.check_stack(1)?;
559 if state.gc_check_needed {
560 state.gc_check_step();
561 }
562
563 let func_val = state.get_at(func_idx).clone();
564 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
565
566 if matches!(tm, LuaValue::Nil) {
567 let offender = state.get_at(func_idx).clone();
568 return Err(crate::debug::call_error(state, &offender, func_idx));
569 }
570
571 let top = state.top_idx();
573 let mut p = top;
574 while p.0 > func_idx.0 {
575 let val = state.get_at(p - 1).clone();
576 state.set_at(p, val);
577 p = p - 1;
578 }
579 state.set_top(top + 1);
580 state.set_at(func_idx, tm);
581 if count_call_metamethods {
582 *call_metamethods += 1;
583 }
584
585 Ok(func_idx)
586}
587
588#[inline(always)]
593fn move_results(
594 state: &mut LuaState,
595 res_idx: StackIdx,
596 nres: i32,
597 wanted: i32,
598) -> Result<(), LuaError> {
599 match wanted {
600 0 => {
601 state.set_top(res_idx);
602 return Ok(());
603 }
604 1 => {
605 if nres == 0 {
606 state.set_at(res_idx, LuaValue::Nil);
607 } else {
608 let top = state.top_idx();
609 let src = state.get_at(top - nres as i32).clone();
610 state.set_at(res_idx, src);
611 }
612 state.set_top(res_idx + 1);
613 return Ok(());
614 }
615 LUA_MULTRET => {
616 }
618 _ => {
619 if wanted < LUA_MULTRET {
621 let ci_idx = state.ci;
622 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
623 state.set_ci_u2_nres(ci_idx, nres);
624
625 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
628
629 let ci_idx = state.ci;
630 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
631
632 if state.hookmask != 0 {
633 let saved_res = res_idx;
635 rethook(state, ci_idx, nres)?;
636 let _ = saved_res; }
638
639 let decoded_wanted = -(wanted) - 3;
641 let wanted = if decoded_wanted == LUA_MULTRET {
642 nres
643 } else {
644 decoded_wanted
645 };
646
647 let first_result = state.top_idx().0 as i32 - nres;
649 let actual_nres = nres.min(wanted);
650 for i in 0..actual_nres {
651 let src = state.get_at((first_result + i) as u32).clone();
652 state.set_at(res_idx + i as i32, src);
653 }
654 for i in actual_nres..wanted {
655 state.set_at(res_idx + i as i32, LuaValue::Nil);
656 }
657 state.set_top(res_idx + wanted as i32);
658 return Ok(());
659 }
660 }
661 }
662
663 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
665 let first_result = state.top_idx().0 as i32 - nres;
666 let actual_nres = nres.min(effective_wanted);
667 for i in 0..actual_nres {
668 let src = state.get_at((first_result + i) as u32).clone();
669 state.set_at(res_idx + i as i32, src);
670 }
671 for i in actual_nres..effective_wanted {
672 state.set_at(res_idx + i as i32, LuaValue::Nil);
673 }
674 state.set_top(res_idx + effective_wanted as i32);
675 Ok(())
676}
677
678#[inline(always)]
682pub(crate) fn poscall(
683 state: &mut LuaState,
684 ci_idx: CallInfoIdx,
685 nres: i32,
686) -> Result<(), LuaError> {
687 let wanted = state.get_ci(ci_idx).nresults as i32;
688
689 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
690 rethook(state, ci_idx, nres)?;
691 }
692
693 let func_idx = state.get_ci(ci_idx).func;
694 move_results(state, func_idx, nres, wanted)?;
695
696 debug_assert!(
697 state.get_ci(ci_idx).callstatus
698 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
699 == 0
700 );
701
702 let previous = state
703 .get_ci(ci_idx)
704 .previous
705 .expect("poscall: no previous call frame");
706 state.ci = previous;
707 Ok(())
708}
709
710#[inline(always)]
724fn prep_call_info(
725 state: &mut LuaState,
726 func_idx: StackIdx,
727 nret: i32,
728 mask: u16,
729 top_idx: StackIdx,
730) -> Result<CallInfoIdx, LuaError> {
731 debug_assert!(
732 mask & crate::state::CIST_TRAP == 0,
733 "prep_call_info must not be handed a pre-set trap bit"
734 );
735 let ci_idx = state.next_ci()?;
737 state.ci = ci_idx;
738 {
739 let ci = state.get_ci_mut(ci_idx);
740 ci.func = func_idx;
741 ci.nresults = nret as i16;
742 ci.callstatus = mask;
743 ci.call_metamethods = 0;
744 ci.top = top_idx;
745 ci.u = crate::state::CallInfoFrame::lua_default();
746 }
747 Ok(ci_idx)
748}
749
750#[inline(always)]
755fn precall_c(
756 state: &mut LuaState,
757 func_idx: StackIdx,
758 nresults: i32,
759 f: crate::state::LuaCallable,
760 call_metamethods: u8,
761) -> Result<i32, LuaError> {
762 state.check_stack(LUA_MINSTACK as i32)?;
763 if state.gc_check_needed {
764 state.gc_check_step();
765 }
766
767 let top_idx = state.top_idx();
768 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
769 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
770
771 debug_assert!(true );
772
773 if state.hookmask & LUA_MASKCALL != 0 {
774 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
775 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
776 }
777
778 let n = f.call(state)? as i32;
779
780 debug_assert!(
782 n <= state.top_idx().0 as i32,
783 "C function returned more values than available"
784 );
785
786 poscall(state, ci_idx, n)?;
787 Ok(n)
788}
789
790pub(crate) fn pretailcall(
808 state: &mut LuaState,
809 ci_idx: CallInfoIdx,
810 mut func_idx: StackIdx,
811 mut narg1: i32,
812 delta: i32,
813) -> Result<i32, LuaError> {
814 let mut call_metamethods = 0u8;
815 loop {
816 let func_val = state.get_at(func_idx).clone();
817 match func_val {
818 LuaValue::Function(LuaClosure::C(ref cl)) => {
819 let cfunc = state.global().c_functions[cl.func].clone();
820 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
821 }
822 LuaValue::Function(LuaClosure::LightC(f)) => {
823 let cfunc = state.global().c_functions[f].clone();
824 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
825 }
826 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
827 let proto = cl.proto.clone();
828 let fsize = proto.maxstacksize as i32;
829 let nfixparams = proto.numparams as i32;
830
831 state.check_stack(fsize - delta)?;
832 if state.gc_check_needed {
833 state.gc_check_step();
834 }
835
836 {
837 let ci = state.get_ci_mut(ci_idx);
838 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
839 }
840 let ci_func = state.get_ci(ci_idx).func;
841
842 for i in 0..narg1 {
843 let src = state.get_at(func_idx + i as i32).clone();
844 state.set_at(ci_func + i as i32, src);
845 }
846
847 func_idx = ci_func;
849
850 while narg1 <= nfixparams {
851 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
852 narg1 += 1;
853 }
854
855 {
856 let new_ci_top = func_idx + 1 + fsize as i32;
857 let stack_last = state.stack_last;
858 let live_top = state.top_idx();
859 let ci = state.get_ci_mut(ci_idx);
860 ci.call_metamethods = call_metamethods;
861 ci.top = new_ci_top;
862 debug_assert!(ci.top.0 <= stack_last.0);
863 ci.set_saved_pc(0);
864 ci.callstatus |= CIST_TAIL;
865 state.clear_stack_range(live_top, new_ci_top);
866 }
867
868 state.set_top(func_idx + narg1 as i32);
869 return Ok(-1); }
871 _ => {
872 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
873 narg1 += 1;
874 }
876 }
877 }
878}
879
880#[inline(always)]
890pub(crate) fn precall(
891 state: &mut LuaState,
892 func_idx: StackIdx,
893 nresults: i32,
894) -> Result<Option<CallInfoIdx>, LuaError> {
895 if let LuaValue::Function(LuaClosure::Lua(cl)) = &state.stack[func_idx.0 as usize].val {
896 let nfixparams = cl.proto.numparams as i32;
897 let fsize = cl.proto.maxstacksize as i32;
898 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
899
900 state.check_stack(fsize)?;
901 if state.gc_check_needed {
902 state.gc_check_step();
903 }
904
905 let ci_idx = prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
906 state.set_ci_savedpc(ci_idx, 0);
907
908 if narg < nfixparams {
909 fill_missing_params(state, narg, nfixparams);
910 }
911 return Ok(Some(ci_idx));
912 }
913 precall_slow(state, func_idx, nresults)
914}
915
916#[cold]
920#[inline(never)]
921fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
922 while narg < nfixparams {
923 let top = state.top_idx();
924 state.set_at(top, LuaValue::Nil);
925 state.set_top(top + 1);
926 narg += 1;
927 }
928}
929
930#[cold]
934#[inline(never)]
935fn precall_slow(
936 state: &mut LuaState,
937 mut func_idx: StackIdx,
938 nresults: i32,
939) -> Result<Option<CallInfoIdx>, LuaError> {
940 let mut call_metamethods = 0u8;
941 loop {
942 let func_val = state.get_at(func_idx).clone();
943 match func_val {
944 LuaValue::Function(LuaClosure::C(ref cl)) => {
945 let cfunc = state.global().c_functions[cl.func].clone();
946 precall_c(state, func_idx, nresults, cfunc, call_metamethods)?;
947 return Ok(None);
948 }
949 LuaValue::Function(LuaClosure::LightC(f)) => {
950 state.check_stack(LUA_MINSTACK as i32)?;
951 if state.gc_check_needed {
952 state.gc_check_step();
953 }
954
955 let top_idx = state.top_idx();
956 let ci_idx =
957 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
958 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
959
960 if state.hookmask & LUA_MASKCALL != 0 {
961 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
962 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
963 }
964
965 let cfunc = state.global().c_functions[f].clone();
966 let n = cfunc.call(state)? as i32;
967 debug_assert!(
968 n <= state.top_idx().0 as i32,
969 "C function returned more values than available"
970 );
971 poscall(state, ci_idx, n)?;
972 return Ok(None);
973 }
974 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
975 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
976 let nfixparams = cl.proto.numparams as i32;
977 let fsize = cl.proto.maxstacksize as i32;
978
979 state.check_stack(fsize)?;
980 if state.gc_check_needed {
981 state.gc_check_step();
982 }
983
984 let ci_idx =
985 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
986 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
987 state.set_ci_savedpc(ci_idx, 0);
988
989 if narg < nfixparams {
990 fill_missing_params(state, narg, nfixparams);
991 }
992 return Ok(Some(ci_idx));
993 }
994 _ => {
995 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
996 }
997 }
998 }
999}
1000
1001#[inline]
1005fn ccall_inner(
1006 state: &mut LuaState,
1007 func_idx: StackIdx,
1008 n_results: i32,
1009 inc: u32,
1010) -> Result<(), LuaError> {
1011 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
1012}
1013
1014#[inline]
1015fn ccall_known_c_inner(
1016 state: &mut LuaState,
1017 func_idx: StackIdx,
1018 n_results: i32,
1019 inc: u32,
1020 f: crate::state::LuaCallable,
1021) -> Result<(), LuaError> {
1022 state.n_ccalls += inc;
1023
1024 if state.c_calls() >= LUAI_MAXCCALLS {
1025 state.check_stack(0)?;
1026 state.check_c_stack()?;
1027 }
1028
1029 precall_c(state, func_idx, n_results, f, 0)?;
1030
1031 state.n_ccalls -= inc;
1032 Ok(())
1033}
1034
1035#[inline]
1036fn ccall_inner_with_status(
1037 state: &mut LuaState,
1038 func_idx: StackIdx,
1039 n_results: i32,
1040 inc: u32,
1041 extra_callstatus: u16,
1042) -> Result<(), LuaError> {
1043 state.n_ccalls += inc;
1044
1045 if state.c_calls() >= LUAI_MAXCCALLS {
1047 state.check_stack(0)?;
1049 state.check_c_stack()?;
1050 }
1051
1052 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
1053 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
1054 vm::execute(state, ci_idx)?;
1055 }
1056
1057 state.n_ccalls -= inc;
1058 Ok(())
1059}
1060
1061pub(crate) fn call(
1064 state: &mut LuaState,
1065 func_idx: StackIdx,
1066 n_results: i32,
1067) -> Result<(), LuaError> {
1068 ccall_inner(state, func_idx, n_results, 1)
1069}
1070
1071pub(crate) fn callnoyield(
1074 state: &mut LuaState,
1075 func_idx: StackIdx,
1076 n_results: i32,
1077) -> Result<(), LuaError> {
1078 ccall_inner(state, func_idx, n_results, NYCI)
1080}
1081
1082#[inline]
1089pub(crate) fn call_known_c(
1090 state: &mut LuaState,
1091 func_idx: StackIdx,
1092 n_results: i32,
1093) -> Result<bool, LuaError> {
1094 let cfunc = match &state.stack[func_idx.0 as usize].val {
1095 LuaValue::Function(LuaClosure::C(cl)) => state.global().c_functions[cl.func].clone(),
1096 LuaValue::Function(LuaClosure::LightC(f)) => state.global().c_functions[*f].clone(),
1097 _ => return Ok(false),
1098 };
1099
1100 ccall_known_c_inner(state, func_idx, n_results, 1, cfunc)?;
1101 Ok(true)
1102}
1103
1104fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
1111 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
1114
1115 if status == LuaStatus::Ok {
1116 status = LuaStatus::Yield;
1117 } else {
1118 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
1119 state.allowhook = state.get_ci(ci_idx).get_oah();
1121 let _func_idx = func::close(state, func_idx, status as i32, true)?;
1123 set_error_obj(state, status, func_idx);
1124
1125 if state.errfunc != 0
1134 && error_status(status)
1135 && status != LuaStatus::ErrErr
1136 && status != LuaStatus::ErrSyntax
1137 {
1138 let errfunc_stk = StackIdx(state.errfunc as u32);
1139 status = run_message_handler(
1140 state,
1141 func_idx,
1142 errfunc_stk,
1143 status,
1144 ci_idx,
1145 state.allowhook,
1146 );
1147 }
1148
1149 shrink_stack(state);
1150 state
1151 .get_ci_mut(ci_idx)
1152 .set_recover_status(LuaStatus::Ok as i32);
1153 }
1154
1155 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1156 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1157 state.errfunc = old_errfunc;
1158
1159 Ok(status)
1160}
1161
1162fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1165 let n;
1166
1167 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1168 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1169 n = state.get_ci_u2_nres(ci_idx);
1170 } else {
1171 debug_assert!(
1172 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1173 "finishCcall: no continuation or non-yieldable"
1174 );
1175
1176 let mut status = LuaStatus::Yield;
1177
1178 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1179 status = finish_pcallk(state, ci_idx)?;
1180 }
1181
1182 state.adjust_results(LUA_MULTRET);
1184
1185 let k = state.get_ci(ci_idx).u_c_k();
1189 let ctx = state.get_ci(ci_idx).u_c_ctx();
1190 if let Some(k_fn) = k {
1191 n = k_fn(state, status as i32, ctx)? as i32;
1192 } else {
1193 return Err(LuaError::runtime(format_args!(
1195 "finishCcall: missing continuation"
1196 )));
1197 }
1198 debug_assert!(
1199 n <= state.top_idx().0 as i32,
1200 "continuation returned more values than available"
1201 );
1202 }
1203
1204 poscall(state, ci_idx, n)?;
1205 Ok(())
1206}
1207
1208fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1211 loop {
1212 let ci_idx = state.ci;
1213 if state.is_base_ci(ci_idx) {
1214 break;
1215 }
1216 if !state.get_ci(ci_idx).is_lua() {
1217 finish_ccall(state, ci_idx)?;
1218 } else {
1219 vm::finish_op(state)?;
1220 vm::execute(state, ci_idx)?;
1221 }
1222 }
1223 Ok(())
1224}
1225
1226fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1229 let mut ci_idx_opt = Some(state.ci);
1230 while let Some(ci_idx) = ci_idx_opt {
1231 let ci = state.get_ci(ci_idx);
1232 if ci.callstatus & CIST_YPCALL != 0 {
1233 return Some(ci_idx);
1234 }
1235 ci_idx_opt = ci.previous;
1236 }
1237 None
1238}
1239
1240fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1243 let top = state.top_idx();
1244 state.set_top(top - narg as i32);
1245 let s = state.intern_str(msg).ok();
1247 let new_top = state.top_idx();
1248 if let Some(s) = s {
1249 state.set_at(new_top, LuaValue::Str(s));
1250 }
1251 state.set_top(new_top + 1);
1252 LuaStatus::ErrRun
1253}
1254
1255fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1258 let top = state.top_idx();
1259 let first_arg = top - nargs as i32;
1260 let ci_idx = state.ci;
1261
1262 if state.status == LuaStatus::Ok as u8 {
1263 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1264 } else {
1265 debug_assert!(state.status == LuaStatus::Yield as u8);
1266 state.status = LuaStatus::Ok as u8;
1267
1268 if state.get_ci(ci_idx).is_lua() {
1269 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1270 let pc = state.ci_savedpc(ci_idx);
1271 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1272 state.set_top(first_arg);
1273 vm::execute(state, ci_idx)?;
1274 } else {
1275 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1276 let ctx = state.get_ci(ci_idx).u_c_ctx();
1277 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1278 debug_assert!(n <= state.top_idx().0 as i32);
1279 poscall(state, ci_idx, n)?;
1280 } else {
1281 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1283 poscall(state, ci_idx, n)?;
1284 }
1285 }
1286
1287 unroll(state)?;
1288 }
1289 Ok(())
1290}
1291
1292fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1295 while error_status(status) {
1296 if let Some(ci_idx) = find_pcall(state) {
1297 state.ci = ci_idx;
1298 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1299 status = match raw_run_protected(state, |s| unroll(s)) {
1304 Ok(()) => LuaStatus::Ok,
1305 Err(e) => {
1306 let s = e.to_status();
1307 if error_status(s) {
1308 state.push(e.into_value());
1309 }
1310 s
1311 }
1312 };
1313 } else {
1314 break;
1315 }
1316 }
1317 status
1318}
1319
1320pub fn lua_resume(
1323 state: &mut LuaState,
1324 from: Option<&mut LuaState>,
1325 nargs: i32,
1326 nresults: &mut i32,
1327) -> LuaStatus {
1328 if state.status == LuaStatus::Ok as u8 {
1334 if !state.is_base_ci(state.ci) {
1335 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1336 }
1337 let ci_func = state.get_ci(state.ci).func;
1338 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1339 return resume_error(state, b"cannot resume dead coroutine", nargs);
1340 }
1341 } else if state.status != LuaStatus::Yield as u8 {
1342 return resume_error(state, b"cannot resume dead coroutine", nargs);
1343 }
1344
1345 state.n_ccalls = from.as_ref().map(|f| f.c_calls() as u32).unwrap_or(0);
1346
1347 if state.c_calls() >= LUAI_MAXCCALLS {
1348 return resume_error(state, b"C stack overflow", nargs);
1349 }
1350 state.n_ccalls += 1;
1351
1352 debug_assert!(
1353 if state.status == LuaStatus::Ok as u8 {
1354 nargs + 1 <= state.top_idx().0 as i32
1355 } else {
1356 nargs <= state.top_idx().0 as i32
1357 },
1358 "lua_resume: not enough stack elements"
1359 );
1360
1361 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1367 Ok(()) => (LuaStatus::Ok, None),
1368 Err(e) => {
1369 let s = e.to_status();
1370 let v = if error_status(s) {
1371 Some(e.into_value())
1372 } else {
1373 None
1374 };
1375 (s, v)
1376 }
1377 };
1378 if let Some(v) = err_value {
1379 state.push(v);
1380 }
1381
1382 status = precover(state, status);
1383
1384 if !error_status(status) {
1385 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1386 } else {
1387 state.status = status as u8;
1389 let top = state.top_idx();
1390 set_error_obj(state, status, top);
1391 let new_top = state.top_idx();
1392 let ci_idx = state.ci;
1393 state.get_ci_mut(ci_idx).top = new_top;
1394 }
1395
1396 let ci_idx = state.ci;
1397 *nresults = if status == LuaStatus::Yield {
1398 state.get_ci_u2_nyield(ci_idx)
1399 } else {
1400 let ci_func = state.get_ci(ci_idx).func;
1401 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1402 };
1403
1404 status
1405}
1406
1407pub fn lua_isyieldable(state: &LuaState) -> bool {
1410 state.is_yieldable()
1412}
1413
1414pub fn lua_yieldk(
1418 state: &mut LuaState,
1419 nresults: i32,
1420 ctx: isize,
1421 k: Option<crate::state::LuaKFunction>,
1422) -> Result<i32, LuaError> {
1423 let ci_idx = state.ci;
1427
1428 debug_assert!(
1429 nresults <= state.top_idx().0 as i32,
1430 "lua_yieldk: not enough elements on stack"
1431 );
1432
1433 if !state.is_yieldable() {
1434 if matches!(state.global().lua_version, lua_types::LuaVersion::V51) {
1435 return Err(LuaError::runtime(format_args!(
1436 "attempt to yield across metamethod/C-call boundary"
1437 )));
1438 }
1439 if !state.is_main_thread() {
1440 return Err(LuaError::runtime(format_args!(
1441 "attempt to yield across a C-call boundary"
1442 )));
1443 } else {
1444 return Err(LuaError::runtime(format_args!(
1445 "attempt to yield from outside a coroutine"
1446 )));
1447 }
1448 }
1449
1450 state.status = LuaStatus::Yield as u8;
1451 state.set_ci_u2_nyield(ci_idx, nresults);
1452
1453 if state.get_ci(ci_idx).is_lua() {
1454 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1455 debug_assert!(nresults == 0, "hooks cannot yield values");
1456 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1457 } else {
1459 let ci = state.get_ci_mut(ci_idx);
1460 ci.set_u_c_k(k);
1461 if k.is_some() {
1462 ci.set_u_c_ctx(ctx);
1463 }
1464 return Err(LuaError::Yield);
1466 }
1467
1468 debug_assert!(
1469 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1470 "lua_yieldk called outside a hook"
1471 );
1472 Ok(0) }
1474
1475struct CloseP {
1482 level: StackIdx,
1483 status: LuaStatus,
1484}
1485
1486fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1489 func::close(state, pcl.level, pcl.status as i32, false)?;
1491 Ok(())
1492}
1493
1494pub(crate) fn close_protected(
1498 state: &mut LuaState,
1499 level: StackIdx,
1500 status: LuaStatus,
1501) -> LuaStatus {
1502 let old_ci = state.ci;
1503 let old_allowhook = state.allowhook;
1504 let mut status = status;
1505
1506 loop {
1507 let mut pcl = CloseP { level, status };
1508 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1509 Ok(()) => (LuaStatus::Ok, None),
1510 Err(e) => (e.to_status(), Some(e.into_value())),
1511 };
1512 if run_status == LuaStatus::Ok {
1513 return pcl.status;
1514 }
1515 state.ci = old_ci;
1516 state.allowhook = old_allowhook;
1517 if let Some(v) = err_value {
1523 state.push(v);
1524 }
1525 status = run_status;
1526 }
1527}
1528
1529pub(crate) fn pcall<F>(state: &mut LuaState, func: F, old_top: StackIdx, ef: isize) -> LuaStatus
1533where
1534 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1535{
1536 let old_ci = state.ci;
1537 let old_allowhook = state.allowhook;
1538 let old_errfunc = state.errfunc;
1539 state.errfunc = ef;
1540
1541 let mut status = match raw_run_protected(state, func) {
1547 Ok(()) => LuaStatus::Ok,
1548 Err(e) => {
1549 let s = e.to_status();
1550 state.push(e.into_value());
1551 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1557 let errfunc_idx = StackIdx(ef as u32);
1558 let err_slot = state.top_idx() - 1;
1559 run_message_handler(state, err_slot, errfunc_idx, s, old_ci, old_allowhook)
1560 } else {
1561 s
1562 }
1563 }
1564 };
1565
1566 if status != LuaStatus::Ok
1574 && status != LuaStatus::ErrSyntax
1575 && state.global().lua_version == lua_types::LuaVersion::V55
1576 {
1577 let top = state.top_idx();
1578 if matches!(state.get_at(top - 1), LuaValue::Nil) {
1579 if let Ok(s) = state.intern_str(b"<no error object>") {
1580 state.set_at(top - 1, LuaValue::Str(s));
1581 }
1582 }
1583 }
1584
1585 if status != LuaStatus::Ok {
1586 state.ci = old_ci;
1587 state.allowhook = old_allowhook;
1588 status = close_protected(state, old_top, status);
1589 set_error_obj(state, status, old_top);
1591 shrink_stack(state);
1592 }
1593
1594 state.errfunc = old_errfunc;
1595 status
1596}
1597
1598struct SParser {
1608 z: ZIO,
1609 buff: LexBuffer,
1611 dyd: DynDataStub,
1613 mode: Option<Vec<u8>>,
1615 name: Vec<u8>,
1616}
1617
1618fn check_mode(mode: Option<&[u8]>, kind: &[u8]) -> Result<(), LuaError> {
1621 if let Some(mode_bytes) = mode {
1622 let kind_char = kind[0];
1623 if !mode_bytes.contains(&kind_char) {
1624 return Err(LuaError::syntax(format_args!(
1627 "attempt to load a {} chunk (mode is '{}')",
1628 core::str::from_utf8(kind).unwrap_or("?"),
1629 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1630 )));
1631 }
1632 }
1633 Ok(())
1634}
1635
1636fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1640 let c = p.z.getc(state)?;
1642
1643 let cl = if c == b'\x1b' as i32 {
1645 check_mode(p.mode.as_deref(), b"binary")?;
1646 crate::undump::undump(state, &mut p.z, &p.name)?
1648 } else {
1649 check_mode(p.mode.as_deref(), b"text")?;
1650 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1652 };
1653
1654 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1655 func::init_upvals(state, &cl)?;
1656
1657 state.check_stack(1)?;
1665 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1666
1667 Ok(())
1668}
1669
1670pub(crate) fn protected_parser(
1682 state: &mut LuaState,
1683 z: ZIO,
1684 name: &[u8],
1685 mode: Option<&[u8]>,
1686) -> LuaStatus {
1687 state.inc_nny();
1689
1690 let mut p = SParser {
1691 z,
1692 buff: LexBuffer::new(),
1693 dyd: DynDataStub::new(),
1694 mode: mode.map(|m| m.to_vec()),
1695 name: name.to_vec(),
1696 };
1697
1698 let saved_gcstp = {
1701 let mut g = state.global_mut();
1702 let old = g.gc_stop_flags();
1703 let _ = g.stop_gc_internal();
1704 old
1705 };
1706
1707 let top_idx = state.top_idx();
1708 let errfunc = state.errfunc;
1709 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1710
1711 state.global_mut().set_gc_stop_flags(saved_gcstp);
1712
1713 state.dec_nny();
1717
1718 status
1719}
1720
1721