1#[allow(unused_imports)] use crate::prelude::*;
9use crate::{
10 func,
11 state::{CallInfoIdx, LuaState},
12 vm,
13};
14use lua_types::{
15 error::LuaError,
16 status::LuaStatus,
17 value::LuaValue,
18};
19use lua_types::StackIdx;
20use lua_types::closure::LuaClosure;
21use lua_types::tagmethod::TagMethod;
22use crate::zio::{ZIO, LexBuffer};
23
24struct DynDataStub;
26impl DynDataStub {
27 fn new() -> Self { DynDataStub }
28}
29
30fn parse_stub(
41 state: &mut LuaState,
42 z: &mut ZIO,
43 _buff: &mut LexBuffer,
44 _dyd: &mut DynDataStub,
45 name: &[u8],
46 c: i32,
47) -> Result<lua_types::GcRef<lua_types::closure::LuaLClosure>, LuaError> {
48 let hook = state.global().parser_hook;
49 if let Some(parse) = hook {
50 let mut source: Vec<u8> = Vec::new();
51 if c >= 0 {
52 source.push(c as u8);
53 }
54 loop {
55 let b = z.getc();
56 if b < 0 {
57 break;
58 }
59 source.push(b as u8);
60 }
61 return parse(state, &source, name, c);
62 }
63 Err(LuaError::syntax(format_args!(
64 "{}: Lua text parser not yet wired (phase-b: lua-parse::parse)",
65 core::str::from_utf8(name).unwrap_or("?"),
66 )))
67}
68
69const LUAI_MAXSTACK: usize = 1_000_000;
73const ERRORSTACKSIZE: usize = LUAI_MAXSTACK + 200;
74
75const EXTRA_STACK: i32 = 5;
76
77const LUA_MINSTACK: i32 = 20;
78
79const LUA_MULTRET: i32 = -1;
80
81const NYCI: u32 = 0x10001;
82
83const LUAI_MAXCCALLS: u32 = 200;
85
86const CIST_C: u16 = 1 << 1;
88const CIST_FRESH: u16 = 1 << 2;
89const CIST_HOOKED: u16 = 1 << 3;
90const CIST_YPCALL: u16 = 1 << 4;
91const CIST_TAIL: u16 = 1 << 5;
92const CIST_HOOKYIELD: u16 = 1 << 6;
93const CIST_TRAN: u16 = 1 << 8;
94const CIST_CLSRET: u16 = 1 << 9;
95const CIST_FIN: u16 = 1 << 7;
96
97const LUA_MASKCALL: u8 = 1 << 0;
99const LUA_MASKRET: u8 = 1 << 1;
100
101const LUA_HOOKCALL: i32 = 0;
102const LUA_HOOKRET: i32 = 1;
103const LUA_HOOKTAILCALL: i32 = 4;
104
105const CLOSE_K_TOP: i32 = -1;
108
109#[inline]
113fn error_status(s: LuaStatus) -> bool {
114 (s as i32) > (LuaStatus::Yield as i32)
115}
116
117pub(crate) fn set_error_obj(state: &mut LuaState, errcode: LuaStatus, old_top: StackIdx) {
130 match errcode {
131 LuaStatus::ErrMem => {
132 let memerrmsg = state.global().memerrmsg.clone();
134 state.set_at(old_top, LuaValue::Str(memerrmsg));
135 }
136 LuaStatus::ErrErr => {
137 if let Ok(s) = state.intern_str(b"error in error handling") {
138 state.set_at(old_top, LuaValue::Str(s));
139 }
140 }
141 LuaStatus::Ok => {
142 state.set_at(old_top, LuaValue::Nil);
143 }
144 _ => {
145 debug_assert!(error_status(errcode));
146 let top = state.top_idx();
147 let err_val = state.get_at(top - 1).clone();
148 state.set_at(old_top, err_val);
149 }
150 }
151 state.set_top(old_top + 1);
152}
153
154pub(crate) fn throw(state: &mut LuaState, errcode: LuaStatus) -> ! {
162 panic!("luaD_throw: unhandled Lua error (status = {:?}), no error handler", errcode)
172}
173
174pub(crate) fn raw_run_protected<F>(state: &mut LuaState, f: F) -> Result<(), LuaError>
183where
184 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
185{
186 let old_n_ccalls = state.nCcalls;
187 let result = f(state);
189 state.nCcalls = old_n_ccalls;
190 result
191}
192
193pub(crate) fn realloc_stack(
208 state: &mut LuaState,
209 new_size: usize,
210 raise_error: bool,
211) -> Result<bool, LuaError> {
212 let old_size = state.stack_size() as usize;
213 debug_assert!(new_size <= LUAI_MAXSTACK || new_size == ERRORSTACKSIZE);
214
215 let old_gcstop = state.global().gcstopem;
218 state.global_mut().gcstopem = true;
219
220 let new_extent = new_size as usize + EXTRA_STACK as usize;
222 let alloc_result = state.stack_resize(new_extent);
223
224 state.global_mut().gcstopem = old_gcstop;
225
226 if alloc_result.is_err() {
227 if raise_error {
228 return Err(LuaError::Memory);
229 } else {
230 return Ok(false);
231 }
232 }
233
234 state.stack_last = StackIdx(new_size as u32);
235
236 let old_extent = old_size + EXTRA_STACK as usize;
238 for i in old_extent..new_extent {
239 state.stack_set_nil(i);
240 }
241
242 Ok(true)
243}
244
245pub(crate) fn grow_stack(
251 state: &mut LuaState,
252 n: i32,
253 raise_error: bool,
254) -> Result<bool, LuaError> {
255 let size = state.stack_size();
256
257 if size > LUAI_MAXSTACK {
258 debug_assert!(state.stack_size() == ERRORSTACKSIZE);
260 if raise_error {
261 return Err(LuaError::with_status(LuaStatus::ErrErr));
262 }
263 return Ok(false);
264 } else if (n as usize) < LUAI_MAXSTACK {
265 let mut new_size = 2 * size;
266 let needed = (state.top_idx().0 as i32 + n) as usize;
267 if new_size > LUAI_MAXSTACK {
268 new_size = LUAI_MAXSTACK;
269 }
270 if new_size < needed {
271 new_size = needed;
272 }
273 if new_size <= LUAI_MAXSTACK {
274 return realloc_stack(state, new_size, raise_error);
275 }
276 }
277 realloc_stack(state, ERRORSTACKSIZE, raise_error)?;
279 if raise_error {
280 return Err(LuaError::runtime(format_args!("stack overflow")));
281 }
282 Ok(false)
283}
284
285fn stack_in_use(state: &LuaState) -> usize {
288 let mut lim = state.top_idx();
289 let mut ci_idx_opt = Some(state.ci);
291 while let Some(ci_idx) = ci_idx_opt {
292 let ci = state.get_ci(ci_idx);
293 if lim.0 < ci.top.0 {
294 lim = ci.top;
295 }
296 ci_idx_opt = ci.previous;
297 }
298 debug_assert!(true );
299 let res = lim.0 as usize + 1;
300 if res < LUA_MINSTACK as usize {
301 LUA_MINSTACK as usize
302 } else {
303 res
304 }
305}
306
307pub(crate) fn shrink_stack(state: &mut LuaState) {
310 let inuse = stack_in_use(state);
311 let max = if inuse > LUAI_MAXSTACK / 3 {
312 LUAI_MAXSTACK
313 } else {
314 inuse * 3
315 };
316 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
317 let nsize = if inuse > LUAI_MAXSTACK / 2 {
318 LUAI_MAXSTACK
319 } else {
320 inuse * 2
321 };
322 let _ = realloc_stack(state, nsize, false);
323 }
324 state.shrink_ci();
325}
326
327pub(crate) fn inc_top(state: &mut LuaState) -> Result<(), LuaError> {
330 state.check_stack(1)?;
332 let t = state.top_idx();
333 state.set_top(t + 1);
334 Ok(())
335}
336
337pub(crate) fn hook(
344 state: &mut LuaState,
345 event: i32,
346 line: i32,
347 ftransfer: i32,
348 ntransfer: i32,
349) -> Result<(), LuaError> {
350 if !state.has_hook() || !state.allowhook {
351 return Ok(());
352 }
353
354 let ci_idx = state.ci;
355
356 let saved_top = state.top_idx();
358 let saved_ci_top = state.get_ci(ci_idx).top;
359
360 let mut mask = CIST_HOOKED;
361
362 if ntransfer != 0 {
363 mask |= CIST_TRAN;
364 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
365 }
366
367 {
368 let ci = state.get_ci(ci_idx);
369 if ci.is_lua() {
370 let ci_top = ci.top;
371 if state.top_idx().0 < ci_top.0 {
372 state.set_top(ci_top);
373 }
374 }
375 }
376
377 state.check_stack(LUA_MINSTACK as i32)?;
378
379 {
380 let top = state.top_idx();
381 let ci = state.get_ci_mut(ci_idx);
382 if ci.top.0 < (top + LUA_MINSTACK).0 {
383 let new_top = top + LUA_MINSTACK;
384 ci.top = new_top;
385 state.clear_stack_range(top, new_top);
386 }
387 }
388
389 state.allowhook = false;
390 state.get_ci_mut(ci_idx).callstatus |= mask;
391
392 let mut ar = crate::debug::LuaDebug::default();
393 ar.event = event;
394 ar.currentline = line;
395 ar.ftransfer = ftransfer as u16;
396 ar.ntransfer = ntransfer as u16;
397 ar.i_ci = Some(ci_idx);
398 let hook_opt = state.hook.take();
399 if let Some(mut h) = hook_opt {
400 h(state, &ar);
401 if state.hook.is_none() {
402 state.hook = Some(h);
403 }
404 }
405
406 debug_assert!(!state.allowhook);
407 state.allowhook = true;
408
409 state.get_ci_mut(ci_idx).top = saved_ci_top;
411 state.set_top(saved_top);
412 state.get_ci_mut(ci_idx).callstatus &= !mask;
413
414 Ok(())
415}
416
417pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
420 state.oldpc = 0;
421 if state.hookmask & LUA_MASKCALL != 0 {
422 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
423 LUA_HOOKTAILCALL
424 } else {
425 LUA_HOOKCALL
426 };
427 let numparams = {
429 state.get_ci_lua_proto_numparams(ci_idx)
432 };
433 let pc = state.ci_savedpc(ci_idx);
434 state.set_ci_savedpc(ci_idx, pc + 1);
435 hook(state, event, -1, 1, numparams as i32)?;
436 state.set_ci_savedpc(ci_idx, pc);
437 }
438 Ok(())
439}
440
441fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
444 if state.hookmask & LUA_MASKRET != 0 {
445 let first_res = state.top_idx().0 as i32 - nres;
446 let mut delta: i32 = 0;
447
448 if state.get_ci(ci_idx).is_lua() {
449 let (is_vararg, nextraargs, numparams) =
451 state.get_ci_vararg_info(ci_idx);
452 if is_vararg {
453 delta = nextraargs + numparams as i32 + 1;
454 }
455 }
456
457 let original_func = state.get_ci(ci_idx).func;
459 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
460
461 let ci_func = state.get_ci(ci_idx).func;
462 let ftransfer = (first_res - ci_func.0 as i32) as u16;
463
464 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
465
466 state.get_ci_mut(ci_idx).func = original_func;
467 }
468
469 let previous = state.get_ci(ci_idx).previous;
471 if let Some(prev_idx) = previous {
472 if state.get_ci(prev_idx).is_lua() {
473 state.oldpc = state.get_ci_pcrel(prev_idx);
477 }
478 }
479
480 Ok(())
481}
482
483fn try_func_tm(state: &mut LuaState, func_idx: StackIdx) -> Result<StackIdx, LuaError> {
493 state.check_stack(1)?;
496 state.gc_check_step();
497
498 let func_val = state.get_at(func_idx).clone();
499 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
500
501 if matches!(tm, LuaValue::Nil) {
502 let offender = state.get_at(func_idx).clone();
503 return Err(crate::debug::call_error(state, &offender, func_idx));
504 }
505
506 let top = state.top_idx();
508 let mut p = top;
509 while p.0 > func_idx.0 {
510 let val = state.get_at(p - 1).clone();
511 state.set_at(p, val);
512 p = p - 1;
513 }
514 state.set_top(top + 1);
515 state.set_at(func_idx, tm);
516
517 Ok(func_idx)
518}
519
520#[inline(always)]
525fn move_results(
526 state: &mut LuaState,
527 res_idx: StackIdx,
528 nres: i32,
529 wanted: i32,
530) -> Result<(), LuaError> {
531 match wanted {
532 0 => {
533 state.set_top(res_idx);
534 return Ok(());
535 }
536 1 => {
537 if nres == 0 {
538 state.set_at(res_idx, LuaValue::Nil);
539 } else {
540 let top = state.top_idx();
541 let src = state.get_at(top - nres as i32).clone();
542 state.set_at(res_idx, src);
543 }
544 state.set_top(res_idx + 1);
545 return Ok(());
546 }
547 LUA_MULTRET => {
548 }
550 _ => {
551 if wanted < LUA_MULTRET {
553 let ci_idx = state.ci;
554 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
555 state.set_ci_u2_nres(ci_idx, nres);
556
557 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
560
561 let ci_idx = state.ci;
562 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
563
564 if state.hookmask != 0 {
565 let saved_res = res_idx;
567 rethook(state, ci_idx, nres)?;
568 let _ = saved_res; }
570
571 let decoded_wanted = -(wanted) - 3;
573 let wanted = if decoded_wanted == LUA_MULTRET {
574 nres
575 } else {
576 decoded_wanted
577 };
578
579 let first_result = state.top_idx().0 as i32 - nres;
581 let actual_nres = nres.min(wanted);
582 for i in 0..actual_nres {
583 let src = state.get_at((first_result + i) as u32).clone();
584 state.set_at(res_idx + i as i32, src);
585 }
586 for i in actual_nres..wanted {
587 state.set_at(res_idx + i as i32, LuaValue::Nil);
588 }
589 state.set_top(res_idx + wanted as i32);
590 return Ok(());
591 }
592 }
593 }
594
595 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
597 let first_result = state.top_idx().0 as i32 - nres;
598 let actual_nres = nres.min(effective_wanted);
599 for i in 0..actual_nres {
600 let src = state.get_at((first_result + i) as u32).clone();
601 state.set_at(res_idx + i as i32, src);
602 }
603 for i in actual_nres..effective_wanted {
604 state.set_at(res_idx + i as i32, LuaValue::Nil);
605 }
606 state.set_top(res_idx + effective_wanted as i32);
607 Ok(())
608}
609
610#[inline(always)]
614pub(crate) fn poscall(
615 state: &mut LuaState,
616 ci_idx: CallInfoIdx,
617 nres: i32,
618) -> Result<(), LuaError> {
619 let wanted = state.get_ci(ci_idx).nresults as i32;
620
621 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
622 rethook(state, ci_idx, nres)?;
623 }
624
625 let func_idx = state.get_ci(ci_idx).func;
626 move_results(state, func_idx, nres, wanted)?;
627
628 debug_assert!(
629 state.get_ci(ci_idx).callstatus
630 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
631 == 0
632 );
633
634 let previous = state
635 .get_ci(ci_idx)
636 .previous
637 .expect("poscall: no previous call frame");
638 state.ci = previous;
639 Ok(())
640}
641
642#[inline(always)]
646fn prep_call_info(
647 state: &mut LuaState,
648 func_idx: StackIdx,
649 nret: i32,
650 mask: u16,
651 top_idx: StackIdx,
652) -> Result<CallInfoIdx, LuaError> {
653 let ci_idx = state.next_ci()?;
655 state.ci = ci_idx;
656 {
657 let ci = state.get_ci_mut(ci_idx);
658 ci.func = func_idx;
659 ci.nresults = nret as i16;
660 ci.callstatus = mask;
661 ci.top = top_idx;
662 ci.u = if (mask & crate::state::CIST_C) != 0 {
663 crate::state::CallInfoFrame::c_default()
664 } else {
665 crate::state::CallInfoFrame::lua_default()
666 };
667 }
668 Ok(ci_idx)
669}
670
671#[inline(always)]
676fn precall_c(
677 state: &mut LuaState,
678 func_idx: StackIdx,
679 nresults: i32,
680 f: crate::state::LuaCFunction,
681) -> Result<i32, LuaError> {
682 state.check_stack(LUA_MINSTACK as i32)?;
683 state.gc_check_step();
684
685 let top_idx = state.top_idx();
686 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
687
688 debug_assert!(true );
689
690 if state.hookmask & LUA_MASKCALL != 0 {
691 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
692 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
693 }
694
695 let n = f(state)? as i32;
696
697 debug_assert!(
699 n <= state.top_idx().0 as i32,
700 "C function returned more values than available"
701 );
702
703 poscall(state, ci_idx, n)?;
704 Ok(n)
705}
706
707pub(crate) fn pretailcall(
712 state: &mut LuaState,
713 ci_idx: CallInfoIdx,
714 mut func_idx: StackIdx,
715 mut narg1: i32,
716 delta: i32,
717) -> Result<i32, LuaError> {
718 loop {
719 let func_val = state.get_at(func_idx).clone();
720 match func_val {
721 LuaValue::Function(LuaClosure::C(ref cl)) => {
722 let cfunc = state.global().c_functions[cl.func];
723 return precall_c(state, func_idx, LUA_MULTRET, cfunc);
724 }
725 LuaValue::Function(LuaClosure::LightC(f)) => {
726 let cfunc = state.global().c_functions[f];
727 return precall_c(state, func_idx, LUA_MULTRET, cfunc);
728 }
729 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
730 let proto = cl.proto.clone();
731 let fsize = proto.maxstacksize as i32;
732 let nfixparams = proto.numparams as i32;
733
734 state.check_stack(fsize - delta)?;
735 state.gc_check_step();
736
737 {
738 let ci = state.get_ci_mut(ci_idx);
739 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
740 }
741 let ci_func = state.get_ci(ci_idx).func;
742
743 for i in 0..narg1 {
744 let src = state.get_at(func_idx + i as i32).clone();
745 state.set_at(ci_func + i as i32, src);
746 }
747
748 func_idx = ci_func;
750
751 while narg1 <= nfixparams {
752 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
753 narg1 += 1;
754 }
755
756 {
757 let new_ci_top = func_idx + 1 + fsize as i32;
758 let stack_last = state.stack_last;
759 let live_top = state.top_idx();
760 let ci = state.get_ci_mut(ci_idx);
761 ci.top = new_ci_top;
762 debug_assert!(ci.top.0 <= stack_last.0);
763 ci.set_saved_pc(0);
764 ci.callstatus |= CIST_TAIL;
765 state.clear_stack_range(live_top, new_ci_top);
766 }
767
768 state.set_top(func_idx + narg1 as i32);
769 return Ok(-1); }
771 _ => {
772 func_idx = try_func_tm(state, func_idx)?;
773 narg1 += 1;
774 }
776 }
777 }
778}
779
780#[inline(always)]
790pub(crate) fn precall(
791 state: &mut LuaState,
792 func_idx: StackIdx,
793 nresults: i32,
794) -> Result<Option<CallInfoIdx>, LuaError> {
795 if let LuaValue::Function(LuaClosure::Lua(cl)) =
796 &state.stack[func_idx.0 as usize].val
797 {
798 let nfixparams = cl.proto.numparams as i32;
799 let fsize = cl.proto.maxstacksize as i32;
800 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
801
802 state.check_stack(fsize)?;
803 state.gc_check_step();
804
805 let ci_idx =
806 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
807 state.set_ci_savedpc(ci_idx, 0);
808
809 if narg < nfixparams {
810 fill_missing_params(state, narg, nfixparams);
811 }
812 return Ok(Some(ci_idx));
813 }
814 precall_slow(state, func_idx, nresults)
815}
816
817#[cold]
821#[inline(never)]
822fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
823 while narg < nfixparams {
824 let top = state.top_idx();
825 state.set_at(top, LuaValue::Nil);
826 state.set_top(top + 1);
827 narg += 1;
828 }
829}
830
831#[cold]
835#[inline(never)]
836fn precall_slow(
837 state: &mut LuaState,
838 mut func_idx: StackIdx,
839 nresults: i32,
840) -> Result<Option<CallInfoIdx>, LuaError> {
841 loop {
842 let func_val = state.get_at(func_idx).clone();
843 match func_val {
844 LuaValue::Function(LuaClosure::C(ref cl)) => {
845 let cfunc = state.global().c_functions[cl.func];
846 precall_c(state, func_idx, nresults, cfunc)?;
847 return Ok(None);
848 }
849 LuaValue::Function(LuaClosure::LightC(f)) => {
850 state.check_stack(LUA_MINSTACK as i32)?;
851 state.gc_check_step();
852
853 let top_idx = state.top_idx();
854 let ci_idx =
855 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
856
857 if state.hookmask & LUA_MASKCALL != 0 {
858 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
859 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
860 }
861
862 let cfunc = state.global().c_functions[f];
863 let n = cfunc(state)? as i32;
864 debug_assert!(
865 n <= state.top_idx().0 as i32,
866 "C function returned more values than available"
867 );
868 poscall(state, ci_idx, n)?;
869 return Ok(None);
870 }
871 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
872 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
873 let nfixparams = cl.proto.numparams as i32;
874 let fsize = cl.proto.maxstacksize as i32;
875
876 state.check_stack(fsize)?;
877 state.gc_check_step();
878
879 let ci_idx = prep_call_info(
880 state,
881 func_idx,
882 nresults,
883 0,
884 func_idx + 1 + fsize as i32,
885 )?;
886 state.set_ci_savedpc(ci_idx, 0);
887
888 if narg < nfixparams {
889 fill_missing_params(state, narg, nfixparams);
890 }
891 return Ok(Some(ci_idx));
892 }
893 _ => {
894 func_idx = try_func_tm(state, func_idx)?;
895 }
896 }
897 }
898}
899
900#[inline]
904fn ccall_inner(
905 state: &mut LuaState,
906 func_idx: StackIdx,
907 n_results: i32,
908 inc: u32,
909) -> Result<(), LuaError> {
910 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
911}
912
913#[inline]
914fn ccall_inner_with_status(
915 state: &mut LuaState,
916 func_idx: StackIdx,
917 n_results: i32,
918 inc: u32,
919 extra_callstatus: u16,
920) -> Result<(), LuaError> {
921 state.nCcalls += inc;
922
923 if state.c_calls() >= LUAI_MAXCCALLS {
925 state.check_stack(0)?;
927 state.check_c_stack()?;
928 }
929
930 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
931 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
932 vm::execute(state, ci_idx)?;
933 }
934
935 state.nCcalls -= inc;
936 Ok(())
937}
938
939pub(crate) fn call(
942 state: &mut LuaState,
943 func_idx: StackIdx,
944 n_results: i32,
945) -> Result<(), LuaError> {
946 ccall_inner(state, func_idx, n_results, 1)
947}
948
949pub(crate) fn callnoyield(
952 state: &mut LuaState,
953 func_idx: StackIdx,
954 n_results: i32,
955) -> Result<(), LuaError> {
956 ccall_inner(state, func_idx, n_results, NYCI)
958}
959
960fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
967 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
970
971 if status == LuaStatus::Ok {
972 status = LuaStatus::Yield;
973 } else {
974 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
975 state.allowhook = state.get_ci(ci_idx).get_oah();
977 let _func_idx = func::close(state, func_idx, status as i32, true)?;
979 set_error_obj(state, status, func_idx);
980
981 if state.errfunc != 0 && error_status(status) && status != LuaStatus::ErrErr && status != LuaStatus::ErrSyntax {
990 let errfunc_stk = StackIdx(state.errfunc as u32);
991 let err_val = state.get_at(func_idx);
999 state.push(err_val);
1000 let handler = state.get_at(errfunc_stk);
1001 state.set_at(state.top_idx() - 2, handler);
1002 if let Err(_) = state.call_no_yield(state.top_idx() - 2, 1) {
1003 status = LuaStatus::ErrErr;
1004 if let Ok(s) = state.intern_str(b"error in error handling") {
1005 state.set_at(func_idx, lua_types::value::LuaValue::Str(s));
1006 }
1007 state.set_top(func_idx + 1);
1008 }
1009 }
1010
1011 shrink_stack(state);
1012 state.get_ci_mut(ci_idx).set_recover_status(LuaStatus::Ok as i32);
1013 }
1014
1015 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1016 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1017 state.errfunc = old_errfunc;
1018
1019 Ok(status)
1020}
1021
1022fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1025 let n;
1026
1027 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1028 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1029 n = state.get_ci_u2_nres(ci_idx);
1030 } else {
1031 debug_assert!(
1032 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1033 "finishCcall: no continuation or non-yieldable"
1034 );
1035
1036 let mut status = LuaStatus::Yield;
1037
1038 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1039 status = finish_pcallk(state, ci_idx)?;
1040 }
1041
1042 state.adjust_results(LUA_MULTRET);
1044
1045 let k = state.get_ci(ci_idx).u_c_k();
1049 let ctx = state.get_ci(ci_idx).u_c_ctx();
1050 if let Some(k_fn) = k {
1051 n = k_fn(state, status as i32, ctx)? as i32;
1052 } else {
1053 return Err(LuaError::runtime(format_args!("finishCcall: missing continuation")));
1055 }
1056 debug_assert!(
1057 n <= state.top_idx().0 as i32,
1058 "continuation returned more values than available"
1059 );
1060 }
1061
1062 poscall(state, ci_idx, n)?;
1063 Ok(())
1064}
1065
1066fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1069 loop {
1070 let ci_idx = state.ci;
1071 if state.is_base_ci(ci_idx) {
1072 break;
1073 }
1074 if !state.get_ci(ci_idx).is_lua() {
1075 finish_ccall(state, ci_idx)?;
1076 } else {
1077 vm::finish_op(state)?;
1078 vm::execute(state, ci_idx)?;
1079 }
1080 }
1081 Ok(())
1082}
1083
1084fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1087 let mut ci_idx_opt = Some(state.ci);
1088 while let Some(ci_idx) = ci_idx_opt {
1089 let ci = state.get_ci(ci_idx);
1090 if ci.callstatus & CIST_YPCALL != 0 {
1091 return Some(ci_idx);
1092 }
1093 ci_idx_opt = ci.previous;
1094 }
1095 None
1096}
1097
1098fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1101 let top = state.top_idx();
1102 state.set_top(top - narg as i32);
1103 let s = state.intern_str(msg).ok();
1105 let new_top = state.top_idx();
1106 if let Some(s) = s { state.set_at(new_top, LuaValue::Str(s)); }
1107 state.set_top(new_top + 1);
1108 LuaStatus::ErrRun
1109}
1110
1111fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1114 let top = state.top_idx();
1115 let first_arg = top - nargs as i32;
1116 let ci_idx = state.ci;
1117
1118 if state.status == LuaStatus::Ok as u8 {
1119 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1120 } else {
1121 debug_assert!(state.status == LuaStatus::Yield as u8);
1122 state.status = LuaStatus::Ok as u8;
1123
1124 if state.get_ci(ci_idx).is_lua() {
1125 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1126 let pc = state.ci_savedpc(ci_idx);
1127 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1128 state.set_top(first_arg);
1129 vm::execute(state, ci_idx)?;
1130 } else {
1131 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1132 let ctx = state.get_ci(ci_idx).u_c_ctx();
1133 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1134 debug_assert!(n <= state.top_idx().0 as i32);
1135 poscall(state, ci_idx, n)?;
1136 } else {
1137 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1139 poscall(state, ci_idx, n)?;
1140 }
1141 }
1142
1143 unroll(state)?;
1144 }
1145 Ok(())
1146}
1147
1148fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1151 while error_status(status) {
1152 if let Some(ci_idx) = find_pcall(state) {
1153 state.ci = ci_idx;
1154 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1155 status = match raw_run_protected(state, |s| unroll(s)) {
1160 Ok(()) => LuaStatus::Ok,
1161 Err(e) => {
1162 let s = e.to_status();
1163 if error_status(s) {
1164 state.push(e.into_value());
1165 }
1166 s
1167 }
1168 };
1169 } else {
1170 break;
1171 }
1172 }
1173 status
1174}
1175
1176pub fn lua_resume(
1179 state: &mut LuaState,
1180 from: Option<&mut LuaState>,
1181 nargs: i32,
1182 nresults: &mut i32,
1183) -> LuaStatus {
1184 if state.status == LuaStatus::Ok as u8 {
1190 if !state.is_base_ci(state.ci) {
1191 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1192 }
1193 let ci_func = state.get_ci(state.ci).func;
1194 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1195 return resume_error(state, b"cannot resume dead coroutine", nargs);
1196 }
1197 } else if state.status != LuaStatus::Yield as u8 {
1198 return resume_error(state, b"cannot resume dead coroutine", nargs);
1199 }
1200
1201 state.nCcalls = from
1202 .as_ref()
1203 .map(|f| f.c_calls() as u32)
1204 .unwrap_or(0);
1205
1206 if state.c_calls() >= LUAI_MAXCCALLS {
1207 return resume_error(state, b"C stack overflow", nargs);
1208 }
1209 state.nCcalls += 1;
1210
1211 debug_assert!(
1212 if state.status == LuaStatus::Ok as u8 {
1213 nargs + 1 <= state.top_idx().0 as i32
1214 } else {
1215 nargs <= state.top_idx().0 as i32
1216 },
1217 "lua_resume: not enough stack elements"
1218 );
1219
1220 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1226 Ok(()) => (LuaStatus::Ok, None),
1227 Err(e) => {
1228 let s = e.to_status();
1229 let v = if error_status(s) { Some(e.into_value()) } else { None };
1230 (s, v)
1231 }
1232 };
1233 if let Some(v) = err_value {
1234 state.push(v);
1235 }
1236
1237 status = precover(state, status);
1238
1239 if !error_status(status) {
1240 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1241 } else {
1242 state.status = status as u8;
1244 let top = state.top_idx();
1245 set_error_obj(state, status, top);
1246 let new_top = state.top_idx();
1247 let ci_idx = state.ci;
1248 state.get_ci_mut(ci_idx).top = new_top;
1249 }
1250
1251 let ci_idx = state.ci;
1252 *nresults = if status == LuaStatus::Yield {
1253 state.get_ci_u2_nyield(ci_idx)
1254 } else {
1255 let ci_func = state.get_ci(ci_idx).func;
1256 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1257 };
1258
1259 status
1260}
1261
1262pub fn lua_isyieldable(state: &LuaState) -> bool {
1265 state.is_yieldable()
1267}
1268
1269pub fn lua_yieldk(
1273 state: &mut LuaState,
1274 nresults: i32,
1275 ctx: isize,
1276 k: Option<crate::state::LuaKFunction>,
1277) -> Result<i32, LuaError> {
1278 let ci_idx = state.ci;
1282
1283 debug_assert!(
1284 nresults <= state.top_idx().0 as i32,
1285 "lua_yieldk: not enough elements on stack"
1286 );
1287
1288 if !state.is_yieldable() {
1289 if !state.is_main_thread() {
1290 return Err(LuaError::runtime(format_args!(
1291 "attempt to yield across a C-call boundary"
1292 )));
1293 } else {
1294 return Err(LuaError::runtime(format_args!(
1295 "attempt to yield from outside a coroutine"
1296 )));
1297 }
1298 }
1299
1300 state.status = LuaStatus::Yield as u8;
1301 state.set_ci_u2_nyield(ci_idx, nresults);
1302
1303 if state.get_ci(ci_idx).is_lua() {
1304 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1305 debug_assert!(nresults == 0, "hooks cannot yield values");
1306 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1307 } else {
1309 if let crate::state::CallInfoFrame::C { k: ref mut frame_k, ctx: ref mut frame_ctx, .. } =
1311 state.get_ci_mut(ci_idx).u {
1312 *frame_k = k;
1313 if k.is_some() {
1314 *frame_ctx = ctx;
1315 }
1316 }
1317 return Err(LuaError::Yield);
1319 }
1320
1321 debug_assert!(
1322 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1323 "lua_yieldk called outside a hook"
1324 );
1325 Ok(0) }
1327
1328struct CloseP {
1335 level: StackIdx,
1336 status: LuaStatus,
1337}
1338
1339fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1342 func::close(state, pcl.level, pcl.status as i32, false)?;
1344 Ok(())
1345}
1346
1347pub(crate) fn close_protected(
1351 state: &mut LuaState,
1352 level: StackIdx,
1353 status: LuaStatus,
1354) -> LuaStatus {
1355 let old_ci = state.ci;
1356 let old_allowhook = state.allowhook;
1357 let mut status = status;
1358
1359 loop {
1360 let mut pcl = CloseP { level, status };
1361 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1362 Ok(()) => (LuaStatus::Ok, None),
1363 Err(e) => (e.to_status(), Some(e.into_value())),
1364 };
1365 if run_status == LuaStatus::Ok {
1366 return pcl.status;
1367 }
1368 state.ci = old_ci;
1369 state.allowhook = old_allowhook;
1370 if let Some(v) = err_value {
1376 state.push(v);
1377 }
1378 status = run_status;
1379 }
1380}
1381
1382pub(crate) fn pcall<F>(
1386 state: &mut LuaState,
1387 func: F,
1388 old_top: StackIdx,
1389 ef: isize,
1390) -> LuaStatus
1391where
1392 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1393{
1394 let old_ci = state.ci;
1395 let old_allowhook = state.allowhook;
1396 let old_errfunc = state.errfunc;
1397 state.errfunc = ef;
1398
1399 let mut status = match raw_run_protected(state, func) {
1405 Ok(()) => LuaStatus::Ok,
1406 Err(e) => {
1407 let s = e.to_status();
1408 state.push(e.into_value());
1409 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1415 let errfunc_idx = StackIdx(ef as u32);
1416 let arg = state.get_at(state.top_idx() - 1).clone();
1417 state.push(arg);
1418 let handler = state.get_at(errfunc_idx).clone();
1419 state.set_at(state.top_idx() - 2, handler);
1420 match state.call_no_yield(state.top_idx() - 2, 1) {
1421 Ok(()) => s,
1422 Err(_) => LuaStatus::ErrErr,
1423 }
1424 } else {
1425 s
1426 }
1427 }
1428 };
1429
1430 if status != LuaStatus::Ok {
1431 state.ci = old_ci;
1432 state.allowhook = old_allowhook;
1433 status = close_protected(state, old_top, status);
1434 set_error_obj(state, status, old_top);
1436 shrink_stack(state);
1437 }
1438
1439 state.errfunc = old_errfunc;
1440 status
1441}
1442
1443struct SParser {
1453 z: ZIO,
1454 buff: LexBuffer,
1456 dyd: DynDataStub,
1458 mode: Option<Vec<u8>>,
1460 name: Vec<u8>,
1461}
1462
1463fn check_mode(
1466 state: &mut LuaState,
1467 mode: Option<&[u8]>,
1468 kind: &[u8],
1469) -> Result<(), LuaError> {
1470 if let Some(mode_bytes) = mode {
1471 let kind_char = kind[0];
1472 if !mode_bytes.contains(&kind_char) {
1473 return Err(LuaError::syntax(format_args!(
1476 "attempt to load a {} chunk (mode is '{}')",
1477 core::str::from_utf8(kind).unwrap_or("?"),
1478 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1479 )));
1480 }
1481 }
1482 Ok(())
1483}
1484
1485fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1489 let c = p.z.getc();
1491
1492 let cl = if c == b'\x1b' as i32 {
1494 check_mode(state, p.mode.as_deref(), b"binary")?;
1495 crate::undump::undump(state, &mut p.z, &p.name)?
1497 } else {
1498 check_mode(state, p.mode.as_deref(), b"text")?;
1499 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1501 };
1502
1503 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1504 func::init_upvals(state, &cl)?;
1505
1506 state.check_stack(1)?;
1514 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1515
1516 Ok(())
1517}
1518
1519pub(crate) fn protected_parser(
1522 state: &mut LuaState,
1523 z: ZIO,
1524 name: &[u8],
1525 mode: Option<&[u8]>,
1526) -> LuaStatus {
1527 state.inc_nny();
1529
1530 let mut p = SParser {
1531 z,
1532 buff: LexBuffer::new(),
1533 dyd: DynDataStub::new(),
1534 mode: mode.map(|m| m.to_vec()),
1535 name: name.to_vec(),
1536 };
1537
1538 let top_idx = state.top_idx();
1541 let errfunc = state.errfunc;
1542 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1543
1544 state.dec_nny();
1548
1549 status
1550}
1551
1552