1#[allow(unused_imports)] use crate::prelude::*;
24use lua_types::{
25 CallInfoIdx, GcRef, LuaError, LuaValue, StackIdx,
26};
27use lua_types::tagmethod::TagMethod;
28use lua_types::opcode::Instruction;
29use crate::state::LuaState;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43#[allow(non_camel_case_types)]
44#[repr(u8)]
45pub enum OpCode {
46 Move = 0,
47 LoadI = 1,
48 LoadF = 2,
49 LoadK = 3,
50 LoadKX = 4,
51 LoadFalse = 5,
52 LFalseSkip = 6,
53 LoadTrue = 7,
54 LoadNil = 8,
55 GetUpVal = 9,
56 SetUpVal = 10,
57 GetTabUp = 11,
58 GetTable = 12,
59 GetI = 13,
60 GetField = 14,
61 SetTabUp = 15,
62 SetTable = 16,
63 SetI = 17,
64 SetField = 18,
65 NewTable = 19,
66 Self_ = 20,
67 AddI = 21,
68 AddK = 22,
69 SubK = 23,
70 MulK = 24,
71 ModK = 25,
72 PowK = 26,
73 DivK = 27,
74 IDivK = 28,
75 BAndK = 29,
76 BOrK = 30,
77 BXOrK = 31,
78 ShrI = 32,
79 ShlI = 33,
80 Add = 34,
81 Sub = 35,
82 Mul = 36,
83 Mod = 37,
84 Pow = 38,
85 Div = 39,
86 IDiv = 40,
87 BAnd = 41,
88 BOr = 42,
89 BXOr = 43,
90 Shl = 44,
91 Shr = 45,
92 MmBin = 46,
93 MmBinI = 47,
94 MmBinK = 48,
95 Unm = 49,
96 BNot = 50,
97 Not = 51,
98 Len = 52,
99 Concat = 53,
100 Close = 54,
101 Tbc = 55,
102 Jmp = 56,
103 Eq = 57,
104 Lt = 58,
105 Le = 59,
106 EqK = 60,
107 EqI = 61,
108 LtI = 62,
109 LeI = 63,
110 GtI = 64,
111 GeI = 65,
112 Test = 66,
113 TestSet = 67,
114 Call = 68,
115 TailCall = 69,
116 Return = 70,
117 Return0 = 71,
118 Return1 = 72,
119 ForLoop = 73,
120 ForPrep = 74,
121 TForPrep = 75,
122 TForCall = 76,
123 TForLoop = 77,
124 SetList = 78,
125 Closure = 79,
126 VarArg = 80,
127 VarArgPrep = 81,
128 ExtraArg = 82,
129}
130
131#[allow(dead_code)]
135const NUM_OPCODES: u8 = 83;
136
137impl OpCode {
138 #[allow(non_upper_case_globals)]
145 pub const LoadKx: OpCode = OpCode::LoadKX;
146
147 #[allow(non_upper_case_globals)]
149 pub const GetUpval: OpCode = OpCode::GetUpVal;
150}
151
152pub trait InstructionExt {
156 fn opcode(&self) -> OpCode;
157 fn arg_a(&self) -> i32;
158 fn arg_b(&self) -> i32;
159 fn arg_c(&self) -> i32;
160 fn arg_k(&self) -> i32;
161 fn arg_ax(&self) -> i32;
162 fn arg_bx(&self) -> i32;
163 fn arg_s_b(&self) -> i32;
164 fn arg_s_c(&self) -> i32;
165 fn arg_s_j(&self) -> i32;
166 fn arg_s_bx(&self) -> i32;
167 fn test_k(&self) -> bool;
168 fn test_a_mode(&self) -> bool;
169 fn is_mm_mode(&self) -> bool;
170 fn is_vararg_prep(&self) -> bool;
171 fn is_in_top(&self) -> bool;
172}
173
174impl InstructionExt for Instruction {
175 #[inline(always)]
183 fn opcode(&self) -> OpCode {
184 match (self.raw() & 0x7F) as u8 {
185 0 => OpCode::Move,
186 1 => OpCode::LoadI,
187 2 => OpCode::LoadF,
188 3 => OpCode::LoadK,
189 4 => OpCode::LoadKX,
190 5 => OpCode::LoadFalse,
191 6 => OpCode::LFalseSkip,
192 7 => OpCode::LoadTrue,
193 8 => OpCode::LoadNil,
194 9 => OpCode::GetUpVal,
195 10 => OpCode::SetUpVal,
196 11 => OpCode::GetTabUp,
197 12 => OpCode::GetTable,
198 13 => OpCode::GetI,
199 14 => OpCode::GetField,
200 15 => OpCode::SetTabUp,
201 16 => OpCode::SetTable,
202 17 => OpCode::SetI,
203 18 => OpCode::SetField,
204 19 => OpCode::NewTable,
205 20 => OpCode::Self_,
206 21 => OpCode::AddI,
207 22 => OpCode::AddK,
208 23 => OpCode::SubK,
209 24 => OpCode::MulK,
210 25 => OpCode::ModK,
211 26 => OpCode::PowK,
212 27 => OpCode::DivK,
213 28 => OpCode::IDivK,
214 29 => OpCode::BAndK,
215 30 => OpCode::BOrK,
216 31 => OpCode::BXOrK,
217 32 => OpCode::ShrI,
218 33 => OpCode::ShlI,
219 34 => OpCode::Add,
220 35 => OpCode::Sub,
221 36 => OpCode::Mul,
222 37 => OpCode::Mod,
223 38 => OpCode::Pow,
224 39 => OpCode::Div,
225 40 => OpCode::IDiv,
226 41 => OpCode::BAnd,
227 42 => OpCode::BOr,
228 43 => OpCode::BXOr,
229 44 => OpCode::Shl,
230 45 => OpCode::Shr,
231 46 => OpCode::MmBin,
232 47 => OpCode::MmBinI,
233 48 => OpCode::MmBinK,
234 49 => OpCode::Unm,
235 50 => OpCode::BNot,
236 51 => OpCode::Not,
237 52 => OpCode::Len,
238 53 => OpCode::Concat,
239 54 => OpCode::Close,
240 55 => OpCode::Tbc,
241 56 => OpCode::Jmp,
242 57 => OpCode::Eq,
243 58 => OpCode::Lt,
244 59 => OpCode::Le,
245 60 => OpCode::EqK,
246 61 => OpCode::EqI,
247 62 => OpCode::LtI,
248 63 => OpCode::LeI,
249 64 => OpCode::GtI,
250 65 => OpCode::GeI,
251 66 => OpCode::Test,
252 67 => OpCode::TestSet,
253 68 => OpCode::Call,
254 69 => OpCode::TailCall,
255 70 => OpCode::Return,
256 71 => OpCode::Return0,
257 72 => OpCode::Return1,
258 73 => OpCode::ForLoop,
259 74 => OpCode::ForPrep,
260 75 => OpCode::TForPrep,
261 76 => OpCode::TForCall,
262 77 => OpCode::TForLoop,
263 78 => OpCode::SetList,
264 79 => OpCode::Closure,
265 80 => OpCode::VarArg,
266 81 => OpCode::VarArgPrep,
267 82 => OpCode::ExtraArg,
268 _ => OpCode::ExtraArg,
269 }
270 }
271 #[inline] fn arg_a(&self) -> i32 { ((self.raw() >> 7) & 0xFF) as i32 }
272 #[inline] fn arg_b(&self) -> i32 { ((self.raw() >> 16) & 0xFF) as i32 }
273 #[inline] fn arg_c(&self) -> i32 { ((self.raw() >> 24) & 0xFF) as i32 }
274 #[inline] fn arg_k(&self) -> i32 { ((self.raw() >> 15) & 0x1) as i32 }
275 #[inline] fn arg_ax(&self) -> i32 { (self.raw() >> 7) as i32 }
276 #[inline] fn arg_bx(&self) -> i32 { (self.raw() >> 15) as i32 }
277 #[inline] fn arg_s_b(&self) -> i32 { self.arg_b() - 0x7F }
278 #[inline] fn arg_s_c(&self) -> i32 { self.arg_c() - 0x7F }
279 #[inline] fn arg_s_j(&self) -> i32 { self.arg_ax() - 0xFFFFFF }
280 #[inline] fn arg_s_bx(&self) -> i32 { self.arg_bx() - 0xFFFF }
281 #[inline] fn test_k(&self) -> bool { (self.raw() & (1 << 15)) != 0 }
282 #[inline]
283 fn test_a_mode(&self) -> bool {
284 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
285 }
286 #[inline]
287 fn is_mm_mode(&self) -> bool {
288 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
289 }
290 #[inline]
291 fn is_vararg_prep(&self) -> bool {
292 matches!(self.opcode(), OpCode::VarArgPrep)
293 }
294 #[inline]
295 fn is_in_top(&self) -> bool {
296 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
297 }
298}
299
300const OP_MODE_BYTES: [u8; NUM_OPCODES as usize] = [
313 0x08, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80, 0x80, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x04, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x68, 0x68, 0x20, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, 0x09, 0x20, 0x09, 0x48, 0x28, 0x03, ];
397
398#[inline(always)]
399fn op_mode_byte(op: OpCode) -> u8 {
400 OP_MODE_BYTES[op as usize]
401}
402
403const MAX_TAG_LOOP: i32 = 2000;
407
408const NBITS: u32 = 64;
409
410#[derive(Debug, Clone, Copy, PartialEq, Eq)]
414pub(crate) enum F2Imod {
415 Eq,
417 Floor,
419 Ceil,
421}
422
423#[inline]
426fn intop_add(a: i64, b: i64) -> i64 {
427 (a as u64).wrapping_add(b as u64) as i64
428}
429
430#[inline]
431fn intop_sub(a: i64, b: i64) -> i64 {
432 (a as u64).wrapping_sub(b as u64) as i64
433}
434
435#[inline]
436fn intop_mul(a: i64, b: i64) -> i64 {
437 (a as u64).wrapping_mul(b as u64) as i64
438}
439
440#[inline]
442fn intop_shr(x: i64, n: u32) -> i64 {
443 (x as u64 >> n) as i64
445}
446
447#[inline]
448fn intop_shl(x: i64, n: u32) -> i64 {
449 (x as u64).wrapping_shl(n) as i64
450}
451
452#[inline]
453fn intop_band(a: i64, b: i64) -> i64 { ((a as u64) & (b as u64)) as i64 }
454#[inline]
455fn intop_bor(a: i64, b: i64) -> i64 { ((a as u64) | (b as u64)) as i64 }
456#[inline]
457fn intop_bxor(a: i64, b: i64) -> i64 { ((a as u64) ^ (b as u64)) as i64 }
458
459#[inline]
464fn int_fits_float(i: i64) -> bool {
465 const MAXINTFITSF: u64 = 1u64 << f64::MANTISSA_DIGITS;
466 (MAXINTFITSF.wrapping_add(i as u64)) <= 2 * MAXINTFITSF
467}
468
469fn str_to_number(obj: &LuaValue) -> Option<LuaValue> {
475 let s = match obj {
477 LuaValue::Str(ts) => ts.as_bytes().to_vec(),
478 _ => return None,
479 };
480 let trimmed = trim_whitespace(&s);
482 if trimmed.is_empty() {
483 return None;
484 }
485 let mut result = LuaValue::Nil;
486 if crate::object::str2num(trimmed, &mut result) != 0 {
487 return Some(result);
488 }
489 None
490}
491
492fn trim_whitespace(s: &[u8]) -> &[u8] {
493 let start = s.iter().position(|&b| !b.is_ascii_whitespace()).unwrap_or(s.len());
494 let end = s.iter().rposition(|&b| !b.is_ascii_whitespace()).map(|i| i + 1).unwrap_or(0);
495 if start <= end { &s[start..end] } else { &s[0..0] }
496}
497
498pub(crate) fn tonumber_(obj: &LuaValue) -> Option<f64> {
504 if let LuaValue::Int(i) = obj {
505 return Some(*i as f64);
506 }
507 if let Some(v) = str_to_number(obj) {
508 return match v {
509 LuaValue::Float(f) => Some(f),
510 LuaValue::Int(i) => Some(i as f64),
511 _ => None,
512 };
513 }
514 None
515}
516
517fn tonumber(obj: &LuaValue) -> Option<f64> {
519 if let LuaValue::Float(f) = obj {
520 return Some(*f);
521 }
522 tonumber_(obj)
523}
524
525pub(crate) fn flt_to_integer(n: f64, mode: F2Imod) -> Option<i64> {
528 let f = n.floor();
529 if n != f {
530 match mode {
531 F2Imod::Eq => return None,
532 F2Imod::Ceil => {
533 let f = f + 1.0;
535 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
537 return Some(f as i64);
538 }
539 return None;
540 }
541 F2Imod::Floor => { }
542 }
543 }
544 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
545 Some(f as i64)
546 } else {
547 None
548 }
549}
550
551pub(crate) fn to_integer_ns(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
553 if let LuaValue::Float(f) = obj {
554 return flt_to_integer(*f, mode);
555 }
556 if let LuaValue::Int(i) = obj {
557 return Some(*i);
558 }
559 None
560}
561
562pub(crate) fn to_integer(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
564 let coerced;
565 let obj = if let Some(v) = str_to_number(obj) {
566 coerced = v;
567 &coerced
568 } else {
569 obj
570 };
571 to_integer_ns(obj, mode)
572}
573
574fn forlimit(
581 state: &mut LuaState,
582 init: i64,
583 lim: &LuaValue,
584 step: i64,
585) -> Result<(bool, i64), LuaError> {
586 let round = if step < 0 { F2Imod::Ceil } else { F2Imod::Floor };
587 if let Some(p) = to_integer(lim, round) {
588 let skip = if step > 0 { init > p } else { init < p };
589 return Ok((skip, p));
590 }
591 let flim = match tonumber(lim) {
592 Some(f) => f,
593 None => return Err(crate::debug::for_error(state, lim, b"limit")),
594 };
595 if 0.0_f64 < flim {
596 if step < 0 {
598 return Ok((true, 0));
599 }
600 Ok((false, i64::MAX))
601 } else {
602 if step > 0 {
604 return Ok((true, 0));
605 }
606 Ok((false, i64::MIN))
607 }
608}
609
610pub(crate) fn forprep(state: &mut LuaState, ra: StackIdx) -> Result<bool, LuaError> {
615 let pinit = state.get_at(ra);
616 let plimit = state.get_at(ra + 1);
617 let pstep = state.get_at(ra + 2);
618
619 if let (LuaValue::Int(init), LuaValue::Int(step)) = (&pinit, &pstep) {
620 let init = *init;
621 let step = *step;
622 if step == 0 {
623 return Err(LuaError::runtime(format_args!("'for' step is zero")));
624 }
625 state.set_at(ra + 3, LuaValue::Int(init));
626
627 let (skip, limit) = forlimit(state, init, &plimit, step)?;
628 if skip {
629 return Ok(true);
630 }
631 let count: u64 = if step > 0 {
632 let c = (limit as u64).wrapping_sub(init as u64);
633 if step != 1 { c / (step as u64) } else { c }
634 } else {
635 let c = (init as u64).wrapping_sub(limit as u64);
636 c / (((-(step + 1)) as u64).wrapping_add(1))
637 };
638 state.set_at(ra + 1, LuaValue::Int(count as i64));
639 Ok(false)
640 } else {
641 let limit_f = match tonumber(&plimit) {
642 Some(f) => f,
643 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
644 };
645 let step_f = match tonumber(&pstep) {
646 Some(f) => f,
647 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
648 };
649 let init_f = match tonumber(&pinit) {
650 Some(f) => f,
651 None => return Err(crate::debug::for_error(state, &pinit, b"initial value")),
652 };
653 if step_f == 0.0 {
654 return Err(LuaError::runtime(format_args!("'for' step is zero")));
655 }
656 let skip = if step_f > 0.0 { limit_f < init_f } else { init_f < limit_f };
657 if skip {
658 return Ok(true);
659 }
660 state.set_at(ra + 1, LuaValue::Float(limit_f));
662 state.set_at(ra + 2, LuaValue::Float(step_f));
663 state.set_at(ra, LuaValue::Float(init_f));
664 state.set_at(ra + 3, LuaValue::Float(init_f));
665 Ok(false)
666 }
667}
668
669fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
671 let step = match state.get_at(ra + 2) {
673 LuaValue::Float(f) => f,
674 _ => return false,
675 };
676 let limit = match state.get_at(ra + 1) {
677 LuaValue::Float(f) => f,
678 _ => return false,
679 };
680 let idx = match state.get_at(ra) {
681 LuaValue::Float(f) => f,
682 _ => return false,
683 };
684 let idx = idx + step;
685 if if step > 0.0 { idx <= limit } else { limit <= idx } {
686 state.set_at(ra, LuaValue::Float(idx));
687 state.set_at(ra + 3, LuaValue::Float(idx));
688 true
689 } else {
690 false
691 }
692}
693
694pub(crate) fn finish_get(
700 state: &mut LuaState,
701 t_val: LuaValue,
702 key: LuaValue,
703 result_idx: StackIdx,
704 slot_empty: bool,
705 t_idx: Option<StackIdx>,
706) -> Result<(), LuaError> {
707 let mut t = t_val;
708 let mut t_idx = t_idx;
709 for _loop in 0..MAX_TAG_LOOP {
710 let tm: LuaValue;
711 if slot_empty && !matches!(t, LuaValue::Table(_)) {
712 tm = state.get_tm_by_obj(&t, TagMethod::Index);
713 if matches!(tm, LuaValue::Nil) {
714 return Err(match t_idx {
715 Some(idx) => crate::debug::type_error(state, &t, idx, b"index"),
716 None => LuaError::type_error(&t, "index"),
717 });
718 }
719 } else {
720 let mt = state.table_metatable(&t);
721 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
722 if matches!(tm, LuaValue::Nil) {
723 state.set_at(result_idx, LuaValue::Nil);
724 return Ok(());
725 }
726 }
727 if matches!(tm, LuaValue::Function(_)) {
728 state.call_tm_res(tm, &t, &key, result_idx)?;
729 return Ok(());
730 }
731 t = tm.clone();
732 t_idx = None;
733 if let Some(v) = state.fast_get(&t, &key)? {
734 state.set_at(result_idx, v);
735 return Ok(());
736 }
737 }
739 Err(LuaError::runtime(format_args!("'__index' chain too long; possible loop")))
740}
741
742pub(crate) fn finish_set(
751 state: &mut LuaState,
752 t_val: LuaValue,
753 key: LuaValue,
754 val: LuaValue,
755 _slot_present: bool,
756 t_idx: Option<StackIdx>,
757 var_hint: Option<(&[u8], &[u8])>,
758) -> Result<(), LuaError> {
759 let mut t = t_val;
760 let mut t_idx = t_idx;
761 for _loop in 0..MAX_TAG_LOOP {
762 let tm: LuaValue;
763 if matches!(t, LuaValue::Table(_)) {
764 let mt = state.table_metatable(&t);
765 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
766 if matches!(tm, LuaValue::Nil) {
767 state.table_raw_set(&t, key, val.clone())?;
768 state.gc_barrier_back(&t, &val);
769 return Ok(());
770 }
771 } else {
772 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
773 if matches!(tm, LuaValue::Nil) {
774 return Err(match (t_idx, var_hint) {
775 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
776 (None, Some((kind, name))) => {
777 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
778 }
779 (None, None) => LuaError::type_error(&t, "index"),
780 });
781 }
782 }
783 if matches!(tm, LuaValue::Function(_)) {
784 state.call_tm(tm, &t, &key, &val)?;
785 return Ok(());
786 }
787 t = tm.clone();
788 t_idx = None;
789 if state.fast_get(&t, &key)?.is_some() {
790 state.table_raw_set(&t, key.clone(), val.clone())?;
791 state.gc_barrier_back(&t, &val);
792 return Ok(());
793 }
794 }
795 Err(LuaError::runtime(format_args!("'__newindex' chain too long; possible loop")))
796}
797
798fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
809 let mut s1 = s1;
812 let mut s2 = s2;
813 loop {
814 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
816 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
817 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
819 if seg_cmp != std::cmp::Ordering::Equal {
820 return seg_cmp;
821 }
822 if z2 == s2.len() {
824 if z1 == s1.len() {
826 return std::cmp::Ordering::Equal;
827 }
828 return std::cmp::Ordering::Greater; }
830 if z1 == s1.len() {
831 return std::cmp::Ordering::Less; }
833 s1 = &s1[z1 + 1..];
835 s2 = &s2[z2 + 1..];
836 }
837}
838
839#[inline]
842fn lt_int_float(i: i64, f: f64) -> bool {
843 if int_fits_float(i) {
844 (i as f64) < f
845 } else {
846 match flt_to_integer(f, F2Imod::Ceil) {
847 Some(fi) => i < fi,
848 None => f > 0.0, }
850 }
851}
852
853#[inline]
854fn le_int_float(i: i64, f: f64) -> bool {
855 if int_fits_float(i) {
856 (i as f64) <= f
857 } else {
858 match flt_to_integer(f, F2Imod::Floor) {
859 Some(fi) => i <= fi,
860 None => f > 0.0,
861 }
862 }
863}
864
865#[inline]
866fn lt_float_int(f: f64, i: i64) -> bool {
867 if int_fits_float(i) {
868 f < (i as f64)
869 } else {
870 match flt_to_integer(f, F2Imod::Floor) {
871 Some(fi) => fi < i,
872 None => f < 0.0,
873 }
874 }
875}
876
877#[inline]
878fn le_float_int(f: f64, i: i64) -> bool {
879 if int_fits_float(i) {
880 f <= (i as f64)
881 } else {
882 match flt_to_integer(f, F2Imod::Ceil) {
883 Some(fi) => fi <= i,
884 None => f < 0.0,
885 }
886 }
887}
888
889#[inline]
890fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
891 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
892 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
893 match (l, r) {
894 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
895 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
896 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
897 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
898 _ => false,
899 }
900}
901
902#[inline]
903fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
904 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
905 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
906 match (l, r) {
907 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
908 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
909 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
910 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
911 _ => false,
912 }
913}
914
915fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
917 debug_assert!(!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
918 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))));
919 match (l, r) {
920 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
921 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
922 }
923 _ => state.call_order_tm(l, r, TagMethod::Lt),
924 }
925}
926
927pub(crate) fn less_than(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
928 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
929 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
930 {
931 Ok(lt_num(l, r))
932 } else {
933 less_than_others(state, l, r)
934 }
935}
936
937fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
938 match (l, r) {
939 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
940 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
941 }
942 _ => state.call_order_tm(l, r, TagMethod::Le),
943 }
944}
945
946pub(crate) fn less_equal(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
947 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
948 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
949 {
950 Ok(le_num(l, r))
951 } else {
952 less_equal_others(state, l, r)
953 }
954}
955
956pub(crate) fn equal_obj(
960 state: Option<&mut LuaState>,
961 t1: &LuaValue,
962 t2: &LuaValue,
963) -> Result<bool, LuaError> {
964 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
967 if !same_variant {
968 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
969 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
970 if !(t1_is_num && t2_is_num) {
971 return Ok(false);
972 }
973 let i1 = to_integer_ns(t1, F2Imod::Eq);
975 let i2 = to_integer_ns(t2, F2Imod::Eq);
976 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
977 }
978
979 match (t1, t2) {
980 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
981 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
982 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
983 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
984 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
985 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
986 use lua_types::closure::LuaClosure;
987 let same = match (f1, f2) {
988 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
989 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
990 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
991 _ => false,
992 };
993 Ok(same)
994 }
995 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
996 Ok(s1 == s2)
999 }
1000 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1001 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1004 return Ok(true);
1005 }
1006 let Some(state) = state else { return Ok(false); };
1007 let tm1 = state.fast_tm_ud(u1, TagMethod::Eq);
1008 let tm = if matches!(tm1, LuaValue::Nil) {
1009 state.fast_tm_ud(u2, TagMethod::Eq)
1010 } else {
1011 tm1
1012 };
1013 if matches!(tm, LuaValue::Nil) {
1014 return Ok(false);
1015 }
1016 let result = state.call_tm_res_bool(tm, t1, t2)?;
1017 Ok(result)
1018 }
1019 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1020 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1021 return Ok(true);
1022 }
1023 let Some(state) = state else { return Ok(false); };
1024 let mt1 = h1.metatable();
1026 let mt2 = h2.metatable();
1027 let tm1 = state.fast_tm_table(mt1.as_ref(), TagMethod::Eq);
1028 let tm = if matches!(tm1, LuaValue::Nil) {
1029 state.fast_tm_table(mt2.as_ref(), TagMethod::Eq)
1030 } else {
1031 tm1
1032 };
1033 if matches!(tm, LuaValue::Nil) {
1034 return Ok(false);
1035 }
1036 let result = state.call_tm_res_bool(tm, t1, t2)?;
1037 Ok(result)
1038 }
1039 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1040 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1041 }
1042}
1043
1044fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1048 buf.clear();
1049 let mut remaining = n;
1050 loop {
1051 let idx = top - remaining as i32;
1052 let v = state.get_at(idx);
1053 if let LuaValue::Str(ts) = v {
1054 buf.extend_from_slice(ts.as_bytes());
1055 }
1056 if remaining <= 1 {
1057 break;
1058 }
1059 remaining -= 1;
1060 }
1061}
1062
1063pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1065 if total == 1 {
1066 return Ok(());
1067 }
1068 let mut total = total;
1069 loop {
1070 let top = state.top_idx();
1071 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1076 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1077 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1079 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1080 if !top2_coercible || !top1_stringlike {
1081 state.try_concat_tm(&v_tm1, &v_tm2)?;
1082 total -= 1;
1087 let top = state.top_idx();
1088 state.set_top(top - 1);
1089 if total <= 1 {
1090 break;
1091 }
1092 continue;
1093 }
1094
1095 let is_empty = |v: &LuaValue| -> bool {
1096 matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty())
1097 };
1098
1099 let n: u32;
1100 if is_empty(&v_tm1) {
1101 state.coerce_to_string(top - 2)?;
1102 n = 2;
1103 } else if is_empty(&v_tm2) {
1104 state.coerce_to_string(top - 1)?;
1107 let v = state.get_at(top - 1);
1108 state.set_at(top - 2, v);
1109 n = 2;
1110 } else {
1111 state.coerce_to_string(top - 1)?;
1113 let s1 = match state.get_at(top - 1) {
1114 LuaValue::Str(ts) => ts.as_bytes().len(),
1115 _ => 0,
1116 };
1117 let mut total_len = s1;
1118 let mut count: u32 = 1;
1119 let top = state.top_idx();
1120 loop {
1121 if count as i32 >= total {
1122 break;
1123 }
1124 let idx = top - (count as i32 + 1);
1125 let v = state.get_at(idx);
1126 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1127 break;
1128 }
1129 state.coerce_to_string(idx)?;
1130 let l = match state.get_at(idx) {
1131 LuaValue::Str(ts) => ts.as_bytes().len(),
1132 _ => 0,
1133 };
1134 if l >= usize::MAX - total_len {
1135 state.set_top(top - total as i32);
1137 return Err(LuaError::runtime(format_args!("string length overflow")));
1138 }
1139 total_len += l;
1140 count += 1;
1141 }
1142 n = count;
1143
1144 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1146 let top = state.top_idx();
1147 copy_to_buf(state, top, n, &mut buf);
1148 let ts = state.intern_or_create_str(&buf)?;
1149 state.set_at(top - n as i32, LuaValue::Str(ts));
1150 }
1151 total -= n as i32 - 1;
1152 let top = state.top_idx();
1153 state.set_top(top - ((n - 1) as i32));
1154
1155 if total <= 1 {
1156 break;
1157 }
1158 }
1159 Ok(())
1160}
1161
1162pub(crate) fn obj_len(state: &mut LuaState, ra: StackIdx, rb: LuaValue) -> Result<(), LuaError> {
1166 match &rb {
1167 LuaValue::Table(_) => {
1168 let mt = state.table_metatable(&rb);
1170 let tm = state.fast_tm_table(mt.as_ref(), TagMethod::Len);
1171 if matches!(tm, LuaValue::Nil) {
1172 let n = state.table_length(&rb)?;
1173 state.set_at(ra, LuaValue::Int(n as i64));
1174 return Ok(());
1175 }
1176 state.call_tm_res(tm, &rb, &rb, ra)?;
1178 }
1179 LuaValue::Str(ts) => {
1180 let n = ts.len();
1183 state.set_at(ra, LuaValue::Int(n as i64));
1184 }
1185 other => {
1186 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1188 if matches!(tm, LuaValue::Nil) {
1189 return Err(LuaError::type_error(other, "get length of"));
1190 }
1191 state.call_tm_res(tm, &rb, &rb, ra)?;
1192 }
1193 }
1194 Ok(())
1195}
1196
1197pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1201 if (n as u64).wrapping_add(1) <= 1 {
1202 if n == 0 {
1203 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1204 }
1205 return Ok(intop_sub(0, m));
1206 }
1207 let q = m / n;
1208 if (m ^ n) < 0 && m % n != 0 {
1210 Ok(q - 1)
1211 } else {
1212 Ok(q)
1213 }
1214}
1215
1216pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1218 if (n as u64).wrapping_add(1) <= 1 {
1219 if n == 0 {
1220 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1221 }
1222 return Ok(0);
1223 }
1224 let r = m % n;
1225 if r != 0 && (r ^ n) < 0 {
1226 Ok(r + n)
1227 } else {
1228 Ok(r)
1229 }
1230}
1231
1232pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1234 let r = m % n;
1235 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1236 if opposite_signs {
1237 r + n
1238 } else {
1239 r
1240 }
1241}
1242
1243pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1246 use TagMethod::*;
1247 match i {
1248 0 => Index, 1 => NewIndex, 2 => Gc, 3 => Mode, 4 => Len, 5 => Eq,
1249 6 => Add, 7 => Sub, 8 => Mul, 9 => Mod, 10 => Pow, 11 => Div,
1250 12 => Idiv, 13 => Band, 14 => Bor, 15 => Bxor, 16 => Shl, 17 => Shr,
1251 18 => Unm, 19 => Bnot, 20 => Lt, 21 => Le, 22 => Concat, 23 => Call,
1252 24 => Close,
1253 _ => Index,
1254 }
1255}
1256
1257pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1260 imod(a, b)
1261}
1262
1263pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1266 idiv(a, b)
1267}
1268
1269pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1272 Ok(fmodf(a, b))
1273}
1274
1275pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1277 if y < 0 {
1278 if y <= -(NBITS as i64) {
1279 0
1280 } else {
1281 intop_shr(x, (-y) as u32)
1282 }
1283 } else {
1284 if y >= NBITS as i64 {
1285 0
1286 } else {
1287 intop_shl(x, y as u32)
1288 }
1289 }
1290}
1291
1292fn push_closure(
1298 state: &mut LuaState,
1299 proto_idx: usize, ci: CallInfoIdx,
1301 base: StackIdx,
1302 ra: StackIdx,
1303) -> Result<(), LuaError> {
1304 state.push_closure(proto_idx, ci, base, ra)
1308}
1309
1310pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1315 let ci = state.current_ci_idx();
1319 let base = state.ci_base(ci);
1320 let inst = state.ci_prev_instruction(ci);
1321 let op = inst.opcode();
1322
1323 match op {
1324 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1326 let prev_inst = state.ci_prev2_instruction(ci);
1327 let a = prev_inst.arg_a();
1328 state.dec_top();
1329 let top = state.top_idx();
1330 let v = state.get_at(top);
1331 state.set_at(base + a, v);
1332 }
1333 OpCode::Unm | OpCode::BNot | OpCode::Len
1335 | OpCode::GetTabUp | OpCode::GetTable | OpCode::GetI
1336 | OpCode::GetField | OpCode::Self_ => {
1337 let a = inst.arg_a();
1338 state.dec_top();
1339 let top = state.top_idx();
1340 let v = state.get_at(top);
1341 state.set_at(base + a, v);
1342 }
1343 OpCode::Lt | OpCode::Le | OpCode::LtI | OpCode::LeI
1347 | OpCode::GtI | OpCode::GeI | OpCode::Eq => {
1348 let top_minus1 = state.top_idx() - 1;
1349 let v = state.get_at(top_minus1);
1350 let res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1351 state.dec_top();
1352 if (res as i32) != inst.arg_k() {
1353 state.ci_skip_next_instruction(ci);
1354 }
1355 }
1357 OpCode::Concat => {
1363 let top = state.top_idx() - 1; let a = inst.arg_a();
1365 let total_concat = (top - 1 - (base + a)) as i32;
1366 let v = state.get_at(top);
1367 state.set_at(top - 2, v);
1368 state.set_top(top - 1);
1369 concat(state, total_concat)?;
1370 }
1371 OpCode::Close => {
1372 state.ci_step_pc_back(ci);
1373 }
1374 OpCode::Return => {
1378 let a = inst.arg_a();
1379 let ra = base + a;
1380 let nres = state.ci_nres(ci);
1381 state.set_top(ra + nres);
1382 state.ci_step_pc_back(ci);
1383 }
1384 other => {
1385 debug_assert!(
1386 matches!(
1387 other,
1388 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1389 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1390 ),
1391 "unexpected opcode in finish_op: {:?}",
1392 other
1393 );
1394 }
1395 }
1396 Ok(())
1397}
1398
1399pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1411 let mut trap: bool;
1412
1413 'startfunc: loop {
1415 trap = state.hook_mask() != 0;
1416
1417 'returning: loop {
1420 let cl = match state.ci_lua_closure(ci) {
1421 Some(c) => c,
1422 None => {
1423 return Err(LuaError::runtime(format_args!(
1424 "internal: execute called on non-Lua frame"
1425 )));
1426 }
1427 };
1428 let mut pc: u32 = state.ci_savedpc(ci);
1430
1431 if trap {
1432 trap = state.trace_call(ci)?;
1433 }
1434 let mut base: StackIdx = state.ci_base(ci);
1435
1436 'dispatch: loop {
1438 if trap {
1439 trap = state.trace_exec(ci, pc)?;
1440 base = state.ci_base(ci); }
1442 let i: Instruction = state.proto_code(&cl, pc);
1443 pc += 1;
1444 let op = i.opcode();
1445
1446 debug_assert!(base == state.ci_base(ci));
1447
1448 #[cfg(debug_assertions)]
1452 {
1453 let op_mode = op_mode_byte(op);
1454 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1455 state.set_top(base);
1456 }
1457 }
1458
1459 match op {
1460 OpCode::Move => {
1462 let ra = base + i.arg_a();
1463 let rb = base + i.arg_b();
1464 let v = state.get_at(rb);
1465 state.set_at(ra, v);
1466 }
1467 OpCode::LoadI => {
1469 let ra = base + i.arg_a();
1470 let b = i.arg_s_bx() as i64;
1471 state.set_at(ra, LuaValue::Int(b));
1472 }
1473 OpCode::LoadF => {
1475 let ra = base + i.arg_a();
1476 let b = i.arg_s_bx() as f64;
1477 state.set_at(ra, LuaValue::Float(b));
1478 }
1479 OpCode::LoadK => {
1481 let ra = base + i.arg_a();
1482 let k_idx = i.arg_bx() as usize;
1483 let v = state.proto_const(&cl, k_idx).clone();
1484 state.set_at(ra, v);
1485 }
1486 OpCode::LoadKX => {
1488 let ra = base + i.arg_a();
1489 let extra = state.proto_code(&cl, pc);
1490 pc += 1;
1491 let k_idx = extra.arg_ax() as usize;
1492 let v = state.proto_const(&cl, k_idx).clone();
1493 state.set_at(ra, v);
1494 }
1495 OpCode::LoadFalse => {
1497 let ra = base + i.arg_a();
1498 state.set_at(ra, LuaValue::Bool(false));
1499 }
1500 OpCode::LFalseSkip => {
1502 let ra = base + i.arg_a();
1503 state.set_at(ra, LuaValue::Bool(false));
1504 pc += 1;
1505 }
1506 OpCode::LoadTrue => {
1508 let ra = base + i.arg_a();
1509 state.set_at(ra, LuaValue::Bool(true));
1510 }
1511 OpCode::LoadNil => {
1513 let ra = base + i.arg_a();
1514 let b = i.arg_b();
1515 for k in 0..=b {
1516 state.set_at(ra + k, LuaValue::Nil);
1517 }
1518 }
1519 OpCode::GetUpVal => {
1521 let ra = base + i.arg_a();
1522 let b = i.arg_b() as usize;
1523 let v = state.upvalue_get(&cl, b);
1524 state.set_at(ra, v);
1525 }
1526 OpCode::SetUpVal => {
1529 let ra = base + i.arg_a();
1530 let b = i.arg_b() as usize;
1531 let v = state.stack[ra.0 as usize].val;
1532 let uv = cl.upval(b);
1533 match uv.try_open_payload() {
1534 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1535 state.stack[idx.0 as usize].val = v;
1536 }
1537 _ => {
1538 state.upvalue_set(&cl, b, v)?;
1539 }
1540 }
1541 }
1542 OpCode::GetTabUp => {
1546 let ra = base + i.arg_a();
1547 let b = i.arg_b() as usize;
1548 let k_idx = i.arg_c() as usize;
1549 let upval = state.upvalue_get(&cl, b);
1550 let key = state.proto_const(&cl, k_idx).clone();
1551 match state.fast_get_short_str(&upval, &key)? {
1552 Some(v) => state.set_at(ra, v),
1553 None => {
1554 state.set_ci_savedpc(ci, pc);
1555 state.set_top(state.ci_top(ci));
1556 finish_get(state, upval, key, ra, true, None)?;
1557 trap = state.ci_trap(ci);
1558 }
1559 }
1560 }
1561 OpCode::GetTable => {
1564 let ra = base + i.arg_a();
1565 let rb_idx = base + i.arg_b();
1566 let rb_v = state.get_at(rb_idx);
1567 let rc_v = state.get_at(base + i.arg_c());
1568 let fast_result = if let LuaValue::Int(n) = &rc_v {
1569 state.fast_get_int(&rb_v, *n)?
1570 } else {
1571 state.fast_get(&rb_v, &rc_v)?
1572 };
1573 match fast_result {
1574 Some(v) => state.set_at(ra, v),
1575 None => {
1576 state.set_ci_savedpc(ci, pc);
1577 state.set_top(state.ci_top(ci));
1578 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1579 trap = state.ci_trap(ci);
1580 }
1581 }
1582 }
1583 OpCode::GetI => {
1587 let ra = base + i.arg_a();
1588 let rb_idx = base + i.arg_b();
1589 let rb_v = state.get_at(rb_idx);
1590 let c = i.arg_c() as i64;
1591 match state.fast_get_int(&rb_v, c)? {
1592 Some(v) => state.set_at(ra, v),
1593 None => {
1594 let key = LuaValue::Int(c);
1595 state.set_ci_savedpc(ci, pc);
1596 state.set_top(state.ci_top(ci));
1597 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1598 trap = state.ci_trap(ci);
1599 }
1600 }
1601 }
1602 OpCode::GetField => {
1604 let ra = base + i.arg_a();
1605 let rb_idx = base + i.arg_b();
1606 let rb_v = state.get_at(rb_idx);
1607 let k_idx = i.arg_c() as usize;
1608 let key = state.proto_const(&cl, k_idx).clone();
1609 match state.fast_get_short_str(&rb_v, &key)? {
1610 Some(v) => state.set_at(ra, v),
1611 None => {
1612 state.set_ci_savedpc(ci, pc);
1613 state.set_top(state.ci_top(ci));
1614 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1615 trap = state.ci_trap(ci);
1616 }
1617 }
1618 }
1619 OpCode::SetTabUp => {
1621 let a = i.arg_a() as usize;
1622 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1624 state.proto_const(&cl, i.arg_c() as usize).clone()
1625 } else {
1626 state.get_at(base + i.arg_c())
1627 };
1628 let upval = state.upvalue_get(&cl, a);
1629 let key = state.proto_const(&cl, b_idx).clone();
1630 match state.fast_get_short_str(&upval, &key)? {
1631 Some(_slot) => {
1632 state.table_raw_set(&upval, key, rc_v.clone())?;
1633 state.gc_barrier_back(&upval, &rc_v);
1634 }
1635 None => {
1636 state.set_ci_savedpc(ci, pc);
1637 state.set_top(state.ci_top(ci));
1638 let upval_name: Vec<u8> = cl
1639 .proto
1640 .upvalues
1641 .get(a)
1642 .and_then(|uv| uv.name.as_ref())
1643 .map(|s| s.as_bytes().to_vec())
1644 .unwrap_or_else(|| b"?".to_vec());
1645 let hint: Option<(&[u8], &[u8])> =
1646 Some((b"upvalue", &upval_name));
1647 finish_set(state, upval, key, rc_v, false, None, hint)?;
1648 trap = state.ci_trap(ci);
1649 }
1650 }
1651 }
1652 OpCode::SetTable => {
1654 let ra_idx = base + i.arg_a();
1655 let ra_v = state.get_at(ra_idx);
1656 let rb_v = state.get_at(base + i.arg_b());
1657 let rc_v = if i.test_k() {
1658 state.proto_const(&cl, i.arg_c() as usize).clone()
1659 } else {
1660 state.get_at(base + i.arg_c())
1661 };
1662 let fast = if let LuaValue::Int(n) = &rb_v {
1663 state.fast_get_int(&ra_v, *n)?
1664 } else {
1665 state.fast_get(&ra_v, &rb_v)?
1666 };
1667 if fast.is_some() {
1668 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1669 state.gc_barrier_back(&ra_v, &rc_v);
1670 } else {
1671 state.set_ci_savedpc(ci, pc);
1672 state.set_top(state.ci_top(ci));
1673 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1674 trap = state.ci_trap(ci);
1675 }
1676 }
1677 OpCode::SetI => {
1679 let ra_idx = base + i.arg_a();
1680 let ra_v = state.get_at(ra_idx);
1681 let c = i.arg_b() as i64;
1682 let rc_v = if i.test_k() {
1683 state.proto_const(&cl, i.arg_c() as usize).clone()
1684 } else {
1685 state.get_at(base + i.arg_c())
1686 };
1687 let fast = state.fast_get_int(&ra_v, c)?;
1688 if fast.is_some() {
1689 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1690 state.gc_barrier_back(&ra_v, &rc_v);
1691 } else {
1692 state.set_ci_savedpc(ci, pc);
1693 state.set_top(state.ci_top(ci));
1694 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1695 trap = state.ci_trap(ci);
1696 }
1697 }
1698 OpCode::SetField => {
1700 let ra_idx = base + i.arg_a();
1701 let ra_v = state.get_at(ra_idx);
1702 let b_idx = i.arg_b() as usize;
1703 let key = state.proto_const(&cl, b_idx).clone();
1704 let rc_v = if i.test_k() {
1705 state.proto_const(&cl, i.arg_c() as usize).clone()
1706 } else {
1707 state.get_at(base + i.arg_c())
1708 };
1709 match state.fast_get_short_str(&ra_v, &key)? {
1710 Some(_) => {
1711 state.table_raw_set(&ra_v, key, rc_v.clone())?;
1712 state.gc_barrier_back(&ra_v, &rc_v);
1713 }
1714 None => {
1715 state.set_ci_savedpc(ci, pc);
1716 state.set_top(state.ci_top(ci));
1717 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
1718 trap = state.ci_trap(ci);
1719 }
1720 }
1721 }
1722 OpCode::NewTable => {
1725 let ra = base + i.arg_a();
1726 let mut b = i.arg_b();
1727 let mut c = i.arg_c();
1728 if b > 0 {
1729 b = 1 << (b - 1);
1730 }
1731 if i.test_k() {
1732 let extra = state.proto_code(&cl, pc);
1733 pc += 1;
1734 const MAXARG_C: i32 = (1 << 8) - 1;
1735 c += extra.arg_ax() * (MAXARG_C + 1);
1736 } else {
1737 pc += 1; }
1739 state.set_top(ra + 1);
1740 let t = state.new_table();
1741 state.set_at(ra, LuaValue::Table(t.clone()));
1742 if b != 0 || c != 0 {
1743 state.table_resize(&t, c as usize, b as usize)?;
1744 }
1745 state.set_ci_savedpc(ci, pc);
1746 state.set_top(ra + 1);
1747 state.gc_cond_step();
1748 trap = state.ci_trap(ci);
1749 }
1750 OpCode::Self_ => {
1752 let ra = base + i.arg_a();
1753 let rb_idx = base + i.arg_b();
1754 let rb_v = state.get_at(rb_idx);
1755 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
1757 state.proto_const(&cl, k_idx).clone()
1758 } else {
1759 state.get_at(base + i.arg_c())
1760 };
1761 state.set_at(ra + 1, rb_v.clone());
1762 match state.fast_get_short_str(&rb_v, &key)? {
1763 Some(v) => state.set_at(ra, v),
1764 None => {
1765 state.set_ci_savedpc(ci, pc);
1766 state.set_top(state.ci_top(ci));
1767 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1768 trap = state.ci_trap(ci);
1769 }
1770 }
1771 }
1772 OpCode::AddI => {
1774 let ra = base + i.arg_a();
1775 let rb = base + i.arg_b();
1776 let imm = i.arg_s_c() as i64;
1777 if let Some(iv1) = state.get_int_at(rb) {
1778 pc += 1;
1779 state.set_at(ra, LuaValue::Int(intop_add(iv1, imm)));
1780 } else if let Some(nb) = state.get_float_at(rb) {
1781 pc += 1;
1782 state.set_at(ra, LuaValue::Float(nb + imm as f64));
1783 }
1784 }
1785 OpCode::AddK => {
1787 let ra = base + i.arg_a();
1788 let rb = base + i.arg_b();
1789 let kidx = i.arg_c() as usize;
1790 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1791 pc += 1;
1792 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
1793 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1794 pc += 1;
1795 state.set_at(ra, LuaValue::Float(n1 + n2));
1796 }
1797 }
1798 OpCode::SubK => {
1799 let ra = base + i.arg_a();
1800 let rb = base + i.arg_b();
1801 let kidx = i.arg_c() as usize;
1802 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1803 pc += 1;
1804 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
1805 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1806 pc += 1;
1807 state.set_at(ra, LuaValue::Float(n1 - n2));
1808 }
1809 }
1810 OpCode::MulK => {
1811 let ra = base + i.arg_a();
1812 let rb = base + i.arg_b();
1813 let kidx = i.arg_c() as usize;
1814 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1815 pc += 1;
1816 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1817 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1818 pc += 1;
1819 state.set_at(ra, LuaValue::Float(n1 * n2));
1820 }
1821 }
1822 OpCode::ModK => {
1823 let ra = base + i.arg_a();
1824 let v1 = state.get_at(base + i.arg_b());
1825 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1826 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
1828 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1829 |a, b| imod(a, b), fmodf)?;
1830 }
1831 OpCode::PowK => {
1832 let ra = base + i.arg_a();
1833 let rb = base + i.arg_b();
1834 let kidx = i.arg_c() as usize;
1835 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1836 pc += 1;
1837 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1838 state.set_at(ra, LuaValue::Float(r));
1839 }
1840 }
1841 OpCode::DivK => {
1842 let ra = base + i.arg_a();
1843 let rb = base + i.arg_b();
1844 let kidx = i.arg_c() as usize;
1845 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1846 pc += 1;
1847 state.set_at(ra, LuaValue::Float(n1 / n2));
1848 }
1849 }
1850 OpCode::IDivK => {
1851 let ra = base + i.arg_a();
1852 let v1 = state.get_at(base + i.arg_b());
1853 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1854 state.set_ci_savedpc(ci, pc);
1855 state.set_top(state.ci_top(ci));
1856 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1857 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
1858 }
1859 OpCode::BAndK => {
1860 let ra = base + i.arg_a();
1861 let v1 = state.get_at(base + i.arg_b());
1862 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1863 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
1864 }
1865 OpCode::BOrK => {
1866 let ra = base + i.arg_a();
1867 let v1 = state.get_at(base + i.arg_b());
1868 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1869 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
1870 }
1871 OpCode::BXOrK => {
1872 let ra = base + i.arg_a();
1873 let v1 = state.get_at(base + i.arg_b());
1874 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1875 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
1876 }
1877 OpCode::ShrI => {
1878 let ra = base + i.arg_a();
1879 let v = state.get_at(base + i.arg_b());
1880 let ic = i.arg_s_c() as i64;
1881 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
1882 pc += 1;
1883 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
1884 }
1885 }
1886 OpCode::ShlI => {
1887 let ra = base + i.arg_a();
1888 let v = state.get_at(base + i.arg_b());
1889 let ic = i.arg_s_c() as i64;
1890 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
1891 pc += 1;
1892 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
1893 }
1894 }
1895 OpCode::Add => {
1897 let ra = base + i.arg_a();
1898 let rb = base + i.arg_b();
1899 let rc = base + i.arg_c();
1900 let ra_u = ra.0 as usize;
1901 let rb_v = state.stack[rb.0 as usize].val;
1902 let rc_v = state.stack[rc.0 as usize].val;
1903 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
1904 pc += 1;
1905 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
1906 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
1907 pc += 1;
1908 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
1909 }
1910 }
1911 OpCode::Sub => {
1912 let ra = base + i.arg_a();
1913 let rb = base + i.arg_b();
1914 let rc = base + i.arg_c();
1915 let ra_u = ra.0 as usize;
1916 let rb_v = state.stack[rb.0 as usize].val;
1917 let rc_v = state.stack[rc.0 as usize].val;
1918 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
1919 pc += 1;
1920 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
1921 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
1922 pc += 1;
1923 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
1924 }
1925 }
1926 OpCode::Mul => {
1927 let ra = base + i.arg_a();
1928 let rb = base + i.arg_b();
1929 let rc = base + i.arg_c();
1930 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
1931 pc += 1;
1932 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1933 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
1934 pc += 1;
1935 state.set_at(ra, LuaValue::Float(n1 * n2));
1936 }
1937 }
1938 OpCode::Mod => {
1939 let ra = base + i.arg_a();
1940 let v1 = state.get_at(base + i.arg_b());
1941 let v2 = state.get_at(base + i.arg_c());
1942 state.set_ci_savedpc(ci, pc);
1943 state.set_top(state.ci_top(ci));
1944 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1945 |a, b| imod(a, b), fmodf)?;
1946 }
1947 OpCode::Pow => {
1948 let ra = base + i.arg_a();
1949 let rb = base + i.arg_b();
1950 let rc = base + i.arg_c();
1951 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
1952 pc += 1;
1953 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1954 state.set_at(ra, LuaValue::Float(r));
1955 }
1956 }
1957 OpCode::Div => {
1958 let ra = base + i.arg_a();
1959 let rb = base + i.arg_b();
1960 let rc = base + i.arg_c();
1961 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
1962 pc += 1;
1963 state.set_at(ra, LuaValue::Float(n1 / n2));
1964 }
1965 }
1966 OpCode::IDiv => {
1967 let ra = base + i.arg_a();
1968 let v1 = state.get_at(base + i.arg_b());
1969 let v2 = state.get_at(base + i.arg_c());
1970 state.set_ci_savedpc(ci, pc);
1971 state.set_top(state.ci_top(ci));
1972 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1973 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
1974 }
1975 OpCode::BAnd => {
1978 let ra = base + i.arg_a();
1979 let v1 = state.get_at(base + i.arg_b());
1980 let v2 = state.get_at(base + i.arg_c());
1981 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
1982 }
1983 OpCode::BOr => {
1984 let ra = base + i.arg_a();
1985 let v1 = state.get_at(base + i.arg_b());
1986 let v2 = state.get_at(base + i.arg_c());
1987 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
1988 }
1989 OpCode::BXOr => {
1990 let ra = base + i.arg_a();
1991 let v1 = state.get_at(base + i.arg_b());
1992 let v2 = state.get_at(base + i.arg_c());
1993 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
1994 }
1995 OpCode::Shr => {
1996 let ra = base + i.arg_a();
1997 let v1 = state.get_at(base + i.arg_b());
1998 let v2 = state.get_at(base + i.arg_c());
1999 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2000 }
2001 OpCode::Shl => {
2002 let ra = base + i.arg_a();
2003 let v1 = state.get_at(base + i.arg_b());
2004 let v2 = state.get_at(base + i.arg_c());
2005 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2006 }
2007 OpCode::MmBin => {
2012 let ra_idx = base + i.arg_a();
2013 let rb_idx = base + i.arg_b();
2014 let ra_v = state.get_at(ra_idx);
2015 let rb_v = state.get_at(rb_idx);
2016 let tm = tagmethod_from_index(i.arg_c() as usize);
2017 let prev_inst = state.proto_code(&cl, pc - 2);
2018 let result_idx = base + prev_inst.arg_a();
2019 state.set_ci_savedpc(ci, pc);
2020 state.set_top(state.ci_top(ci));
2021 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2022 trap = state.ci_trap(ci);
2023 }
2024 OpCode::MmBinI => {
2025 let ra_idx = base + i.arg_a();
2026 let ra_v = state.get_at(ra_idx);
2027 let imm = i.arg_s_b() as i64;
2028 let tm = tagmethod_from_index(i.arg_c() as usize);
2029 let flip = i.arg_k() != 0;
2030 let prev_inst = state.proto_code(&cl, pc - 2);
2031 let result_idx = base + prev_inst.arg_a();
2032 state.set_ci_savedpc(ci, pc);
2033 state.set_top(state.ci_top(ci));
2034 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2035 trap = state.ci_trap(ci);
2036 }
2037 OpCode::MmBinK => {
2038 let ra_idx = base + i.arg_a();
2039 let ra_v = state.get_at(ra_idx);
2040 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2041 let tm = tagmethod_from_index(i.arg_c() as usize);
2042 let flip = i.arg_k() != 0;
2043 let prev_inst = state.proto_code(&cl, pc - 2);
2044 let result_idx = base + prev_inst.arg_a();
2045 state.set_ci_savedpc(ci, pc);
2046 state.set_top(state.ci_top(ci));
2047 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2048 trap = state.ci_trap(ci);
2049 }
2050 OpCode::Unm => {
2054 let ra = base + i.arg_a();
2055 let rb_idx = base + i.arg_b();
2056 let rb_v = state.get_at(rb_idx);
2057 match &rb_v {
2058 LuaValue::Int(ib) => {
2059 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2060 }
2061 LuaValue::Float(nb) => {
2062 state.set_at(ra, LuaValue::Float(-nb));
2063 }
2064 _ => {
2065 state.set_ci_savedpc(ci, pc);
2066 state.set_top(state.ci_top(ci));
2067 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2068 trap = state.ci_trap(ci);
2069 }
2070 }
2071 }
2072 OpCode::BNot => {
2074 let ra = base + i.arg_a();
2075 let rb_idx = base + i.arg_b();
2076 let rb_v = state.get_at(rb_idx);
2077 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2078 state.set_at(ra, LuaValue::Int(!ib));
2079 } else {
2080 state.set_ci_savedpc(ci, pc);
2081 state.set_top(state.ci_top(ci));
2082 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2083 trap = state.ci_trap(ci);
2084 }
2085 }
2086 OpCode::Not => {
2088 let ra = base + i.arg_a();
2089 let rb_v = state.get_at(base + i.arg_b());
2090 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2091 state.set_at(ra, LuaValue::Bool(falsy));
2092 }
2093 OpCode::Len => {
2095 let ra = base + i.arg_a();
2096 let rb_v = state.get_at(base + i.arg_b());
2097 state.set_ci_savedpc(ci, pc);
2098 state.set_top(state.ci_top(ci));
2099 obj_len(state, ra, rb_v)?;
2100 trap = state.ci_trap(ci);
2101 }
2102 OpCode::Concat => {
2104 let ra = base + i.arg_a();
2105 let n = i.arg_b() as i32;
2106 state.set_top(ra + n as i32);
2107 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2109 trap = state.ci_trap(ci);
2110 let top = state.top_idx();
2111 state.set_ci_savedpc(ci, pc);
2112 state.set_top(top);
2113 state.gc_cond_step();
2114 trap = state.ci_trap(ci);
2115 }
2116 OpCode::Close => {
2118 let ra = base + i.arg_a();
2119 state.set_ci_savedpc(ci, pc);
2120 state.set_top(state.ci_top(ci));
2121 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2122 trap = state.ci_trap(ci);
2123 }
2124 OpCode::Tbc => {
2126 let ra = base + i.arg_a();
2127 state.set_ci_savedpc(ci, pc);
2128 state.set_top(state.ci_top(ci));
2129 state.new_tbc_upval(ra)?;
2130 }
2131 OpCode::Jmp => {
2133 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2134 trap = state.ci_trap(ci);
2135 }
2136 OpCode::Eq => {
2138 let ra_v = state.get_at(base + i.arg_a());
2139 let rb_v = state.get_at(base + i.arg_b());
2140 state.set_ci_savedpc(ci, pc);
2141 state.set_top(state.ci_top(ci));
2142 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2143 trap = state.ci_trap(ci);
2144 if (cond as i32) != i.arg_k() {
2145 pc += 1;
2146 } else {
2147 let next = state.proto_code(&cl, pc);
2148 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2149 trap = state.ci_trap(ci);
2150 }
2151 }
2152 OpCode::Lt => {
2154 let ra_v = state.get_at(base + i.arg_a());
2155 let rb_v = state.get_at(base + i.arg_b());
2156 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2157 *ia < *ib
2158 } else if matches!((&ra_v, &rb_v),
2159 (LuaValue::Int(_) | LuaValue::Float(_),
2160 LuaValue::Int(_) | LuaValue::Float(_))) {
2161 lt_num(&ra_v, &rb_v)
2162 } else {
2163 state.set_ci_savedpc(ci, pc);
2164 state.set_top(state.ci_top(ci));
2165 let r = less_than_others(state, &ra_v, &rb_v)?;
2166 trap = state.ci_trap(ci);
2167 r
2168 };
2169 if (cond as i32) != i.arg_k() {
2170 pc += 1;
2171 } else {
2172 let next = state.proto_code(&cl, pc);
2173 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2174 trap = state.ci_trap(ci);
2175 }
2176 }
2177 OpCode::Le => {
2179 let ra_v = state.get_at(base + i.arg_a());
2180 let rb_v = state.get_at(base + i.arg_b());
2181 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2182 *ia <= *ib
2183 } else if matches!((&ra_v, &rb_v),
2184 (LuaValue::Int(_) | LuaValue::Float(_),
2185 LuaValue::Int(_) | LuaValue::Float(_))) {
2186 le_num(&ra_v, &rb_v)
2187 } else {
2188 state.set_ci_savedpc(ci, pc);
2189 state.set_top(state.ci_top(ci));
2190 let r = less_equal_others(state, &ra_v, &rb_v)?;
2191 trap = state.ci_trap(ci);
2192 r
2193 };
2194 if (cond as i32) != i.arg_k() {
2195 pc += 1;
2196 } else {
2197 let next = state.proto_code(&cl, pc);
2198 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2199 trap = state.ci_trap(ci);
2200 }
2201 }
2202 OpCode::EqK => {
2204 let ra_v = state.get_at(base + i.arg_a());
2205 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2206 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2207 if (cond as i32) != i.arg_k() {
2208 pc += 1;
2209 } else {
2210 let next = state.proto_code(&cl, pc);
2211 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2212 trap = state.ci_trap(ci);
2213 }
2214 }
2215 OpCode::EqI => {
2220 let ra_v = state.get_at(base + i.arg_a());
2221 let im = i.arg_s_b() as i64;
2222 let cond: bool = match &ra_v {
2223 LuaValue::Int(iv) => *iv == im,
2224 LuaValue::Float(fv) => *fv == im as f64,
2225 _ => false,
2226 };
2227 if (cond as i32) != i.arg_k() {
2228 pc += 1;
2229 } else {
2230 let next = state.proto_code(&cl, pc);
2231 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2232 trap = state.ci_trap(ci);
2233 }
2234 }
2235 OpCode::LtI => {
2238 let ra = base + i.arg_a();
2239 let im = i.arg_s_b() as i64;
2240 let fast_cond = match &state.stack[ra.0 as usize].val {
2241 LuaValue::Int(ia) => Some(*ia < im),
2242 LuaValue::Float(fa) => Some(*fa < im as f64),
2243 _ => None,
2244 };
2245 let cond = match fast_cond {
2246 Some(cond) => cond,
2247 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2248 };
2249 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2250 }
2251 OpCode::LeI => {
2252 let ra = base + i.arg_a();
2253 let im = i.arg_s_b() as i64;
2254 let fast_cond = match &state.stack[ra.0 as usize].val {
2255 LuaValue::Int(ia) => Some(*ia <= im),
2256 LuaValue::Float(fa) => Some(*fa <= im as f64),
2257 _ => None,
2258 };
2259 let cond = match fast_cond {
2260 Some(cond) => cond,
2261 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2262 };
2263 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2264 }
2265 OpCode::GtI => {
2266 let ra = base + i.arg_a();
2267 let im = i.arg_s_b() as i64;
2268 let fast_cond = match &state.stack[ra.0 as usize].val {
2269 LuaValue::Int(ia) => Some(*ia > im),
2270 LuaValue::Float(fa) => Some(*fa > im as f64),
2271 _ => None,
2272 };
2273 let cond = match fast_cond {
2274 Some(cond) => cond,
2275 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2276 };
2277 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2278 }
2279 OpCode::GeI => {
2280 let ra = base + i.arg_a();
2281 let im = i.arg_s_b() as i64;
2282 let fast_cond = match &state.stack[ra.0 as usize].val {
2283 LuaValue::Int(ia) => Some(*ia >= im),
2284 LuaValue::Float(fa) => Some(*fa >= im as f64),
2285 _ => None,
2286 };
2287 let cond = match fast_cond {
2288 Some(cond) => cond,
2289 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2290 };
2291 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2292 }
2293 OpCode::Test => {
2295 let ra_v = state.get_at(base + i.arg_a());
2296 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2297 if (cond as i32) != i.arg_k() {
2298 pc += 1;
2299 } else {
2300 let next = state.proto_code(&cl, pc);
2301 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2302 trap = state.ci_trap(ci);
2303 }
2304 }
2305 OpCode::TestSet => {
2308 let ra = base + i.arg_a();
2309 let rb_v = state.get_at(base + i.arg_b());
2310 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2311 if (falsy as i32) == i.arg_k() {
2312 pc += 1;
2313 } else {
2314 state.set_at(ra, rb_v);
2315 let next = state.proto_code(&cl, pc);
2316 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2317 trap = state.ci_trap(ci);
2318 }
2319 }
2320 OpCode::Call => {
2324 let ra = base + i.arg_a();
2325 let b = i.arg_b();
2326 let nresults = i.arg_c() as i32 - 1;
2327 if b != 0 {
2328 state.set_top(ra + b);
2329 }
2330 state.set_ci_savedpc(ci, pc); match state.precall(ra, nresults)? {
2332 None => {
2333 trap = state.ci_trap(ci); }
2336 Some(new_ci) => {
2337 ci = new_ci;
2339 continue 'startfunc;
2340 }
2341 }
2342 }
2343 OpCode::TailCall => {
2348 let ra = base + i.arg_a();
2349 let b = i.arg_b();
2350 let nparams1 = i.arg_c();
2351 let delta = if nparams1 != 0 {
2352 state.ci_nextraargs(ci) + nparams1 as i32
2353 } else {
2354 0
2355 };
2356 let top_b: i32 = if b != 0 {
2357 state.set_top(ra + b);
2358 b
2359 } else {
2360 state.top_idx() - ra
2361 };
2362 state.set_ci_savedpc(ci, pc);
2363 if i.test_k() {
2364 state.close_upvals_from_base(ci)?;
2365 }
2366 let n = state.pretailcall(ci, ra, top_b, delta)?;
2367 if n < 0 {
2368 continue 'startfunc;
2370 } else {
2371 state.ci_adjust_func(ci, delta);
2373 state.poscall(ci, n as u32)?;
2374 trap = state.ci_trap(ci);
2375 break 'dispatch; }
2377 }
2378 OpCode::Return => {
2383 let ra = base + i.arg_a();
2384 let n_raw = i.arg_b() as i32 - 1;
2385 let nparams1 = i.arg_c();
2386 let n: u32 = if n_raw < 0 {
2387 (state.top_idx() - ra) as u32
2388 } else {
2389 n_raw as u32
2390 };
2391 state.set_ci_savedpc(ci, pc);
2392 if i.test_k() {
2393 state.ci_nres_set(ci, n as i32);
2394 let ci_top = state.ci_top(ci);
2395 if state.top_idx().0 < ci_top.0 {
2396 state.set_top(ci_top);
2397 }
2398 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2399 trap = state.ci_trap(ci);
2400 base = state.ci_base(ci); }
2402 if nparams1 != 0 {
2403 let nextraargs = state.ci_nextraargs(ci) as u32;
2404 state.ci_adjust_func(ci, (nextraargs as i32 + nparams1 as i32));
2405 }
2406 state.set_top(ra + n as i32);
2407 state.poscall(ci, n)?;
2408 trap = state.ci_trap(ci);
2409 break 'dispatch; }
2411 OpCode::Return0 => {
2417 if state.hookmask == 0 {
2418 let ci_slot = ci.as_usize();
2419 let nres = state.call_info[ci_slot].nresults as i32;
2420 state.ci = state.call_info[ci_slot]
2421 .previous
2422 .expect("RETURN0: returning frame has no previous CallInfo");
2423 state.top = base - 1;
2424 for _ in 0..nres.max(0) {
2425 state.push(LuaValue::Nil);
2426 }
2427 } else {
2428 return0_hook(state, ci, base, i, pc, &mut trap)?;
2429 }
2430 break 'dispatch; }
2432 OpCode::Return1 => {
2436 if state.hookmask == 0 {
2437 let ci_slot = ci.as_usize();
2438 let nres = state.call_info[ci_slot].nresults as i32;
2439 state.ci = state.call_info[ci_slot]
2440 .previous
2441 .expect("RETURN1: returning frame has no previous CallInfo");
2442 if nres == 0 {
2443 state.top = base - 1;
2444 } else {
2445 let ra = base + i.arg_a();
2446 state.stack[(base - 1).0 as usize].val =
2447 state.stack[ra.0 as usize].val; state.top = base;
2449 for _ in 1..nres.max(0) {
2450 state.push(LuaValue::Nil);
2451 }
2452 }
2453 } else {
2454 return1_hook(state, ci, base, i, pc, &mut trap)?;
2455 }
2456 break 'dispatch; }
2458 OpCode::ForLoop => {
2462 let ra = base + i.arg_a();
2463 let ra_u = ra.0 as usize;
2464 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2465 let count = match state.stack[ra_u + 1].val {
2466 LuaValue::Int(c) => c as u64,
2467 _ => 0,
2468 };
2469 if count > 0 {
2470 let idx = match state.stack[ra_u].val {
2471 LuaValue::Int(x) => x,
2472 _ => 0,
2473 };
2474 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2475 let new_idx = intop_add(idx, step);
2476 state.stack[ra_u].val = LuaValue::Int(new_idx);
2477 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2478 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2479 }
2480 } else if float_for_loop(state, ra) {
2481 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2482 }
2483 trap = state.ci_trap(ci);
2484 }
2485 OpCode::ForPrep => {
2487 let ra = base + i.arg_a();
2488 state.set_ci_savedpc(ci, pc);
2489 state.set_top(state.ci_top(ci));
2490 if forprep(state, ra)? {
2491 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2492 }
2493 }
2494 OpCode::TForPrep => {
2498 let ra = base + i.arg_a();
2499 state.set_ci_savedpc(ci, pc);
2500 state.set_top(state.ci_top(ci));
2501 state.new_tbc_upval(ra + 3)?;
2502 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2503 let tfc_i = state.proto_code(&cl, pc);
2504 pc += 1;
2505 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2506 let tfc_ra = base + tfc_i.arg_a();
2508 for k in 0..3u32 {
2509 let v = state.get_at(tfc_ra + k as i32);
2510 state.set_at(tfc_ra + 4 + k as i32, v);
2511 }
2512 state.set_top(tfc_ra + 4 + 3);
2513 state.set_ci_savedpc(ci, pc);
2514 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2515 trap = state.ci_trap(ci);
2516 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2518 pc += 1;
2519 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2520 let tfl_ra = base + tfl_i.arg_a();
2521 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2523 let v = state.get_at(tfl_ra + 4);
2524 state.set_at(tfl_ra + 2, v);
2525 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2526 }
2527 }
2528 OpCode::TForCall => {
2530 let ra = base + i.arg_a();
2531 for k in 0..3u32 {
2532 let v = state.get_at(ra + k as i32);
2533 state.set_at(ra + 4 + k as i32, v);
2534 }
2535 state.set_top(ra + 4 + 3);
2536 state.set_ci_savedpc(ci, pc);
2537 state.call_at(ra + 4, i.arg_c() as i32)?;
2538 trap = state.ci_trap(ci);
2539 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2541 pc += 1;
2542 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2543 let tfl_ra = base + tfl_i.arg_a();
2544 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2545 let v = state.get_at(tfl_ra + 4);
2546 state.set_at(tfl_ra + 2, v);
2547 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2548 }
2549 }
2550 OpCode::TForLoop => {
2552 let ra = base + i.arg_a();
2553 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2554 let v = state.get_at(ra + 4);
2555 state.set_at(ra + 2, v);
2556 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2557 }
2558 }
2559 OpCode::SetList => {
2563 let ra = base + i.arg_a();
2564 let n_raw = i.arg_b();
2565 let mut last = i.arg_c();
2566 let t_val = state.get_at(ra);
2567 let n: i32 = if n_raw == 0 {
2568 state.top_idx() - ra - 1
2569 } else {
2570 state.set_top(state.ci_top(ci));
2571 n_raw
2572 };
2573 last += n;
2574 if i.test_k() {
2575 let extra = state.proto_code(&cl, pc);
2576 pc += 1;
2577 const MAXARG_C: i32 = (1 << 8) - 1;
2578 last += extra.arg_ax() * (MAXARG_C + 1);
2579 }
2580 state.table_ensure_array(&t_val, last as usize)?;
2581 for k in (1..=n).rev() {
2582 let val = state.get_at(ra + k as i32);
2583 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2584 last -= 1;
2585 state.gc_barrier_back(&t_val, &val);
2586 }
2587 }
2588 OpCode::Closure => {
2592 let ra = base + i.arg_a();
2593 let proto_idx = i.arg_bx() as usize;
2594 state.set_ci_savedpc(ci, pc);
2595 state.set_top(state.ci_top(ci));
2596 push_closure(state, proto_idx, ci, base, ra)?;
2597 state.set_ci_savedpc(ci, pc);
2599 state.set_top(ra + 1);
2600 state.gc_cond_step();
2601 trap = state.ci_trap(ci);
2602 }
2603 OpCode::VarArg => {
2605 let ra = base + i.arg_a();
2606 let n = i.arg_c() as i32 - 1;
2607 state.set_ci_savedpc(ci, pc);
2608 state.set_top(state.ci_top(ci));
2609 state.get_varargs(ci, ra, n)?;
2610 trap = state.ci_trap(ci);
2611 }
2612 OpCode::VarArgPrep => {
2616 let nparams = i.arg_a();
2617 state.set_ci_savedpc(ci, pc);
2618 state.adjust_varargs(ci, nparams, &cl)?;
2619 trap = state.ci_trap(ci);
2620 if trap {
2621 state.hook_call(ci)?;
2622 state.set_oldpc(1);
2623 }
2624 base = state.ci_base(ci);
2625 }
2626 OpCode::ExtraArg => {
2628 debug_assert!(false, "OP_EXTRAARG executed directly");
2629 }
2630 #[allow(unreachable_patterns)]
2632 _ => {
2633 todo!("unrecognised opcode");
2635 }
2636 } } if state.ci_is_fresh(ci) {
2641 return Ok(());
2642 } else {
2643 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2644 continue 'returning;
2645 }
2646 } } }
2649
2650#[inline(always)]
2653fn number_value(v: LuaValue) -> Option<f64> {
2654 match v {
2655 LuaValue::Float(f) => Some(f),
2656 LuaValue::Int(i) => Some(i as f64),
2657 _ => None,
2658 }
2659}
2660
2661#[allow(dead_code)]
2663#[inline]
2664fn arith_op_aux_rr(
2665 state: &mut LuaState,
2666 ra: StackIdx,
2667 v1: &LuaValue,
2668 v2: &LuaValue,
2669 pc: &mut u32,
2670 iop: fn(i64, i64) -> i64,
2671 fop: fn(f64, f64) -> f64,
2672) {
2673 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2674 *pc += 1;
2675 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
2676 } else {
2677 arith_float_aux(state, ra, v1, v2, pc, fop);
2678 }
2679}
2680
2681#[allow(dead_code)]
2682#[inline]
2683fn arith_float_aux(
2684 state: &mut LuaState,
2685 ra: StackIdx,
2686 v1: &LuaValue,
2687 v2: &LuaValue,
2688 pc: &mut u32,
2689 fop: fn(f64, f64) -> f64,
2690) {
2691 let n1 = match v1 {
2692 LuaValue::Float(f) => Some(*f),
2693 LuaValue::Int(i) => Some(*i as f64),
2694 _ => None,
2695 };
2696 let n2 = match v2 {
2697 LuaValue::Float(f) => Some(*f),
2698 LuaValue::Int(i) => Some(*i as f64),
2699 _ => None,
2700 };
2701 if let (Some(n1), Some(n2)) = (n1, n2) {
2702 *pc += 1;
2703 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
2704 }
2705}
2706
2707#[allow(dead_code)]
2708#[inline]
2709fn arith_op_checked(
2710 state: &mut LuaState,
2711 ra: StackIdx,
2712 v1: &LuaValue,
2713 v2: &LuaValue,
2714 pc: &mut u32,
2715 iop: fn(i64, i64) -> Result<i64, LuaError>,
2716 fop: fn(f64, f64) -> f64,
2717) -> Result<(), LuaError> {
2718 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2719 *pc += 1;
2720 let result = iop(*i1, *i2).map_err(|e| match e {
2721 LuaError::Runtime(LuaValue::Str(s)) => {
2722 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
2723 }
2724 other => other,
2725 })?;
2726 state.set_at(ra, LuaValue::Int(result));
2727 } else {
2728 arith_float_aux(state, ra, v1, v2, pc, fop);
2729 }
2730 Ok(())
2731}
2732
2733#[allow(dead_code)]
2734#[inline]
2735fn bitwise_op_k(
2736 state: &mut LuaState,
2737 ra: StackIdx,
2738 v1: &LuaValue,
2739 v2: &LuaValue, pc: &mut u32,
2741 op: fn(i64, i64) -> i64,
2742) {
2743 let i2 = match v2 {
2744 LuaValue::Int(i) => *i,
2745 _ => return,
2746 };
2747 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
2748 *pc += 1;
2749 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2750 }
2751}
2752
2753#[allow(dead_code)]
2754#[inline]
2755fn bitwise_op_rr(
2756 state: &mut LuaState,
2757 ra: StackIdx,
2758 v1: &LuaValue,
2759 v2: &LuaValue,
2760 pc: &mut u32,
2761 op: fn(i64, i64) -> i64,
2762) {
2763 if let (Some(i1), Some(i2)) = (
2764 to_integer_ns(v1, F2Imod::Eq),
2765 to_integer_ns(v2, F2Imod::Eq),
2766 ) {
2767 *pc += 1;
2768 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2769 }
2770}
2771
2772#[allow(dead_code)]
2774#[inline]
2775fn bitwise_shift_rr(
2776 state: &mut LuaState,
2777 ra: StackIdx,
2778 v1: &LuaValue,
2779 v2: &LuaValue,
2780 pc: &mut u32,
2781 right: bool,
2782) {
2783 if let (Some(i1), Some(i2)) = (
2784 to_integer_ns(v1, F2Imod::Eq),
2785 to_integer_ns(v2, F2Imod::Eq),
2786 ) {
2787 let y = if right { intop_sub(0, i2) } else { i2 };
2788 *pc += 1;
2789 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
2790 }
2791}
2792
2793#[cold]
2796#[inline(never)]
2797#[allow(clippy::too_many_arguments)]
2798fn order_imm_slow(
2799 state: &mut LuaState,
2800 ra: StackIdx,
2801 pc: u32,
2802 trap: &mut bool,
2803 ci: CallInfoIdx,
2804 i: Instruction,
2805 im: i64,
2806 inv: bool,
2807 tm: TagMethod,
2808) -> Result<bool, LuaError> {
2809 let ra_v = state.get_at(ra);
2810 let isf = i.arg_c() != 0;
2811 state.set_ci_savedpc(ci, pc);
2812 state.set_top(state.ci_top(ci));
2813 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
2814 *trap = state.ci_trap(ci);
2815 Ok(r)
2816}
2817
2818#[inline(always)]
2819fn finish_order_imm_jump(
2820 state: &mut LuaState,
2821 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
2822 pc: &mut u32,
2823 trap: &mut bool,
2824 ci: CallInfoIdx,
2825 i: Instruction,
2826 cond: bool,
2827) {
2828 if (cond as i32) != i.arg_k() {
2829 *pc += 1;
2830 } else {
2831 let next = state.proto_code(&cl, *pc);
2832 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2833 *trap = state.ci_trap(ci);
2834 }
2835}
2836
2837#[cold]
2838#[inline(never)]
2839fn return0_hook(
2840 state: &mut LuaState,
2841 ci: CallInfoIdx,
2842 base: StackIdx,
2843 i: Instruction,
2844 pc: u32,
2845 trap: &mut bool,
2846) -> Result<(), LuaError> {
2847 let ra = base + i.arg_a();
2848 state.set_top(ra);
2849 state.set_ci_savedpc(ci, pc);
2850 state.poscall(ci, 0)?;
2851 *trap = true;
2852 Ok(())
2853}
2854
2855#[cold]
2856#[inline(never)]
2857fn return1_hook(
2858 state: &mut LuaState,
2859 ci: CallInfoIdx,
2860 base: StackIdx,
2861 i: Instruction,
2862 pc: u32,
2863 trap: &mut bool,
2864) -> Result<(), LuaError> {
2865 let ra = base + i.arg_a();
2866 state.set_top(ra + 1);
2867 state.set_ci_savedpc(ci, pc);
2868 state.poscall(ci, 1)?;
2869 *trap = true;
2870 Ok(())
2871}
2872
2873