1#[allow(unused_imports)]
6use crate::prelude::*;
7use crate::zio::{LexBuffer, ZIO};
8use crate::{
9 func,
10 state::{CallInfoIdx, LuaState},
11 vm,
12};
13use lua_types::closure::LuaClosure;
14use lua_types::tagmethod::TagMethod;
15use lua_types::StackIdx;
16use lua_types::{error::LuaError, status::LuaStatus, value::LuaValue};
17
18struct DynDataStub;
22impl DynDataStub {
23 fn new() -> Self {
24 DynDataStub
25 }
26}
27
28fn 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 return parse(state, z, name, c);
51 }
52 Err(LuaError::syntax(format_args!(
53 "{}: Lua text parser not yet wired (phase-b: lua-parse::parse)",
54 core::str::from_utf8(name).unwrap_or("?"),
55 )))
56}
57
58const LUAI_MAXSTACK: usize = 1_000_000;
61const ERRORSTACKSIZE: usize = LUAI_MAXSTACK + 200;
62
63const LUAI_MAXSTACK_51: usize = 65500;
72
73#[inline]
77fn max_stack(state: &LuaState) -> usize {
78 if state.global().lua_version == lua_types::LuaVersion::V51 {
79 LUAI_MAXSTACK_51
80 } else {
81 LUAI_MAXSTACK
82 }
83}
84
85const EXTRA_STACK: i32 = 5;
86
87const LUA_MINSTACK: i32 = 20;
88
89const LUA_MULTRET: i32 = -1;
90
91const NYCI: u32 = 0x10001;
92
93use crate::state::LUAI_MAXCCALLS;
94
95const CIST_C: u16 = 1 << 1;
97const CIST_FRESH: u16 = 1 << 2;
98const CIST_HOOKED: u16 = 1 << 3;
99const CIST_YPCALL: u16 = 1 << 4;
100const CIST_TAIL: u16 = 1 << 5;
101const CIST_HOOKYIELD: u16 = 1 << 6;
102const CIST_TRAN: u16 = 1 << 8;
103const CIST_CLSRET: u16 = 1 << 9;
104const CIST_FIN: u16 = 1 << 7;
105
106const LUA_MASKCALL: u8 = 1 << 0;
107const LUA_MASKRET: u8 = 1 << 1;
108
109const LUA_HOOKCALL: i32 = 0;
110const LUA_HOOKRET: i32 = 1;
111const LUA_HOOKTAILCALL: i32 = 4;
112const LUA_HOOKTAILRET: i32 = 4;
117
118const CLOSE_K_TOP: i32 = -1;
119
120#[inline]
124fn error_status(s: LuaStatus) -> bool {
125 (s as i32) > (LuaStatus::Yield as i32)
126}
127
128fn run_message_handler(
129 state: &mut LuaState,
130 err_slot: StackIdx,
131 errfunc_idx: StackIdx,
132 original_status: LuaStatus,
133 recover_ci: CallInfoIdx,
134 recover_allowhook: bool,
135) -> LuaStatus {
136 let saved_n_ccalls = state.n_ccalls;
137 state.n_ccalls += NYCI;
140 loop {
141 let arg = state.get_at(err_slot).clone();
142 state.set_top(err_slot + 1);
143 state.push(arg);
144 let handler = state.get_at(errfunc_idx).clone();
145 let func_idx = state.top_idx() - 2;
146 state.set_at(func_idx, handler);
147
148 match state.call_no_yield(func_idx, 1) {
149 Ok(()) => {
150 state.n_ccalls = saved_n_ccalls;
151 return original_status;
152 }
153 Err(e) => {
154 let status = e.to_status();
155 let value = e.into_value();
156 state.ci = recover_ci;
157 state.allowhook = recover_allowhook;
158 state.set_top(err_slot + 1);
159 state.set_at(err_slot, value);
160
161 if status == LuaStatus::ErrRun {
162 continue;
163 }
164
165 state.n_ccalls = saved_n_ccalls;
166 return LuaStatus::ErrErr;
167 }
168 }
169 }
170}
171
172pub(crate) fn set_error_obj(state: &mut LuaState, errcode: LuaStatus, old_top: StackIdx) {
185 match errcode {
186 LuaStatus::ErrMem => {
187 let memerrmsg = state.global().memerrmsg.clone();
189 state.set_at(old_top, LuaValue::Str(memerrmsg));
190 }
191 LuaStatus::ErrErr => {
192 if let Ok(s) = state.intern_str(b"error in error handling") {
193 state.set_at(old_top, LuaValue::Str(s));
194 }
195 }
196 LuaStatus::Ok => {
197 state.set_at(old_top, LuaValue::Nil);
198 }
199 _ => {
200 debug_assert!(error_status(errcode));
201 let top = state.top_idx();
202 let err_val = state.get_at(top - 1).clone();
203 state.set_at(old_top, err_val);
204 }
205 }
206 state.set_top(old_top + 1);
207}
208
209pub(crate) fn raw_run_protected<F>(state: &mut LuaState, f: F) -> Result<(), LuaError>
217where
218 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
219{
220 let old_n_ccalls = state.n_ccalls;
221 let result = f(state);
222 state.n_ccalls = old_n_ccalls;
223 result
224}
225
226pub(crate) fn realloc_stack(
241 state: &mut LuaState,
242 new_size: usize,
243 raise_error: bool,
244) -> Result<bool, LuaError> {
245 let old_size = state.stack_size() as usize;
246 debug_assert!(new_size <= LUAI_MAXSTACK || new_size == ERRORSTACKSIZE);
247
248 let old_gcstop = state.global().gcstopem;
251 state.global_mut().gcstopem = true;
252
253 let new_extent = new_size as usize + EXTRA_STACK as usize;
254 let alloc_result = state.stack_resize(new_extent);
255
256 state.global_mut().gcstopem = old_gcstop;
257
258 if alloc_result.is_err() {
259 if raise_error {
260 return Err(LuaError::Memory);
261 } else {
262 return Ok(false);
263 }
264 }
265
266 state.stack_last = StackIdx(new_size as u32);
267
268 let old_extent = old_size + EXTRA_STACK as usize;
270 for i in old_extent..new_extent {
271 state.stack_set_nil(i);
272 }
273
274 Ok(true)
275}
276
277pub(crate) fn grow_stack(
283 state: &mut LuaState,
284 n: i32,
285 raise_error: bool,
286) -> Result<bool, LuaError> {
287 let size = state.stack_size();
288 let cap = max_stack(state);
289
290 if size > cap {
291 debug_assert!(state.stack_size() == ERRORSTACKSIZE);
293 if raise_error {
294 return Err(LuaError::with_status(LuaStatus::ErrErr));
295 }
296 return Ok(false);
297 } else if (n as usize) < cap {
298 let mut new_size = 2 * size;
299 let needed = (state.top_idx().0 as i32 + n) as usize;
300 if new_size > cap {
301 new_size = cap;
302 }
303 if new_size < needed {
304 new_size = needed;
305 }
306 if new_size <= cap {
307 return realloc_stack(state, new_size, raise_error);
308 }
309 }
310 realloc_stack(state, ERRORSTACKSIZE, raise_error)?;
312 if raise_error {
313 return Err(crate::debug::prefixed_runtime_pub(
314 state,
315 b"stack overflow".to_vec(),
316 ));
317 }
318 Ok(false)
319}
320
321fn stack_in_use(state: &LuaState) -> usize {
324 let mut lim = state.top_idx();
325 let mut ci_idx_opt = Some(state.ci);
326 while let Some(ci_idx) = ci_idx_opt {
327 let ci = state.get_ci(ci_idx);
328 if lim.0 < ci.top.0 {
329 lim = ci.top;
330 }
331 ci_idx_opt = ci.previous;
332 }
333 debug_assert!(
334 lim.0 <= state.stack_last.0 + EXTRA_STACK as u32,
335 "stack_in_use: max frame top {} exceeds stack_last {} + EXTRA_STACK",
336 lim.0,
337 state.stack_last.0
338 );
339 let res = lim.0 as usize + 1;
340 if res < LUA_MINSTACK as usize {
341 LUA_MINSTACK as usize
342 } else {
343 res
344 }
345}
346
347pub(crate) fn shrink_stack(state: &mut LuaState) {
350 let inuse = stack_in_use(state);
351 let max = if inuse > LUAI_MAXSTACK / 3 {
352 LUAI_MAXSTACK
353 } else {
354 inuse * 3
355 };
356 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
357 let nsize = if inuse > LUAI_MAXSTACK / 2 {
358 LUAI_MAXSTACK
359 } else {
360 inuse * 2
361 };
362 let _ = realloc_stack(state, nsize, false);
363 }
364 state.shrink_ci();
365}
366
367pub(crate) fn hook(
374 state: &mut LuaState,
375 event: i32,
376 line: i32,
377 ftransfer: i32,
378 ntransfer: i32,
379) -> Result<(), LuaError> {
380 if !state.has_hook() || !state.allowhook {
381 return Ok(());
382 }
383
384 let ci_idx = state.ci;
385
386 let saved_top = state.top_idx();
387 let saved_ci_top = state.get_ci(ci_idx).top;
388
389 let mut mask = CIST_HOOKED;
390
391 if ntransfer != 0 {
392 mask |= CIST_TRAN;
393 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
394 }
395
396 {
397 let ci = state.get_ci(ci_idx);
398 if ci.is_lua() {
399 let ci_top = ci.top;
400 if state.top_idx().0 < ci_top.0 {
401 state.set_top(ci_top);
402 }
403 }
404 }
405
406 state.check_stack(LUA_MINSTACK as i32)?;
407
408 {
409 let top = state.top_idx();
410 let ci = state.get_ci_mut(ci_idx);
411 if ci.top.0 < (top + LUA_MINSTACK).0 {
412 let new_top = top + LUA_MINSTACK;
413 ci.top = new_top;
414 state.clear_stack_range(top, new_top);
415 }
416 }
417
418 state.allowhook = false;
419 state.get_ci_mut(ci_idx).callstatus |= mask;
420
421 let mut ar = crate::debug::LuaDebug::default();
422 ar.event = event;
423 ar.currentline = line;
424 ar.ftransfer = ftransfer as u16;
425 ar.ntransfer = ntransfer as u16;
426 ar.i_ci = Some(ci_idx);
427 let hook_opt = state.hook.take();
428 if let Some(mut h) = hook_opt {
429 h(state, &ar);
430 if state.hook.is_none() {
431 state.hook = Some(h);
432 }
433 }
434
435 debug_assert!(!state.allowhook);
436 state.allowhook = true;
437
438 state.get_ci_mut(ci_idx).top = saved_ci_top;
439 state.set_top(saved_top);
440 state.get_ci_mut(ci_idx).callstatus &= !mask;
441
442 Ok(())
443}
444
445pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
448 state.oldpc = 0;
449 if state.hookmask & LUA_MASKCALL != 0 {
450 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
451 LUA_HOOKTAILCALL
452 } else {
453 LUA_HOOKCALL
454 };
455 let numparams = {
456 state.get_ci_lua_proto_numparams(ci_idx)
457 };
458 let pc = state.ci_savedpc(ci_idx);
459 state.set_ci_savedpc(ci_idx, pc + 1);
460 hook(state, event, -1, 1, numparams as i32)?;
461 state.set_ci_savedpc(ci_idx, pc);
462 }
463 Ok(())
464}
465
466fn fire_tail_returns(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
476 if !state.get_ci(ci_idx).is_lua() {
477 return Ok(());
478 }
479 while state.get_ci(ci_idx).tailcalls > 0 {
480 state.get_ci_mut(ci_idx).tailcalls -= 1;
481 hook(state, LUA_HOOKTAILRET, -1, 0, 0)?;
482 }
483 Ok(())
484}
485
486fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
489 if state.hookmask & LUA_MASKRET != 0 {
490 let first_res = state.top_idx().0 as i32 - nres;
491 let mut delta: i32 = 0;
492
493 if state.get_ci(ci_idx).is_lua() {
494 let (is_vararg, nextraargs, numparams) = state.get_ci_vararg_info(ci_idx);
495 if is_vararg {
496 delta = nextraargs + numparams as i32 + 1;
497 }
498 }
499
500 let original_func = state.get_ci(ci_idx).func;
502 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
503
504 let ci_func = state.get_ci(ci_idx).func;
505 let ftransfer = (first_res - ci_func.0 as i32) as u16;
506
507 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
508
509 state.get_ci_mut(ci_idx).func = original_func;
510
511 fire_tail_returns(state, ci_idx)?;
512 }
513
514 let previous = state.get_ci(ci_idx).previous;
515 if let Some(prev_idx) = previous {
516 if state.get_ci(prev_idx).is_lua() {
517 state.oldpc = state.get_ci_pcrel(prev_idx);
518 }
519 }
520
521 Ok(())
522}
523
524fn try_func_tm(
534 state: &mut LuaState,
535 func_idx: StackIdx,
536 call_metamethods: &mut u8,
537) -> Result<StackIdx, LuaError> {
538 let count_call_metamethods = state.global().lua_version == lua_types::LuaVersion::V55;
539 if count_call_metamethods && *call_metamethods == 15 {
540 return Err(LuaError::runtime(format_args!("'__call' chain too long")));
541 }
542 state.check_stack(1)?;
544 if state.gc_check_needed {
545 state.gc_check_step();
546 }
547
548 let func_val = state.get_at(func_idx).clone();
549 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
550
551 if matches!(tm, LuaValue::Nil) {
552 let offender = state.get_at(func_idx).clone();
553 return Err(crate::debug::call_error(state, &offender, func_idx));
554 }
555
556 let top = state.top_idx();
558 let mut p = top;
559 while p.0 > func_idx.0 {
560 let val = state.get_at(p - 1).clone();
561 state.set_at(p, val);
562 p = p - 1;
563 }
564 state.set_top(top + 1);
565 state.set_at(func_idx, tm);
566 if count_call_metamethods {
567 *call_metamethods += 1;
568 }
569
570 Ok(func_idx)
571}
572
573#[inline(always)]
578fn move_results(
579 state: &mut LuaState,
580 res_idx: StackIdx,
581 nres: i32,
582 wanted: i32,
583) -> Result<(), LuaError> {
584 match wanted {
585 0 => {
586 state.set_top(res_idx);
587 return Ok(());
588 }
589 1 => {
590 if nres == 0 {
591 state.set_at(res_idx, LuaValue::Nil);
592 } else {
593 let top = state.top_idx();
594 let src = state.get_at(top - nres as i32).clone();
595 state.set_at(res_idx, src);
596 }
597 state.set_top(res_idx + 1);
598 return Ok(());
599 }
600 LUA_MULTRET => {
601 }
603 _ => {
604 if wanted < LUA_MULTRET {
605 let ci_idx = state.ci;
606 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
607 state.set_ci_u2_nres(ci_idx, nres);
608
609 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
610
611 let ci_idx = state.ci;
612 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
613
614 if state.hookmask != 0 {
615 let saved_res = res_idx;
616 rethook(state, ci_idx, nres)?;
617 let _ = saved_res; }
619
620 let decoded_wanted = -(wanted) - 3;
621 let wanted = if decoded_wanted == LUA_MULTRET {
622 nres
623 } else {
624 decoded_wanted
625 };
626
627 let first_result = state.top_idx().0 as i32 - nres;
629 let actual_nres = nres.min(wanted);
630 for i in 0..actual_nres {
631 let src = state.get_at((first_result + i) as u32).clone();
632 state.set_at(res_idx + i as i32, src);
633 }
634 for i in actual_nres..wanted {
635 state.set_at(res_idx + i as i32, LuaValue::Nil);
636 }
637 state.set_top(res_idx + wanted as i32);
638 return Ok(());
639 }
640 }
641 }
642
643 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
645 let first_result = state.top_idx().0 as i32 - nres;
646 let actual_nres = nres.min(effective_wanted);
647 for i in 0..actual_nres {
648 let src = state.get_at((first_result + i) as u32).clone();
649 state.set_at(res_idx + i as i32, src);
650 }
651 for i in actual_nres..effective_wanted {
652 state.set_at(res_idx + i as i32, LuaValue::Nil);
653 }
654 state.set_top(res_idx + effective_wanted as i32);
655 Ok(())
656}
657
658#[inline(always)]
662pub(crate) fn poscall(
663 state: &mut LuaState,
664 ci_idx: CallInfoIdx,
665 nres: i32,
666) -> Result<(), LuaError> {
667 let wanted = state.get_ci(ci_idx).nresults as i32;
668
669 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
670 rethook(state, ci_idx, nres)?;
671 }
672
673 let func_idx = state.get_ci(ci_idx).func;
674 move_results(state, func_idx, nres, wanted)?;
675
676 debug_assert!(
677 state.get_ci(ci_idx).callstatus
678 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
679 == 0
680 );
681
682 let previous = state
683 .get_ci(ci_idx)
684 .previous
685 .expect("poscall: no previous call frame");
686 state.ci = previous;
687 Ok(())
688}
689
690#[inline(always)]
704fn prep_call_info(
705 state: &mut LuaState,
706 func_idx: StackIdx,
707 nret: i32,
708 mask: u16,
709 top_idx: StackIdx,
710) -> Result<CallInfoIdx, LuaError> {
711 debug_assert!(
712 mask & crate::state::CIST_TRAP == 0,
713 "prep_call_info must not be handed a pre-set trap bit"
714 );
715 let ci_idx = state.next_ci()?;
717 state.ci = ci_idx;
718 {
719 let ci = state.get_ci_mut(ci_idx);
720 ci.func = func_idx;
721 ci.nresults = nret as i16;
722 ci.callstatus = mask;
723 ci.call_metamethods = 0;
724 ci.top = top_idx;
725 ci.u = crate::state::CallInfoFrame::lua_default();
726 }
727 Ok(ci_idx)
728}
729
730#[inline(always)]
735fn precall_c(
736 state: &mut LuaState,
737 func_idx: StackIdx,
738 nresults: i32,
739 f: crate::state::LuaCallable,
740 call_metamethods: u8,
741) -> Result<i32, LuaError> {
742 state.check_stack(LUA_MINSTACK as i32)?;
743 if state.gc_check_needed {
744 state.gc_check_step();
745 }
746
747 let top_idx = state.top_idx();
748 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
749 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
750
751 debug_assert!(
752 state.get_ci(ci_idx).top.0 <= state.stack_last.0,
753 "precall_c: ci.top {} exceeds stack_last {}",
754 state.get_ci(ci_idx).top.0,
755 state.stack_last.0
756 );
757
758 if state.hookmask & LUA_MASKCALL != 0 {
759 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
760 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
761 }
762
763 let n = f.call(state)? as i32;
764
765 debug_assert!(
766 n <= state.top_idx().0 as i32,
767 "C function returned more values than available"
768 );
769
770 poscall(state, ci_idx, n)?;
771 Ok(n)
772}
773
774pub(crate) fn pretailcall(
792 state: &mut LuaState,
793 ci_idx: CallInfoIdx,
794 mut func_idx: StackIdx,
795 mut narg1: i32,
796 delta: i32,
797) -> Result<i32, LuaError> {
798 let mut call_metamethods = 0u8;
799 loop {
800 let func_val = state.get_at(func_idx).clone();
801 match func_val {
802 LuaValue::Function(LuaClosure::C(ref cl)) => {
803 let cfunc = state.global().c_functions[cl.func].clone();
804 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
805 }
806 LuaValue::Function(LuaClosure::LightC(f)) => {
807 let cfunc = state.global().c_functions[f].clone();
808 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
809 }
810 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
811 let proto = cl.proto.clone();
812 let fsize = proto.maxstacksize as i32;
813 let nfixparams = proto.numparams as i32;
814
815 state.check_stack(fsize - delta)?;
816 if state.gc_check_needed {
817 state.gc_check_step();
818 }
819
820 {
821 let ci = state.get_ci_mut(ci_idx);
822 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
823 }
824 let ci_func = state.get_ci(ci_idx).func;
825
826 for i in 0..narg1 {
827 let src = state.get_at(func_idx + i as i32).clone();
828 state.set_at(ci_func + i as i32, src);
829 }
830
831 func_idx = ci_func;
833
834 while narg1 <= nfixparams {
835 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
836 narg1 += 1;
837 }
838
839 {
840 let new_ci_top = func_idx + 1 + fsize as i32;
841 let stack_last = state.stack_last;
842 let live_top = state.top_idx();
843 let ci = state.get_ci_mut(ci_idx);
844 ci.call_metamethods = call_metamethods;
845 ci.top = new_ci_top;
846 debug_assert!(ci.top.0 <= stack_last.0);
847 ci.set_saved_pc(0);
848 ci.callstatus |= CIST_TAIL;
849 state.clear_stack_range(live_top, new_ci_top);
850 }
851
852 state.set_top(func_idx + narg1 as i32);
853 return Ok(-1); }
855 _ => {
856 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
857 narg1 += 1;
858 }
860 }
861 }
862}
863
864#[inline(always)]
875pub(crate) fn precall(
876 state: &mut LuaState,
877 func_idx: StackIdx,
878 nresults: i32,
879) -> Result<Option<CallInfoIdx>, LuaError> {
880 if let LuaValue::Function(LuaClosure::Lua(cl)) = &state.stack[func_idx.0 as usize].val {
881 let nfixparams = cl.proto.numparams as i32;
882 let fsize = cl.proto.maxstacksize as i32;
883 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
884
885 state.check_stack(fsize)?;
886 if state.gc_check_needed {
887 state.gc_check_step();
888 }
889
890 let ci_idx = prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
891 state.set_ci_savedpc(ci_idx, 0);
892
893 if narg < nfixparams {
894 fill_missing_params(state, narg, nfixparams);
895 }
896 return Ok(Some(ci_idx));
897 }
898 precall_slow(state, func_idx, nresults)
899}
900
901#[cold]
905#[inline(never)]
906fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
907 while narg < nfixparams {
908 let top = state.top_idx();
909 state.set_at(top, LuaValue::Nil);
910 state.set_top(top + 1);
911 narg += 1;
912 }
913}
914
915#[cold]
919#[inline(never)]
920fn precall_slow(
921 state: &mut LuaState,
922 mut func_idx: StackIdx,
923 nresults: i32,
924) -> Result<Option<CallInfoIdx>, LuaError> {
925 let mut call_metamethods = 0u8;
926 loop {
927 let func_val = state.get_at(func_idx).clone();
928 match func_val {
929 LuaValue::Function(LuaClosure::C(ref cl)) => {
930 let cfunc = state.global().c_functions[cl.func].clone();
931 precall_c(state, func_idx, nresults, cfunc, call_metamethods)?;
932 return Ok(None);
933 }
934 LuaValue::Function(LuaClosure::LightC(f)) => {
935 state.check_stack(LUA_MINSTACK as i32)?;
936 if state.gc_check_needed {
937 state.gc_check_step();
938 }
939
940 let top_idx = state.top_idx();
941 let ci_idx =
942 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
943 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
944
945 if state.hookmask & LUA_MASKCALL != 0 {
946 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
947 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
948 }
949
950 let cfunc = state.global().c_functions[f].clone();
951 let n = cfunc.call(state)? as i32;
952 debug_assert!(
953 n <= state.top_idx().0 as i32,
954 "C function returned more values than available"
955 );
956 poscall(state, ci_idx, n)?;
957 return Ok(None);
958 }
959 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
960 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
961 let nfixparams = cl.proto.numparams as i32;
962 let fsize = cl.proto.maxstacksize as i32;
963
964 state.check_stack(fsize)?;
965 if state.gc_check_needed {
966 state.gc_check_step();
967 }
968
969 let ci_idx =
970 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
971 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
972 state.set_ci_savedpc(ci_idx, 0);
973
974 if narg < nfixparams {
975 fill_missing_params(state, narg, nfixparams);
976 }
977 return Ok(Some(ci_idx));
978 }
979 _ => {
980 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
981 }
982 }
983 }
984}
985
986#[inline]
990fn ccall_inner(
991 state: &mut LuaState,
992 func_idx: StackIdx,
993 n_results: i32,
994 inc: u32,
995) -> Result<(), LuaError> {
996 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
997}
998
999#[inline]
1000fn ccall_known_c_inner(
1001 state: &mut LuaState,
1002 func_idx: StackIdx,
1003 n_results: i32,
1004 inc: u32,
1005 f: crate::state::LuaCallable,
1006) -> Result<(), LuaError> {
1007 state.n_ccalls += inc;
1008
1009 if state.c_calls() >= LUAI_MAXCCALLS {
1010 state.check_stack(0)?;
1011 state.check_c_stack()?;
1012 }
1013
1014 precall_c(state, func_idx, n_results, f, 0)?;
1015
1016 state.n_ccalls -= inc;
1017 Ok(())
1018}
1019
1020#[inline]
1021fn ccall_inner_with_status(
1022 state: &mut LuaState,
1023 func_idx: StackIdx,
1024 n_results: i32,
1025 inc: u32,
1026 extra_callstatus: u16,
1027) -> Result<(), LuaError> {
1028 state.n_ccalls += inc;
1029
1030 if state.c_calls() >= LUAI_MAXCCALLS {
1031 state.check_stack(0)?;
1032 state.check_c_stack()?;
1033 }
1034
1035 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
1036 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
1037 vm::execute(state, ci_idx)?;
1038 }
1039
1040 state.n_ccalls -= inc;
1041 Ok(())
1042}
1043
1044pub(crate) fn call(
1047 state: &mut LuaState,
1048 func_idx: StackIdx,
1049 n_results: i32,
1050) -> Result<(), LuaError> {
1051 ccall_inner(state, func_idx, n_results, 1)
1052}
1053
1054pub(crate) fn callnoyield(
1057 state: &mut LuaState,
1058 func_idx: StackIdx,
1059 n_results: i32,
1060) -> Result<(), LuaError> {
1061 ccall_inner(state, func_idx, n_results, NYCI)
1063}
1064
1065#[inline]
1072pub(crate) fn call_known_c(
1073 state: &mut LuaState,
1074 func_idx: StackIdx,
1075 n_results: i32,
1076) -> Result<bool, LuaError> {
1077 let cfunc = match &state.stack[func_idx.0 as usize].val {
1078 LuaValue::Function(LuaClosure::C(cl)) => state.global().c_functions[cl.func].clone(),
1079 LuaValue::Function(LuaClosure::LightC(f)) => state.global().c_functions[*f].clone(),
1080 _ => return Ok(false),
1081 };
1082
1083 ccall_known_c_inner(state, func_idx, n_results, 1, cfunc)?;
1084 Ok(true)
1085}
1086
1087fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
1094 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
1096
1097 if status == LuaStatus::Ok {
1098 status = LuaStatus::Yield;
1099 } else {
1100 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
1101 state.allowhook = state.get_ci(ci_idx).get_oah();
1102 let _func_idx = func::close(state, func_idx, status as i32, true)?;
1103 set_error_obj(state, status, func_idx);
1104
1105 if state.errfunc != 0
1114 && error_status(status)
1115 && status != LuaStatus::ErrErr
1116 && status != LuaStatus::ErrSyntax
1117 {
1118 let errfunc_stk = StackIdx(state.errfunc as u32);
1119 status = run_message_handler(
1120 state,
1121 func_idx,
1122 errfunc_stk,
1123 status,
1124 ci_idx,
1125 state.allowhook,
1126 );
1127 }
1128
1129 shrink_stack(state);
1130 state
1131 .get_ci_mut(ci_idx)
1132 .set_recover_status(LuaStatus::Ok as i32);
1133 }
1134
1135 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1136 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1137 state.errfunc = old_errfunc;
1138
1139 Ok(status)
1140}
1141
1142fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1145 let n;
1146
1147 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1148 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1149 n = state.get_ci_u2_nres(ci_idx);
1150 } else {
1151 debug_assert!(
1152 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1153 "finishCcall: no continuation or non-yieldable"
1154 );
1155
1156 let mut status = LuaStatus::Yield;
1157
1158 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1159 status = finish_pcallk(state, ci_idx)?;
1160 }
1161
1162 state.adjust_results(LUA_MULTRET);
1163
1164 let k = state.get_ci(ci_idx).u_c_k();
1169 let ctx = state.get_ci(ci_idx).u_c_ctx();
1170 if let Some(k_fn) = k {
1171 n = k_fn(state, status as i32, ctx)? as i32;
1172 } else {
1173 return Err(LuaError::runtime(format_args!(
1176 "finishCcall: missing continuation"
1177 )));
1178 }
1179 debug_assert!(
1180 n <= state.top_idx().0 as i32,
1181 "continuation returned more values than available"
1182 );
1183 }
1184
1185 poscall(state, ci_idx, n)?;
1186 Ok(())
1187}
1188
1189fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1192 loop {
1193 let ci_idx = state.ci;
1194 if state.is_base_ci(ci_idx) {
1195 break;
1196 }
1197 if !state.get_ci(ci_idx).is_lua() {
1198 finish_ccall(state, ci_idx)?;
1199 } else {
1200 vm::finish_op(state)?;
1201 vm::execute(state, ci_idx)?;
1202 }
1203 }
1204 Ok(())
1205}
1206
1207fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1210 let mut ci_idx_opt = Some(state.ci);
1211 while let Some(ci_idx) = ci_idx_opt {
1212 let ci = state.get_ci(ci_idx);
1213 if ci.callstatus & CIST_YPCALL != 0 {
1214 return Some(ci_idx);
1215 }
1216 ci_idx_opt = ci.previous;
1217 }
1218 None
1219}
1220
1221fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1224 let top = state.top_idx();
1225 state.set_top(top - narg as i32);
1226 let s = state.intern_str(msg).ok();
1227 let new_top = state.top_idx();
1228 if let Some(s) = s {
1229 state.set_at(new_top, LuaValue::Str(s));
1230 }
1231 state.set_top(new_top + 1);
1232 LuaStatus::ErrRun
1233}
1234
1235fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1238 let top = state.top_idx();
1239 let first_arg = top - nargs as i32;
1240 let ci_idx = state.ci;
1241
1242 if state.status == LuaStatus::Ok as u8 {
1243 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1244 } else {
1245 debug_assert!(state.status == LuaStatus::Yield as u8);
1246 state.status = LuaStatus::Ok as u8;
1247
1248 if state.get_ci(ci_idx).is_lua() {
1249 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1250 let pc = state.ci_savedpc(ci_idx);
1251 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1252 state.set_top(first_arg);
1253 vm::execute(state, ci_idx)?;
1254 } else {
1255 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1256 let ctx = state.get_ci(ci_idx).u_c_ctx();
1257 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1258 debug_assert!(n <= state.top_idx().0 as i32);
1259 poscall(state, ci_idx, n)?;
1260 } else {
1261 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1263 poscall(state, ci_idx, n)?;
1264 }
1265 }
1266
1267 unroll(state)?;
1268 }
1269 Ok(())
1270}
1271
1272fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1275 while error_status(status) {
1276 if let Some(ci_idx) = find_pcall(state) {
1277 state.ci = ci_idx;
1278 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1279 status = match raw_run_protected(state, |s| unroll(s)) {
1284 Ok(()) => LuaStatus::Ok,
1285 Err(e) => {
1286 let s = e.to_status();
1287 if error_status(s) {
1288 state.push(e.into_value());
1289 }
1290 s
1291 }
1292 };
1293 } else {
1294 break;
1295 }
1296 }
1297 status
1298}
1299
1300pub fn lua_resume(
1303 state: &mut LuaState,
1304 from: Option<&mut LuaState>,
1305 nargs: i32,
1306 nresults: &mut i32,
1307) -> LuaStatus {
1308 let _heap_guard = {
1313 let g = state.global.borrow();
1314 lua_gc::HeapGuard::push(&g.heap)
1315 };
1316 if state.status == LuaStatus::Ok as u8 {
1317 if !state.is_base_ci(state.ci) {
1318 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1319 }
1320 let ci_func = state.get_ci(state.ci).func;
1321 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1322 return resume_error(state, b"cannot resume dead coroutine", nargs);
1323 }
1324 } else if state.status != LuaStatus::Yield as u8 {
1325 return resume_error(state, b"cannot resume dead coroutine", nargs);
1326 }
1327
1328 state.n_ccalls = from.as_ref().map(|f| f.c_calls() as u32).unwrap_or(0);
1329
1330 if state.c_calls() >= LUAI_MAXCCALLS {
1331 return resume_error(state, b"C stack overflow", nargs);
1332 }
1333 state.n_ccalls += 1;
1334
1335 debug_assert!(
1336 if state.status == LuaStatus::Ok as u8 {
1337 nargs + 1 <= state.top_idx().0 as i32
1338 } else {
1339 nargs <= state.top_idx().0 as i32
1340 },
1341 "lua_resume: not enough stack elements"
1342 );
1343
1344 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1350 Ok(()) => (LuaStatus::Ok, None),
1351 Err(e) => {
1352 let s = e.to_status();
1353 let v = if error_status(s) {
1354 Some(e.into_value())
1355 } else {
1356 None
1357 };
1358 (s, v)
1359 }
1360 };
1361 if let Some(v) = err_value {
1362 state.push(v);
1363 }
1364
1365 status = precover(state, status);
1366
1367 if !error_status(status) {
1368 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1369 } else {
1370 state.status = status as u8;
1372 let top = state.top_idx();
1373 set_error_obj(state, status, top);
1374 let new_top = state.top_idx();
1375 let ci_idx = state.ci;
1376 state.get_ci_mut(ci_idx).top = new_top;
1377 }
1378
1379 let ci_idx = state.ci;
1380 *nresults = if status == LuaStatus::Yield {
1381 state.get_ci_u2_nyield(ci_idx)
1382 } else {
1383 let ci_func = state.get_ci(ci_idx).func;
1384 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1385 };
1386
1387 status
1388}
1389
1390pub fn lua_isyieldable(state: &LuaState) -> bool {
1393 state.is_yieldable()
1394}
1395
1396pub fn lua_yieldk(
1400 state: &mut LuaState,
1401 nresults: i32,
1402 ctx: isize,
1403 k: Option<crate::state::LuaKFunction>,
1404) -> Result<i32, LuaError> {
1405 let ci_idx = state.ci;
1406
1407 debug_assert!(
1408 nresults <= state.top_idx().0 as i32,
1409 "lua_yieldk: not enough elements on stack"
1410 );
1411
1412 if !state.is_yieldable() {
1413 if matches!(state.global().lua_version, lua_types::LuaVersion::V51) {
1414 return Err(LuaError::runtime(format_args!(
1415 "attempt to yield across metamethod/C-call boundary"
1416 )));
1417 }
1418 if !state.is_main_thread() {
1419 return Err(LuaError::runtime(format_args!(
1420 "attempt to yield across a C-call boundary"
1421 )));
1422 } else {
1423 return Err(LuaError::runtime(format_args!(
1424 "attempt to yield from outside a coroutine"
1425 )));
1426 }
1427 }
1428
1429 state.status = LuaStatus::Yield as u8;
1430 state.set_ci_u2_nyield(ci_idx, nresults);
1431
1432 if state.get_ci(ci_idx).is_lua() {
1433 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1434 debug_assert!(nresults == 0, "hooks cannot yield values");
1435 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1436 } else {
1438 let ci = state.get_ci_mut(ci_idx);
1439 ci.set_u_c_k(k);
1440 if k.is_some() {
1441 ci.set_u_c_ctx(ctx);
1442 }
1443 return Err(LuaError::Yield);
1445 }
1446
1447 debug_assert!(
1448 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1449 "lua_yieldk called outside a hook"
1450 );
1451 Ok(0) }
1453
1454struct CloseP {
1461 level: StackIdx,
1462 status: LuaStatus,
1463}
1464
1465fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1468 func::close(state, pcl.level, pcl.status as i32, false)?;
1469 Ok(())
1470}
1471
1472pub(crate) fn close_protected(
1476 state: &mut LuaState,
1477 level: StackIdx,
1478 status: LuaStatus,
1479) -> LuaStatus {
1480 let old_ci = state.ci;
1481 let old_allowhook = state.allowhook;
1482 let mut status = status;
1483
1484 loop {
1485 let mut pcl = CloseP { level, status };
1486 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1487 Ok(()) => (LuaStatus::Ok, None),
1488 Err(e) => (e.to_status(), Some(e.into_value())),
1489 };
1490 if run_status == LuaStatus::Ok {
1491 return pcl.status;
1492 }
1493 state.ci = old_ci;
1494 state.allowhook = old_allowhook;
1495 if let Some(v) = err_value {
1501 state.push(v);
1502 }
1503 status = run_status;
1504 }
1505}
1506
1507pub(crate) fn pcall<F>(state: &mut LuaState, func: F, old_top: StackIdx, ef: isize) -> LuaStatus
1511where
1512 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1513{
1514 let old_ci = state.ci;
1515 let old_allowhook = state.allowhook;
1516 let old_errfunc = state.errfunc;
1517 state.errfunc = ef;
1518
1519 let mut status = match raw_run_protected(state, func) {
1525 Ok(()) => LuaStatus::Ok,
1526 Err(e) => {
1527 let s = e.to_status();
1528 state.push(e.into_value());
1529 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1535 let errfunc_idx = StackIdx(ef as u32);
1536 let err_slot = state.top_idx() - 1;
1537 run_message_handler(state, err_slot, errfunc_idx, s, old_ci, old_allowhook)
1538 } else {
1539 s
1540 }
1541 }
1542 };
1543
1544 if status != LuaStatus::Ok
1552 && status != LuaStatus::ErrSyntax
1553 && state.global().lua_version == lua_types::LuaVersion::V55
1554 {
1555 let top = state.top_idx();
1556 if matches!(state.get_at(top - 1), LuaValue::Nil) {
1557 if let Ok(s) = state.intern_str(b"<no error object>") {
1558 state.set_at(top - 1, LuaValue::Str(s));
1559 }
1560 }
1561 }
1562
1563 if status != LuaStatus::Ok {
1564 state.ci = old_ci;
1565 state.allowhook = old_allowhook;
1566 status = close_protected(state, old_top, status);
1567 set_error_obj(state, status, old_top);
1569 shrink_stack(state);
1570 }
1571
1572 state.errfunc = old_errfunc;
1573 status
1574}
1575
1576struct SParser {
1585 z: ZIO,
1586 buff: LexBuffer,
1588 dyd: DynDataStub,
1590 mode: Option<Vec<u8>>,
1592 name: Vec<u8>,
1593}
1594
1595fn check_mode(mode: Option<&[u8]>, kind: &[u8]) -> Result<(), LuaError> {
1598 if let Some(mode_bytes) = mode {
1599 let kind_char = kind[0];
1600 if !mode_bytes.contains(&kind_char) {
1601 return Err(LuaError::syntax(format_args!(
1604 "attempt to load a {} chunk (mode is '{}')",
1605 core::str::from_utf8(kind).unwrap_or("?"),
1606 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1607 )));
1608 }
1609 }
1610 Ok(())
1611}
1612
1613fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1617 let c = p.z.getc(state)?;
1618
1619 let cl = if c == b'\x1b' as i32 {
1620 check_mode(p.mode.as_deref(), b"binary")?;
1621 crate::undump::undump(state, &mut p.z, &p.name)?
1622 } else {
1623 check_mode(p.mode.as_deref(), b"text")?;
1624 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1625 };
1626
1627 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1628
1629 state.check_stack(1)?;
1647 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1648
1649 Ok(())
1650}
1651
1652pub(crate) fn protected_parser(
1664 state: &mut LuaState,
1665 z: ZIO,
1666 name: &[u8],
1667 mode: Option<&[u8]>,
1668) -> LuaStatus {
1669 state.inc_nny();
1670
1671 let mut p = SParser {
1672 z,
1673 buff: LexBuffer::new(),
1674 dyd: DynDataStub::new(),
1675 mode: mode.map(|m| m.to_vec()),
1676 name: name.to_vec(),
1677 };
1678
1679 let saved_gcstp = {
1680 let mut g = state.global_mut();
1681 let old = g.gc_stop_flags();
1682 let _ = g.stop_gc_internal();
1683 old
1684 };
1685
1686 let top_idx = state.top_idx();
1687 let errfunc = state.errfunc;
1688 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1689
1690 state.global_mut().set_gc_stop_flags(saved_gcstp);
1691
1692 state.dec_nny();
1695
1696 status
1697}