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!(true );
334 let res = lim.0 as usize + 1;
335 if res < LUA_MINSTACK as usize {
336 LUA_MINSTACK as usize
337 } else {
338 res
339 }
340}
341
342pub(crate) fn shrink_stack(state: &mut LuaState) {
345 let inuse = stack_in_use(state);
346 let max = if inuse > LUAI_MAXSTACK / 3 {
347 LUAI_MAXSTACK
348 } else {
349 inuse * 3
350 };
351 if inuse <= LUAI_MAXSTACK && state.stack_size() > max {
352 let nsize = if inuse > LUAI_MAXSTACK / 2 {
353 LUAI_MAXSTACK
354 } else {
355 inuse * 2
356 };
357 let _ = realloc_stack(state, nsize, false);
358 }
359 state.shrink_ci();
360}
361
362pub(crate) fn hook(
369 state: &mut LuaState,
370 event: i32,
371 line: i32,
372 ftransfer: i32,
373 ntransfer: i32,
374) -> Result<(), LuaError> {
375 if !state.has_hook() || !state.allowhook {
376 return Ok(());
377 }
378
379 let ci_idx = state.ci;
380
381 let saved_top = state.top_idx();
382 let saved_ci_top = state.get_ci(ci_idx).top;
383
384 let mut mask = CIST_HOOKED;
385
386 if ntransfer != 0 {
387 mask |= CIST_TRAN;
388 state.set_ci_transfer_info(ci_idx, ftransfer as u16, ntransfer as u16);
389 }
390
391 {
392 let ci = state.get_ci(ci_idx);
393 if ci.is_lua() {
394 let ci_top = ci.top;
395 if state.top_idx().0 < ci_top.0 {
396 state.set_top(ci_top);
397 }
398 }
399 }
400
401 state.check_stack(LUA_MINSTACK as i32)?;
402
403 {
404 let top = state.top_idx();
405 let ci = state.get_ci_mut(ci_idx);
406 if ci.top.0 < (top + LUA_MINSTACK).0 {
407 let new_top = top + LUA_MINSTACK;
408 ci.top = new_top;
409 state.clear_stack_range(top, new_top);
410 }
411 }
412
413 state.allowhook = false;
414 state.get_ci_mut(ci_idx).callstatus |= mask;
415
416 let mut ar = crate::debug::LuaDebug::default();
417 ar.event = event;
418 ar.currentline = line;
419 ar.ftransfer = ftransfer as u16;
420 ar.ntransfer = ntransfer as u16;
421 ar.i_ci = Some(ci_idx);
422 let hook_opt = state.hook.take();
423 if let Some(mut h) = hook_opt {
424 h(state, &ar);
425 if state.hook.is_none() {
426 state.hook = Some(h);
427 }
428 }
429
430 debug_assert!(!state.allowhook);
431 state.allowhook = true;
432
433 state.get_ci_mut(ci_idx).top = saved_ci_top;
434 state.set_top(saved_top);
435 state.get_ci_mut(ci_idx).callstatus &= !mask;
436
437 Ok(())
438}
439
440pub(crate) fn hookcall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
443 state.oldpc = 0;
444 if state.hookmask & LUA_MASKCALL != 0 {
445 let event = if state.get_ci(ci_idx).callstatus & CIST_TAIL != 0 {
446 LUA_HOOKTAILCALL
447 } else {
448 LUA_HOOKCALL
449 };
450 let numparams = {
451 state.get_ci_lua_proto_numparams(ci_idx)
452 };
453 let pc = state.ci_savedpc(ci_idx);
454 state.set_ci_savedpc(ci_idx, pc + 1);
455 hook(state, event, -1, 1, numparams as i32)?;
456 state.set_ci_savedpc(ci_idx, pc);
457 }
458 Ok(())
459}
460
461fn fire_tail_returns(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
471 if !state.get_ci(ci_idx).is_lua() {
472 return Ok(());
473 }
474 while state.get_ci(ci_idx).tailcalls > 0 {
475 state.get_ci_mut(ci_idx).tailcalls -= 1;
476 hook(state, LUA_HOOKTAILRET, -1, 0, 0)?;
477 }
478 Ok(())
479}
480
481fn rethook(state: &mut LuaState, ci_idx: CallInfoIdx, nres: i32) -> Result<(), LuaError> {
484 if state.hookmask & LUA_MASKRET != 0 {
485 let first_res = state.top_idx().0 as i32 - nres;
486 let mut delta: i32 = 0;
487
488 if state.get_ci(ci_idx).is_lua() {
489 let (is_vararg, nextraargs, numparams) = state.get_ci_vararg_info(ci_idx);
490 if is_vararg {
491 delta = nextraargs + numparams as i32 + 1;
492 }
493 }
494
495 let original_func = state.get_ci(ci_idx).func;
497 state.get_ci_mut(ci_idx).func = StackIdx((original_func.0 as i32 + delta) as u32);
498
499 let ci_func = state.get_ci(ci_idx).func;
500 let ftransfer = (first_res - ci_func.0 as i32) as u16;
501
502 hook(state, LUA_HOOKRET, -1, ftransfer as i32, nres)?;
503
504 state.get_ci_mut(ci_idx).func = original_func;
505
506 fire_tail_returns(state, ci_idx)?;
507 }
508
509 let previous = state.get_ci(ci_idx).previous;
510 if let Some(prev_idx) = previous {
511 if state.get_ci(prev_idx).is_lua() {
512 state.oldpc = state.get_ci_pcrel(prev_idx);
513 }
514 }
515
516 Ok(())
517}
518
519fn try_func_tm(
529 state: &mut LuaState,
530 func_idx: StackIdx,
531 call_metamethods: &mut u8,
532) -> Result<StackIdx, LuaError> {
533 let count_call_metamethods = state.global().lua_version == lua_types::LuaVersion::V55;
534 if count_call_metamethods && *call_metamethods == 15 {
535 return Err(LuaError::runtime(format_args!("'__call' chain too long")));
536 }
537 state.check_stack(1)?;
539 if state.gc_check_needed {
540 state.gc_check_step();
541 }
542
543 let func_val = state.get_at(func_idx).clone();
544 let tm = state.get_tm_by_obj(&func_val, TagMethod::Call);
545
546 if matches!(tm, LuaValue::Nil) {
547 let offender = state.get_at(func_idx).clone();
548 return Err(crate::debug::call_error(state, &offender, func_idx));
549 }
550
551 let top = state.top_idx();
553 let mut p = top;
554 while p.0 > func_idx.0 {
555 let val = state.get_at(p - 1).clone();
556 state.set_at(p, val);
557 p = p - 1;
558 }
559 state.set_top(top + 1);
560 state.set_at(func_idx, tm);
561 if count_call_metamethods {
562 *call_metamethods += 1;
563 }
564
565 Ok(func_idx)
566}
567
568#[inline(always)]
573fn move_results(
574 state: &mut LuaState,
575 res_idx: StackIdx,
576 nres: i32,
577 wanted: i32,
578) -> Result<(), LuaError> {
579 match wanted {
580 0 => {
581 state.set_top(res_idx);
582 return Ok(());
583 }
584 1 => {
585 if nres == 0 {
586 state.set_at(res_idx, LuaValue::Nil);
587 } else {
588 let top = state.top_idx();
589 let src = state.get_at(top - nres as i32).clone();
590 state.set_at(res_idx, src);
591 }
592 state.set_top(res_idx + 1);
593 return Ok(());
594 }
595 LUA_MULTRET => {
596 }
598 _ => {
599 if wanted < LUA_MULTRET {
600 let ci_idx = state.ci;
601 state.get_ci_mut(ci_idx).callstatus |= CIST_CLSRET;
602 state.set_ci_u2_nres(ci_idx, nres);
603
604 let res_idx = func::close(state, res_idx, CLOSE_K_TOP, true)?;
605
606 let ci_idx = state.ci;
607 state.get_ci_mut(ci_idx).callstatus &= !CIST_CLSRET;
608
609 if state.hookmask != 0 {
610 let saved_res = res_idx;
611 rethook(state, ci_idx, nres)?;
612 let _ = saved_res; }
614
615 let decoded_wanted = -(wanted) - 3;
616 let wanted = if decoded_wanted == LUA_MULTRET {
617 nres
618 } else {
619 decoded_wanted
620 };
621
622 let first_result = state.top_idx().0 as i32 - nres;
624 let actual_nres = nres.min(wanted);
625 for i in 0..actual_nres {
626 let src = state.get_at((first_result + i) as u32).clone();
627 state.set_at(res_idx + i as i32, src);
628 }
629 for i in actual_nres..wanted {
630 state.set_at(res_idx + i as i32, LuaValue::Nil);
631 }
632 state.set_top(res_idx + wanted as i32);
633 return Ok(());
634 }
635 }
636 }
637
638 let effective_wanted = if wanted == LUA_MULTRET { nres } else { wanted };
640 let first_result = state.top_idx().0 as i32 - nres;
641 let actual_nres = nres.min(effective_wanted);
642 for i in 0..actual_nres {
643 let src = state.get_at((first_result + i) as u32).clone();
644 state.set_at(res_idx + i as i32, src);
645 }
646 for i in actual_nres..effective_wanted {
647 state.set_at(res_idx + i as i32, LuaValue::Nil);
648 }
649 state.set_top(res_idx + effective_wanted as i32);
650 Ok(())
651}
652
653#[inline(always)]
657pub(crate) fn poscall(
658 state: &mut LuaState,
659 ci_idx: CallInfoIdx,
660 nres: i32,
661) -> Result<(), LuaError> {
662 let wanted = state.get_ci(ci_idx).nresults as i32;
663
664 if state.hookmask != 0 && !(wanted < LUA_MULTRET) {
665 rethook(state, ci_idx, nres)?;
666 }
667
668 let func_idx = state.get_ci(ci_idx).func;
669 move_results(state, func_idx, nres, wanted)?;
670
671 debug_assert!(
672 state.get_ci(ci_idx).callstatus
673 & (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)
674 == 0
675 );
676
677 let previous = state
678 .get_ci(ci_idx)
679 .previous
680 .expect("poscall: no previous call frame");
681 state.ci = previous;
682 Ok(())
683}
684
685#[inline(always)]
699fn prep_call_info(
700 state: &mut LuaState,
701 func_idx: StackIdx,
702 nret: i32,
703 mask: u16,
704 top_idx: StackIdx,
705) -> Result<CallInfoIdx, LuaError> {
706 debug_assert!(
707 mask & crate::state::CIST_TRAP == 0,
708 "prep_call_info must not be handed a pre-set trap bit"
709 );
710 let ci_idx = state.next_ci()?;
712 state.ci = ci_idx;
713 {
714 let ci = state.get_ci_mut(ci_idx);
715 ci.func = func_idx;
716 ci.nresults = nret as i16;
717 ci.callstatus = mask;
718 ci.call_metamethods = 0;
719 ci.top = top_idx;
720 ci.u = crate::state::CallInfoFrame::lua_default();
721 }
722 Ok(ci_idx)
723}
724
725#[inline(always)]
730fn precall_c(
731 state: &mut LuaState,
732 func_idx: StackIdx,
733 nresults: i32,
734 f: crate::state::LuaCallable,
735 call_metamethods: u8,
736) -> Result<i32, LuaError> {
737 state.check_stack(LUA_MINSTACK as i32)?;
738 if state.gc_check_needed {
739 state.gc_check_step();
740 }
741
742 let top_idx = state.top_idx();
743 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
744 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
745
746 debug_assert!(true );
747
748 if state.hookmask & LUA_MASKCALL != 0 {
749 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
750 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
751 }
752
753 let n = f.call(state)? as i32;
754
755 debug_assert!(
756 n <= state.top_idx().0 as i32,
757 "C function returned more values than available"
758 );
759
760 poscall(state, ci_idx, n)?;
761 Ok(n)
762}
763
764pub(crate) fn pretailcall(
782 state: &mut LuaState,
783 ci_idx: CallInfoIdx,
784 mut func_idx: StackIdx,
785 mut narg1: i32,
786 delta: i32,
787) -> Result<i32, LuaError> {
788 let mut call_metamethods = 0u8;
789 loop {
790 let func_val = state.get_at(func_idx).clone();
791 match func_val {
792 LuaValue::Function(LuaClosure::C(ref cl)) => {
793 let cfunc = state.global().c_functions[cl.func].clone();
794 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
795 }
796 LuaValue::Function(LuaClosure::LightC(f)) => {
797 let cfunc = state.global().c_functions[f].clone();
798 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
799 }
800 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
801 let proto = cl.proto.clone();
802 let fsize = proto.maxstacksize as i32;
803 let nfixparams = proto.numparams as i32;
804
805 state.check_stack(fsize - delta)?;
806 if state.gc_check_needed {
807 state.gc_check_step();
808 }
809
810 {
811 let ci = state.get_ci_mut(ci_idx);
812 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
813 }
814 let ci_func = state.get_ci(ci_idx).func;
815
816 for i in 0..narg1 {
817 let src = state.get_at(func_idx + i as i32).clone();
818 state.set_at(ci_func + i as i32, src);
819 }
820
821 func_idx = ci_func;
823
824 while narg1 <= nfixparams {
825 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
826 narg1 += 1;
827 }
828
829 {
830 let new_ci_top = func_idx + 1 + fsize as i32;
831 let stack_last = state.stack_last;
832 let live_top = state.top_idx();
833 let ci = state.get_ci_mut(ci_idx);
834 ci.call_metamethods = call_metamethods;
835 ci.top = new_ci_top;
836 debug_assert!(ci.top.0 <= stack_last.0);
837 ci.set_saved_pc(0);
838 ci.callstatus |= CIST_TAIL;
839 state.clear_stack_range(live_top, new_ci_top);
840 }
841
842 state.set_top(func_idx + narg1 as i32);
843 return Ok(-1); }
845 _ => {
846 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
847 narg1 += 1;
848 }
850 }
851 }
852}
853
854#[inline(always)]
865pub(crate) fn precall(
866 state: &mut LuaState,
867 func_idx: StackIdx,
868 nresults: i32,
869) -> Result<Option<CallInfoIdx>, LuaError> {
870 if let LuaValue::Function(LuaClosure::Lua(cl)) = &state.stack[func_idx.0 as usize].val {
871 let nfixparams = cl.proto.numparams as i32;
872 let fsize = cl.proto.maxstacksize as i32;
873 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
874
875 state.check_stack(fsize)?;
876 if state.gc_check_needed {
877 state.gc_check_step();
878 }
879
880 let ci_idx = prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
881 state.set_ci_savedpc(ci_idx, 0);
882
883 if narg < nfixparams {
884 fill_missing_params(state, narg, nfixparams);
885 }
886 return Ok(Some(ci_idx));
887 }
888 precall_slow(state, func_idx, nresults)
889}
890
891#[cold]
895#[inline(never)]
896fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
897 while narg < nfixparams {
898 let top = state.top_idx();
899 state.set_at(top, LuaValue::Nil);
900 state.set_top(top + 1);
901 narg += 1;
902 }
903}
904
905#[cold]
909#[inline(never)]
910fn precall_slow(
911 state: &mut LuaState,
912 mut func_idx: StackIdx,
913 nresults: i32,
914) -> Result<Option<CallInfoIdx>, LuaError> {
915 let mut call_metamethods = 0u8;
916 loop {
917 let func_val = state.get_at(func_idx).clone();
918 match func_val {
919 LuaValue::Function(LuaClosure::C(ref cl)) => {
920 let cfunc = state.global().c_functions[cl.func].clone();
921 precall_c(state, func_idx, nresults, cfunc, call_metamethods)?;
922 return Ok(None);
923 }
924 LuaValue::Function(LuaClosure::LightC(f)) => {
925 state.check_stack(LUA_MINSTACK as i32)?;
926 if state.gc_check_needed {
927 state.gc_check_step();
928 }
929
930 let top_idx = state.top_idx();
931 let ci_idx =
932 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
933 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
934
935 if state.hookmask & LUA_MASKCALL != 0 {
936 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
937 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
938 }
939
940 let cfunc = state.global().c_functions[f].clone();
941 let n = cfunc.call(state)? as i32;
942 debug_assert!(
943 n <= state.top_idx().0 as i32,
944 "C function returned more values than available"
945 );
946 poscall(state, ci_idx, n)?;
947 return Ok(None);
948 }
949 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
950 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
951 let nfixparams = cl.proto.numparams as i32;
952 let fsize = cl.proto.maxstacksize as i32;
953
954 state.check_stack(fsize)?;
955 if state.gc_check_needed {
956 state.gc_check_step();
957 }
958
959 let ci_idx =
960 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
961 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
962 state.set_ci_savedpc(ci_idx, 0);
963
964 if narg < nfixparams {
965 fill_missing_params(state, narg, nfixparams);
966 }
967 return Ok(Some(ci_idx));
968 }
969 _ => {
970 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
971 }
972 }
973 }
974}
975
976#[inline]
980fn ccall_inner(
981 state: &mut LuaState,
982 func_idx: StackIdx,
983 n_results: i32,
984 inc: u32,
985) -> Result<(), LuaError> {
986 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
987}
988
989#[inline]
990fn ccall_known_c_inner(
991 state: &mut LuaState,
992 func_idx: StackIdx,
993 n_results: i32,
994 inc: u32,
995 f: crate::state::LuaCallable,
996) -> Result<(), LuaError> {
997 state.n_ccalls += inc;
998
999 if state.c_calls() >= LUAI_MAXCCALLS {
1000 state.check_stack(0)?;
1001 state.check_c_stack()?;
1002 }
1003
1004 precall_c(state, func_idx, n_results, f, 0)?;
1005
1006 state.n_ccalls -= inc;
1007 Ok(())
1008}
1009
1010#[inline]
1011fn ccall_inner_with_status(
1012 state: &mut LuaState,
1013 func_idx: StackIdx,
1014 n_results: i32,
1015 inc: u32,
1016 extra_callstatus: u16,
1017) -> Result<(), LuaError> {
1018 state.n_ccalls += inc;
1019
1020 if state.c_calls() >= LUAI_MAXCCALLS {
1021 state.check_stack(0)?;
1022 state.check_c_stack()?;
1023 }
1024
1025 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
1026 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
1027 vm::execute(state, ci_idx)?;
1028 }
1029
1030 state.n_ccalls -= inc;
1031 Ok(())
1032}
1033
1034pub(crate) fn call(
1037 state: &mut LuaState,
1038 func_idx: StackIdx,
1039 n_results: i32,
1040) -> Result<(), LuaError> {
1041 ccall_inner(state, func_idx, n_results, 1)
1042}
1043
1044pub(crate) fn callnoyield(
1047 state: &mut LuaState,
1048 func_idx: StackIdx,
1049 n_results: i32,
1050) -> Result<(), LuaError> {
1051 ccall_inner(state, func_idx, n_results, NYCI)
1053}
1054
1055#[inline]
1062pub(crate) fn call_known_c(
1063 state: &mut LuaState,
1064 func_idx: StackIdx,
1065 n_results: i32,
1066) -> Result<bool, LuaError> {
1067 let cfunc = match &state.stack[func_idx.0 as usize].val {
1068 LuaValue::Function(LuaClosure::C(cl)) => state.global().c_functions[cl.func].clone(),
1069 LuaValue::Function(LuaClosure::LightC(f)) => state.global().c_functions[*f].clone(),
1070 _ => return Ok(false),
1071 };
1072
1073 ccall_known_c_inner(state, func_idx, n_results, 1, cfunc)?;
1074 Ok(true)
1075}
1076
1077fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
1084 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
1086
1087 if status == LuaStatus::Ok {
1088 status = LuaStatus::Yield;
1089 } else {
1090 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
1091 state.allowhook = state.get_ci(ci_idx).get_oah();
1092 let _func_idx = func::close(state, func_idx, status as i32, true)?;
1093 set_error_obj(state, status, func_idx);
1094
1095 if state.errfunc != 0
1104 && error_status(status)
1105 && status != LuaStatus::ErrErr
1106 && status != LuaStatus::ErrSyntax
1107 {
1108 let errfunc_stk = StackIdx(state.errfunc as u32);
1109 status = run_message_handler(
1110 state,
1111 func_idx,
1112 errfunc_stk,
1113 status,
1114 ci_idx,
1115 state.allowhook,
1116 );
1117 }
1118
1119 shrink_stack(state);
1120 state
1121 .get_ci_mut(ci_idx)
1122 .set_recover_status(LuaStatus::Ok as i32);
1123 }
1124
1125 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1126 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1127 state.errfunc = old_errfunc;
1128
1129 Ok(status)
1130}
1131
1132fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1135 let n;
1136
1137 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1138 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1139 n = state.get_ci_u2_nres(ci_idx);
1140 } else {
1141 debug_assert!(
1142 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1143 "finishCcall: no continuation or non-yieldable"
1144 );
1145
1146 let mut status = LuaStatus::Yield;
1147
1148 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1149 status = finish_pcallk(state, ci_idx)?;
1150 }
1151
1152 state.adjust_results(LUA_MULTRET);
1153
1154 let k = state.get_ci(ci_idx).u_c_k();
1159 let ctx = state.get_ci(ci_idx).u_c_ctx();
1160 if let Some(k_fn) = k {
1161 n = k_fn(state, status as i32, ctx)? as i32;
1162 } else {
1163 return Err(LuaError::runtime(format_args!(
1166 "finishCcall: missing continuation"
1167 )));
1168 }
1169 debug_assert!(
1170 n <= state.top_idx().0 as i32,
1171 "continuation returned more values than available"
1172 );
1173 }
1174
1175 poscall(state, ci_idx, n)?;
1176 Ok(())
1177}
1178
1179fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1182 loop {
1183 let ci_idx = state.ci;
1184 if state.is_base_ci(ci_idx) {
1185 break;
1186 }
1187 if !state.get_ci(ci_idx).is_lua() {
1188 finish_ccall(state, ci_idx)?;
1189 } else {
1190 vm::finish_op(state)?;
1191 vm::execute(state, ci_idx)?;
1192 }
1193 }
1194 Ok(())
1195}
1196
1197fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1200 let mut ci_idx_opt = Some(state.ci);
1201 while let Some(ci_idx) = ci_idx_opt {
1202 let ci = state.get_ci(ci_idx);
1203 if ci.callstatus & CIST_YPCALL != 0 {
1204 return Some(ci_idx);
1205 }
1206 ci_idx_opt = ci.previous;
1207 }
1208 None
1209}
1210
1211fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1214 let top = state.top_idx();
1215 state.set_top(top - narg as i32);
1216 let s = state.intern_str(msg).ok();
1217 let new_top = state.top_idx();
1218 if let Some(s) = s {
1219 state.set_at(new_top, LuaValue::Str(s));
1220 }
1221 state.set_top(new_top + 1);
1222 LuaStatus::ErrRun
1223}
1224
1225fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1228 let top = state.top_idx();
1229 let first_arg = top - nargs as i32;
1230 let ci_idx = state.ci;
1231
1232 if state.status == LuaStatus::Ok as u8 {
1233 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1234 } else {
1235 debug_assert!(state.status == LuaStatus::Yield as u8);
1236 state.status = LuaStatus::Ok as u8;
1237
1238 if state.get_ci(ci_idx).is_lua() {
1239 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1240 let pc = state.ci_savedpc(ci_idx);
1241 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1242 state.set_top(first_arg);
1243 vm::execute(state, ci_idx)?;
1244 } else {
1245 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1246 let ctx = state.get_ci(ci_idx).u_c_ctx();
1247 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1248 debug_assert!(n <= state.top_idx().0 as i32);
1249 poscall(state, ci_idx, n)?;
1250 } else {
1251 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1253 poscall(state, ci_idx, n)?;
1254 }
1255 }
1256
1257 unroll(state)?;
1258 }
1259 Ok(())
1260}
1261
1262fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1265 while error_status(status) {
1266 if let Some(ci_idx) = find_pcall(state) {
1267 state.ci = ci_idx;
1268 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1269 status = match raw_run_protected(state, |s| unroll(s)) {
1274 Ok(()) => LuaStatus::Ok,
1275 Err(e) => {
1276 let s = e.to_status();
1277 if error_status(s) {
1278 state.push(e.into_value());
1279 }
1280 s
1281 }
1282 };
1283 } else {
1284 break;
1285 }
1286 }
1287 status
1288}
1289
1290pub fn lua_resume(
1293 state: &mut LuaState,
1294 from: Option<&mut LuaState>,
1295 nargs: i32,
1296 nresults: &mut i32,
1297) -> LuaStatus {
1298 let _heap_guard = {
1303 let g = state.global.borrow();
1304 lua_gc::HeapGuard::push(&g.heap)
1305 };
1306 if state.status == LuaStatus::Ok as u8 {
1307 if !state.is_base_ci(state.ci) {
1308 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1309 }
1310 let ci_func = state.get_ci(state.ci).func;
1311 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1312 return resume_error(state, b"cannot resume dead coroutine", nargs);
1313 }
1314 } else if state.status != LuaStatus::Yield as u8 {
1315 return resume_error(state, b"cannot resume dead coroutine", nargs);
1316 }
1317
1318 state.n_ccalls = from.as_ref().map(|f| f.c_calls() as u32).unwrap_or(0);
1319
1320 if state.c_calls() >= LUAI_MAXCCALLS {
1321 return resume_error(state, b"C stack overflow", nargs);
1322 }
1323 state.n_ccalls += 1;
1324
1325 debug_assert!(
1326 if state.status == LuaStatus::Ok as u8 {
1327 nargs + 1 <= state.top_idx().0 as i32
1328 } else {
1329 nargs <= state.top_idx().0 as i32
1330 },
1331 "lua_resume: not enough stack elements"
1332 );
1333
1334 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1340 Ok(()) => (LuaStatus::Ok, None),
1341 Err(e) => {
1342 let s = e.to_status();
1343 let v = if error_status(s) {
1344 Some(e.into_value())
1345 } else {
1346 None
1347 };
1348 (s, v)
1349 }
1350 };
1351 if let Some(v) = err_value {
1352 state.push(v);
1353 }
1354
1355 status = precover(state, status);
1356
1357 if !error_status(status) {
1358 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1359 } else {
1360 state.status = status as u8;
1362 let top = state.top_idx();
1363 set_error_obj(state, status, top);
1364 let new_top = state.top_idx();
1365 let ci_idx = state.ci;
1366 state.get_ci_mut(ci_idx).top = new_top;
1367 }
1368
1369 let ci_idx = state.ci;
1370 *nresults = if status == LuaStatus::Yield {
1371 state.get_ci_u2_nyield(ci_idx)
1372 } else {
1373 let ci_func = state.get_ci(ci_idx).func;
1374 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1375 };
1376
1377 status
1378}
1379
1380pub fn lua_isyieldable(state: &LuaState) -> bool {
1383 state.is_yieldable()
1384}
1385
1386pub fn lua_yieldk(
1390 state: &mut LuaState,
1391 nresults: i32,
1392 ctx: isize,
1393 k: Option<crate::state::LuaKFunction>,
1394) -> Result<i32, LuaError> {
1395 let ci_idx = state.ci;
1396
1397 debug_assert!(
1398 nresults <= state.top_idx().0 as i32,
1399 "lua_yieldk: not enough elements on stack"
1400 );
1401
1402 if !state.is_yieldable() {
1403 if matches!(state.global().lua_version, lua_types::LuaVersion::V51) {
1404 return Err(LuaError::runtime(format_args!(
1405 "attempt to yield across metamethod/C-call boundary"
1406 )));
1407 }
1408 if !state.is_main_thread() {
1409 return Err(LuaError::runtime(format_args!(
1410 "attempt to yield across a C-call boundary"
1411 )));
1412 } else {
1413 return Err(LuaError::runtime(format_args!(
1414 "attempt to yield from outside a coroutine"
1415 )));
1416 }
1417 }
1418
1419 state.status = LuaStatus::Yield as u8;
1420 state.set_ci_u2_nyield(ci_idx, nresults);
1421
1422 if state.get_ci(ci_idx).is_lua() {
1423 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1424 debug_assert!(nresults == 0, "hooks cannot yield values");
1425 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1426 } else {
1428 let ci = state.get_ci_mut(ci_idx);
1429 ci.set_u_c_k(k);
1430 if k.is_some() {
1431 ci.set_u_c_ctx(ctx);
1432 }
1433 return Err(LuaError::Yield);
1435 }
1436
1437 debug_assert!(
1438 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1439 "lua_yieldk called outside a hook"
1440 );
1441 Ok(0) }
1443
1444struct CloseP {
1451 level: StackIdx,
1452 status: LuaStatus,
1453}
1454
1455fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1458 func::close(state, pcl.level, pcl.status as i32, false)?;
1459 Ok(())
1460}
1461
1462pub(crate) fn close_protected(
1466 state: &mut LuaState,
1467 level: StackIdx,
1468 status: LuaStatus,
1469) -> LuaStatus {
1470 let old_ci = state.ci;
1471 let old_allowhook = state.allowhook;
1472 let mut status = status;
1473
1474 loop {
1475 let mut pcl = CloseP { level, status };
1476 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1477 Ok(()) => (LuaStatus::Ok, None),
1478 Err(e) => (e.to_status(), Some(e.into_value())),
1479 };
1480 if run_status == LuaStatus::Ok {
1481 return pcl.status;
1482 }
1483 state.ci = old_ci;
1484 state.allowhook = old_allowhook;
1485 if let Some(v) = err_value {
1491 state.push(v);
1492 }
1493 status = run_status;
1494 }
1495}
1496
1497pub(crate) fn pcall<F>(state: &mut LuaState, func: F, old_top: StackIdx, ef: isize) -> LuaStatus
1501where
1502 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1503{
1504 let old_ci = state.ci;
1505 let old_allowhook = state.allowhook;
1506 let old_errfunc = state.errfunc;
1507 state.errfunc = ef;
1508
1509 let mut status = match raw_run_protected(state, func) {
1515 Ok(()) => LuaStatus::Ok,
1516 Err(e) => {
1517 let s = e.to_status();
1518 state.push(e.into_value());
1519 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1525 let errfunc_idx = StackIdx(ef as u32);
1526 let err_slot = state.top_idx() - 1;
1527 run_message_handler(state, err_slot, errfunc_idx, s, old_ci, old_allowhook)
1528 } else {
1529 s
1530 }
1531 }
1532 };
1533
1534 if status != LuaStatus::Ok
1542 && status != LuaStatus::ErrSyntax
1543 && state.global().lua_version == lua_types::LuaVersion::V55
1544 {
1545 let top = state.top_idx();
1546 if matches!(state.get_at(top - 1), LuaValue::Nil) {
1547 if let Ok(s) = state.intern_str(b"<no error object>") {
1548 state.set_at(top - 1, LuaValue::Str(s));
1549 }
1550 }
1551 }
1552
1553 if status != LuaStatus::Ok {
1554 state.ci = old_ci;
1555 state.allowhook = old_allowhook;
1556 status = close_protected(state, old_top, status);
1557 set_error_obj(state, status, old_top);
1559 shrink_stack(state);
1560 }
1561
1562 state.errfunc = old_errfunc;
1563 status
1564}
1565
1566struct SParser {
1575 z: ZIO,
1576 buff: LexBuffer,
1578 dyd: DynDataStub,
1580 mode: Option<Vec<u8>>,
1582 name: Vec<u8>,
1583}
1584
1585fn check_mode(mode: Option<&[u8]>, kind: &[u8]) -> Result<(), LuaError> {
1588 if let Some(mode_bytes) = mode {
1589 let kind_char = kind[0];
1590 if !mode_bytes.contains(&kind_char) {
1591 return Err(LuaError::syntax(format_args!(
1594 "attempt to load a {} chunk (mode is '{}')",
1595 core::str::from_utf8(kind).unwrap_or("?"),
1596 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1597 )));
1598 }
1599 }
1600 Ok(())
1601}
1602
1603fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1607 let c = p.z.getc(state)?;
1608
1609 let cl = if c == b'\x1b' as i32 {
1610 check_mode(p.mode.as_deref(), b"binary")?;
1611 crate::undump::undump(state, &mut p.z, &p.name)?
1612 } else {
1613 check_mode(p.mode.as_deref(), b"text")?;
1614 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1615 };
1616
1617 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1618 func::init_upvals(state, &cl)?;
1619
1620 state.check_stack(1)?;
1628 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1629
1630 Ok(())
1631}
1632
1633pub(crate) fn protected_parser(
1645 state: &mut LuaState,
1646 z: ZIO,
1647 name: &[u8],
1648 mode: Option<&[u8]>,
1649) -> LuaStatus {
1650 state.inc_nny();
1651
1652 let mut p = SParser {
1653 z,
1654 buff: LexBuffer::new(),
1655 dyd: DynDataStub::new(),
1656 mode: mode.map(|m| m.to_vec()),
1657 name: name.to_vec(),
1658 };
1659
1660 let saved_gcstp = {
1661 let mut g = state.global_mut();
1662 let old = g.gc_stop_flags();
1663 let _ = g.stop_gc_internal();
1664 old
1665 };
1666
1667 let top_idx = state.top_idx();
1668 let errfunc = state.errfunc;
1669 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1670
1671 state.global_mut().set_gc_stop_flags(saved_gcstp);
1672
1673 state.dec_nny();
1676
1677 status
1678}