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