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.stack[rb.0 as usize].val;
1465 state.stack[ra.0 as usize].val = 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 let rb_v = state.stack[rb.0 as usize].val;
1778 match rb_v {
1779 LuaValue::Int(iv1) => {
1780 pc += 1;
1781 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
1782 }
1783 LuaValue::Float(nb) => {
1784 pc += 1;
1785 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
1786 }
1787 _ => {}
1788 }
1789 }
1790 OpCode::AddK => {
1792 let ra = base + i.arg_a();
1793 let rb = base + i.arg_b();
1794 let kidx = i.arg_c() as usize;
1795 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1796 pc += 1;
1797 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
1798 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1799 pc += 1;
1800 state.set_at(ra, LuaValue::Float(n1 + n2));
1801 }
1802 }
1803 OpCode::SubK => {
1804 let ra = base + i.arg_a();
1805 let rb = base + i.arg_b();
1806 let kidx = i.arg_c() as usize;
1807 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1808 pc += 1;
1809 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
1810 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1811 pc += 1;
1812 state.set_at(ra, LuaValue::Float(n1 - n2));
1813 }
1814 }
1815 OpCode::MulK => {
1816 let ra = base + i.arg_a();
1817 let rb = base + i.arg_b();
1818 let kidx = i.arg_c() as usize;
1819 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1820 pc += 1;
1821 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1822 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1823 pc += 1;
1824 state.set_at(ra, LuaValue::Float(n1 * n2));
1825 }
1826 }
1827 OpCode::ModK => {
1828 let ra = base + i.arg_a();
1829 let v1 = state.get_at(base + i.arg_b());
1830 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1831 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
1833 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1834 |a, b| imod(a, b), fmodf)?;
1835 }
1836 OpCode::PowK => {
1837 let ra = base + i.arg_a();
1838 let rb = base + i.arg_b();
1839 let kidx = i.arg_c() as usize;
1840 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1841 pc += 1;
1842 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1843 state.set_at(ra, LuaValue::Float(r));
1844 }
1845 }
1846 OpCode::DivK => {
1847 let ra = base + i.arg_a();
1848 let rb = base + i.arg_b();
1849 let kidx = i.arg_c() as usize;
1850 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1851 pc += 1;
1852 state.set_at(ra, LuaValue::Float(n1 / n2));
1853 }
1854 }
1855 OpCode::IDivK => {
1856 let ra = base + i.arg_a();
1857 let v1 = state.get_at(base + i.arg_b());
1858 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1859 state.set_ci_savedpc(ci, pc);
1860 state.set_top(state.ci_top(ci));
1861 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1862 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
1863 }
1864 OpCode::BAndK => {
1865 let ra = base + i.arg_a();
1866 let v1 = state.get_at(base + i.arg_b());
1867 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1868 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
1869 }
1870 OpCode::BOrK => {
1871 let ra = base + i.arg_a();
1872 let v1 = state.get_at(base + i.arg_b());
1873 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1874 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
1875 }
1876 OpCode::BXOrK => {
1877 let ra = base + i.arg_a();
1878 let v1 = state.get_at(base + i.arg_b());
1879 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1880 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
1881 }
1882 OpCode::ShrI => {
1883 let ra = base + i.arg_a();
1884 let v = state.get_at(base + i.arg_b());
1885 let ic = i.arg_s_c() as i64;
1886 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
1887 pc += 1;
1888 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
1889 }
1890 }
1891 OpCode::ShlI => {
1892 let ra = base + i.arg_a();
1893 let v = state.get_at(base + i.arg_b());
1894 let ic = i.arg_s_c() as i64;
1895 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
1896 pc += 1;
1897 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
1898 }
1899 }
1900 OpCode::Add => {
1902 let ra = base + i.arg_a();
1903 let rb = base + i.arg_b();
1904 let rc = base + i.arg_c();
1905 let ra_u = ra.0 as usize;
1906 let rb_v = state.stack[rb.0 as usize].val;
1907 let rc_v = state.stack[rc.0 as usize].val;
1908 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
1909 pc += 1;
1910 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
1911 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
1912 pc += 1;
1913 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
1914 }
1915 }
1916 OpCode::Sub => {
1917 let ra = base + i.arg_a();
1918 let rb = base + i.arg_b();
1919 let rc = base + i.arg_c();
1920 let ra_u = ra.0 as usize;
1921 let rb_v = state.stack[rb.0 as usize].val;
1922 let rc_v = state.stack[rc.0 as usize].val;
1923 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
1924 pc += 1;
1925 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
1926 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
1927 pc += 1;
1928 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
1929 }
1930 }
1931 OpCode::Mul => {
1932 let ra = base + i.arg_a();
1933 let rb = base + i.arg_b();
1934 let rc = base + i.arg_c();
1935 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
1936 pc += 1;
1937 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1938 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
1939 pc += 1;
1940 state.set_at(ra, LuaValue::Float(n1 * n2));
1941 }
1942 }
1943 OpCode::Mod => {
1944 let ra = base + i.arg_a();
1945 let v1 = state.get_at(base + i.arg_b());
1946 let v2 = state.get_at(base + i.arg_c());
1947 state.set_ci_savedpc(ci, pc);
1948 state.set_top(state.ci_top(ci));
1949 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1950 |a, b| imod(a, b), fmodf)?;
1951 }
1952 OpCode::Pow => {
1953 let ra = base + i.arg_a();
1954 let rb = base + i.arg_b();
1955 let rc = base + i.arg_c();
1956 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
1957 pc += 1;
1958 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1959 state.set_at(ra, LuaValue::Float(r));
1960 }
1961 }
1962 OpCode::Div => {
1963 let ra = base + i.arg_a();
1964 let rb = base + i.arg_b();
1965 let rc = base + i.arg_c();
1966 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
1967 pc += 1;
1968 state.set_at(ra, LuaValue::Float(n1 / n2));
1969 }
1970 }
1971 OpCode::IDiv => {
1972 let ra = base + i.arg_a();
1973 let v1 = state.get_at(base + i.arg_b());
1974 let v2 = state.get_at(base + i.arg_c());
1975 state.set_ci_savedpc(ci, pc);
1976 state.set_top(state.ci_top(ci));
1977 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1978 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
1979 }
1980 OpCode::BAnd => {
1983 let ra = base + i.arg_a();
1984 let v1 = state.get_at(base + i.arg_b());
1985 let v2 = state.get_at(base + i.arg_c());
1986 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
1987 }
1988 OpCode::BOr => {
1989 let ra = base + i.arg_a();
1990 let v1 = state.get_at(base + i.arg_b());
1991 let v2 = state.get_at(base + i.arg_c());
1992 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
1993 }
1994 OpCode::BXOr => {
1995 let ra = base + i.arg_a();
1996 let v1 = state.get_at(base + i.arg_b());
1997 let v2 = state.get_at(base + i.arg_c());
1998 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
1999 }
2000 OpCode::Shr => {
2001 let ra = base + i.arg_a();
2002 let v1 = state.get_at(base + i.arg_b());
2003 let v2 = state.get_at(base + i.arg_c());
2004 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2005 }
2006 OpCode::Shl => {
2007 let ra = base + i.arg_a();
2008 let v1 = state.get_at(base + i.arg_b());
2009 let v2 = state.get_at(base + i.arg_c());
2010 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2011 }
2012 OpCode::MmBin => {
2017 let ra_idx = base + i.arg_a();
2018 let rb_idx = base + i.arg_b();
2019 let ra_v = state.get_at(ra_idx);
2020 let rb_v = state.get_at(rb_idx);
2021 let tm = tagmethod_from_index(i.arg_c() as usize);
2022 let prev_inst = state.proto_code(&cl, pc - 2);
2023 let result_idx = base + prev_inst.arg_a();
2024 state.set_ci_savedpc(ci, pc);
2025 state.set_top(state.ci_top(ci));
2026 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2027 trap = state.ci_trap(ci);
2028 }
2029 OpCode::MmBinI => {
2030 let ra_idx = base + i.arg_a();
2031 let ra_v = state.get_at(ra_idx);
2032 let imm = i.arg_s_b() as i64;
2033 let tm = tagmethod_from_index(i.arg_c() as usize);
2034 let flip = i.arg_k() != 0;
2035 let prev_inst = state.proto_code(&cl, pc - 2);
2036 let result_idx = base + prev_inst.arg_a();
2037 state.set_ci_savedpc(ci, pc);
2038 state.set_top(state.ci_top(ci));
2039 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2040 trap = state.ci_trap(ci);
2041 }
2042 OpCode::MmBinK => {
2043 let ra_idx = base + i.arg_a();
2044 let ra_v = state.get_at(ra_idx);
2045 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2046 let tm = tagmethod_from_index(i.arg_c() as usize);
2047 let flip = i.arg_k() != 0;
2048 let prev_inst = state.proto_code(&cl, pc - 2);
2049 let result_idx = base + prev_inst.arg_a();
2050 state.set_ci_savedpc(ci, pc);
2051 state.set_top(state.ci_top(ci));
2052 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2053 trap = state.ci_trap(ci);
2054 }
2055 OpCode::Unm => {
2059 let ra = base + i.arg_a();
2060 let rb_idx = base + i.arg_b();
2061 let rb_v = state.get_at(rb_idx);
2062 match &rb_v {
2063 LuaValue::Int(ib) => {
2064 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2065 }
2066 LuaValue::Float(nb) => {
2067 state.set_at(ra, LuaValue::Float(-nb));
2068 }
2069 _ => {
2070 state.set_ci_savedpc(ci, pc);
2071 state.set_top(state.ci_top(ci));
2072 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2073 trap = state.ci_trap(ci);
2074 }
2075 }
2076 }
2077 OpCode::BNot => {
2079 let ra = base + i.arg_a();
2080 let rb_idx = base + i.arg_b();
2081 let rb_v = state.get_at(rb_idx);
2082 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2083 state.set_at(ra, LuaValue::Int(!ib));
2084 } else {
2085 state.set_ci_savedpc(ci, pc);
2086 state.set_top(state.ci_top(ci));
2087 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2088 trap = state.ci_trap(ci);
2089 }
2090 }
2091 OpCode::Not => {
2093 let ra = base + i.arg_a();
2094 let rb_v = state.get_at(base + i.arg_b());
2095 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2096 state.set_at(ra, LuaValue::Bool(falsy));
2097 }
2098 OpCode::Len => {
2100 let ra = base + i.arg_a();
2101 let rb_v = state.get_at(base + i.arg_b());
2102 state.set_ci_savedpc(ci, pc);
2103 state.set_top(state.ci_top(ci));
2104 obj_len(state, ra, rb_v)?;
2105 trap = state.ci_trap(ci);
2106 }
2107 OpCode::Concat => {
2109 let ra = base + i.arg_a();
2110 let n = i.arg_b() as i32;
2111 state.set_top(ra + n as i32);
2112 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2114 trap = state.ci_trap(ci);
2115 let top = state.top_idx();
2116 state.set_ci_savedpc(ci, pc);
2117 state.set_top(top);
2118 state.gc_cond_step();
2119 trap = state.ci_trap(ci);
2120 }
2121 OpCode::Close => {
2123 let ra = base + i.arg_a();
2124 state.set_ci_savedpc(ci, pc);
2125 state.set_top(state.ci_top(ci));
2126 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2127 trap = state.ci_trap(ci);
2128 }
2129 OpCode::Tbc => {
2131 let ra = base + i.arg_a();
2132 state.set_ci_savedpc(ci, pc);
2133 state.set_top(state.ci_top(ci));
2134 state.new_tbc_upval(ra)?;
2135 }
2136 OpCode::Jmp => {
2138 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2139 trap = state.ci_trap(ci);
2140 }
2141 OpCode::Eq => {
2143 let ra_v = state.get_at(base + i.arg_a());
2144 let rb_v = state.get_at(base + i.arg_b());
2145 state.set_ci_savedpc(ci, pc);
2146 state.set_top(state.ci_top(ci));
2147 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2148 trap = state.ci_trap(ci);
2149 if (cond as i32) != i.arg_k() {
2150 pc += 1;
2151 } else {
2152 let next = state.proto_code(&cl, pc);
2153 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2154 trap = state.ci_trap(ci);
2155 }
2156 }
2157 OpCode::Lt => {
2159 let ra_v = state.get_at(base + i.arg_a());
2160 let rb_v = state.get_at(base + i.arg_b());
2161 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2162 *ia < *ib
2163 } else if matches!((&ra_v, &rb_v),
2164 (LuaValue::Int(_) | LuaValue::Float(_),
2165 LuaValue::Int(_) | LuaValue::Float(_))) {
2166 lt_num(&ra_v, &rb_v)
2167 } else {
2168 state.set_ci_savedpc(ci, pc);
2169 state.set_top(state.ci_top(ci));
2170 let r = less_than_others(state, &ra_v, &rb_v)?;
2171 trap = state.ci_trap(ci);
2172 r
2173 };
2174 if (cond as i32) != i.arg_k() {
2175 pc += 1;
2176 } else {
2177 let next = state.proto_code(&cl, pc);
2178 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2179 trap = state.ci_trap(ci);
2180 }
2181 }
2182 OpCode::Le => {
2184 let ra_v = state.get_at(base + i.arg_a());
2185 let rb_v = state.get_at(base + i.arg_b());
2186 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2187 *ia <= *ib
2188 } else if matches!((&ra_v, &rb_v),
2189 (LuaValue::Int(_) | LuaValue::Float(_),
2190 LuaValue::Int(_) | LuaValue::Float(_))) {
2191 le_num(&ra_v, &rb_v)
2192 } else {
2193 state.set_ci_savedpc(ci, pc);
2194 state.set_top(state.ci_top(ci));
2195 let r = less_equal_others(state, &ra_v, &rb_v)?;
2196 trap = state.ci_trap(ci);
2197 r
2198 };
2199 if (cond as i32) != i.arg_k() {
2200 pc += 1;
2201 } else {
2202 let next = state.proto_code(&cl, pc);
2203 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2204 trap = state.ci_trap(ci);
2205 }
2206 }
2207 OpCode::EqK => {
2209 let ra_v = state.get_at(base + i.arg_a());
2210 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2211 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2212 if (cond as i32) != i.arg_k() {
2213 pc += 1;
2214 } else {
2215 let next = state.proto_code(&cl, pc);
2216 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2217 trap = state.ci_trap(ci);
2218 }
2219 }
2220 OpCode::EqI => {
2225 let ra_v = state.get_at(base + i.arg_a());
2226 let im = i.arg_s_b() as i64;
2227 let cond: bool = match &ra_v {
2228 LuaValue::Int(iv) => *iv == im,
2229 LuaValue::Float(fv) => *fv == im as f64,
2230 _ => false,
2231 };
2232 if (cond as i32) != i.arg_k() {
2233 pc += 1;
2234 } else {
2235 let next = state.proto_code(&cl, pc);
2236 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2237 trap = state.ci_trap(ci);
2238 }
2239 }
2240 OpCode::LtI => {
2243 let ra = base + i.arg_a();
2244 let im = i.arg_s_b() as i64;
2245 let fast_cond = match &state.stack[ra.0 as usize].val {
2246 LuaValue::Int(ia) => Some(*ia < im),
2247 LuaValue::Float(fa) => Some(*fa < im as f64),
2248 _ => None,
2249 };
2250 let cond = match fast_cond {
2251 Some(cond) => cond,
2252 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2253 };
2254 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2255 }
2256 OpCode::LeI => {
2257 let ra = base + i.arg_a();
2258 let im = i.arg_s_b() as i64;
2259 let fast_cond = match &state.stack[ra.0 as usize].val {
2260 LuaValue::Int(ia) => Some(*ia <= im),
2261 LuaValue::Float(fa) => Some(*fa <= im as f64),
2262 _ => None,
2263 };
2264 let cond = match fast_cond {
2265 Some(cond) => cond,
2266 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2267 };
2268 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2269 }
2270 OpCode::GtI => {
2271 let ra = base + i.arg_a();
2272 let im = i.arg_s_b() as i64;
2273 let fast_cond = match &state.stack[ra.0 as usize].val {
2274 LuaValue::Int(ia) => Some(*ia > im),
2275 LuaValue::Float(fa) => Some(*fa > im as f64),
2276 _ => None,
2277 };
2278 let cond = match fast_cond {
2279 Some(cond) => cond,
2280 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2281 };
2282 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2283 }
2284 OpCode::GeI => {
2285 let ra = base + i.arg_a();
2286 let im = i.arg_s_b() as i64;
2287 let fast_cond = match &state.stack[ra.0 as usize].val {
2288 LuaValue::Int(ia) => Some(*ia >= im),
2289 LuaValue::Float(fa) => Some(*fa >= im as f64),
2290 _ => None,
2291 };
2292 let cond = match fast_cond {
2293 Some(cond) => cond,
2294 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2295 };
2296 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2297 }
2298 OpCode::Test => {
2300 let ra_v = state.get_at(base + i.arg_a());
2301 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2302 if (cond as i32) != i.arg_k() {
2303 pc += 1;
2304 } else {
2305 let next = state.proto_code(&cl, pc);
2306 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2307 trap = state.ci_trap(ci);
2308 }
2309 }
2310 OpCode::TestSet => {
2313 let ra = base + i.arg_a();
2314 let rb_v = state.get_at(base + i.arg_b());
2315 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2316 if (falsy as i32) == i.arg_k() {
2317 pc += 1;
2318 } else {
2319 state.set_at(ra, rb_v);
2320 let next = state.proto_code(&cl, pc);
2321 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2322 trap = state.ci_trap(ci);
2323 }
2324 }
2325 OpCode::Call => {
2329 let ra = base + i.arg_a();
2330 let b = i.arg_b();
2331 let nresults = i.arg_c() as i32 - 1;
2332 if b != 0 {
2333 state.set_top(ra + b);
2334 }
2335 state.set_ci_savedpc(ci, pc); match state.precall(ra, nresults)? {
2337 None => {
2338 trap = state.ci_trap(ci); }
2341 Some(new_ci) => {
2342 ci = new_ci;
2344 continue 'startfunc;
2345 }
2346 }
2347 }
2348 OpCode::TailCall => {
2353 let ra = base + i.arg_a();
2354 let b = i.arg_b();
2355 let nparams1 = i.arg_c();
2356 let delta = if nparams1 != 0 {
2357 state.ci_nextraargs(ci) + nparams1 as i32
2358 } else {
2359 0
2360 };
2361 let top_b: i32 = if b != 0 {
2362 state.set_top(ra + b);
2363 b
2364 } else {
2365 state.top_idx() - ra
2366 };
2367 state.set_ci_savedpc(ci, pc);
2368 if i.test_k() {
2369 state.close_upvals_from_base(ci)?;
2370 }
2371 let n = state.pretailcall(ci, ra, top_b, delta)?;
2372 if n < 0 {
2373 continue 'startfunc;
2375 } else {
2376 state.ci_adjust_func(ci, delta);
2378 state.poscall(ci, n as u32)?;
2379 trap = state.ci_trap(ci);
2380 break 'dispatch; }
2382 }
2383 OpCode::Return => {
2388 let ra = base + i.arg_a();
2389 let n_raw = i.arg_b() as i32 - 1;
2390 let nparams1 = i.arg_c();
2391 let n: u32 = if n_raw < 0 {
2392 (state.top_idx() - ra) as u32
2393 } else {
2394 n_raw as u32
2395 };
2396 state.set_ci_savedpc(ci, pc);
2397 if i.test_k() {
2398 state.ci_nres_set(ci, n as i32);
2399 let ci_top = state.ci_top(ci);
2400 if state.top_idx().0 < ci_top.0 {
2401 state.set_top(ci_top);
2402 }
2403 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2404 trap = state.ci_trap(ci);
2405 base = state.ci_base(ci); }
2407 if nparams1 != 0 {
2408 let nextraargs = state.ci_nextraargs(ci) as u32;
2409 state.ci_adjust_func(ci, (nextraargs as i32 + nparams1 as i32));
2410 }
2411 state.set_top(ra + n as i32);
2412 state.poscall(ci, n)?;
2413 trap = state.ci_trap(ci);
2414 break 'dispatch; }
2416 OpCode::Return0 => {
2422 if state.hookmask == 0 {
2423 let ci_slot = ci.as_usize();
2424 let nres = state.call_info[ci_slot].nresults as i32;
2425 state.ci = state.call_info[ci_slot]
2426 .previous
2427 .expect("RETURN0: returning frame has no previous CallInfo");
2428 state.top = base - 1;
2429 for _ in 0..nres.max(0) {
2430 state.push(LuaValue::Nil);
2431 }
2432 } else {
2433 return0_hook(state, ci, base, i, pc, &mut trap)?;
2434 }
2435 break 'dispatch; }
2437 OpCode::Return1 => {
2441 if state.hookmask == 0 {
2442 let ci_slot = ci.as_usize();
2443 let nres = state.call_info[ci_slot].nresults as i32;
2444 state.ci = state.call_info[ci_slot]
2445 .previous
2446 .expect("RETURN1: returning frame has no previous CallInfo");
2447 if nres == 0 {
2448 state.top = base - 1;
2449 } else {
2450 let ra = base + i.arg_a();
2451 state.stack[(base - 1).0 as usize].val =
2452 state.stack[ra.0 as usize].val; state.top = base;
2454 for _ in 1..nres.max(0) {
2455 state.push(LuaValue::Nil);
2456 }
2457 }
2458 } else {
2459 return1_hook(state, ci, base, i, pc, &mut trap)?;
2460 }
2461 break 'dispatch; }
2463 OpCode::ForLoop => {
2467 let ra = base + i.arg_a();
2468 let ra_u = ra.0 as usize;
2469 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2470 let count = match state.stack[ra_u + 1].val {
2471 LuaValue::Int(c) => c as u64,
2472 _ => 0,
2473 };
2474 if count > 0 {
2475 let idx = match state.stack[ra_u].val {
2476 LuaValue::Int(x) => x,
2477 _ => 0,
2478 };
2479 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2480 let new_idx = intop_add(idx, step);
2481 state.stack[ra_u].val = LuaValue::Int(new_idx);
2482 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2483 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2484 }
2485 } else if float_for_loop(state, ra) {
2486 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2487 }
2488 trap = state.ci_trap(ci);
2489 }
2490 OpCode::ForPrep => {
2492 let ra = base + i.arg_a();
2493 state.set_ci_savedpc(ci, pc);
2494 state.set_top(state.ci_top(ci));
2495 if forprep(state, ra)? {
2496 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2497 }
2498 }
2499 OpCode::TForPrep => {
2503 let ra = base + i.arg_a();
2504 state.set_ci_savedpc(ci, pc);
2505 state.set_top(state.ci_top(ci));
2506 state.new_tbc_upval(ra + 3)?;
2507 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2508 let tfc_i = state.proto_code(&cl, pc);
2509 pc += 1;
2510 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2511 let tfc_ra = base + tfc_i.arg_a();
2513 for k in 0..3u32 {
2514 let v = state.get_at(tfc_ra + k as i32);
2515 state.set_at(tfc_ra + 4 + k as i32, v);
2516 }
2517 state.set_top(tfc_ra + 4 + 3);
2518 state.set_ci_savedpc(ci, pc);
2519 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2520 trap = state.ci_trap(ci);
2521 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2523 pc += 1;
2524 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2525 let tfl_ra = base + tfl_i.arg_a();
2526 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2528 let v = state.get_at(tfl_ra + 4);
2529 state.set_at(tfl_ra + 2, v);
2530 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2531 }
2532 }
2533 OpCode::TForCall => {
2535 let ra = base + i.arg_a();
2536 for k in 0..3u32 {
2537 let v = state.get_at(ra + k as i32);
2538 state.set_at(ra + 4 + k as i32, v);
2539 }
2540 state.set_top(ra + 4 + 3);
2541 state.set_ci_savedpc(ci, pc);
2542 state.call_at(ra + 4, i.arg_c() as i32)?;
2543 trap = state.ci_trap(ci);
2544 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2546 pc += 1;
2547 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2548 let tfl_ra = base + tfl_i.arg_a();
2549 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2550 let v = state.get_at(tfl_ra + 4);
2551 state.set_at(tfl_ra + 2, v);
2552 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2553 }
2554 }
2555 OpCode::TForLoop => {
2557 let ra = base + i.arg_a();
2558 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2559 let v = state.get_at(ra + 4);
2560 state.set_at(ra + 2, v);
2561 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2562 }
2563 }
2564 OpCode::SetList => {
2568 let ra = base + i.arg_a();
2569 let n_raw = i.arg_b();
2570 let mut last = i.arg_c();
2571 let t_val = state.get_at(ra);
2572 let n: i32 = if n_raw == 0 {
2573 state.top_idx() - ra - 1
2574 } else {
2575 state.set_top(state.ci_top(ci));
2576 n_raw
2577 };
2578 last += n;
2579 if i.test_k() {
2580 let extra = state.proto_code(&cl, pc);
2581 pc += 1;
2582 const MAXARG_C: i32 = (1 << 8) - 1;
2583 last += extra.arg_ax() * (MAXARG_C + 1);
2584 }
2585 state.table_ensure_array(&t_val, last as usize)?;
2586 for k in (1..=n).rev() {
2587 let val = state.get_at(ra + k as i32);
2588 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2589 last -= 1;
2590 state.gc_barrier_back(&t_val, &val);
2591 }
2592 }
2593 OpCode::Closure => {
2597 let ra = base + i.arg_a();
2598 let proto_idx = i.arg_bx() as usize;
2599 state.set_ci_savedpc(ci, pc);
2600 state.set_top(state.ci_top(ci));
2601 push_closure(state, proto_idx, ci, base, ra)?;
2602 state.set_ci_savedpc(ci, pc);
2604 state.set_top(ra + 1);
2605 state.gc_cond_step();
2606 trap = state.ci_trap(ci);
2607 }
2608 OpCode::VarArg => {
2610 let ra = base + i.arg_a();
2611 let n = i.arg_c() as i32 - 1;
2612 state.set_ci_savedpc(ci, pc);
2613 state.set_top(state.ci_top(ci));
2614 state.get_varargs(ci, ra, n)?;
2615 trap = state.ci_trap(ci);
2616 }
2617 OpCode::VarArgPrep => {
2621 let nparams = i.arg_a();
2622 state.set_ci_savedpc(ci, pc);
2623 state.adjust_varargs(ci, nparams, &cl)?;
2624 trap = state.ci_trap(ci);
2625 if trap {
2626 state.hook_call(ci)?;
2627 state.set_oldpc(1);
2628 }
2629 base = state.ci_base(ci);
2630 }
2631 OpCode::ExtraArg => {
2633 debug_assert!(false, "OP_EXTRAARG executed directly");
2634 }
2635 #[allow(unreachable_patterns)]
2637 _ => {
2638 todo!("unrecognised opcode");
2640 }
2641 } } if state.ci_is_fresh(ci) {
2646 return Ok(());
2647 } else {
2648 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2649 continue 'returning;
2650 }
2651 } } }
2654
2655#[inline(always)]
2658fn number_value(v: LuaValue) -> Option<f64> {
2659 match v {
2660 LuaValue::Float(f) => Some(f),
2661 LuaValue::Int(i) => Some(i as f64),
2662 _ => None,
2663 }
2664}
2665
2666#[allow(dead_code)]
2668#[inline]
2669fn arith_op_aux_rr(
2670 state: &mut LuaState,
2671 ra: StackIdx,
2672 v1: &LuaValue,
2673 v2: &LuaValue,
2674 pc: &mut u32,
2675 iop: fn(i64, i64) -> i64,
2676 fop: fn(f64, f64) -> f64,
2677) {
2678 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2679 *pc += 1;
2680 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
2681 } else {
2682 arith_float_aux(state, ra, v1, v2, pc, fop);
2683 }
2684}
2685
2686#[allow(dead_code)]
2687#[inline]
2688fn arith_float_aux(
2689 state: &mut LuaState,
2690 ra: StackIdx,
2691 v1: &LuaValue,
2692 v2: &LuaValue,
2693 pc: &mut u32,
2694 fop: fn(f64, f64) -> f64,
2695) {
2696 let n1 = match v1 {
2697 LuaValue::Float(f) => Some(*f),
2698 LuaValue::Int(i) => Some(*i as f64),
2699 _ => None,
2700 };
2701 let n2 = match v2 {
2702 LuaValue::Float(f) => Some(*f),
2703 LuaValue::Int(i) => Some(*i as f64),
2704 _ => None,
2705 };
2706 if let (Some(n1), Some(n2)) = (n1, n2) {
2707 *pc += 1;
2708 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
2709 }
2710}
2711
2712#[allow(dead_code)]
2713#[inline]
2714fn arith_op_checked(
2715 state: &mut LuaState,
2716 ra: StackIdx,
2717 v1: &LuaValue,
2718 v2: &LuaValue,
2719 pc: &mut u32,
2720 iop: fn(i64, i64) -> Result<i64, LuaError>,
2721 fop: fn(f64, f64) -> f64,
2722) -> Result<(), LuaError> {
2723 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2724 *pc += 1;
2725 let result = iop(*i1, *i2).map_err(|e| match e {
2726 LuaError::Runtime(LuaValue::Str(s)) => {
2727 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
2728 }
2729 other => other,
2730 })?;
2731 state.set_at(ra, LuaValue::Int(result));
2732 } else {
2733 arith_float_aux(state, ra, v1, v2, pc, fop);
2734 }
2735 Ok(())
2736}
2737
2738#[allow(dead_code)]
2739#[inline]
2740fn bitwise_op_k(
2741 state: &mut LuaState,
2742 ra: StackIdx,
2743 v1: &LuaValue,
2744 v2: &LuaValue, pc: &mut u32,
2746 op: fn(i64, i64) -> i64,
2747) {
2748 let i2 = match v2 {
2749 LuaValue::Int(i) => *i,
2750 _ => return,
2751 };
2752 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
2753 *pc += 1;
2754 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2755 }
2756}
2757
2758#[allow(dead_code)]
2759#[inline]
2760fn bitwise_op_rr(
2761 state: &mut LuaState,
2762 ra: StackIdx,
2763 v1: &LuaValue,
2764 v2: &LuaValue,
2765 pc: &mut u32,
2766 op: fn(i64, i64) -> i64,
2767) {
2768 if let (Some(i1), Some(i2)) = (
2769 to_integer_ns(v1, F2Imod::Eq),
2770 to_integer_ns(v2, F2Imod::Eq),
2771 ) {
2772 *pc += 1;
2773 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2774 }
2775}
2776
2777#[allow(dead_code)]
2779#[inline]
2780fn bitwise_shift_rr(
2781 state: &mut LuaState,
2782 ra: StackIdx,
2783 v1: &LuaValue,
2784 v2: &LuaValue,
2785 pc: &mut u32,
2786 right: bool,
2787) {
2788 if let (Some(i1), Some(i2)) = (
2789 to_integer_ns(v1, F2Imod::Eq),
2790 to_integer_ns(v2, F2Imod::Eq),
2791 ) {
2792 let y = if right { intop_sub(0, i2) } else { i2 };
2793 *pc += 1;
2794 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
2795 }
2796}
2797
2798#[cold]
2801#[inline(never)]
2802#[allow(clippy::too_many_arguments)]
2803fn order_imm_slow(
2804 state: &mut LuaState,
2805 ra: StackIdx,
2806 pc: u32,
2807 trap: &mut bool,
2808 ci: CallInfoIdx,
2809 i: Instruction,
2810 im: i64,
2811 inv: bool,
2812 tm: TagMethod,
2813) -> Result<bool, LuaError> {
2814 let ra_v = state.get_at(ra);
2815 let isf = i.arg_c() != 0;
2816 state.set_ci_savedpc(ci, pc);
2817 state.set_top(state.ci_top(ci));
2818 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
2819 *trap = state.ci_trap(ci);
2820 Ok(r)
2821}
2822
2823#[inline(always)]
2824fn finish_order_imm_jump(
2825 state: &mut LuaState,
2826 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
2827 pc: &mut u32,
2828 trap: &mut bool,
2829 ci: CallInfoIdx,
2830 i: Instruction,
2831 cond: bool,
2832) {
2833 if (cond as i32) != i.arg_k() {
2834 *pc += 1;
2835 } else {
2836 let next = state.proto_code(&cl, *pc);
2837 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2838 *trap = state.ci_trap(ci);
2839 }
2840}
2841
2842#[cold]
2843#[inline(never)]
2844fn return0_hook(
2845 state: &mut LuaState,
2846 ci: CallInfoIdx,
2847 base: StackIdx,
2848 i: Instruction,
2849 pc: u32,
2850 trap: &mut bool,
2851) -> Result<(), LuaError> {
2852 let ra = base + i.arg_a();
2853 state.set_top(ra);
2854 state.set_ci_savedpc(ci, pc);
2855 state.poscall(ci, 0)?;
2856 *trap = true;
2857 Ok(())
2858}
2859
2860#[cold]
2861#[inline(never)]
2862fn return1_hook(
2863 state: &mut LuaState,
2864 ci: CallInfoIdx,
2865 base: StackIdx,
2866 i: Instruction,
2867 pc: u32,
2868 trap: &mut bool,
2869) -> Result<(), LuaError> {
2870 let ra = base + i.arg_a();
2871 state.set_top(ra + 1);
2872 state.set_ci_savedpc(ci, pc);
2873 state.poscall(ci, 1)?;
2874 *trap = true;
2875 Ok(())
2876}
2877
2878