1#[allow(unused_imports)] use crate::prelude::*;
7use crate::{
8 func,
9 state::{CallInfoIdx, LuaState},
10 vm,
11};
12use lua_types::{
13 error::LuaError,
14 status::LuaStatus,
15 value::LuaValue,
16};
17use lua_types::StackIdx;
18use lua_types::closure::LuaClosure;
19use lua_types::tagmethod::TagMethod;
20use crate::zio::{ZIO, LexBuffer};
21
22struct DynDataStub;
24impl DynDataStub {
25 fn new() -> Self { DynDataStub }
26}
27
28fn parse_stub(
39 state: &mut LuaState,
40 z: &mut ZIO,
41 _buff: &mut LexBuffer,
42 _dyd: &mut DynDataStub,
43 name: &[u8],
44 c: i32,
45) -> Result<lua_types::GcRef<lua_types::closure::LuaLClosure>, LuaError> {
46 let hook = state.global().parser_hook;
47 if let Some(parse) = hook {
48 let mut source: Vec<u8> = Vec::new();
49 if c >= 0 {
50 source.push(c as u8);
51 }
52 loop {
53 let b = z.getc();
54 if b < 0 {
55 break;
56 }
57 source.push(b as u8);
58 }
59 return parse(state, &source, name, c);
60 }
61 Err(LuaError::syntax(format_args!(
62 "{}: Lua text parser not yet wired (phase-b: lua-parse::parse)",
63 core::str::from_utf8(name).unwrap_or("?"),
64 )))
65}
66
67const LUAI_MAXSTACK: usize = 1_000_000;
71const ERRORSTACKSIZE: usize = LUAI_MAXSTACK + 200;
72
73const EXTRA_STACK: i32 = 5;
74
75const LUA_MINSTACK: i32 = 20;
76
77const LUA_MULTRET: i32 = -1;
78
79const NYCI: u32 = 0x10001;
80
81use crate::state::LUAI_MAXCCALLS;
82
83const CIST_C: u16 = 1 << 1;
85const CIST_FRESH: u16 = 1 << 2;
86const CIST_HOOKED: u16 = 1 << 3;
87const CIST_YPCALL: u16 = 1 << 4;
88const CIST_TAIL: u16 = 1 << 5;
89const CIST_HOOKYIELD: u16 = 1 << 6;
90const CIST_TRAN: u16 = 1 << 8;
91const CIST_CLSRET: u16 = 1 << 9;
92const CIST_FIN: u16 = 1 << 7;
93
94const LUA_MASKCALL: u8 = 1 << 0;
96const LUA_MASKRET: u8 = 1 << 1;
97
98const LUA_HOOKCALL: i32 = 0;
99const LUA_HOOKRET: i32 = 1;
100const LUA_HOOKTAILCALL: i32 = 4;
101
102const CLOSE_K_TOP: i32 = -1;
105
106#[inline]
110fn error_status(s: LuaStatus) -> bool {
111 (s as i32) > (LuaStatus::Yield as i32)
112}
113
114pub(crate) fn set_error_obj(state: &mut LuaState, errcode: LuaStatus, old_top: StackIdx) {
127 match errcode {
128 LuaStatus::ErrMem => {
129 let memerrmsg = state.global().memerrmsg.clone();
131 state.set_at(old_top, LuaValue::Str(memerrmsg));
132 }
133 LuaStatus::ErrErr => {
134 if let Ok(s) = state.intern_str(b"error in error handling") {
135 state.set_at(old_top, LuaValue::Str(s));
136 }
137 }
138 LuaStatus::Ok => {
139 state.set_at(old_top, LuaValue::Nil);
140 }
141 _ => {
142 debug_assert!(error_status(errcode));
143 let top = state.top_idx();
144 let err_val = state.get_at(top - 1).clone();
145 state.set_at(old_top, err_val);
146 }
147 }
148 state.set_top(old_top + 1);
149}
150
151pub(crate) fn raw_run_protected<F>(state: &mut LuaState, f: F) -> Result<(), LuaError>
160where
161 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
162{
163 let old_n_ccalls = state.n_ccalls;
164 let result = f(state);
166 state.n_ccalls = old_n_ccalls;
167 result
168}
169
170pub(crate) fn realloc_stack(
185 state: &mut LuaState,
186 new_size: usize,
187 raise_error: bool,
188) -> Result<bool, LuaError> {
189 let old_size = state.stack_size() as usize;
190 debug_assert!(new_size <= LUAI_MAXSTACK || new_size == ERRORSTACKSIZE);
191
192 let old_gcstop = state.global().gcstopem;
195 state.global_mut().gcstopem = true;
196
197 let new_extent = new_size as usize + EXTRA_STACK as usize;
199 let alloc_result = state.stack_resize(new_extent);
200
201 state.global_mut().gcstopem = old_gcstop;
202
203 if alloc_result.is_err() {
204 if raise_error {
205 return Err(LuaError::Memory);
206 } else {
207 return Ok(false);
208 }
209 }
210
211 state.stack_last = StackIdx(new_size as u32);
212
213 let old_extent = old_size + EXTRA_STACK as usize;
215 for i in old_extent..new_extent {
216 state.stack_set_nil(i);
217 }
218
219 Ok(true)
220}
221
222pub(crate) fn grow_stack(
228 state: &mut LuaState,
229 n: i32,
230 raise_error: bool,
231) -> Result<bool, LuaError> {
232 let size = state.stack_size();
233
234 if size > LUAI_MAXSTACK {
235 debug_assert!(state.stack_size() == ERRORSTACKSIZE);
237 if raise_error {
238 return Err(LuaError::with_status(LuaStatus::ErrErr));
239 }
240 return Ok(false);
241 } else if (n as usize) < LUAI_MAXSTACK {
242 let mut new_size = 2 * size;
243 let needed = (state.top_idx().0 as i32 + n) as usize;
244 if new_size > LUAI_MAXSTACK {
245 new_size = LUAI_MAXSTACK;
246 }
247 if new_size < needed {
248 new_size = needed;
249 }
250 if new_size <= LUAI_MAXSTACK {
251 return realloc_stack(state, new_size, raise_error);
252 }
253 }
254 realloc_stack(state, ERRORSTACKSIZE, raise_error)?;
256 if raise_error {
257 return Err(LuaError::runtime(format_args!("stack overflow")));
258 }
259 Ok(false)
260}
261
262fn stack_in_use(state: &LuaState) -> usize {
265 let mut lim = state.top_idx();
266 let mut ci_idx_opt = Some(state.ci);
268 while let Some(ci_idx) = ci_idx_opt {
269 let ci = state.get_ci(ci_idx);
270 if lim.0 < ci.top.0 {
271 lim = ci.top;
272 }
273 ci_idx_opt = ci.previous;
274 }
275 debug_assert!(true );
276 let res = lim.0 as usize + 1;
277 if res < LUA_MINSTACK as usize {
278 LUA_MINSTACK as usize
279 } else {
280 res
281 }
282}
283
284pub(crate) fn shrink_stack(state: &mut LuaState) {
287 let inuse = stack_in_use(state);
288 let max = if inuse > LUAI_MAXSTACK / 3 {
289 LUAI_MAXSTACK
290 } else {
291 inuse * 3
292 };
293 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
294 let nsize = if inuse > LUAI_MAXSTACK / 2 {
295 LUAI_MAXSTACK
296 } else {
297 inuse * 2
298 };
299 let _ = realloc_stack(state, nsize, false);
300 }
301 state.shrink_ci();
302}
303
304pub(crate) fn hook(
311 state: &mut LuaState,
312 event: i32,
313 line: i32,
314 ftransfer: i32,
315 ntransfer: i32,
316) -> Result<(), LuaError> {
317 if !state.has_hook() || !state.allowhook {
318 return Ok(());
319 }
320
321 let ci_idx = state.ci;
322
323 let saved_top = state.top_idx();
325 let saved_ci_top = state.get_ci(ci_idx).top;
326
327 let mut mask = CIST_HOOKED;
328
329 if ntransfer != 0 {
330 mask |= CIST_TRAN;
331 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
332 }
333
334 {
335 let ci = state.get_ci(ci_idx);
336 if ci.is_lua() {
337 let ci_top = ci.top;
338 if state.top_idx().0 < ci_top.0 {
339 state.set_top(ci_top);
340 }
341 }
342 }
343
344 state.check_stack(LUA_MINSTACK as i32)?;
345
346 {
347 let top = state.top_idx();
348 let ci = state.get_ci_mut(ci_idx);
349 if ci.top.0 < (top + LUA_MINSTACK).0 {
350 let new_top = top + LUA_MINSTACK;
351 ci.top = new_top;
352 state.clear_stack_range(top, new_top);
353 }
354 }
355
356 state.allowhook = false;
357 state.get_ci_mut(ci_idx).callstatus |= mask;
358
359 let mut ar = crate::debug::LuaDebug::default();
360 ar.event = event;
361 ar.currentline = line;
362 ar.ftransfer = ftransfer as u16;
363 ar.ntransfer = ntransfer as u16;
364 ar.i_ci = Some(ci_idx);
365 let hook_opt = state.hook.take();
366 if let Some(mut h) = hook_opt {
367 h(state, &ar);
368 if state.hook.is_none() {
369 state.hook = Some(h);
370 }
371 }
372
373 debug_assert!(!state.allowhook);
374 state.allowhook = true;
375
376 state.get_ci_mut(ci_idx).top = saved_ci_top;
378 state.set_top(saved_top);
379 state.get_ci_mut(ci_idx).callstatus &= !mask;
380
381 Ok(())
382}
383
384pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
387 state.oldpc = 0;
388 if state.hookmask & LUA_MASKCALL != 0 {
389 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
390 LUA_HOOKTAILCALL
391 } else {
392 LUA_HOOKCALL
393 };
394 let numparams = {
396 state.get_ci_lua_proto_numparams(ci_idx)
399 };
400 let pc = state.ci_savedpc(ci_idx);
401 state.set_ci_savedpc(ci_idx, pc + 1);
402 hook(state, event, -1, 1, numparams as i32)?;
403 state.set_ci_savedpc(ci_idx, pc);
404 }
405 Ok(())
406}
407
408fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
411 if state.hookmask & LUA_MASKRET != 0 {
412 let first_res = state.top_idx().0 as i32 - nres;
413 let mut delta: i32 = 0;
414
415 if state.get_ci(ci_idx).is_lua() {
416 let (is_vararg, nextraargs, numparams) =
418 state.get_ci_vararg_info(ci_idx);
419 if is_vararg {
420 delta = nextraargs + numparams as i32 + 1;
421 }
422 }
423
424 let original_func = state.get_ci(ci_idx).func;
426 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
427
428 let ci_func = state.get_ci(ci_idx).func;
429 let ftransfer = (first_res - ci_func.0 as i32) as u16;
430
431 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
432
433 state.get_ci_mut(ci_idx).func = original_func;
434 }
435
436 let previous = state.get_ci(ci_idx).previous;
438 if let Some(prev_idx) = previous {
439 if state.get_ci(prev_idx).is_lua() {
440 state.oldpc = state.get_ci_pcrel(prev_idx);
444 }
445 }
446
447 Ok(())
448}
449
450fn try_func_tm(state: &mut LuaState, func_idx: StackIdx) -> Result<StackIdx, LuaError> {
460 state.check_stack(1)?;
463 if state.gc_check_needed {
464 state.gc_check_step();
465 }
466
467 let func_val = state.get_at(func_idx).clone();
468 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
469
470 if matches!(tm, LuaValue::Nil) {
471 let offender = state.get_at(func_idx).clone();
472 return Err(crate::debug::call_error(state, &offender, func_idx));
473 }
474
475 let top = state.top_idx();
477 let mut p = top;
478 while p.0 > func_idx.0 {
479 let val = state.get_at(p - 1).clone();
480 state.set_at(p, val);
481 p = p - 1;
482 }
483 state.set_top(top + 1);
484 state.set_at(func_idx, tm);
485
486 Ok(func_idx)
487}
488
489#[inline(always)]
494fn move_results(
495 state: &mut LuaState,
496 res_idx: StackIdx,
497 nres: i32,
498 wanted: i32,
499) -> Result<(), LuaError> {
500 match wanted {
501 0 => {
502 state.set_top(res_idx);
503 return Ok(());
504 }
505 1 => {
506 if nres == 0 {
507 state.set_at(res_idx, LuaValue::Nil);
508 } else {
509 let top = state.top_idx();
510 let src = state.get_at(top - nres as i32).clone();
511 state.set_at(res_idx, src);
512 }
513 state.set_top(res_idx + 1);
514 return Ok(());
515 }
516 LUA_MULTRET => {
517 }
519 _ => {
520 if wanted < LUA_MULTRET {
522 let ci_idx = state.ci;
523 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
524 state.set_ci_u2_nres(ci_idx, nres);
525
526 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
529
530 let ci_idx = state.ci;
531 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
532
533 if state.hookmask != 0 {
534 let saved_res = res_idx;
536 rethook(state, ci_idx, nres)?;
537 let _ = saved_res; }
539
540 let decoded_wanted = -(wanted) - 3;
542 let wanted = if decoded_wanted == LUA_MULTRET {
543 nres
544 } else {
545 decoded_wanted
546 };
547
548 let first_result = state.top_idx().0 as i32 - nres;
550 let actual_nres = nres.min(wanted);
551 for i in 0..actual_nres {
552 let src = state.get_at((first_result + i) as u32).clone();
553 state.set_at(res_idx + i as i32, src);
554 }
555 for i in actual_nres..wanted {
556 state.set_at(res_idx + i as i32, LuaValue::Nil);
557 }
558 state.set_top(res_idx + wanted as i32);
559 return Ok(());
560 }
561 }
562 }
563
564 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
566 let first_result = state.top_idx().0 as i32 - nres;
567 let actual_nres = nres.min(effective_wanted);
568 for i in 0..actual_nres {
569 let src = state.get_at((first_result + i) as u32).clone();
570 state.set_at(res_idx + i as i32, src);
571 }
572 for i in actual_nres..effective_wanted {
573 state.set_at(res_idx + i as i32, LuaValue::Nil);
574 }
575 state.set_top(res_idx + effective_wanted as i32);
576 Ok(())
577}
578
579#[inline(always)]
583pub(crate) fn poscall(
584 state: &mut LuaState,
585 ci_idx: CallInfoIdx,
586 nres: i32,
587) -> Result<(), LuaError> {
588 let wanted = state.get_ci(ci_idx).nresults as i32;
589
590 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
591 rethook(state, ci_idx, nres)?;
592 }
593
594 let func_idx = state.get_ci(ci_idx).func;
595 move_results(state, func_idx, nres, wanted)?;
596
597 debug_assert!(
598 state.get_ci(ci_idx).callstatus
599 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
600 == 0
601 );
602
603 let previous = state
604 .get_ci(ci_idx)
605 .previous
606 .expect("poscall: no previous call frame");
607 state.ci = previous;
608 Ok(())
609}
610
611#[inline(always)]
615fn prep_call_info(
616 state: &mut LuaState,
617 func_idx: StackIdx,
618 nret: i32,
619 mask: u16,
620 top_idx: StackIdx,
621) -> Result<CallInfoIdx, LuaError> {
622 let ci_idx = state.next_ci()?;
624 state.ci = ci_idx;
625 {
626 let ci = state.get_ci_mut(ci_idx);
627 ci.func = func_idx;
628 ci.nresults = nret as i16;
629 ci.callstatus = mask;
630 ci.top = top_idx;
631 ci.u = if (mask & crate::state::CIST_C) != 0 {
632 crate::state::CallInfoFrame::c_default()
633 } else {
634 crate::state::CallInfoFrame::lua_default()
635 };
636 }
637 Ok(ci_idx)
638}
639
640#[inline(always)]
645fn precall_c(
646 state: &mut LuaState,
647 func_idx: StackIdx,
648 nresults: i32,
649 f: crate::state::LuaCallable,
650) -> Result<i32, LuaError> {
651 state.check_stack(LUA_MINSTACK as i32)?;
652 if state.gc_check_needed {
653 state.gc_check_step();
654 }
655
656 let top_idx = state.top_idx();
657 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
658
659 debug_assert!(true );
660
661 if state.hookmask & LUA_MASKCALL != 0 {
662 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
663 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
664 }
665
666 let n = f.call(state)? as i32;
667
668 debug_assert!(
670 n <= state.top_idx().0 as i32,
671 "C function returned more values than available"
672 );
673
674 poscall(state, ci_idx, n)?;
675 Ok(n)
676}
677
678pub(crate) fn pretailcall(
683 state: &mut LuaState,
684 ci_idx: CallInfoIdx,
685 mut func_idx: StackIdx,
686 mut narg1: i32,
687 delta: i32,
688) -> Result<i32, LuaError> {
689 loop {
690 let func_val = state.get_at(func_idx).clone();
691 match func_val {
692 LuaValue::Function(LuaClosure::C(ref cl)) => {
693 let cfunc = state.global().c_functions[cl.func].clone();
694 return precall_c(state, func_idx, LUA_MULTRET, cfunc);
695 }
696 LuaValue::Function(LuaClosure::LightC(f)) => {
697 let cfunc = state.global().c_functions[f].clone();
698 return precall_c(state, func_idx, LUA_MULTRET, cfunc);
699 }
700 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
701 let proto = cl.proto.clone();
702 let fsize = proto.maxstacksize as i32;
703 let nfixparams = proto.numparams as i32;
704
705 state.check_stack(fsize - delta)?;
706 if state.gc_check_needed {
707 state.gc_check_step();
708 }
709
710 {
711 let ci = state.get_ci_mut(ci_idx);
712 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
713 }
714 let ci_func = state.get_ci(ci_idx).func;
715
716 for i in 0..narg1 {
717 let src = state.get_at(func_idx + i as i32).clone();
718 state.set_at(ci_func + i as i32, src);
719 }
720
721 func_idx = ci_func;
723
724 while narg1 <= nfixparams {
725 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
726 narg1 += 1;
727 }
728
729 {
730 let new_ci_top = func_idx + 1 + fsize as i32;
731 let stack_last = state.stack_last;
732 let live_top = state.top_idx();
733 let ci = state.get_ci_mut(ci_idx);
734 ci.top = new_ci_top;
735 debug_assert!(ci.top.0 <= stack_last.0);
736 ci.set_saved_pc(0);
737 ci.callstatus |= CIST_TAIL;
738 state.clear_stack_range(live_top, new_ci_top);
739 }
740
741 state.set_top(func_idx + narg1 as i32);
742 return Ok(-1); }
744 _ => {
745 func_idx = try_func_tm(state, func_idx)?;
746 narg1 += 1;
747 }
749 }
750 }
751}
752
753#[inline(always)]
763pub(crate) fn precall(
764 state: &mut LuaState,
765 func_idx: StackIdx,
766 nresults: i32,
767) -> Result<Option<CallInfoIdx>, LuaError> {
768 if let LuaValue::Function(LuaClosure::Lua(cl)) =
769 &state.stack[func_idx.0 as usize].val
770 {
771 let nfixparams = cl.proto.numparams as i32;
772 let fsize = cl.proto.maxstacksize as i32;
773 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
774
775 state.check_stack(fsize)?;
776 if state.gc_check_needed {
777 state.gc_check_step();
778 }
779
780 let ci_idx =
781 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
782 state.set_ci_savedpc(ci_idx, 0);
783
784 if narg < nfixparams {
785 fill_missing_params(state, narg, nfixparams);
786 }
787 return Ok(Some(ci_idx));
788 }
789 precall_slow(state, func_idx, nresults)
790}
791
792#[cold]
796#[inline(never)]
797fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
798 while narg < nfixparams {
799 let top = state.top_idx();
800 state.set_at(top, LuaValue::Nil);
801 state.set_top(top + 1);
802 narg += 1;
803 }
804}
805
806#[cold]
810#[inline(never)]
811fn precall_slow(
812 state: &mut LuaState,
813 mut func_idx: StackIdx,
814 nresults: i32,
815) -> Result<Option<CallInfoIdx>, LuaError> {
816 loop {
817 let func_val = state.get_at(func_idx).clone();
818 match func_val {
819 LuaValue::Function(LuaClosure::C(ref cl)) => {
820 let cfunc = state.global().c_functions[cl.func].clone();
821 precall_c(state, func_idx, nresults, cfunc)?;
822 return Ok(None);
823 }
824 LuaValue::Function(LuaClosure::LightC(f)) => {
825 state.check_stack(LUA_MINSTACK as i32)?;
826 if state.gc_check_needed {
827 state.gc_check_step();
828 }
829
830 let top_idx = state.top_idx();
831 let ci_idx =
832 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
833
834 if state.hookmask & LUA_MASKCALL != 0 {
835 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
836 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
837 }
838
839 let cfunc = state.global().c_functions[f].clone();
840 let n = cfunc.call(state)? as i32;
841 debug_assert!(
842 n <= state.top_idx().0 as i32,
843 "C function returned more values than available"
844 );
845 poscall(state, ci_idx, n)?;
846 return Ok(None);
847 }
848 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
849 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
850 let nfixparams = cl.proto.numparams as i32;
851 let fsize = cl.proto.maxstacksize as i32;
852
853 state.check_stack(fsize)?;
854 if state.gc_check_needed {
855 state.gc_check_step();
856 }
857
858 let ci_idx = prep_call_info(
859 state,
860 func_idx,
861 nresults,
862 0,
863 func_idx + 1 + fsize as i32,
864 )?;
865 state.set_ci_savedpc(ci_idx, 0);
866
867 if narg < nfixparams {
868 fill_missing_params(state, narg, nfixparams);
869 }
870 return Ok(Some(ci_idx));
871 }
872 _ => {
873 func_idx = try_func_tm(state, func_idx)?;
874 }
875 }
876 }
877}
878
879#[inline]
883fn ccall_inner(
884 state: &mut LuaState,
885 func_idx: StackIdx,
886 n_results: i32,
887 inc: u32,
888) -> Result<(), LuaError> {
889 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
890}
891
892#[inline]
893fn ccall_inner_with_status(
894 state: &mut LuaState,
895 func_idx: StackIdx,
896 n_results: i32,
897 inc: u32,
898 extra_callstatus: u16,
899) -> Result<(), LuaError> {
900 state.n_ccalls += inc;
901
902 if state.c_calls() >= LUAI_MAXCCALLS {
904 state.check_stack(0)?;
906 state.check_c_stack()?;
907 }
908
909 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
910 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
911 vm::execute(state, ci_idx)?;
912 }
913
914 state.n_ccalls -= inc;
915 Ok(())
916}
917
918pub(crate) fn call(
921 state: &mut LuaState,
922 func_idx: StackIdx,
923 n_results: i32,
924) -> Result<(), LuaError> {
925 ccall_inner(state, func_idx, n_results, 1)
926}
927
928pub(crate) fn callnoyield(
931 state: &mut LuaState,
932 func_idx: StackIdx,
933 n_results: i32,
934) -> Result<(), LuaError> {
935 ccall_inner(state, func_idx, n_results, NYCI)
937}
938
939fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
946 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
949
950 if status == LuaStatus::Ok {
951 status = LuaStatus::Yield;
952 } else {
953 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
954 state.allowhook = state.get_ci(ci_idx).get_oah();
956 let _func_idx = func::close(state, func_idx, status as i32, true)?;
958 set_error_obj(state, status, func_idx);
959
960 if state.errfunc != 0 && error_status(status) && status != LuaStatus::ErrErr && status != LuaStatus::ErrSyntax {
969 let errfunc_stk = StackIdx(state.errfunc as u32);
970 let err_val = state.get_at(func_idx);
978 state.push(err_val);
979 let handler = state.get_at(errfunc_stk);
980 state.set_at(state.top_idx() - 2, handler);
981 if let Err(_) = state.call_no_yield(state.top_idx() - 2, 1) {
982 status = LuaStatus::ErrErr;
983 if let Ok(s) = state.intern_str(b"error in error handling") {
984 state.set_at(func_idx, lua_types::value::LuaValue::Str(s));
985 }
986 state.set_top(func_idx + 1);
987 }
988 }
989
990 shrink_stack(state);
991 state.get_ci_mut(ci_idx).set_recover_status(LuaStatus::Ok as i32);
992 }
993
994 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
995 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
996 state.errfunc = old_errfunc;
997
998 Ok(status)
999}
1000
1001fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1004 let n;
1005
1006 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1007 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1008 n = state.get_ci_u2_nres(ci_idx);
1009 } else {
1010 debug_assert!(
1011 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1012 "finishCcall: no continuation or non-yieldable"
1013 );
1014
1015 let mut status = LuaStatus::Yield;
1016
1017 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1018 status = finish_pcallk(state, ci_idx)?;
1019 }
1020
1021 state.adjust_results(LUA_MULTRET);
1023
1024 let k = state.get_ci(ci_idx).u_c_k();
1028 let ctx = state.get_ci(ci_idx).u_c_ctx();
1029 if let Some(k_fn) = k {
1030 n = k_fn(state, status as i32, ctx)? as i32;
1031 } else {
1032 return Err(LuaError::runtime(format_args!("finishCcall: missing continuation")));
1034 }
1035 debug_assert!(
1036 n <= state.top_idx().0 as i32,
1037 "continuation returned more values than available"
1038 );
1039 }
1040
1041 poscall(state, ci_idx, n)?;
1042 Ok(())
1043}
1044
1045fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1048 loop {
1049 let ci_idx = state.ci;
1050 if state.is_base_ci(ci_idx) {
1051 break;
1052 }
1053 if !state.get_ci(ci_idx).is_lua() {
1054 finish_ccall(state, ci_idx)?;
1055 } else {
1056 vm::finish_op(state)?;
1057 vm::execute(state, ci_idx)?;
1058 }
1059 }
1060 Ok(())
1061}
1062
1063fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1066 let mut ci_idx_opt = Some(state.ci);
1067 while let Some(ci_idx) = ci_idx_opt {
1068 let ci = state.get_ci(ci_idx);
1069 if ci.callstatus & CIST_YPCALL != 0 {
1070 return Some(ci_idx);
1071 }
1072 ci_idx_opt = ci.previous;
1073 }
1074 None
1075}
1076
1077fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1080 let top = state.top_idx();
1081 state.set_top(top - narg as i32);
1082 let s = state.intern_str(msg).ok();
1084 let new_top = state.top_idx();
1085 if let Some(s) = s { state.set_at(new_top, LuaValue::Str(s)); }
1086 state.set_top(new_top + 1);
1087 LuaStatus::ErrRun
1088}
1089
1090fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1093 let top = state.top_idx();
1094 let first_arg = top - nargs as i32;
1095 let ci_idx = state.ci;
1096
1097 if state.status == LuaStatus::Ok as u8 {
1098 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1099 } else {
1100 debug_assert!(state.status == LuaStatus::Yield as u8);
1101 state.status = LuaStatus::Ok as u8;
1102
1103 if state.get_ci(ci_idx).is_lua() {
1104 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1105 let pc = state.ci_savedpc(ci_idx);
1106 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1107 state.set_top(first_arg);
1108 vm::execute(state, ci_idx)?;
1109 } else {
1110 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1111 let ctx = state.get_ci(ci_idx).u_c_ctx();
1112 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1113 debug_assert!(n <= state.top_idx().0 as i32);
1114 poscall(state, ci_idx, n)?;
1115 } else {
1116 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1118 poscall(state, ci_idx, n)?;
1119 }
1120 }
1121
1122 unroll(state)?;
1123 }
1124 Ok(())
1125}
1126
1127fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1130 while error_status(status) {
1131 if let Some(ci_idx) = find_pcall(state) {
1132 state.ci = ci_idx;
1133 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1134 status = match raw_run_protected(state, |s| unroll(s)) {
1139 Ok(()) => LuaStatus::Ok,
1140 Err(e) => {
1141 let s = e.to_status();
1142 if error_status(s) {
1143 state.push(e.into_value());
1144 }
1145 s
1146 }
1147 };
1148 } else {
1149 break;
1150 }
1151 }
1152 status
1153}
1154
1155pub fn lua_resume(
1158 state: &mut LuaState,
1159 from: Option<&mut LuaState>,
1160 nargs: i32,
1161 nresults: &mut i32,
1162) -> LuaStatus {
1163 if state.status == LuaStatus::Ok as u8 {
1169 if !state.is_base_ci(state.ci) {
1170 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1171 }
1172 let ci_func = state.get_ci(state.ci).func;
1173 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1174 return resume_error(state, b"cannot resume dead coroutine", nargs);
1175 }
1176 } else if state.status != LuaStatus::Yield as u8 {
1177 return resume_error(state, b"cannot resume dead coroutine", nargs);
1178 }
1179
1180 state.n_ccalls = from
1181 .as_ref()
1182 .map(|f| f.c_calls() as u32)
1183 .unwrap_or(0);
1184
1185 if state.c_calls() >= LUAI_MAXCCALLS {
1186 return resume_error(state, b"C stack overflow", nargs);
1187 }
1188 state.n_ccalls += 1;
1189
1190 debug_assert!(
1191 if state.status == LuaStatus::Ok as u8 {
1192 nargs + 1 <= state.top_idx().0 as i32
1193 } else {
1194 nargs <= state.top_idx().0 as i32
1195 },
1196 "lua_resume: not enough stack elements"
1197 );
1198
1199 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1205 Ok(()) => (LuaStatus::Ok, None),
1206 Err(e) => {
1207 let s = e.to_status();
1208 let v = if error_status(s) { Some(e.into_value()) } else { None };
1209 (s, v)
1210 }
1211 };
1212 if let Some(v) = err_value {
1213 state.push(v);
1214 }
1215
1216 status = precover(state, status);
1217
1218 if !error_status(status) {
1219 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1220 } else {
1221 state.status = status as u8;
1223 let top = state.top_idx();
1224 set_error_obj(state, status, top);
1225 let new_top = state.top_idx();
1226 let ci_idx = state.ci;
1227 state.get_ci_mut(ci_idx).top = new_top;
1228 }
1229
1230 let ci_idx = state.ci;
1231 *nresults = if status == LuaStatus::Yield {
1232 state.get_ci_u2_nyield(ci_idx)
1233 } else {
1234 let ci_func = state.get_ci(ci_idx).func;
1235 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1236 };
1237
1238 status
1239}
1240
1241pub fn lua_isyieldable(state: &LuaState) -> bool {
1244 state.is_yieldable()
1246}
1247
1248pub fn lua_yieldk(
1252 state: &mut LuaState,
1253 nresults: i32,
1254 ctx: isize,
1255 k: Option<crate::state::LuaKFunction>,
1256) -> Result<i32, LuaError> {
1257 let ci_idx = state.ci;
1261
1262 debug_assert!(
1263 nresults <= state.top_idx().0 as i32,
1264 "lua_yieldk: not enough elements on stack"
1265 );
1266
1267 if !state.is_yieldable() {
1268 if !state.is_main_thread() {
1269 return Err(LuaError::runtime(format_args!(
1270 "attempt to yield across a C-call boundary"
1271 )));
1272 } else {
1273 return Err(LuaError::runtime(format_args!(
1274 "attempt to yield from outside a coroutine"
1275 )));
1276 }
1277 }
1278
1279 state.status = LuaStatus::Yield as u8;
1280 state.set_ci_u2_nyield(ci_idx, nresults);
1281
1282 if state.get_ci(ci_idx).is_lua() {
1283 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1284 debug_assert!(nresults == 0, "hooks cannot yield values");
1285 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1286 } else {
1288 if let crate::state::CallInfoFrame::C { k: ref mut frame_k, ctx: ref mut frame_ctx, .. } =
1290 state.get_ci_mut(ci_idx).u {
1291 *frame_k = k;
1292 if k.is_some() {
1293 *frame_ctx = ctx;
1294 }
1295 }
1296 return Err(LuaError::Yield);
1298 }
1299
1300 debug_assert!(
1301 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1302 "lua_yieldk called outside a hook"
1303 );
1304 Ok(0) }
1306
1307struct CloseP {
1314 level: StackIdx,
1315 status: LuaStatus,
1316}
1317
1318fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1321 func::close(state, pcl.level, pcl.status as i32, false)?;
1323 Ok(())
1324}
1325
1326pub(crate) fn close_protected(
1330 state: &mut LuaState,
1331 level: StackIdx,
1332 status: LuaStatus,
1333) -> LuaStatus {
1334 let old_ci = state.ci;
1335 let old_allowhook = state.allowhook;
1336 let mut status = status;
1337
1338 loop {
1339 let mut pcl = CloseP { level, status };
1340 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1341 Ok(()) => (LuaStatus::Ok, None),
1342 Err(e) => (e.to_status(), Some(e.into_value())),
1343 };
1344 if run_status == LuaStatus::Ok {
1345 return pcl.status;
1346 }
1347 state.ci = old_ci;
1348 state.allowhook = old_allowhook;
1349 if let Some(v) = err_value {
1355 state.push(v);
1356 }
1357 status = run_status;
1358 }
1359}
1360
1361pub(crate) fn pcall<F>(
1365 state: &mut LuaState,
1366 func: F,
1367 old_top: StackIdx,
1368 ef: isize,
1369) -> LuaStatus
1370where
1371 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1372{
1373 let old_ci = state.ci;
1374 let old_allowhook = state.allowhook;
1375 let old_errfunc = state.errfunc;
1376 state.errfunc = ef;
1377
1378 let mut status = match raw_run_protected(state, func) {
1384 Ok(()) => LuaStatus::Ok,
1385 Err(e) => {
1386 let s = e.to_status();
1387 state.push(e.into_value());
1388 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1394 let errfunc_idx = StackIdx(ef as u32);
1395 let arg = state.get_at(state.top_idx() - 1).clone();
1396 state.push(arg);
1397 let handler = state.get_at(errfunc_idx).clone();
1398 state.set_at(state.top_idx() - 2, handler);
1399 match state.call_no_yield(state.top_idx() - 2, 1) {
1400 Ok(()) => s,
1401 Err(_) => LuaStatus::ErrErr,
1402 }
1403 } else {
1404 s
1405 }
1406 }
1407 };
1408
1409 if status != LuaStatus::Ok {
1410 state.ci = old_ci;
1411 state.allowhook = old_allowhook;
1412 status = close_protected(state, old_top, status);
1413 set_error_obj(state, status, old_top);
1415 shrink_stack(state);
1416 }
1417
1418 state.errfunc = old_errfunc;
1419 status
1420}
1421
1422struct SParser {
1432 z: ZIO,
1433 buff: LexBuffer,
1435 dyd: DynDataStub,
1437 mode: Option<Vec<u8>>,
1439 name: Vec<u8>,
1440}
1441
1442fn check_mode(
1445 mode: Option<&[u8]>,
1446 kind: &[u8],
1447) -> Result<(), LuaError> {
1448 if let Some(mode_bytes) = mode {
1449 let kind_char = kind[0];
1450 if !mode_bytes.contains(&kind_char) {
1451 return Err(LuaError::syntax(format_args!(
1454 "attempt to load a {} chunk (mode is '{}')",
1455 core::str::from_utf8(kind).unwrap_or("?"),
1456 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1457 )));
1458 }
1459 }
1460 Ok(())
1461}
1462
1463fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1467 let c = p.z.getc();
1469
1470 let cl = if c == b'\x1b' as i32 {
1472 check_mode(p.mode.as_deref(), b"binary")?;
1473 crate::undump::undump(state, &mut p.z, &p.name)?
1475 } else {
1476 check_mode(p.mode.as_deref(), b"text")?;
1477 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1479 };
1480
1481 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1482 func::init_upvals(state, &cl)?;
1483
1484 state.check_stack(1)?;
1492 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1493
1494 Ok(())
1495}
1496
1497pub(crate) fn protected_parser(
1500 state: &mut LuaState,
1501 z: ZIO,
1502 name: &[u8],
1503 mode: Option<&[u8]>,
1504) -> LuaStatus {
1505 state.inc_nny();
1507
1508 let mut p = SParser {
1509 z,
1510 buff: LexBuffer::new(),
1511 dyd: DynDataStub::new(),
1512 mode: mode.map(|m| m.to_vec()),
1513 name: name.to_vec(),
1514 };
1515
1516 let top_idx = state.top_idx();
1519 let errfunc = state.errfunc;
1520 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1521
1522 state.dec_nny();
1526
1527 status
1528}
1529
1530