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)]
678fn prep_call_info(
679 state: &mut LuaState,
680 func_idx: StackIdx,
681 nret: i32,
682 mask: u16,
683 top_idx: StackIdx,
684) -> Result<CallInfoIdx, LuaError> {
685 debug_assert!(
686 mask & crate::state::CIST_TRAP == 0,
687 "prep_call_info must not be handed a pre-set trap bit"
688 );
689 let ci_idx = state.next_ci()?;
691 state.ci = ci_idx;
692 {
693 let ci = state.get_ci_mut(ci_idx);
694 ci.func = func_idx;
695 ci.nresults = nret as i16;
696 ci.callstatus = mask;
697 ci.call_metamethods = 0;
698 ci.top = top_idx;
699 ci.u = crate::state::CallInfoFrame::lua_default();
700 }
701 Ok(ci_idx)
702}
703
704#[inline(always)]
709fn precall_c(
710 state: &mut LuaState,
711 func_idx: StackIdx,
712 nresults: i32,
713 f: crate::state::LuaCallable,
714 call_metamethods: u8,
715) -> Result<i32, LuaError> {
716 state.check_stack(LUA_MINSTACK as i32)?;
717 if state.gc_check_needed {
718 state.gc_check_step();
719 }
720
721 let top_idx = state.top_idx();
722 let ci_idx = prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
723 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
724
725 debug_assert!(true );
726
727 if state.hookmask & LUA_MASKCALL != 0 {
728 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
729 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
730 }
731
732 let n = f.call(state)? as i32;
733
734 debug_assert!(
736 n <= state.top_idx().0 as i32,
737 "C function returned more values than available"
738 );
739
740 poscall(state, ci_idx, n)?;
741 Ok(n)
742}
743
744pub(crate) fn pretailcall(
762 state: &mut LuaState,
763 ci_idx: CallInfoIdx,
764 mut func_idx: StackIdx,
765 mut narg1: i32,
766 delta: i32,
767) -> Result<i32, LuaError> {
768 let mut call_metamethods = 0u8;
769 loop {
770 let func_val = state.get_at(func_idx).clone();
771 match func_val {
772 LuaValue::Function(LuaClosure::C(ref cl)) => {
773 let cfunc = state.global().c_functions[cl.func].clone();
774 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
775 }
776 LuaValue::Function(LuaClosure::LightC(f)) => {
777 let cfunc = state.global().c_functions[f].clone();
778 return precall_c(state, func_idx, LUA_MULTRET, cfunc, call_metamethods);
779 }
780 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
781 let proto = cl.proto.clone();
782 let fsize = proto.maxstacksize as i32;
783 let nfixparams = proto.numparams as i32;
784
785 state.check_stack(fsize - delta)?;
786 if state.gc_check_needed {
787 state.gc_check_step();
788 }
789
790 {
791 let ci = state.get_ci_mut(ci_idx);
792 ci.func = StackIdx((ci.func.0 as i32 - delta) as u32);
793 }
794 let ci_func = state.get_ci(ci_idx).func;
795
796 for i in 0..narg1 {
797 let src = state.get_at(func_idx + i as i32).clone();
798 state.set_at(ci_func + i as i32, src);
799 }
800
801 func_idx = ci_func;
803
804 while narg1 <= nfixparams {
805 state.set_at(func_idx + narg1 as i32, LuaValue::Nil);
806 narg1 += 1;
807 }
808
809 {
810 let new_ci_top = func_idx + 1 + fsize as i32;
811 let stack_last = state.stack_last;
812 let live_top = state.top_idx();
813 let ci = state.get_ci_mut(ci_idx);
814 ci.call_metamethods = call_metamethods;
815 ci.top = new_ci_top;
816 debug_assert!(ci.top.0 <= stack_last.0);
817 ci.set_saved_pc(0);
818 ci.callstatus |= CIST_TAIL;
819 state.clear_stack_range(live_top, new_ci_top);
820 }
821
822 state.set_top(func_idx + narg1 as i32);
823 return Ok(-1); }
825 _ => {
826 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
827 narg1 += 1;
828 }
830 }
831 }
832}
833
834#[inline(always)]
844pub(crate) fn precall(
845 state: &mut LuaState,
846 func_idx: StackIdx,
847 nresults: i32,
848) -> Result<Option<CallInfoIdx>, LuaError> {
849 if let LuaValue::Function(LuaClosure::Lua(cl)) = &state.stack[func_idx.0 as usize].val {
850 let nfixparams = cl.proto.numparams as i32;
851 let fsize = cl.proto.maxstacksize as i32;
852 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
853
854 state.check_stack(fsize)?;
855 if state.gc_check_needed {
856 state.gc_check_step();
857 }
858
859 let ci_idx = prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
860 state.set_ci_savedpc(ci_idx, 0);
861
862 if narg < nfixparams {
863 fill_missing_params(state, narg, nfixparams);
864 }
865 return Ok(Some(ci_idx));
866 }
867 precall_slow(state, func_idx, nresults)
868}
869
870#[cold]
874#[inline(never)]
875fn fill_missing_params(state: &mut LuaState, mut narg: i32, nfixparams: i32) {
876 while narg < nfixparams {
877 let top = state.top_idx();
878 state.set_at(top, LuaValue::Nil);
879 state.set_top(top + 1);
880 narg += 1;
881 }
882}
883
884#[cold]
888#[inline(never)]
889fn precall_slow(
890 state: &mut LuaState,
891 mut func_idx: StackIdx,
892 nresults: i32,
893) -> Result<Option<CallInfoIdx>, LuaError> {
894 let mut call_metamethods = 0u8;
895 loop {
896 let func_val = state.get_at(func_idx).clone();
897 match func_val {
898 LuaValue::Function(LuaClosure::C(ref cl)) => {
899 let cfunc = state.global().c_functions[cl.func].clone();
900 precall_c(state, func_idx, nresults, cfunc, call_metamethods)?;
901 return Ok(None);
902 }
903 LuaValue::Function(LuaClosure::LightC(f)) => {
904 state.check_stack(LUA_MINSTACK as i32)?;
905 if state.gc_check_needed {
906 state.gc_check_step();
907 }
908
909 let top_idx = state.top_idx();
910 let ci_idx =
911 prep_call_info(state, func_idx, nresults, CIST_C, top_idx + LUA_MINSTACK)?;
912 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
913
914 if state.hookmask & LUA_MASKCALL != 0 {
915 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
916 hook(state, LUA_HOOKCALL, -1, 1, narg)?;
917 }
918
919 let cfunc = state.global().c_functions[f].clone();
920 let n = cfunc.call(state)? as i32;
921 debug_assert!(
922 n <= state.top_idx().0 as i32,
923 "C function returned more values than available"
924 );
925 poscall(state, ci_idx, n)?;
926 return Ok(None);
927 }
928 LuaValue::Function(LuaClosure::Lua(ref cl)) => {
929 let narg = (state.top_idx().0 as i32 - func_idx.0 as i32) - 1;
930 let nfixparams = cl.proto.numparams as i32;
931 let fsize = cl.proto.maxstacksize as i32;
932
933 state.check_stack(fsize)?;
934 if state.gc_check_needed {
935 state.gc_check_step();
936 }
937
938 let ci_idx =
939 prep_call_info(state, func_idx, nresults, 0, func_idx + 1 + fsize as i32)?;
940 state.get_ci_mut(ci_idx).call_metamethods = call_metamethods;
941 state.set_ci_savedpc(ci_idx, 0);
942
943 if narg < nfixparams {
944 fill_missing_params(state, narg, nfixparams);
945 }
946 return Ok(Some(ci_idx));
947 }
948 _ => {
949 func_idx = try_func_tm(state, func_idx, &mut call_metamethods)?;
950 }
951 }
952 }
953}
954
955#[inline]
959fn ccall_inner(
960 state: &mut LuaState,
961 func_idx: StackIdx,
962 n_results: i32,
963 inc: u32,
964) -> Result<(), LuaError> {
965 ccall_inner_with_status(state, func_idx, n_results, inc, 0)
966}
967
968#[inline]
969fn ccall_known_c_inner(
970 state: &mut LuaState,
971 func_idx: StackIdx,
972 n_results: i32,
973 inc: u32,
974 f: crate::state::LuaCallable,
975) -> Result<(), LuaError> {
976 state.n_ccalls += inc;
977
978 if state.c_calls() >= LUAI_MAXCCALLS {
979 state.check_stack(0)?;
980 state.check_c_stack()?;
981 }
982
983 precall_c(state, func_idx, n_results, f, 0)?;
984
985 state.n_ccalls -= inc;
986 Ok(())
987}
988
989#[inline]
990fn ccall_inner_with_status(
991 state: &mut LuaState,
992 func_idx: StackIdx,
993 n_results: i32,
994 inc: u32,
995 extra_callstatus: u16,
996) -> Result<(), LuaError> {
997 state.n_ccalls += inc;
998
999 if state.c_calls() >= LUAI_MAXCCALLS {
1001 state.check_stack(0)?;
1003 state.check_c_stack()?;
1004 }
1005
1006 if let Some(ci_idx) = precall(state, func_idx, n_results)? {
1007 state.get_ci_mut(ci_idx).callstatus = CIST_FRESH | extra_callstatus;
1008 vm::execute(state, ci_idx)?;
1009 }
1010
1011 state.n_ccalls -= inc;
1012 Ok(())
1013}
1014
1015pub(crate) fn call(
1018 state: &mut LuaState,
1019 func_idx: StackIdx,
1020 n_results: i32,
1021) -> Result<(), LuaError> {
1022 ccall_inner(state, func_idx, n_results, 1)
1023}
1024
1025pub(crate) fn callnoyield(
1028 state: &mut LuaState,
1029 func_idx: StackIdx,
1030 n_results: i32,
1031) -> Result<(), LuaError> {
1032 ccall_inner(state, func_idx, n_results, NYCI)
1034}
1035
1036#[inline]
1043pub(crate) fn call_known_c(
1044 state: &mut LuaState,
1045 func_idx: StackIdx,
1046 n_results: i32,
1047) -> Result<bool, LuaError> {
1048 let cfunc = match &state.stack[func_idx.0 as usize].val {
1049 LuaValue::Function(LuaClosure::C(cl)) => state.global().c_functions[cl.func].clone(),
1050 LuaValue::Function(LuaClosure::LightC(f)) => state.global().c_functions[*f].clone(),
1051 _ => return Ok(false),
1052 };
1053
1054 ccall_known_c_inner(state, func_idx, n_results, 1, cfunc)?;
1055 Ok(true)
1056}
1057
1058fn finish_pcallk(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<LuaStatus, LuaError> {
1065 let mut status = LuaStatus::from_raw(state.get_ci(ci_idx).recover_status());
1068
1069 if status == LuaStatus::Ok {
1070 status = LuaStatus::Yield;
1071 } else {
1072 let func_idx = StackIdx(state.get_ci_u2_funcidx(ci_idx) as u32);
1073 state.allowhook = state.get_ci(ci_idx).get_oah();
1075 let _func_idx = func::close(state, func_idx, status as i32, true)?;
1077 set_error_obj(state, status, func_idx);
1078
1079 if state.errfunc != 0
1088 && error_status(status)
1089 && status != LuaStatus::ErrErr
1090 && status != LuaStatus::ErrSyntax
1091 {
1092 let errfunc_stk = StackIdx(state.errfunc as u32);
1093 status = run_message_handler(
1094 state,
1095 func_idx,
1096 errfunc_stk,
1097 status,
1098 ci_idx,
1099 state.allowhook,
1100 );
1101 }
1102
1103 shrink_stack(state);
1104 state
1105 .get_ci_mut(ci_idx)
1106 .set_recover_status(LuaStatus::Ok as i32);
1107 }
1108
1109 state.get_ci_mut(ci_idx).callstatus &= !CIST_YPCALL;
1110 let old_errfunc = state.get_ci(ci_idx).u_c_old_errfunc();
1111 state.errfunc = old_errfunc;
1112
1113 Ok(status)
1114}
1115
1116fn finish_ccall(state: &mut LuaState, ci_idx: CallInfoIdx) -> Result<(), LuaError> {
1119 let n;
1120
1121 if state.get_ci(ci_idx).callstatus & CIST_CLSRET != 0 {
1122 debug_assert!((state.get_ci(ci_idx).nresults as i32) < LUA_MULTRET);
1123 n = state.get_ci_u2_nres(ci_idx);
1124 } else {
1125 debug_assert!(
1126 state.get_ci(ci_idx).u_c_k().is_some() && state.is_yieldable(),
1127 "finishCcall: no continuation or non-yieldable"
1128 );
1129
1130 let mut status = LuaStatus::Yield;
1131
1132 if state.get_ci(ci_idx).callstatus & CIST_YPCALL != 0 {
1133 status = finish_pcallk(state, ci_idx)?;
1134 }
1135
1136 state.adjust_results(LUA_MULTRET);
1138
1139 let k = state.get_ci(ci_idx).u_c_k();
1143 let ctx = state.get_ci(ci_idx).u_c_ctx();
1144 if let Some(k_fn) = k {
1145 n = k_fn(state, status as i32, ctx)? as i32;
1146 } else {
1147 return Err(LuaError::runtime(format_args!(
1149 "finishCcall: missing continuation"
1150 )));
1151 }
1152 debug_assert!(
1153 n <= state.top_idx().0 as i32,
1154 "continuation returned more values than available"
1155 );
1156 }
1157
1158 poscall(state, ci_idx, n)?;
1159 Ok(())
1160}
1161
1162fn unroll(state: &mut LuaState) -> Result<(), LuaError> {
1165 loop {
1166 let ci_idx = state.ci;
1167 if state.is_base_ci(ci_idx) {
1168 break;
1169 }
1170 if !state.get_ci(ci_idx).is_lua() {
1171 finish_ccall(state, ci_idx)?;
1172 } else {
1173 vm::finish_op(state)?;
1174 vm::execute(state, ci_idx)?;
1175 }
1176 }
1177 Ok(())
1178}
1179
1180fn find_pcall(state: &LuaState) -> Option<CallInfoIdx> {
1183 let mut ci_idx_opt = Some(state.ci);
1184 while let Some(ci_idx) = ci_idx_opt {
1185 let ci = state.get_ci(ci_idx);
1186 if ci.callstatus & CIST_YPCALL != 0 {
1187 return Some(ci_idx);
1188 }
1189 ci_idx_opt = ci.previous;
1190 }
1191 None
1192}
1193
1194fn resume_error(state: &mut LuaState, msg: &[u8], narg: i32) -> LuaStatus {
1197 let top = state.top_idx();
1198 state.set_top(top - narg as i32);
1199 let s = state.intern_str(msg).ok();
1201 let new_top = state.top_idx();
1202 if let Some(s) = s {
1203 state.set_at(new_top, LuaValue::Str(s));
1204 }
1205 state.set_top(new_top + 1);
1206 LuaStatus::ErrRun
1207}
1208
1209fn resume_coroutine(state: &mut LuaState, nargs: i32) -> Result<(), LuaError> {
1212 let top = state.top_idx();
1213 let first_arg = top - nargs as i32;
1214 let ci_idx = state.ci;
1215
1216 if state.status == LuaStatus::Ok as u8 {
1217 ccall_inner(state, first_arg - 1, LUA_MULTRET, 0)?;
1218 } else {
1219 debug_assert!(state.status == LuaStatus::Yield as u8);
1220 state.status = LuaStatus::Ok as u8;
1221
1222 if state.get_ci(ci_idx).is_lua() {
1223 debug_assert!(state.get_ci(ci_idx).callstatus & CIST_HOOKYIELD != 0);
1224 let pc = state.ci_savedpc(ci_idx);
1225 state.set_ci_savedpc(ci_idx, pc.saturating_sub(1));
1226 state.set_top(first_arg);
1227 vm::execute(state, ci_idx)?;
1228 } else {
1229 if let Some(k_fn) = state.get_ci(ci_idx).u_c_k() {
1230 let ctx = state.get_ci(ci_idx).u_c_ctx();
1231 let n = k_fn(state, LuaStatus::Yield as i32, ctx)? as i32;
1232 debug_assert!(n <= state.top_idx().0 as i32);
1233 poscall(state, ci_idx, n)?;
1234 } else {
1235 let n = (state.top_idx().0 as i32 - first_arg.0 as i32).max(0);
1237 poscall(state, ci_idx, n)?;
1238 }
1239 }
1240
1241 unroll(state)?;
1242 }
1243 Ok(())
1244}
1245
1246fn precover(state: &mut LuaState, mut status: LuaStatus) -> LuaStatus {
1249 while error_status(status) {
1250 if let Some(ci_idx) = find_pcall(state) {
1251 state.ci = ci_idx;
1252 state.get_ci_mut(ci_idx).set_recover_status(status as i32);
1253 status = match raw_run_protected(state, |s| unroll(s)) {
1258 Ok(()) => LuaStatus::Ok,
1259 Err(e) => {
1260 let s = e.to_status();
1261 if error_status(s) {
1262 state.push(e.into_value());
1263 }
1264 s
1265 }
1266 };
1267 } else {
1268 break;
1269 }
1270 }
1271 status
1272}
1273
1274pub fn lua_resume(
1277 state: &mut LuaState,
1278 from: Option<&mut LuaState>,
1279 nargs: i32,
1280 nresults: &mut i32,
1281) -> LuaStatus {
1282 if state.status == LuaStatus::Ok as u8 {
1288 if !state.is_base_ci(state.ci) {
1289 return resume_error(state, b"cannot resume non-suspended coroutine", nargs);
1290 }
1291 let ci_func = state.get_ci(state.ci).func;
1292 if state.top_idx().0 as i32 - (ci_func.0 as i32 + 1) == nargs {
1293 return resume_error(state, b"cannot resume dead coroutine", nargs);
1294 }
1295 } else if state.status != LuaStatus::Yield as u8 {
1296 return resume_error(state, b"cannot resume dead coroutine", nargs);
1297 }
1298
1299 state.n_ccalls = from.as_ref().map(|f| f.c_calls() as u32).unwrap_or(0);
1300
1301 if state.c_calls() >= LUAI_MAXCCALLS {
1302 return resume_error(state, b"C stack overflow", nargs);
1303 }
1304 state.n_ccalls += 1;
1305
1306 debug_assert!(
1307 if state.status == LuaStatus::Ok as u8 {
1308 nargs + 1 <= state.top_idx().0 as i32
1309 } else {
1310 nargs <= state.top_idx().0 as i32
1311 },
1312 "lua_resume: not enough stack elements"
1313 );
1314
1315 let (mut status, err_value) = match raw_run_protected(state, |s| resume_coroutine(s, nargs)) {
1321 Ok(()) => (LuaStatus::Ok, None),
1322 Err(e) => {
1323 let s = e.to_status();
1324 let v = if error_status(s) {
1325 Some(e.into_value())
1326 } else {
1327 None
1328 };
1329 (s, v)
1330 }
1331 };
1332 if let Some(v) = err_value {
1333 state.push(v);
1334 }
1335
1336 status = precover(state, status);
1337
1338 if !error_status(status) {
1339 debug_assert!(status as u8 == state.status, "lua_resume: status mismatch");
1340 } else {
1341 state.status = status as u8;
1343 let top = state.top_idx();
1344 set_error_obj(state, status, top);
1345 let new_top = state.top_idx();
1346 let ci_idx = state.ci;
1347 state.get_ci_mut(ci_idx).top = new_top;
1348 }
1349
1350 let ci_idx = state.ci;
1351 *nresults = if status == LuaStatus::Yield {
1352 state.get_ci_u2_nyield(ci_idx)
1353 } else {
1354 let ci_func = state.get_ci(ci_idx).func;
1355 state.top_idx().0 as i32 - (ci_func.0 as i32 + 1)
1356 };
1357
1358 status
1359}
1360
1361pub fn lua_isyieldable(state: &LuaState) -> bool {
1364 state.is_yieldable()
1366}
1367
1368pub fn lua_yieldk(
1372 state: &mut LuaState,
1373 nresults: i32,
1374 ctx: isize,
1375 k: Option<crate::state::LuaKFunction>,
1376) -> Result<i32, LuaError> {
1377 let ci_idx = state.ci;
1381
1382 debug_assert!(
1383 nresults <= state.top_idx().0 as i32,
1384 "lua_yieldk: not enough elements on stack"
1385 );
1386
1387 if !state.is_yieldable() {
1388 if !state.is_main_thread() {
1389 return Err(LuaError::runtime(format_args!(
1390 "attempt to yield across a C-call boundary"
1391 )));
1392 } else {
1393 return Err(LuaError::runtime(format_args!(
1394 "attempt to yield from outside a coroutine"
1395 )));
1396 }
1397 }
1398
1399 state.status = LuaStatus::Yield as u8;
1400 state.set_ci_u2_nyield(ci_idx, nresults);
1401
1402 if state.get_ci(ci_idx).is_lua() {
1403 debug_assert!(!state.get_ci(ci_idx).is_lua_code());
1404 debug_assert!(nresults == 0, "hooks cannot yield values");
1405 debug_assert!(k.is_none(), "hooks cannot continue after yielding");
1406 } else {
1408 let ci = state.get_ci_mut(ci_idx);
1409 ci.set_u_c_k(k);
1410 if k.is_some() {
1411 ci.set_u_c_ctx(ctx);
1412 }
1413 return Err(LuaError::Yield);
1415 }
1416
1417 debug_assert!(
1418 state.get_ci(ci_idx).callstatus & CIST_HOOKED != 0,
1419 "lua_yieldk called outside a hook"
1420 );
1421 Ok(0) }
1423
1424struct CloseP {
1431 level: StackIdx,
1432 status: LuaStatus,
1433}
1434
1435fn close_aux(state: &mut LuaState, pcl: &mut CloseP) -> Result<(), LuaError> {
1438 func::close(state, pcl.level, pcl.status as i32, false)?;
1440 Ok(())
1441}
1442
1443pub(crate) fn close_protected(
1447 state: &mut LuaState,
1448 level: StackIdx,
1449 status: LuaStatus,
1450) -> LuaStatus {
1451 let old_ci = state.ci;
1452 let old_allowhook = state.allowhook;
1453 let mut status = status;
1454
1455 loop {
1456 let mut pcl = CloseP { level, status };
1457 let (run_status, err_value) = match raw_run_protected(state, |s| close_aux(s, &mut pcl)) {
1458 Ok(()) => (LuaStatus::Ok, None),
1459 Err(e) => (e.to_status(), Some(e.into_value())),
1460 };
1461 if run_status == LuaStatus::Ok {
1462 return pcl.status;
1463 }
1464 state.ci = old_ci;
1465 state.allowhook = old_allowhook;
1466 if let Some(v) = err_value {
1472 state.push(v);
1473 }
1474 status = run_status;
1475 }
1476}
1477
1478pub(crate) fn pcall<F>(state: &mut LuaState, func: F, old_top: StackIdx, ef: isize) -> LuaStatus
1482where
1483 F: FnOnce(&mut LuaState) -> Result<(), LuaError>,
1484{
1485 let old_ci = state.ci;
1486 let old_allowhook = state.allowhook;
1487 let old_errfunc = state.errfunc;
1488 state.errfunc = ef;
1489
1490 let mut status = match raw_run_protected(state, func) {
1496 Ok(()) => LuaStatus::Ok,
1497 Err(e) => {
1498 let s = e.to_status();
1499 state.push(e.into_value());
1500 if ef != 0 && error_status(s) && s != LuaStatus::ErrErr && s != LuaStatus::ErrSyntax {
1506 let errfunc_idx = StackIdx(ef as u32);
1507 let err_slot = state.top_idx() - 1;
1508 run_message_handler(state, err_slot, errfunc_idx, s, old_ci, old_allowhook)
1509 } else {
1510 s
1511 }
1512 }
1513 };
1514
1515 if status != LuaStatus::Ok
1523 && status != LuaStatus::ErrSyntax
1524 && state.global().lua_version == lua_types::LuaVersion::V55
1525 {
1526 let top = state.top_idx();
1527 if matches!(state.get_at(top - 1), LuaValue::Nil) {
1528 if let Ok(s) = state.intern_str(b"<no error object>") {
1529 state.set_at(top - 1, LuaValue::Str(s));
1530 }
1531 }
1532 }
1533
1534 if status != LuaStatus::Ok {
1535 state.ci = old_ci;
1536 state.allowhook = old_allowhook;
1537 status = close_protected(state, old_top, status);
1538 set_error_obj(state, status, old_top);
1540 shrink_stack(state);
1541 }
1542
1543 state.errfunc = old_errfunc;
1544 status
1545}
1546
1547struct SParser {
1557 z: ZIO,
1558 buff: LexBuffer,
1560 dyd: DynDataStub,
1562 mode: Option<Vec<u8>>,
1564 name: Vec<u8>,
1565}
1566
1567fn check_mode(mode: Option<&[u8]>, kind: &[u8]) -> Result<(), LuaError> {
1570 if let Some(mode_bytes) = mode {
1571 let kind_char = kind[0];
1572 if !mode_bytes.contains(&kind_char) {
1573 return Err(LuaError::syntax(format_args!(
1576 "attempt to load a {} chunk (mode is '{}')",
1577 core::str::from_utf8(kind).unwrap_or("?"),
1578 core::str::from_utf8(mode_bytes).unwrap_or("?"),
1579 )));
1580 }
1581 }
1582 Ok(())
1583}
1584
1585fn f_parser(state: &mut LuaState, p: &mut SParser) -> Result<(), LuaError> {
1589 let c = p.z.getc();
1591
1592 let cl = if c == b'\x1b' as i32 {
1594 check_mode(p.mode.as_deref(), b"binary")?;
1595 crate::undump::undump(state, &mut p.z, &p.name)?
1597 } else {
1598 check_mode(p.mode.as_deref(), b"text")?;
1599 parse_stub(state, &mut p.z, &mut p.buff, &mut p.dyd, &p.name, c)?
1601 };
1602
1603 debug_assert!(cl.upvals.len() == cl.proto.upvalues.len());
1604 func::init_upvals(state, &cl)?;
1605
1606 state.check_stack(1)?;
1614 state.push(LuaValue::Function(LuaClosure::Lua(cl)));
1615
1616 Ok(())
1617}
1618
1619pub(crate) fn protected_parser(
1622 state: &mut LuaState,
1623 z: ZIO,
1624 name: &[u8],
1625 mode: Option<&[u8]>,
1626) -> LuaStatus {
1627 state.inc_nny();
1629
1630 let mut p = SParser {
1631 z,
1632 buff: LexBuffer::new(),
1633 dyd: DynDataStub::new(),
1634 mode: mode.map(|m| m.to_vec()),
1635 name: name.to_vec(),
1636 };
1637
1638 let top_idx = state.top_idx();
1641 let errfunc = state.errfunc;
1642 let status = pcall(state, |s| f_parser(s, &mut p), top_idx, errfunc);
1643
1644 state.dec_nny();
1648
1649 status
1650}
1651
1652