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