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