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(
38 state: &mut LuaState,
39 z: &mut ZIO,
40 _buff: &mut LexBuffer,
41 _dyd: &mut DynDataStub,
42 name: &[u8],
43 c: i32,
44) -> Result<lua_types::GcRef<lua_types::closure::LuaLClosure>, LuaError> {
45 let hook = state.global().parser_hook;
46 if let Some(parse) = hook {
47 let mut source: Vec<u8> = Vec::new();
48 if c >= 0 {
49 source.push(c as u8);
50 }
51 loop {
52 let b = z.getc();
53 if b < 0 {
54 break;
55 }
56 source.push(b as u8);
57 }
58 return parse(state, &source, name, c);
59 }
60 Err(LuaError::syntax(format_args!(
61 "{}: Lua text parser not yet wired (phase-b: lua-parse::parse)",
62 core::str::from_utf8(name).unwrap_or("?"),
63 )))
64}
65
66const LUAI_MAXSTACK: usize = 1_000_000;
70const ERRORSTACKSIZE: usize = LUAI_MAXSTACK + 200;
71
72const EXTRA_STACK: i32 = 5;
73
74const LUA_MINSTACK: i32 = 20;
75
76const LUA_MULTRET: i32 = -1;
77
78const NYCI: u32 = 0x10001;
79
80use crate::state::LUAI_MAXCCALLS;
81
82const CIST_C: u16 = 1 << 1;
84const CIST_FRESH: u16 = 1 << 2;
85const CIST_HOOKED: u16 = 1 << 3;
86const CIST_YPCALL: u16 = 1 << 4;
87const CIST_TAIL: u16 = 1 << 5;
88const CIST_HOOKYIELD: u16 = 1 << 6;
89const CIST_TRAN: u16 = 1 << 8;
90const CIST_CLSRET: u16 = 1 << 9;
91const CIST_FIN: u16 = 1 << 7;
92
93const LUA_MASKCALL: u8 = 1 << 0;
95const LUA_MASKRET: u8 = 1 << 1;
96
97const LUA_HOOKCALL: i32 = 0;
98const LUA_HOOKRET: i32 = 1;
99const LUA_HOOKTAILCALL: i32 = 4;
100
101const CLOSE_K_TOP: i32 = -1;
104
105#[inline]
109fn error_status(s: LuaStatus) -> bool {
110 (s as i32) > (LuaStatus::Yield as i32)
111}
112
113fn run_message_handler(
114 state: &mut LuaState,
115 err_slot: StackIdx,
116 errfunc_idx: StackIdx,
117 original_status: LuaStatus,
118 recover_ci: CallInfoIdx,
119 recover_allowhook: bool,
120) -> LuaStatus {
121 let saved_n_ccalls = state.n_ccalls;
122 state.n_ccalls += NYCI;
125 loop {
126 let arg = state.get_at(err_slot).clone();
127 state.set_top(err_slot + 1);
128 state.push(arg);
129 let handler = state.get_at(errfunc_idx).clone();
130 let func_idx = state.top_idx() - 2;
131 state.set_at(func_idx, handler);
132
133 match state.call_no_yield(func_idx, 1) {
134 Ok(()) => {
135 state.n_ccalls = saved_n_ccalls;
136 return original_status;
137 }
138 Err(e) => {
139 let status = e.to_status();
140 let value = e.into_value();
141 state.ci = recover_ci;
142 state.allowhook = recover_allowhook;
143 state.set_top(err_slot + 1);
144 state.set_at(err_slot, value);
145
146 if status == LuaStatus::ErrRun {
147 continue;
148 }
149
150 state.n_ccalls = saved_n_ccalls;
151 return LuaStatus::ErrErr;
152 }
153 }
154 }
155}
156
157pub(crate) fn set_error_obj(state: &mut LuaState, errcode: LuaStatus, old_top: StackIdx) {
170 match errcode {
171 LuaStatus::ErrMem => {
172 let memerrmsg = state.global().memerrmsg.clone();
174 state.set_at(old_top, LuaValue::Str(memerrmsg));
175 }
176 LuaStatus::ErrErr => {
177 if let Ok(s) = state.intern_str(b"error in error handling") {
178 state.set_at(old_top, LuaValue::Str(s));
179 }
180 }
181 LuaStatus::Ok => {
182 state.set_at(old_top, LuaValue::Nil);
183 }
184 _ => {
185 debug_assert!(error_status(errcode));
186 let top = state.top_idx();
187 let err_val = state.get_at(top - 1).clone();
188 state.set_at(old_top, err_val);
189 }
190 }
191 state.set_top(old_top + 1);
192}
193
194pub(crate) fn raw_run_protected<F>(state: &mut LuaState, f: F) -> Result<(), LuaError>
203where
204 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
205{
206 let old_n_ccalls = state.n_ccalls;
207 let result = f(state);
209 state.n_ccalls = old_n_ccalls;
210 result
211}
212
213pub(crate) fn realloc_stack(
228 state: &mut LuaState,
229 new_size: usize,
230 raise_error: bool,
231) -> Result<bool, LuaError> {
232 let old_size = state.stack_size() as usize;
233 debug_assert!(new_size <= LUAI_MAXSTACK || new_size == ERRORSTACKSIZE);
234
235 let old_gcstop = state.global().gcstopem;
238 state.global_mut().gcstopem = true;
239
240 let new_extent = new_size as usize + EXTRA_STACK as usize;
242 let alloc_result = state.stack_resize(new_extent);
243
244 state.global_mut().gcstopem = old_gcstop;
245
246 if alloc_result.is_err() {
247 if raise_error {
248 return Err(LuaError::Memory);
249 } else {
250 return Ok(false);
251 }
252 }
253
254 state.stack_last = StackIdx(new_size as u32);
255
256 let old_extent = old_size + EXTRA_STACK as usize;
258 for i in old_extent..new_extent {
259 state.stack_set_nil(i);
260 }
261
262 Ok(true)
263}
264
265pub(crate) fn grow_stack(
271 state: &mut LuaState,
272 n: i32,
273 raise_error: bool,
274) -> Result<bool, LuaError> {
275 let size = state.stack_size();
276
277 if size > LUAI_MAXSTACK {
278 debug_assert!(state.stack_size() == ERRORSTACKSIZE);
280 if raise_error {
281 return Err(LuaError::with_status(LuaStatus::ErrErr));
282 }
283 return Ok(false);
284 } else if (n as usize) < LUAI_MAXSTACK {
285 let mut new_size = 2 * size;
286 let needed = (state.top_idx().0 as i32 + n) as usize;
287 if new_size > LUAI_MAXSTACK {
288 new_size = LUAI_MAXSTACK;
289 }
290 if new_size < needed {
291 new_size = needed;
292 }
293 if new_size <= LUAI_MAXSTACK {
294 return realloc_stack(state, new_size, raise_error);
295 }
296 }
297 realloc_stack(state, ERRORSTACKSIZE, raise_error)?;
299 if raise_error {
300 return Err(LuaError::runtime(format_args!("stack overflow")));
301 }
302 Ok(false)
303}
304
305fn stack_in_use(state: &LuaState) -> usize {
308 let mut lim = state.top_idx();
309 let mut ci_idx_opt = Some(state.ci);
311 while let Some(ci_idx) = ci_idx_opt {
312 let ci = state.get_ci(ci_idx);
313 if lim.0 < ci.top.0 {
314 lim = ci.top;
315 }
316 ci_idx_opt = ci.previous;
317 }
318 debug_assert!(true );
319 let res = lim.0 as usize + 1;
320 if res < LUA_MINSTACK as usize {
321 LUA_MINSTACK as usize
322 } else {
323 res
324 }
325}
326
327pub(crate) fn shrink_stack(state: &mut LuaState) {
330 let inuse = stack_in_use(state);
331 let max = if inuse > LUAI_MAXSTACK / 3 {
332 LUAI_MAXSTACK
333 } else {
334 inuse * 3
335 };
336 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
337 let nsize = if inuse > LUAI_MAXSTACK / 2 {
338 LUAI_MAXSTACK
339 } else {
340 inuse * 2
341 };
342 let _ = realloc_stack(state, nsize, false);
343 }
344 state.shrink_ci();
345}
346
347pub(crate) fn hook(
354 state: &mut LuaState,
355 event: i32,
356 line: i32,
357 ftransfer: i32,
358 ntransfer: i32,
359) -> Result<(), LuaError> {
360 if !state.has_hook() || !state.allowhook {
361 return Ok(());
362 }
363
364 let ci_idx = state.ci;
365
366 let saved_top = state.top_idx();
368 let saved_ci_top = state.get_ci(ci_idx).top;
369
370 let mut mask = CIST_HOOKED;
371
372 if ntransfer != 0 {
373 mask |= CIST_TRAN;
374 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
375 }
376
377 {
378 let ci = state.get_ci(ci_idx);
379 if ci.is_lua() {
380 let ci_top = ci.top;
381 if state.top_idx().0 < ci_top.0 {
382 state.set_top(ci_top);
383 }
384 }
385 }
386
387 state.check_stack(LUA_MINSTACK as i32)?;
388
389 {
390 let top = state.top_idx();
391 let ci = state.get_ci_mut(ci_idx);
392 if ci.top.0 < (top + LUA_MINSTACK).0 {
393 let new_top = top + LUA_MINSTACK;
394 ci.top = new_top;
395 state.clear_stack_range(top, new_top);
396 }
397 }
398
399 state.allowhook = false;
400 state.get_ci_mut(ci_idx).callstatus |= mask;
401
402 let mut ar = crate::debug::LuaDebug::default();
403 ar.event = event;
404 ar.currentline = line;
405 ar.ftransfer = ftransfer as u16;
406 ar.ntransfer = ntransfer as u16;
407 ar.i_ci = Some(ci_idx);
408 let hook_opt = state.hook.take();
409 if let Some(mut h) = hook_opt {
410 h(state, &ar);
411 if state.hook.is_none() {
412 state.hook = Some(h);
413 }
414 }
415
416 debug_assert!(!state.allowhook);
417 state.allowhook = true;
418
419 state.get_ci_mut(ci_idx).top = saved_ci_top;
421 state.set_top(saved_top);
422 state.get_ci_mut(ci_idx).callstatus &= !mask;
423
424 Ok(())
425}
426
427pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
430 state.oldpc = 0;
431 if state.hookmask & LUA_MASKCALL != 0 {
432 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
433 LUA_HOOKTAILCALL
434 } else {
435 LUA_HOOKCALL
436 };
437 let numparams = {
439 state.get_ci_lua_proto_numparams(ci_idx)
442 };
443 let pc = state.ci_savedpc(ci_idx);
444 state.set_ci_savedpc(ci_idx, pc + 1);
445 hook(state, event, -1, 1, numparams as i32)?;
446 state.set_ci_savedpc(ci_idx, pc);
447 }
448 Ok(())
449}
450
451fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
454 if state.hookmask & LUA_MASKRET != 0 {
455 let first_res = state.top_idx().0 as i32 - nres;
456 let mut delta: i32 = 0;
457
458 if state.get_ci(ci_idx).is_lua() {
459 let (is_vararg, nextraargs, numparams) = state.get_ci_vararg_info(ci_idx);
461 if is_vararg {
462 delta = nextraargs + numparams as i32 + 1;
463 }
464 }
465
466 let original_func = state.get_ci(ci_idx).func;
468 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
469
470 let ci_func = state.get_ci(ci_idx).func;
471 let ftransfer = (first_res - ci_func.0 as i32) as u16;
472
473 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
474
475 state.get_ci_mut(ci_idx).func = original_func;
476 }
477
478 let previous = state.get_ci(ci_idx).previous;
480 if let Some(prev_idx) = previous {
481 if state.get_ci(prev_idx).is_lua() {
482 state.oldpc = state.get_ci_pcrel(prev_idx);
486 }
487 }
488
489 Ok(())
490}
491
492fn try_func_tm(
502 state: &mut LuaState,
503 func_idx: StackIdx,
504 call_metamethods: &mut u8,
505) -> Result<StackIdx, LuaError> {
506 if *call_metamethods == 15 {
507 return Err(LuaError::runtime(format_args!("'__call' chain too long")));
508 }
509 state.check_stack(1)?;
512 if state.gc_check_needed {
513 state.gc_check_step();
514 }
515
516 let func_val = state.get_at(func_idx).clone();
517 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
518
519 if matches!(tm, LuaValue::Nil) {
520 let offender = state.get_at(func_idx).clone();
521 return Err(crate::debug::call_error(state, &offender, func_idx));
522 }
523
524 let top = state.top_idx();
526 let mut p = top;
527 while p.0 > func_idx.0 {
528 let val = state.get_at(p - 1).clone();
529 state.set_at(p, val);
530 p = p - 1;
531 }
532 state.set_top(top + 1);
533 state.set_at(func_idx, tm);
534 *call_metamethods += 1;
535
536 Ok(func_idx)
537}
538
539#[inline(always)]
544fn move_results(
545 state: &mut LuaState,
546 res_idx: StackIdx,
547 nres: i32,
548 wanted: i32,
549) -> Result<(), LuaError> {
550 match wanted {
551 0 => {
552 state.set_top(res_idx);
553 return Ok(());
554 }
555 1 => {
556 if nres == 0 {
557 state.set_at(res_idx, LuaValue::Nil);
558 } else {
559 let top = state.top_idx();
560 let src = state.get_at(top - nres as i32).clone();
561 state.set_at(res_idx, src);
562 }
563 state.set_top(res_idx + 1);
564 return Ok(());
565 }
566 LUA_MULTRET => {
567 }
569 _ => {
570 if wanted < LUA_MULTRET {
572 let ci_idx = state.ci;
573 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
574 state.set_ci_u2_nres(ci_idx, nres);
575
576 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
579
580 let ci_idx = state.ci;
581 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
582
583 if state.hookmask != 0 {
584 let saved_res = res_idx;
586 rethook(state, ci_idx, nres)?;
587 let _ = saved_res; }
589
590 let decoded_wanted = -(wanted) - 3;
592 let wanted = if decoded_wanted == LUA_MULTRET {
593 nres
594 } else {
595 decoded_wanted
596 };
597
598 let first_result = state.top_idx().0 as i32 - nres;
600 let actual_nres = nres.min(wanted);
601 for i in 0..actual_nres {
602 let src = state.get_at((first_result + i) as u32).clone();
603 state.set_at(res_idx + i as i32, src);
604 }
605 for i in actual_nres..wanted {
606 state.set_at(res_idx + i as i32, LuaValue::Nil);
607 }
608 state.set_top(res_idx + wanted as i32);
609 return Ok(());
610 }
611 }
612 }
613
614 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
616 let first_result = state.top_idx().0 as i32 - nres;
617 let actual_nres = nres.min(effective_wanted);
618 for i in 0..actual_nres {
619 let src = state.get_at((first_result + i) as u32).clone();
620 state.set_at(res_idx + i as i32, src);
621 }
622 for i in actual_nres..effective_wanted {
623 state.set_at(res_idx + i as i32, LuaValue::Nil);
624 }
625 state.set_top(res_idx + effective_wanted as i32);
626 Ok(())
627}
628
629#[inline(always)]
633pub(crate) fn poscall(
634 state: &mut LuaState,
635 ci_idx: CallInfoIdx,
636 nres: i32,
637) -> Result<(), LuaError> {
638 let wanted = state.get_ci(ci_idx).nresults as i32;
639
640 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
641 rethook(state, ci_idx, nres)?;
642 }
643
644 let func_idx = state.get_ci(ci_idx).func;
645 move_results(state, func_idx, nres, wanted)?;
646
647 debug_assert!(
648 state.get_ci(ci_idx).callstatus
649 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
650 == 0
651 );
652
653 let previous = state
654 .get_ci(ci_idx)
655 .previous
656 .expect("poscall: no previous call frame");
657 state.ci = previous;
658 Ok(())
659}
660
661#[inline(always)]
665fn prep_call_info(
666 state: &mut LuaState,
667 func_idx: StackIdx,
668 nret: i32,
669 mask: u16,
670 top_idx: StackIdx,
671) -> Result<CallInfoIdx, LuaError> {
672 let ci_idx = state.next_ci()?;
674 state.ci = ci_idx;
675 {
676 let ci = state.get_ci_mut(ci_idx);
677 ci.func = func_idx;
678 ci.nresults = nret as i16;
679 ci.callstatus = mask;
680 ci.call_metamethods = 0;
681 ci.top = top_idx;
682 ci.u = if (mask & crate::state::CIST_C) != 0 {
683 crate::state::CallInfoFrame::c_default()
684 } else {
685 crate::state::CallInfoFrame::lua_default()
686 };
687 }
688 Ok(ci_idx)
689}
690
691#[inline(always)]
696fn precall_c(
697 state: &mut LuaState,
698 func_idx: StackIdx,
699 nresults: i32,
700 f: crate::state::LuaCallable,
701 call_metamethods: u8,
702) -> Result<i32, LuaError> {
703 state.check_stack(LUA_MINSTACK as i32)?;
704 if state.gc_check_needed {
705 state.gc_check_step();
706 }
707
708 let top_idx = state.top_idx();
709 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
710 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
711
712 debug_assert!(true );
713
714 if state.hookmask & LUA_MASKCALL != 0 {
715 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
716 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
717 }
718
719 let n = f.call(state)? as i32;
720
721 debug_assert!(
723 n <= state.top_idx().0 as i32,
724 "C function returned more values than available"
725 );
726
727 poscall(state, ci_idx, n)?;
728 Ok(n)
729}
730
731pub(crate) fn pretailcall(
736 state: &mut LuaState,
737 ci_idx: CallInfoIdx,
738 mut func_idx: StackIdx,
739 mut narg1: i32,
740 delta: i32,
741) -> Result<i32, LuaError> {
742 let mut call_metamethods = 0u8;
743 loop {
744 let func_val = state.get_at(func_idx).clone();
745 match func_val {
746 LuaValue::Function(LuaClosure::C(ref cl)) => {
747 let cfunc = state.global().c_functions[cl.func].clone();
748 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
749 }
750 LuaValue::Function(LuaClosure::LightC(f)) => {
751 let cfunc = state.global().c_functions[f].clone();
752 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
753 }
754 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
755 let proto = cl.proto.clone();
756 let fsize = proto.maxstacksize as i32;
757 let nfixparams = proto.numparams as i32;
758
759 state.check_stack(fsize - delta)?;
760 if state.gc_check_needed {
761 state.gc_check_step();
762 }
763
764 {
765 let ci = state.get_ci_mut(ci_idx);
766 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
767 }
768 let ci_func = state.get_ci(ci_idx).func;
769
770 for i in 0..narg1 {
771 let src = state.get_at(func_idx + i as i32).clone();
772 state.set_at(ci_func + i as i32, src);
773 }
774
775 func_idx = ci_func;
777
778 while narg1 <= nfixparams {
779 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
780 narg1 += 1;
781 }
782
783 {
784 let new_ci_top = func_idx + 1 + fsize as i32;
785 let stack_last = state.stack_last;
786 let live_top = state.top_idx();
787 let ci = state.get_ci_mut(ci_idx);
788 ci.call_metamethods = call_metamethods;
789 ci.top = new_ci_top;
790 debug_assert!(ci.top.0 <= stack_last.0);
791 ci.set_saved_pc(0);
792 ci.callstatus |= CIST_TAIL;
793 state.clear_stack_range(live_top, new_ci_top);
794 }
795
796 state.set_top(func_idx + narg1 as i32);
797 return Ok(-1); }
799 _ => {
800 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
801 narg1 += 1;
802 }
804 }
805 }
806}
807
808#[inline(always)]
818pub(crate) fn precall(
819 state: &mut LuaState,
820 func_idx: StackIdx,
821 nresults: i32,
822) -> Result<Option<CallInfoIdx>, LuaError> {
823 if let LuaValue::Function(LuaClosure::Lua(cl)) = &state.stack[func_idx.0 as usize].val {
824 let nfixparams = cl.proto.numparams as i32;
825 let fsize = cl.proto.maxstacksize as i32;
826 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
827
828 state.check_stack(fsize)?;
829 if state.gc_check_needed {
830 state.gc_check_step();
831 }
832
833 let ci_idx = prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
834 state.set_ci_savedpc(ci_idx, 0);
835
836 if narg < nfixparams {
837 fill_missing_params(state, narg, nfixparams);
838 }
839 return Ok(Some(ci_idx));
840 }
841 precall_slow(state, func_idx, nresults)
842}
843
844#[cold]
848#[inline(never)]
849fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
850 while narg < nfixparams {
851 let top = state.top_idx();
852 state.set_at(top, LuaValue::Nil);
853 state.set_top(top + 1);
854 narg += 1;
855 }
856}
857
858#[cold]
862#[inline(never)]
863fn precall_slow(
864 state: &mut LuaState,
865 mut func_idx: StackIdx,
866 nresults: i32,
867) -> Result<Option<CallInfoIdx>, LuaError> {
868 let mut call_metamethods = 0u8;
869 loop {
870 let func_val = state.get_at(func_idx).clone();
871 match func_val {
872 LuaValue::Function(LuaClosure::C(ref cl)) => {
873 let cfunc = state.global().c_functions[cl.func].clone();
874 precall_c(state, func_idx, nresults, cfunc, call_metamethods)?;
875 return Ok(None);
876 }
877 LuaValue::Function(LuaClosure::LightC(f)) => {
878 state.check_stack(LUA_MINSTACK as i32)?;
879 if state.gc_check_needed {
880 state.gc_check_step();
881 }
882
883 let top_idx = state.top_idx();
884 let ci_idx =
885 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
886 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
887
888 if state.hookmask & LUA_MASKCALL != 0 {
889 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
890 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
891 }
892
893 let cfunc = state.global().c_functions[f].clone();
894 let n = cfunc.call(state)? as i32;
895 debug_assert!(
896 n <= state.top_idx().0 as i32,
897 "C function returned more values than available"
898 );
899 poscall(state, ci_idx, n)?;
900 return Ok(None);
901 }
902 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
903 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
904 let nfixparams = cl.proto.numparams as i32;
905 let fsize = cl.proto.maxstacksize as i32;
906
907 state.check_stack(fsize)?;
908 if state.gc_check_needed {
909 state.gc_check_step();
910 }
911
912 let ci_idx =
913 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
914 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
915 state.set_ci_savedpc(ci_idx, 0);
916
917 if narg < nfixparams {
918 fill_missing_params(state, narg, nfixparams);
919 }
920 return Ok(Some(ci_idx));
921 }
922 _ => {
923 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
924 }
925 }
926 }
927}
928
929#[inline]
933fn ccall_inner(
934 state: &mut LuaState,
935 func_idx: StackIdx,
936 n_results: i32,
937 inc: u32,
938) -> Result<(), LuaError> {
939 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
940}
941
942#[inline]
943fn ccall_inner_with_status(
944 state: &mut LuaState,
945 func_idx: StackIdx,
946 n_results: i32,
947 inc: u32,
948 extra_callstatus: u16,
949) -> Result<(), LuaError> {
950 state.n_ccalls += inc;
951
952 if state.c_calls() >= LUAI_MAXCCALLS {
954 state.check_stack(0)?;
956 state.check_c_stack()?;
957 }
958
959 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
960 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
961 vm::execute(state, ci_idx)?;
962 }
963
964 state.n_ccalls -= inc;
965 Ok(())
966}
967
968pub(crate) fn call(
971 state: &mut LuaState,
972 func_idx: StackIdx,
973 n_results: i32,
974) -> Result<(), LuaError> {
975 ccall_inner(state, func_idx, n_results, 1)
976}
977
978pub(crate) fn callnoyield(
981 state: &mut LuaState,
982 func_idx: StackIdx,
983 n_results: i32,
984) -> Result<(), LuaError> {
985 ccall_inner(state, func_idx, n_results, NYCI)
987}
988
989fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
996 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
999
1000 if status == LuaStatus::Ok {
1001 status = LuaStatus::Yield;
1002 } else {
1003 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
1004 state.allowhook = state.get_ci(ci_idx).get_oah();
1006 let _func_idx = func::close(state, func_idx, status as i32, true)?;
1008 set_error_obj(state, status, func_idx);
1009
1010 if state.errfunc != 0
1019 && error_status(status)
1020 && status != LuaStatus::ErrErr
1021 && status != LuaStatus::ErrSyntax
1022 {
1023 let errfunc_stk = StackIdx(state.errfunc as u32);
1024 status = run_message_handler(
1025 state,
1026 func_idx,
1027 errfunc_stk,
1028 status,
1029 ci_idx,
1030 state.allowhook,
1031 );
1032 }
1033
1034 shrink_stack(state);
1035 state
1036 .get_ci_mut(ci_idx)
1037 .set_recover_status(LuaStatus::Ok as i32);
1038 }
1039
1040 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1041 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1042 state.errfunc = old_errfunc;
1043
1044 Ok(status)
1045}
1046
1047fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1050 let n;
1051
1052 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1053 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1054 n = state.get_ci_u2_nres(ci_idx);
1055 } else {
1056 debug_assert!(
1057 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1058 "finishCcall: no continuation or non-yieldable"
1059 );
1060
1061 let mut status = LuaStatus::Yield;
1062
1063 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1064 status = finish_pcallk(state, ci_idx)?;
1065 }
1066
1067 state.adjust_results(LUA_MULTRET);
1069
1070 let k = state.get_ci(ci_idx).u_c_k();
1074 let ctx = state.get_ci(ci_idx).u_c_ctx();
1075 if let Some(k_fn) = k {
1076 n = k_fn(state, status as i32, ctx)? as i32;
1077 } else {
1078 return Err(LuaError::runtime(format_args!(
1080 "finishCcall: missing continuation"
1081 )));
1082 }
1083 debug_assert!(
1084 n <= state.top_idx().0 as i32,
1085 "continuation returned more values than available"
1086 );
1087 }
1088
1089 poscall(state, ci_idx, n)?;
1090 Ok(())
1091}
1092
1093fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1096 loop {
1097 let ci_idx = state.ci;
1098 if state.is_base_ci(ci_idx) {
1099 break;
1100 }
1101 if !state.get_ci(ci_idx).is_lua() {
1102 finish_ccall(state, ci_idx)?;
1103 } else {
1104 vm::finish_op(state)?;
1105 vm::execute(state, ci_idx)?;
1106 }
1107 }
1108 Ok(())
1109}
1110
1111fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1114 let mut ci_idx_opt = Some(state.ci);
1115 while let Some(ci_idx) = ci_idx_opt {
1116 let ci = state.get_ci(ci_idx);
1117 if ci.callstatus & CIST_YPCALL != 0 {
1118 return Some(ci_idx);
1119 }
1120 ci_idx_opt = ci.previous;
1121 }
1122 None
1123}
1124
1125fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1128 let top = state.top_idx();
1129 state.set_top(top - narg as i32);
1130 let s = state.intern_str(msg).ok();
1132 let new_top = state.top_idx();
1133 if let Some(s) = s {
1134 state.set_at(new_top, LuaValue::Str(s));
1135 }
1136 state.set_top(new_top + 1);
1137 LuaStatus::ErrRun
1138}
1139
1140fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1143 let top = state.top_idx();
1144 let first_arg = top - nargs as i32;
1145 let ci_idx = state.ci;
1146
1147 if state.status == LuaStatus::Ok as u8 {
1148 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1149 } else {
1150 debug_assert!(state.status == LuaStatus::Yield as u8);
1151 state.status = LuaStatus::Ok as u8;
1152
1153 if state.get_ci(ci_idx).is_lua() {
1154 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1155 let pc = state.ci_savedpc(ci_idx);
1156 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1157 state.set_top(first_arg);
1158 vm::execute(state, ci_idx)?;
1159 } else {
1160 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1161 let ctx = state.get_ci(ci_idx).u_c_ctx();
1162 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1163 debug_assert!(n <= state.top_idx().0 as i32);
1164 poscall(state, ci_idx, n)?;
1165 } else {
1166 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1168 poscall(state, ci_idx, n)?;
1169 }
1170 }
1171
1172 unroll(state)?;
1173 }
1174 Ok(())
1175}
1176
1177fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1180 while error_status(status) {
1181 if let Some(ci_idx) = find_pcall(state) {
1182 state.ci = ci_idx;
1183 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1184 status = match raw_run_protected(state, |s| unroll(s)) {
1189 Ok(()) => LuaStatus::Ok,
1190 Err(e) => {
1191 let s = e.to_status();
1192 if error_status(s) {
1193 state.push(e.into_value());
1194 }
1195 s
1196 }
1197 };
1198 } else {
1199 break;
1200 }
1201 }
1202 status
1203}
1204
1205pub fn lua_resume(
1208 state: &mut LuaState,
1209 from: Option<&mut LuaState>,
1210 nargs: i32,
1211 nresults: &mut i32,
1212) -> LuaStatus {
1213 if state.status == LuaStatus::Ok as u8 {
1219 if !state.is_base_ci(state.ci) {
1220 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1221 }
1222 let ci_func = state.get_ci(state.ci).func;
1223 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1224 return resume_error(state, b"cannot resume dead coroutine", nargs);
1225 }
1226 } else if state.status != LuaStatus::Yield as u8 {
1227 return resume_error(state, b"cannot resume dead coroutine", nargs);
1228 }
1229
1230 state.n_ccalls = from.as_ref().map(|f| f.c_calls() as u32).unwrap_or(0);
1231
1232 if state.c_calls() >= LUAI_MAXCCALLS {
1233 return resume_error(state, b"C stack overflow", nargs);
1234 }
1235 state.n_ccalls += 1;
1236
1237 debug_assert!(
1238 if state.status == LuaStatus::Ok as u8 {
1239 nargs + 1 <= state.top_idx().0 as i32
1240 } else {
1241 nargs <= state.top_idx().0 as i32
1242 },
1243 "lua_resume: not enough stack elements"
1244 );
1245
1246 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1252 Ok(()) => (LuaStatus::Ok, None),
1253 Err(e) => {
1254 let s = e.to_status();
1255 let v = if error_status(s) {
1256 Some(e.into_value())
1257 } else {
1258 None
1259 };
1260 (s, v)
1261 }
1262 };
1263 if let Some(v) = err_value {
1264 state.push(v);
1265 }
1266
1267 status = precover(state, status);
1268
1269 if !error_status(status) {
1270 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1271 } else {
1272 state.status = status as u8;
1274 let top = state.top_idx();
1275 set_error_obj(state, status, top);
1276 let new_top = state.top_idx();
1277 let ci_idx = state.ci;
1278 state.get_ci_mut(ci_idx).top = new_top;
1279 }
1280
1281 let ci_idx = state.ci;
1282 *nresults = if status == LuaStatus::Yield {
1283 state.get_ci_u2_nyield(ci_idx)
1284 } else {
1285 let ci_func = state.get_ci(ci_idx).func;
1286 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1287 };
1288
1289 status
1290}
1291
1292pub fn lua_isyieldable(state: &LuaState) -> bool {
1295 state.is_yieldable()
1297}
1298
1299pub fn lua_yieldk(
1303 state: &mut LuaState,
1304 nresults: i32,
1305 ctx: isize,
1306 k: Option<crate::state::LuaKFunction>,
1307) -> Result<i32, LuaError> {
1308 let ci_idx = state.ci;
1312
1313 debug_assert!(
1314 nresults <= state.top_idx().0 as i32,
1315 "lua_yieldk: not enough elements on stack"
1316 );
1317
1318 if !state.is_yieldable() {
1319 if !state.is_main_thread() {
1320 return Err(LuaError::runtime(format_args!(
1321 "attempt to yield across a C-call boundary"
1322 )));
1323 } else {
1324 return Err(LuaError::runtime(format_args!(
1325 "attempt to yield from outside a coroutine"
1326 )));
1327 }
1328 }
1329
1330 state.status = LuaStatus::Yield as u8;
1331 state.set_ci_u2_nyield(ci_idx, nresults);
1332
1333 if state.get_ci(ci_idx).is_lua() {
1334 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1335 debug_assert!(nresults == 0, "hooks cannot yield values");
1336 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1337 } else {
1339 if let crate::state::CallInfoFrame::C {
1341 k: ref mut frame_k,
1342 ctx: ref mut frame_ctx,
1343 ..
1344 } = state.get_ci_mut(ci_idx).u
1345 {
1346 *frame_k = k;
1347 if k.is_some() {
1348 *frame_ctx = ctx;
1349 }
1350 }
1351 return Err(LuaError::Yield);
1353 }
1354
1355 debug_assert!(
1356 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1357 "lua_yieldk called outside a hook"
1358 );
1359 Ok(0) }
1361
1362struct CloseP {
1369 level: StackIdx,
1370 status: LuaStatus,
1371}
1372
1373fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1376 func::close(state, pcl.level, pcl.status as i32, false)?;
1378 Ok(())
1379}
1380
1381pub(crate) fn close_protected(
1385 state: &mut LuaState,
1386 level: StackIdx,
1387 status: LuaStatus,
1388) -> LuaStatus {
1389 let old_ci = state.ci;
1390 let old_allowhook = state.allowhook;
1391 let mut status = status;
1392
1393 loop {
1394 let mut pcl = CloseP { level, status };
1395 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1396 Ok(()) => (LuaStatus::Ok, None),
1397 Err(e) => (e.to_status(), Some(e.into_value())),
1398 };
1399 if run_status == LuaStatus::Ok {
1400 return pcl.status;
1401 }
1402 state.ci = old_ci;
1403 state.allowhook = old_allowhook;
1404 if let Some(v) = err_value {
1410 state.push(v);
1411 }
1412 status = run_status;
1413 }
1414}
1415
1416pub(crate) fn pcall<F>(state: &mut LuaState, func: F, old_top: StackIdx, ef: isize) -> LuaStatus
1420where
1421 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1422{
1423 let old_ci = state.ci;
1424 let old_allowhook = state.allowhook;
1425 let old_errfunc = state.errfunc;
1426 state.errfunc = ef;
1427
1428 let mut status = match raw_run_protected(state, func) {
1434 Ok(()) => LuaStatus::Ok,
1435 Err(e) => {
1436 let s = e.to_status();
1437 state.push(e.into_value());
1438 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1444 let errfunc_idx = StackIdx(ef as u32);
1445 let err_slot = state.top_idx() - 1;
1446 run_message_handler(state, err_slot, errfunc_idx, s, old_ci, old_allowhook)
1447 } else {
1448 s
1449 }
1450 }
1451 };
1452
1453 if status != LuaStatus::Ok
1461 && status != LuaStatus::ErrSyntax
1462 && state.global().lua_version == lua_types::LuaVersion::V55
1463 {
1464 let top = state.top_idx();
1465 if matches!(state.get_at(top - 1), LuaValue::Nil) {
1466 if let Ok(s) = state.intern_str(b"<no error object>") {
1467 state.set_at(top - 1, LuaValue::Str(s));
1468 }
1469 }
1470 }
1471
1472 if status != LuaStatus::Ok {
1473 state.ci = old_ci;
1474 state.allowhook = old_allowhook;
1475 status = close_protected(state, old_top, status);
1476 set_error_obj(state, status, old_top);
1478 shrink_stack(state);
1479 }
1480
1481 state.errfunc = old_errfunc;
1482 status
1483}
1484
1485struct SParser {
1495 z: ZIO,
1496 buff: LexBuffer,
1498 dyd: DynDataStub,
1500 mode: Option<Vec<u8>>,
1502 name: Vec<u8>,
1503}
1504
1505fn check_mode(mode: Option<&[u8]>, kind: &[u8]) -> Result<(), LuaError> {
1508 if let Some(mode_bytes) = mode {
1509 let kind_char = kind[0];
1510 if !mode_bytes.contains(&kind_char) {
1511 return Err(LuaError::syntax(format_args!(
1514 "attempt to load a {} chunk (mode is '{}')",
1515 core::str::from_utf8(kind).unwrap_or("?"),
1516 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1517 )));
1518 }
1519 }
1520 Ok(())
1521}
1522
1523fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1527 let c = p.z.getc();
1529
1530 let cl = if c == b'\x1b' as i32 {
1532 check_mode(p.mode.as_deref(), b"binary")?;
1533 crate::undump::undump(state, &mut p.z, &p.name)?
1535 } else {
1536 check_mode(p.mode.as_deref(), b"text")?;
1537 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1539 };
1540
1541 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1542 func::init_upvals(state, &cl)?;
1543
1544 state.check_stack(1)?;
1552 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1553
1554 Ok(())
1555}
1556
1557pub(crate) fn protected_parser(
1560 state: &mut LuaState,
1561 z: ZIO,
1562 name: &[u8],
1563 mode: Option<&[u8]>,
1564) -> LuaStatus {
1565 state.inc_nny();
1567
1568 let mut p = SParser {
1569 z,
1570 buff: LexBuffer::new(),
1571 dyd: DynDataStub::new(),
1572 mode: mode.map(|m| m.to_vec()),
1573 name: name.to_vec(),
1574 };
1575
1576 let top_idx = state.top_idx();
1579 let errfunc = state.errfunc;
1580 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1581
1582 state.dec_nny();
1586
1587 status
1588}
1589
1590