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(crate::debug::prefixed_runtime_pub(
301 state,
302 b"stack overflow".to_vec(),
303 ));
304 }
305 Ok(false)
306}
307
308fn stack_in_use(state: &LuaState) -> usize {
311 let mut lim = state.top_idx();
312 let mut ci_idx_opt = Some(state.ci);
314 while let Some(ci_idx) = ci_idx_opt {
315 let ci = state.get_ci(ci_idx);
316 if lim.0 < ci.top.0 {
317 lim = ci.top;
318 }
319 ci_idx_opt = ci.previous;
320 }
321 debug_assert!(true );
322 let res = lim.0 as usize + 1;
323 if res < LUA_MINSTACK as usize {
324 LUA_MINSTACK as usize
325 } else {
326 res
327 }
328}
329
330pub(crate) fn shrink_stack(state: &mut LuaState) {
333 let inuse = stack_in_use(state);
334 let max = if inuse > LUAI_MAXSTACK / 3 {
335 LUAI_MAXSTACK
336 } else {
337 inuse * 3
338 };
339 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
340 let nsize = if inuse > LUAI_MAXSTACK / 2 {
341 LUAI_MAXSTACK
342 } else {
343 inuse * 2
344 };
345 let _ = realloc_stack(state, nsize, false);
346 }
347 state.shrink_ci();
348}
349
350pub(crate) fn hook(
357 state: &mut LuaState,
358 event: i32,
359 line: i32,
360 ftransfer: i32,
361 ntransfer: i32,
362) -> Result<(), LuaError> {
363 if !state.has_hook() || !state.allowhook {
364 return Ok(());
365 }
366
367 let ci_idx = state.ci;
368
369 let saved_top = state.top_idx();
371 let saved_ci_top = state.get_ci(ci_idx).top;
372
373 let mut mask = CIST_HOOKED;
374
375 if ntransfer != 0 {
376 mask |= CIST_TRAN;
377 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
378 }
379
380 {
381 let ci = state.get_ci(ci_idx);
382 if ci.is_lua() {
383 let ci_top = ci.top;
384 if state.top_idx().0 < ci_top.0 {
385 state.set_top(ci_top);
386 }
387 }
388 }
389
390 state.check_stack(LUA_MINSTACK as i32)?;
391
392 {
393 let top = state.top_idx();
394 let ci = state.get_ci_mut(ci_idx);
395 if ci.top.0 < (top + LUA_MINSTACK).0 {
396 let new_top = top + LUA_MINSTACK;
397 ci.top = new_top;
398 state.clear_stack_range(top, new_top);
399 }
400 }
401
402 state.allowhook = false;
403 state.get_ci_mut(ci_idx).callstatus |= mask;
404
405 let mut ar = crate::debug::LuaDebug::default();
406 ar.event = event;
407 ar.currentline = line;
408 ar.ftransfer = ftransfer as u16;
409 ar.ntransfer = ntransfer as u16;
410 ar.i_ci = Some(ci_idx);
411 let hook_opt = state.hook.take();
412 if let Some(mut h) = hook_opt {
413 h(state, &ar);
414 if state.hook.is_none() {
415 state.hook = Some(h);
416 }
417 }
418
419 debug_assert!(!state.allowhook);
420 state.allowhook = true;
421
422 state.get_ci_mut(ci_idx).top = saved_ci_top;
424 state.set_top(saved_top);
425 state.get_ci_mut(ci_idx).callstatus &= !mask;
426
427 Ok(())
428}
429
430pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
433 state.oldpc = 0;
434 if state.hookmask & LUA_MASKCALL != 0 {
435 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
436 LUA_HOOKTAILCALL
437 } else {
438 LUA_HOOKCALL
439 };
440 let numparams = {
442 state.get_ci_lua_proto_numparams(ci_idx)
445 };
446 let pc = state.ci_savedpc(ci_idx);
447 state.set_ci_savedpc(ci_idx, pc + 1);
448 hook(state, event, -1, 1, numparams as i32)?;
449 state.set_ci_savedpc(ci_idx, pc);
450 }
451 Ok(())
452}
453
454fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
457 if state.hookmask & LUA_MASKRET != 0 {
458 let first_res = state.top_idx().0 as i32 - nres;
459 let mut delta: i32 = 0;
460
461 if state.get_ci(ci_idx).is_lua() {
462 let (is_vararg, nextraargs, numparams) = state.get_ci_vararg_info(ci_idx);
464 if is_vararg {
465 delta = nextraargs + numparams as i32 + 1;
466 }
467 }
468
469 let original_func = state.get_ci(ci_idx).func;
471 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
472
473 let ci_func = state.get_ci(ci_idx).func;
474 let ftransfer = (first_res - ci_func.0 as i32) as u16;
475
476 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
477
478 state.get_ci_mut(ci_idx).func = original_func;
479 }
480
481 let previous = state.get_ci(ci_idx).previous;
483 if let Some(prev_idx) = previous {
484 if state.get_ci(prev_idx).is_lua() {
485 state.oldpc = state.get_ci_pcrel(prev_idx);
489 }
490 }
491
492 Ok(())
493}
494
495fn try_func_tm(
505 state: &mut LuaState,
506 func_idx: StackIdx,
507 call_metamethods: &mut u8,
508) -> Result<StackIdx, LuaError> {
509 let count_call_metamethods = state.global().lua_version == lua_types::LuaVersion::V55;
510 if count_call_metamethods && *call_metamethods == 15 {
511 return Err(LuaError::runtime(format_args!("'__call' chain too long")));
512 }
513 state.check_stack(1)?;
516 if state.gc_check_needed {
517 state.gc_check_step();
518 }
519
520 let func_val = state.get_at(func_idx).clone();
521 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
522
523 if matches!(tm, LuaValue::Nil) {
524 let offender = state.get_at(func_idx).clone();
525 return Err(crate::debug::call_error(state, &offender, func_idx));
526 }
527
528 let top = state.top_idx();
530 let mut p = top;
531 while p.0 > func_idx.0 {
532 let val = state.get_at(p - 1).clone();
533 state.set_at(p, val);
534 p = p - 1;
535 }
536 state.set_top(top + 1);
537 state.set_at(func_idx, tm);
538 if count_call_metamethods {
539 *call_metamethods += 1;
540 }
541
542 Ok(func_idx)
543}
544
545#[inline(always)]
550fn move_results(
551 state: &mut LuaState,
552 res_idx: StackIdx,
553 nres: i32,
554 wanted: i32,
555) -> Result<(), LuaError> {
556 match wanted {
557 0 => {
558 state.set_top(res_idx);
559 return Ok(());
560 }
561 1 => {
562 if nres == 0 {
563 state.set_at(res_idx, LuaValue::Nil);
564 } else {
565 let top = state.top_idx();
566 let src = state.get_at(top - nres as i32).clone();
567 state.set_at(res_idx, src);
568 }
569 state.set_top(res_idx + 1);
570 return Ok(());
571 }
572 LUA_MULTRET => {
573 }
575 _ => {
576 if wanted < LUA_MULTRET {
578 let ci_idx = state.ci;
579 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
580 state.set_ci_u2_nres(ci_idx, nres);
581
582 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
585
586 let ci_idx = state.ci;
587 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
588
589 if state.hookmask != 0 {
590 let saved_res = res_idx;
592 rethook(state, ci_idx, nres)?;
593 let _ = saved_res; }
595
596 let decoded_wanted = -(wanted) - 3;
598 let wanted = if decoded_wanted == LUA_MULTRET {
599 nres
600 } else {
601 decoded_wanted
602 };
603
604 let first_result = state.top_idx().0 as i32 - nres;
606 let actual_nres = nres.min(wanted);
607 for i in 0..actual_nres {
608 let src = state.get_at((first_result + i) as u32).clone();
609 state.set_at(res_idx + i as i32, src);
610 }
611 for i in actual_nres..wanted {
612 state.set_at(res_idx + i as i32, LuaValue::Nil);
613 }
614 state.set_top(res_idx + wanted as i32);
615 return Ok(());
616 }
617 }
618 }
619
620 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
622 let first_result = state.top_idx().0 as i32 - nres;
623 let actual_nres = nres.min(effective_wanted);
624 for i in 0..actual_nres {
625 let src = state.get_at((first_result + i) as u32).clone();
626 state.set_at(res_idx + i as i32, src);
627 }
628 for i in actual_nres..effective_wanted {
629 state.set_at(res_idx + i as i32, LuaValue::Nil);
630 }
631 state.set_top(res_idx + effective_wanted as i32);
632 Ok(())
633}
634
635#[inline(always)]
639pub(crate) fn poscall(
640 state: &mut LuaState,
641 ci_idx: CallInfoIdx,
642 nres: i32,
643) -> Result<(), LuaError> {
644 let wanted = state.get_ci(ci_idx).nresults as i32;
645
646 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
647 rethook(state, ci_idx, nres)?;
648 }
649
650 let func_idx = state.get_ci(ci_idx).func;
651 move_results(state, func_idx, nres, wanted)?;
652
653 debug_assert!(
654 state.get_ci(ci_idx).callstatus
655 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
656 == 0
657 );
658
659 let previous = state
660 .get_ci(ci_idx)
661 .previous
662 .expect("poscall: no previous call frame");
663 state.ci = previous;
664 Ok(())
665}
666
667#[inline(always)]
681fn prep_call_info(
682 state: &mut LuaState,
683 func_idx: StackIdx,
684 nret: i32,
685 mask: u16,
686 top_idx: StackIdx,
687) -> Result<CallInfoIdx, LuaError> {
688 debug_assert!(
689 mask & crate::state::CIST_TRAP == 0,
690 "prep_call_info must not be handed a pre-set trap bit"
691 );
692 let ci_idx = state.next_ci()?;
694 state.ci = ci_idx;
695 {
696 let ci = state.get_ci_mut(ci_idx);
697 ci.func = func_idx;
698 ci.nresults = nret as i16;
699 ci.callstatus = mask;
700 ci.call_metamethods = 0;
701 ci.top = top_idx;
702 ci.u = crate::state::CallInfoFrame::lua_default();
703 }
704 Ok(ci_idx)
705}
706
707#[inline(always)]
712fn precall_c(
713 state: &mut LuaState,
714 func_idx: StackIdx,
715 nresults: i32,
716 f: crate::state::LuaCallable,
717 call_metamethods: u8,
718) -> Result<i32, LuaError> {
719 state.check_stack(LUA_MINSTACK as i32)?;
720 if state.gc_check_needed {
721 state.gc_check_step();
722 }
723
724 let top_idx = state.top_idx();
725 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
726 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
727
728 debug_assert!(true );
729
730 if state.hookmask & LUA_MASKCALL != 0 {
731 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
732 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
733 }
734
735 let n = f.call(state)? as i32;
736
737 debug_assert!(
739 n <= state.top_idx().0 as i32,
740 "C function returned more values than available"
741 );
742
743 poscall(state, ci_idx, n)?;
744 Ok(n)
745}
746
747pub(crate) fn pretailcall(
765 state: &mut LuaState,
766 ci_idx: CallInfoIdx,
767 mut func_idx: StackIdx,
768 mut narg1: i32,
769 delta: i32,
770) -> Result<i32, LuaError> {
771 let mut call_metamethods = 0u8;
772 loop {
773 let func_val = state.get_at(func_idx).clone();
774 match func_val {
775 LuaValue::Function(LuaClosure::C(ref cl)) => {
776 let cfunc = state.global().c_functions[cl.func].clone();
777 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
778 }
779 LuaValue::Function(LuaClosure::LightC(f)) => {
780 let cfunc = state.global().c_functions[f].clone();
781 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
782 }
783 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
784 let proto = cl.proto.clone();
785 let fsize = proto.maxstacksize as i32;
786 let nfixparams = proto.numparams as i32;
787
788 state.check_stack(fsize - delta)?;
789 if state.gc_check_needed {
790 state.gc_check_step();
791 }
792
793 {
794 let ci = state.get_ci_mut(ci_idx);
795 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
796 }
797 let ci_func = state.get_ci(ci_idx).func;
798
799 for i in 0..narg1 {
800 let src = state.get_at(func_idx + i as i32).clone();
801 state.set_at(ci_func + i as i32, src);
802 }
803
804 func_idx = ci_func;
806
807 while narg1 <= nfixparams {
808 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
809 narg1 += 1;
810 }
811
812 {
813 let new_ci_top = func_idx + 1 + fsize as i32;
814 let stack_last = state.stack_last;
815 let live_top = state.top_idx();
816 let ci = state.get_ci_mut(ci_idx);
817 ci.call_metamethods = call_metamethods;
818 ci.top = new_ci_top;
819 debug_assert!(ci.top.0 <= stack_last.0);
820 ci.set_saved_pc(0);
821 ci.callstatus |= CIST_TAIL;
822 state.clear_stack_range(live_top, new_ci_top);
823 }
824
825 state.set_top(func_idx + narg1 as i32);
826 return Ok(-1); }
828 _ => {
829 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
830 narg1 += 1;
831 }
833 }
834 }
835}
836
837#[inline(always)]
847pub(crate) fn precall(
848 state: &mut LuaState,
849 func_idx: StackIdx,
850 nresults: i32,
851) -> Result<Option<CallInfoIdx>, LuaError> {
852 if let LuaValue::Function(LuaClosure::Lua(cl)) = &state.stack[func_idx.0 as usize].val {
853 let nfixparams = cl.proto.numparams as i32;
854 let fsize = cl.proto.maxstacksize as i32;
855 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
856
857 state.check_stack(fsize)?;
858 if state.gc_check_needed {
859 state.gc_check_step();
860 }
861
862 let ci_idx = prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
863 state.set_ci_savedpc(ci_idx, 0);
864
865 if narg < nfixparams {
866 fill_missing_params(state, narg, nfixparams);
867 }
868 return Ok(Some(ci_idx));
869 }
870 precall_slow(state, func_idx, nresults)
871}
872
873#[cold]
877#[inline(never)]
878fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
879 while narg < nfixparams {
880 let top = state.top_idx();
881 state.set_at(top, LuaValue::Nil);
882 state.set_top(top + 1);
883 narg += 1;
884 }
885}
886
887#[cold]
891#[inline(never)]
892fn precall_slow(
893 state: &mut LuaState,
894 mut func_idx: StackIdx,
895 nresults: i32,
896) -> Result<Option<CallInfoIdx>, LuaError> {
897 let mut call_metamethods = 0u8;
898 loop {
899 let func_val = state.get_at(func_idx).clone();
900 match func_val {
901 LuaValue::Function(LuaClosure::C(ref cl)) => {
902 let cfunc = state.global().c_functions[cl.func].clone();
903 precall_c(state, func_idx, nresults, cfunc, call_metamethods)?;
904 return Ok(None);
905 }
906 LuaValue::Function(LuaClosure::LightC(f)) => {
907 state.check_stack(LUA_MINSTACK as i32)?;
908 if state.gc_check_needed {
909 state.gc_check_step();
910 }
911
912 let top_idx = state.top_idx();
913 let ci_idx =
914 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
915 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
916
917 if state.hookmask & LUA_MASKCALL != 0 {
918 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
919 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
920 }
921
922 let cfunc = state.global().c_functions[f].clone();
923 let n = cfunc.call(state)? as i32;
924 debug_assert!(
925 n <= state.top_idx().0 as i32,
926 "C function returned more values than available"
927 );
928 poscall(state, ci_idx, n)?;
929 return Ok(None);
930 }
931 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
932 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
933 let nfixparams = cl.proto.numparams as i32;
934 let fsize = cl.proto.maxstacksize as i32;
935
936 state.check_stack(fsize)?;
937 if state.gc_check_needed {
938 state.gc_check_step();
939 }
940
941 let ci_idx =
942 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
943 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
944 state.set_ci_savedpc(ci_idx, 0);
945
946 if narg < nfixparams {
947 fill_missing_params(state, narg, nfixparams);
948 }
949 return Ok(Some(ci_idx));
950 }
951 _ => {
952 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
953 }
954 }
955 }
956}
957
958#[inline]
962fn ccall_inner(
963 state: &mut LuaState,
964 func_idx: StackIdx,
965 n_results: i32,
966 inc: u32,
967) -> Result<(), LuaError> {
968 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
969}
970
971#[inline]
972fn ccall_known_c_inner(
973 state: &mut LuaState,
974 func_idx: StackIdx,
975 n_results: i32,
976 inc: u32,
977 f: crate::state::LuaCallable,
978) -> Result<(), LuaError> {
979 state.n_ccalls += inc;
980
981 if state.c_calls() >= LUAI_MAXCCALLS {
982 state.check_stack(0)?;
983 state.check_c_stack()?;
984 }
985
986 precall_c(state, func_idx, n_results, f, 0)?;
987
988 state.n_ccalls -= inc;
989 Ok(())
990}
991
992#[inline]
993fn ccall_inner_with_status(
994 state: &mut LuaState,
995 func_idx: StackIdx,
996 n_results: i32,
997 inc: u32,
998 extra_callstatus: u16,
999) -> Result<(), LuaError> {
1000 state.n_ccalls += inc;
1001
1002 if state.c_calls() >= LUAI_MAXCCALLS {
1004 state.check_stack(0)?;
1006 state.check_c_stack()?;
1007 }
1008
1009 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
1010 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
1011 vm::execute(state, ci_idx)?;
1012 }
1013
1014 state.n_ccalls -= inc;
1015 Ok(())
1016}
1017
1018pub(crate) fn call(
1021 state: &mut LuaState,
1022 func_idx: StackIdx,
1023 n_results: i32,
1024) -> Result<(), LuaError> {
1025 ccall_inner(state, func_idx, n_results, 1)
1026}
1027
1028pub(crate) fn callnoyield(
1031 state: &mut LuaState,
1032 func_idx: StackIdx,
1033 n_results: i32,
1034) -> Result<(), LuaError> {
1035 ccall_inner(state, func_idx, n_results, NYCI)
1037}
1038
1039#[inline]
1046pub(crate) fn call_known_c(
1047 state: &mut LuaState,
1048 func_idx: StackIdx,
1049 n_results: i32,
1050) -> Result<bool, LuaError> {
1051 let cfunc = match &state.stack[func_idx.0 as usize].val {
1052 LuaValue::Function(LuaClosure::C(cl)) => state.global().c_functions[cl.func].clone(),
1053 LuaValue::Function(LuaClosure::LightC(f)) => state.global().c_functions[*f].clone(),
1054 _ => return Ok(false),
1055 };
1056
1057 ccall_known_c_inner(state, func_idx, n_results, 1, cfunc)?;
1058 Ok(true)
1059}
1060
1061fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
1068 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
1071
1072 if status == LuaStatus::Ok {
1073 status = LuaStatus::Yield;
1074 } else {
1075 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
1076 state.allowhook = state.get_ci(ci_idx).get_oah();
1078 let _func_idx = func::close(state, func_idx, status as i32, true)?;
1080 set_error_obj(state, status, func_idx);
1081
1082 if state.errfunc != 0
1091 && error_status(status)
1092 && status != LuaStatus::ErrErr
1093 && status != LuaStatus::ErrSyntax
1094 {
1095 let errfunc_stk = StackIdx(state.errfunc as u32);
1096 status = run_message_handler(
1097 state,
1098 func_idx,
1099 errfunc_stk,
1100 status,
1101 ci_idx,
1102 state.allowhook,
1103 );
1104 }
1105
1106 shrink_stack(state);
1107 state
1108 .get_ci_mut(ci_idx)
1109 .set_recover_status(LuaStatus::Ok as i32);
1110 }
1111
1112 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1113 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1114 state.errfunc = old_errfunc;
1115
1116 Ok(status)
1117}
1118
1119fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1122 let n;
1123
1124 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1125 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1126 n = state.get_ci_u2_nres(ci_idx);
1127 } else {
1128 debug_assert!(
1129 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1130 "finishCcall: no continuation or non-yieldable"
1131 );
1132
1133 let mut status = LuaStatus::Yield;
1134
1135 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1136 status = finish_pcallk(state, ci_idx)?;
1137 }
1138
1139 state.adjust_results(LUA_MULTRET);
1141
1142 let k = state.get_ci(ci_idx).u_c_k();
1146 let ctx = state.get_ci(ci_idx).u_c_ctx();
1147 if let Some(k_fn) = k {
1148 n = k_fn(state, status as i32, ctx)? as i32;
1149 } else {
1150 return Err(LuaError::runtime(format_args!(
1152 "finishCcall: missing continuation"
1153 )));
1154 }
1155 debug_assert!(
1156 n <= state.top_idx().0 as i32,
1157 "continuation returned more values than available"
1158 );
1159 }
1160
1161 poscall(state, ci_idx, n)?;
1162 Ok(())
1163}
1164
1165fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1168 loop {
1169 let ci_idx = state.ci;
1170 if state.is_base_ci(ci_idx) {
1171 break;
1172 }
1173 if !state.get_ci(ci_idx).is_lua() {
1174 finish_ccall(state, ci_idx)?;
1175 } else {
1176 vm::finish_op(state)?;
1177 vm::execute(state, ci_idx)?;
1178 }
1179 }
1180 Ok(())
1181}
1182
1183fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1186 let mut ci_idx_opt = Some(state.ci);
1187 while let Some(ci_idx) = ci_idx_opt {
1188 let ci = state.get_ci(ci_idx);
1189 if ci.callstatus & CIST_YPCALL != 0 {
1190 return Some(ci_idx);
1191 }
1192 ci_idx_opt = ci.previous;
1193 }
1194 None
1195}
1196
1197fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1200 let top = state.top_idx();
1201 state.set_top(top - narg as i32);
1202 let s = state.intern_str(msg).ok();
1204 let new_top = state.top_idx();
1205 if let Some(s) = s {
1206 state.set_at(new_top, LuaValue::Str(s));
1207 }
1208 state.set_top(new_top + 1);
1209 LuaStatus::ErrRun
1210}
1211
1212fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1215 let top = state.top_idx();
1216 let first_arg = top - nargs as i32;
1217 let ci_idx = state.ci;
1218
1219 if state.status == LuaStatus::Ok as u8 {
1220 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1221 } else {
1222 debug_assert!(state.status == LuaStatus::Yield as u8);
1223 state.status = LuaStatus::Ok as u8;
1224
1225 if state.get_ci(ci_idx).is_lua() {
1226 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1227 let pc = state.ci_savedpc(ci_idx);
1228 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1229 state.set_top(first_arg);
1230 vm::execute(state, ci_idx)?;
1231 } else {
1232 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1233 let ctx = state.get_ci(ci_idx).u_c_ctx();
1234 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1235 debug_assert!(n <= state.top_idx().0 as i32);
1236 poscall(state, ci_idx, n)?;
1237 } else {
1238 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1240 poscall(state, ci_idx, n)?;
1241 }
1242 }
1243
1244 unroll(state)?;
1245 }
1246 Ok(())
1247}
1248
1249fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1252 while error_status(status) {
1253 if let Some(ci_idx) = find_pcall(state) {
1254 state.ci = ci_idx;
1255 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1256 status = match raw_run_protected(state, |s| unroll(s)) {
1261 Ok(()) => LuaStatus::Ok,
1262 Err(e) => {
1263 let s = e.to_status();
1264 if error_status(s) {
1265 state.push(e.into_value());
1266 }
1267 s
1268 }
1269 };
1270 } else {
1271 break;
1272 }
1273 }
1274 status
1275}
1276
1277pub fn lua_resume(
1280 state: &mut LuaState,
1281 from: Option<&mut LuaState>,
1282 nargs: i32,
1283 nresults: &mut i32,
1284) -> LuaStatus {
1285 if state.status == LuaStatus::Ok as u8 {
1291 if !state.is_base_ci(state.ci) {
1292 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1293 }
1294 let ci_func = state.get_ci(state.ci).func;
1295 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1296 return resume_error(state, b"cannot resume dead coroutine", nargs);
1297 }
1298 } else if state.status != LuaStatus::Yield as u8 {
1299 return resume_error(state, b"cannot resume dead coroutine", nargs);
1300 }
1301
1302 state.n_ccalls = from.as_ref().map(|f| f.c_calls() as u32).unwrap_or(0);
1303
1304 if state.c_calls() >= LUAI_MAXCCALLS {
1305 return resume_error(state, b"C stack overflow", nargs);
1306 }
1307 state.n_ccalls += 1;
1308
1309 debug_assert!(
1310 if state.status == LuaStatus::Ok as u8 {
1311 nargs + 1 <= state.top_idx().0 as i32
1312 } else {
1313 nargs <= state.top_idx().0 as i32
1314 },
1315 "lua_resume: not enough stack elements"
1316 );
1317
1318 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1324 Ok(()) => (LuaStatus::Ok, None),
1325 Err(e) => {
1326 let s = e.to_status();
1327 let v = if error_status(s) {
1328 Some(e.into_value())
1329 } else {
1330 None
1331 };
1332 (s, v)
1333 }
1334 };
1335 if let Some(v) = err_value {
1336 state.push(v);
1337 }
1338
1339 status = precover(state, status);
1340
1341 if !error_status(status) {
1342 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1343 } else {
1344 state.status = status as u8;
1346 let top = state.top_idx();
1347 set_error_obj(state, status, top);
1348 let new_top = state.top_idx();
1349 let ci_idx = state.ci;
1350 state.get_ci_mut(ci_idx).top = new_top;
1351 }
1352
1353 let ci_idx = state.ci;
1354 *nresults = if status == LuaStatus::Yield {
1355 state.get_ci_u2_nyield(ci_idx)
1356 } else {
1357 let ci_func = state.get_ci(ci_idx).func;
1358 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1359 };
1360
1361 status
1362}
1363
1364pub fn lua_isyieldable(state: &LuaState) -> bool {
1367 state.is_yieldable()
1369}
1370
1371pub fn lua_yieldk(
1375 state: &mut LuaState,
1376 nresults: i32,
1377 ctx: isize,
1378 k: Option<crate::state::LuaKFunction>,
1379) -> Result<i32, LuaError> {
1380 let ci_idx = state.ci;
1384
1385 debug_assert!(
1386 nresults <= state.top_idx().0 as i32,
1387 "lua_yieldk: not enough elements on stack"
1388 );
1389
1390 if !state.is_yieldable() {
1391 if matches!(state.global().lua_version, lua_types::LuaVersion::V51) {
1392 return Err(LuaError::runtime(format_args!(
1393 "attempt to yield across metamethod/C-call boundary"
1394 )));
1395 }
1396 if !state.is_main_thread() {
1397 return Err(LuaError::runtime(format_args!(
1398 "attempt to yield across a C-call boundary"
1399 )));
1400 } else {
1401 return Err(LuaError::runtime(format_args!(
1402 "attempt to yield from outside a coroutine"
1403 )));
1404 }
1405 }
1406
1407 state.status = LuaStatus::Yield as u8;
1408 state.set_ci_u2_nyield(ci_idx, nresults);
1409
1410 if state.get_ci(ci_idx).is_lua() {
1411 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1412 debug_assert!(nresults == 0, "hooks cannot yield values");
1413 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1414 } else {
1416 let ci = state.get_ci_mut(ci_idx);
1417 ci.set_u_c_k(k);
1418 if k.is_some() {
1419 ci.set_u_c_ctx(ctx);
1420 }
1421 return Err(LuaError::Yield);
1423 }
1424
1425 debug_assert!(
1426 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1427 "lua_yieldk called outside a hook"
1428 );
1429 Ok(0) }
1431
1432struct CloseP {
1439 level: StackIdx,
1440 status: LuaStatus,
1441}
1442
1443fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1446 func::close(state, pcl.level, pcl.status as i32, false)?;
1448 Ok(())
1449}
1450
1451pub(crate) fn close_protected(
1455 state: &mut LuaState,
1456 level: StackIdx,
1457 status: LuaStatus,
1458) -> LuaStatus {
1459 let old_ci = state.ci;
1460 let old_allowhook = state.allowhook;
1461 let mut status = status;
1462
1463 loop {
1464 let mut pcl = CloseP { level, status };
1465 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1466 Ok(()) => (LuaStatus::Ok, None),
1467 Err(e) => (e.to_status(), Some(e.into_value())),
1468 };
1469 if run_status == LuaStatus::Ok {
1470 return pcl.status;
1471 }
1472 state.ci = old_ci;
1473 state.allowhook = old_allowhook;
1474 if let Some(v) = err_value {
1480 state.push(v);
1481 }
1482 status = run_status;
1483 }
1484}
1485
1486pub(crate) fn pcall<F>(state: &mut LuaState, func: F, old_top: StackIdx, ef: isize) -> LuaStatus
1490where
1491 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1492{
1493 let old_ci = state.ci;
1494 let old_allowhook = state.allowhook;
1495 let old_errfunc = state.errfunc;
1496 state.errfunc = ef;
1497
1498 let mut status = match raw_run_protected(state, func) {
1504 Ok(()) => LuaStatus::Ok,
1505 Err(e) => {
1506 let s = e.to_status();
1507 state.push(e.into_value());
1508 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1514 let errfunc_idx = StackIdx(ef as u32);
1515 let err_slot = state.top_idx() - 1;
1516 run_message_handler(state, err_slot, errfunc_idx, s, old_ci, old_allowhook)
1517 } else {
1518 s
1519 }
1520 }
1521 };
1522
1523 if status != LuaStatus::Ok
1531 && status != LuaStatus::ErrSyntax
1532 && state.global().lua_version == lua_types::LuaVersion::V55
1533 {
1534 let top = state.top_idx();
1535 if matches!(state.get_at(top - 1), LuaValue::Nil) {
1536 if let Ok(s) = state.intern_str(b"<no error object>") {
1537 state.set_at(top - 1, LuaValue::Str(s));
1538 }
1539 }
1540 }
1541
1542 if status != LuaStatus::Ok {
1543 state.ci = old_ci;
1544 state.allowhook = old_allowhook;
1545 status = close_protected(state, old_top, status);
1546 set_error_obj(state, status, old_top);
1548 shrink_stack(state);
1549 }
1550
1551 state.errfunc = old_errfunc;
1552 status
1553}
1554
1555struct SParser {
1565 z: ZIO,
1566 buff: LexBuffer,
1568 dyd: DynDataStub,
1570 mode: Option<Vec<u8>>,
1572 name: Vec<u8>,
1573}
1574
1575fn check_mode(mode: Option<&[u8]>, kind: &[u8]) -> Result<(), LuaError> {
1578 if let Some(mode_bytes) = mode {
1579 let kind_char = kind[0];
1580 if !mode_bytes.contains(&kind_char) {
1581 return Err(LuaError::syntax(format_args!(
1584 "attempt to load a {} chunk (mode is '{}')",
1585 core::str::from_utf8(kind).unwrap_or("?"),
1586 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1587 )));
1588 }
1589 }
1590 Ok(())
1591}
1592
1593fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1597 let c = p.z.getc();
1599
1600 let cl = if c == b'\x1b' as i32 {
1602 check_mode(p.mode.as_deref(), b"binary")?;
1603 crate::undump::undump(state, &mut p.z, &p.name)?
1605 } else {
1606 check_mode(p.mode.as_deref(), b"text")?;
1607 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1609 };
1610
1611 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1612 func::init_upvals(state, &cl)?;
1613
1614 state.check_stack(1)?;
1622 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1623
1624 Ok(())
1625}
1626
1627pub(crate) fn protected_parser(
1630 state: &mut LuaState,
1631 z: ZIO,
1632 name: &[u8],
1633 mode: Option<&[u8]>,
1634) -> LuaStatus {
1635 state.inc_nny();
1637
1638 let mut p = SParser {
1639 z,
1640 buff: LexBuffer::new(),
1641 dyd: DynDataStub::new(),
1642 mode: mode.map(|m| m.to_vec()),
1643 name: name.to_vec(),
1644 };
1645
1646 let top_idx = state.top_idx();
1649 let errfunc = state.errfunc;
1650 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1651
1652 state.dec_nny();
1656
1657 status
1658}
1659
1660