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, PartialOrd, Ord)]
57#[allow(non_camel_case_types)]
58#[repr(u8)]
59pub enum OpCode {
60 Move = 0,
61 LoadI = 1,
62 LoadF = 2,
63 LoadK = 3,
64 LoadKX = 4,
65 LoadFalse = 5,
66 LFalseSkip = 6,
67 LoadTrue = 7,
68 LoadNil = 8,
69 GetUpVal = 9,
70 SetUpVal = 10,
71 GetTabUp = 11,
72 GetTable = 12,
73 GetI = 13,
74 GetField = 14,
75 SetTabUp = 15,
76 SetTable = 16,
77 SetI = 17,
78 SetField = 18,
79 NewTable = 19,
80 Self_ = 20,
81 AddI = 21,
82 AddK = 22,
83 SubK = 23,
84 MulK = 24,
85 ModK = 25,
86 PowK = 26,
87 DivK = 27,
88 IDivK = 28,
89 BAndK = 29,
90 BOrK = 30,
91 BXOrK = 31,
92 ShrI = 32,
93 ShlI = 33,
94 Add = 34,
95 Sub = 35,
96 Mul = 36,
97 Mod = 37,
98 Pow = 38,
99 Div = 39,
100 IDiv = 40,
101 BAnd = 41,
102 BOr = 42,
103 BXOr = 43,
104 Shl = 44,
105 Shr = 45,
106 MmBin = 46,
107 MmBinI = 47,
108 MmBinK = 48,
109 Unm = 49,
110 BNot = 50,
111 Not = 51,
112 Len = 52,
113 Concat = 53,
114 Close = 54,
115 Tbc = 55,
116 Jmp = 56,
117 Eq = 57,
118 Lt = 58,
119 Le = 59,
120 EqK = 60,
121 EqI = 61,
122 LtI = 62,
123 LeI = 63,
124 GtI = 64,
125 GeI = 65,
126 Test = 66,
127 TestSet = 67,
128 Call = 68,
129 TailCall = 69,
130 Return = 70,
131 Return0 = 71,
132 Return1 = 72,
133 ForLoop = 73,
134 ForPrep = 74,
135 TForPrep = 75,
136 TForCall = 76,
137 TForLoop = 77,
138 SetList = 78,
139 Closure = 79,
140 VarArg = 80,
141 VarArgPrep = 81,
142 ExtraArg = 82,
143}
144
145#[allow(dead_code)]
149const NUM_OPCODES: u8 = 83;
150
151impl OpCode {
152 #[allow(non_upper_case_globals)]
159 pub const LoadKx: OpCode = OpCode::LoadKX;
160
161 #[allow(non_upper_case_globals)]
163 pub const GetUpval: OpCode = OpCode::GetUpVal;
164
165 pub fn from_u32(v: u32) -> Option<Self> {
169 match v {
170 0 => Some(Self::Move),
171 1 => Some(Self::LoadI),
172 2 => Some(Self::LoadF),
173 3 => Some(Self::LoadK),
174 4 => Some(Self::LoadKX),
175 5 => Some(Self::LoadFalse),
176 6 => Some(Self::LFalseSkip),
177 7 => Some(Self::LoadTrue),
178 8 => Some(Self::LoadNil),
179 9 => Some(Self::GetUpVal),
180 10 => Some(Self::SetUpVal),
181 11 => Some(Self::GetTabUp),
182 12 => Some(Self::GetTable),
183 13 => Some(Self::GetI),
184 14 => Some(Self::GetField),
185 15 => Some(Self::SetTabUp),
186 16 => Some(Self::SetTable),
187 17 => Some(Self::SetI),
188 18 => Some(Self::SetField),
189 19 => Some(Self::NewTable),
190 20 => Some(Self::Self_),
191 21 => Some(Self::AddI),
192 22 => Some(Self::AddK),
193 23 => Some(Self::SubK),
194 24 => Some(Self::MulK),
195 25 => Some(Self::ModK),
196 26 => Some(Self::PowK),
197 27 => Some(Self::DivK),
198 28 => Some(Self::IDivK),
199 29 => Some(Self::BAndK),
200 30 => Some(Self::BOrK),
201 31 => Some(Self::BXOrK),
202 32 => Some(Self::ShrI),
203 33 => Some(Self::ShlI),
204 34 => Some(Self::Add),
205 35 => Some(Self::Sub),
206 36 => Some(Self::Mul),
207 37 => Some(Self::Mod),
208 38 => Some(Self::Pow),
209 39 => Some(Self::Div),
210 40 => Some(Self::IDiv),
211 41 => Some(Self::BAnd),
212 42 => Some(Self::BOr),
213 43 => Some(Self::BXOr),
214 44 => Some(Self::Shl),
215 45 => Some(Self::Shr),
216 46 => Some(Self::MmBin),
217 47 => Some(Self::MmBinI),
218 48 => Some(Self::MmBinK),
219 49 => Some(Self::Unm),
220 50 => Some(Self::BNot),
221 51 => Some(Self::Not),
222 52 => Some(Self::Len),
223 53 => Some(Self::Concat),
224 54 => Some(Self::Close),
225 55 => Some(Self::Tbc),
226 56 => Some(Self::Jmp),
227 57 => Some(Self::Eq),
228 58 => Some(Self::Lt),
229 59 => Some(Self::Le),
230 60 => Some(Self::EqK),
231 61 => Some(Self::EqI),
232 62 => Some(Self::LtI),
233 63 => Some(Self::LeI),
234 64 => Some(Self::GtI),
235 65 => Some(Self::GeI),
236 66 => Some(Self::Test),
237 67 => Some(Self::TestSet),
238 68 => Some(Self::Call),
239 69 => Some(Self::TailCall),
240 70 => Some(Self::Return),
241 71 => Some(Self::Return0),
242 72 => Some(Self::Return1),
243 73 => Some(Self::ForLoop),
244 74 => Some(Self::ForPrep),
245 75 => Some(Self::TForPrep),
246 76 => Some(Self::TForCall),
247 77 => Some(Self::TForLoop),
248 78 => Some(Self::SetList),
249 79 => Some(Self::Closure),
250 80 => Some(Self::VarArg),
251 81 => Some(Self::VarArgPrep),
252 82 => Some(Self::ExtraArg),
253 _ => None,
254 }
255 }
256}
257
258pub trait InstructionExt {
262 fn opcode(&self) -> OpCode;
263 fn arg_a(&self) -> i32;
264 fn arg_b(&self) -> i32;
265 fn arg_c(&self) -> i32;
266 fn arg_k(&self) -> i32;
267 fn arg_ax(&self) -> i32;
268 fn arg_bx(&self) -> i32;
269 fn arg_s_b(&self) -> i32;
270 fn arg_s_c(&self) -> i32;
271 fn arg_s_j(&self) -> i32;
272 fn arg_s_bx(&self) -> i32;
273 fn test_k(&self) -> bool;
274 fn test_a_mode(&self) -> bool;
275 fn is_mm_mode(&self) -> bool;
276 fn is_vararg_prep(&self) -> bool;
277 fn is_in_top(&self) -> bool;
278}
279
280impl InstructionExt for Instruction {
281 #[inline(always)]
289 fn opcode(&self) -> OpCode {
290 match (self.raw() & 0x7F) as u8 {
291 0 => OpCode::Move,
292 1 => OpCode::LoadI,
293 2 => OpCode::LoadF,
294 3 => OpCode::LoadK,
295 4 => OpCode::LoadKX,
296 5 => OpCode::LoadFalse,
297 6 => OpCode::LFalseSkip,
298 7 => OpCode::LoadTrue,
299 8 => OpCode::LoadNil,
300 9 => OpCode::GetUpVal,
301 10 => OpCode::SetUpVal,
302 11 => OpCode::GetTabUp,
303 12 => OpCode::GetTable,
304 13 => OpCode::GetI,
305 14 => OpCode::GetField,
306 15 => OpCode::SetTabUp,
307 16 => OpCode::SetTable,
308 17 => OpCode::SetI,
309 18 => OpCode::SetField,
310 19 => OpCode::NewTable,
311 20 => OpCode::Self_,
312 21 => OpCode::AddI,
313 22 => OpCode::AddK,
314 23 => OpCode::SubK,
315 24 => OpCode::MulK,
316 25 => OpCode::ModK,
317 26 => OpCode::PowK,
318 27 => OpCode::DivK,
319 28 => OpCode::IDivK,
320 29 => OpCode::BAndK,
321 30 => OpCode::BOrK,
322 31 => OpCode::BXOrK,
323 32 => OpCode::ShrI,
324 33 => OpCode::ShlI,
325 34 => OpCode::Add,
326 35 => OpCode::Sub,
327 36 => OpCode::Mul,
328 37 => OpCode::Mod,
329 38 => OpCode::Pow,
330 39 => OpCode::Div,
331 40 => OpCode::IDiv,
332 41 => OpCode::BAnd,
333 42 => OpCode::BOr,
334 43 => OpCode::BXOr,
335 44 => OpCode::Shl,
336 45 => OpCode::Shr,
337 46 => OpCode::MmBin,
338 47 => OpCode::MmBinI,
339 48 => OpCode::MmBinK,
340 49 => OpCode::Unm,
341 50 => OpCode::BNot,
342 51 => OpCode::Not,
343 52 => OpCode::Len,
344 53 => OpCode::Concat,
345 54 => OpCode::Close,
346 55 => OpCode::Tbc,
347 56 => OpCode::Jmp,
348 57 => OpCode::Eq,
349 58 => OpCode::Lt,
350 59 => OpCode::Le,
351 60 => OpCode::EqK,
352 61 => OpCode::EqI,
353 62 => OpCode::LtI,
354 63 => OpCode::LeI,
355 64 => OpCode::GtI,
356 65 => OpCode::GeI,
357 66 => OpCode::Test,
358 67 => OpCode::TestSet,
359 68 => OpCode::Call,
360 69 => OpCode::TailCall,
361 70 => OpCode::Return,
362 71 => OpCode::Return0,
363 72 => OpCode::Return1,
364 73 => OpCode::ForLoop,
365 74 => OpCode::ForPrep,
366 75 => OpCode::TForPrep,
367 76 => OpCode::TForCall,
368 77 => OpCode::TForLoop,
369 78 => OpCode::SetList,
370 79 => OpCode::Closure,
371 80 => OpCode::VarArg,
372 81 => OpCode::VarArgPrep,
373 82 => OpCode::ExtraArg,
374 _ => OpCode::ExtraArg,
375 }
376 }
377 #[inline] fn arg_a(&self) -> i32 { ((self.raw() >> 7) & 0xFF) as i32 }
378 #[inline] fn arg_b(&self) -> i32 { ((self.raw() >> 16) & 0xFF) as i32 }
379 #[inline] fn arg_c(&self) -> i32 { ((self.raw() >> 24) & 0xFF) as i32 }
380 #[inline] fn arg_k(&self) -> i32 { ((self.raw() >> 15) & 0x1) as i32 }
381 #[inline] fn arg_ax(&self) -> i32 { (self.raw() >> 7) as i32 }
382 #[inline] fn arg_bx(&self) -> i32 { (self.raw() >> 15) as i32 }
383 #[inline] fn arg_s_b(&self) -> i32 { self.arg_b() - 0x7F }
384 #[inline] fn arg_s_c(&self) -> i32 { self.arg_c() - 0x7F }
385 #[inline] fn arg_s_j(&self) -> i32 { self.arg_ax() - 0xFFFFFF }
386 #[inline] fn arg_s_bx(&self) -> i32 { self.arg_bx() - 0xFFFF }
387 #[inline] fn test_k(&self) -> bool { (self.raw() & (1 << 15)) != 0 }
388 #[inline]
389 fn test_a_mode(&self) -> bool {
390 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
391 }
392 #[inline]
393 fn is_mm_mode(&self) -> bool {
394 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
395 }
396 #[inline]
397 fn is_vararg_prep(&self) -> bool {
398 matches!(self.opcode(), OpCode::VarArgPrep)
399 }
400 #[inline]
401 fn is_in_top(&self) -> bool {
402 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
403 }
404}
405
406const OP_MODE_BYTES: [u8; NUM_OPCODES as usize] = [
419 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, ];
503
504#[inline(always)]
505fn op_mode_byte(op: OpCode) -> u8 {
506 OP_MODE_BYTES[op as usize]
507}
508
509const MAX_TAG_LOOP: i32 = 2000;
513
514const NBITS: u32 = 64;
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq)]
520pub(crate) enum F2Imod {
521 Eq,
523 Floor,
525 Ceil,
527}
528
529#[inline]
532fn intop_add(a: i64, b: i64) -> i64 {
533 (a as u64).wrapping_add(b as u64) as i64
534}
535
536#[inline]
537fn intop_sub(a: i64, b: i64) -> i64 {
538 (a as u64).wrapping_sub(b as u64) as i64
539}
540
541#[inline]
542fn intop_mul(a: i64, b: i64) -> i64 {
543 (a as u64).wrapping_mul(b as u64) as i64
544}
545
546#[inline]
548fn intop_shr(x: i64, n: u32) -> i64 {
549 (x as u64 >> n) as i64
551}
552
553#[inline]
554fn intop_shl(x: i64, n: u32) -> i64 {
555 (x as u64).wrapping_shl(n) as i64
556}
557
558#[inline]
559fn intop_band(a: i64, b: i64) -> i64 { ((a as u64) & (b as u64)) as i64 }
560#[inline]
561fn intop_bor(a: i64, b: i64) -> i64 { ((a as u64) | (b as u64)) as i64 }
562#[inline]
563fn intop_bxor(a: i64, b: i64) -> i64 { ((a as u64) ^ (b as u64)) as i64 }
564
565#[inline]
570fn int_fits_float(i: i64) -> bool {
571 const MAXINTFITSF: u64 = 1u64 << f64::MANTISSA_DIGITS;
572 (MAXINTFITSF.wrapping_add(i as u64)) <= 2 * MAXINTFITSF
573}
574
575fn str_to_number(obj: &LuaValue) -> Option<LuaValue> {
581 let s = match obj {
583 LuaValue::Str(ts) => ts.as_bytes().to_vec(),
584 _ => return None,
585 };
586 let trimmed = trim_whitespace(&s);
588 if trimmed.is_empty() {
589 return None;
590 }
591 let mut result = LuaValue::Nil;
592 if crate::object::str2num(trimmed, &mut result) != 0 {
593 return Some(result);
594 }
595 None
596}
597
598fn trim_whitespace(s: &[u8]) -> &[u8] {
599 let start = s.iter().position(|&b| !b.is_ascii_whitespace()).unwrap_or(s.len());
600 let end = s.iter().rposition(|&b| !b.is_ascii_whitespace()).map(|i| i + 1).unwrap_or(0);
601 if start <= end { &s[start..end] } else { &s[0..0] }
602}
603
604pub(crate) fn tonumber_(obj: &LuaValue) -> Option<f64> {
610 if let LuaValue::Int(i) = obj {
611 return Some(*i as f64);
612 }
613 if let Some(v) = str_to_number(obj) {
614 return match v {
615 LuaValue::Float(f) => Some(f),
616 LuaValue::Int(i) => Some(i as f64),
617 _ => None,
618 };
619 }
620 None
621}
622
623fn tonumber(obj: &LuaValue) -> Option<f64> {
625 if let LuaValue::Float(f) = obj {
626 return Some(*f);
627 }
628 tonumber_(obj)
629}
630
631pub(crate) fn flt_to_integer(n: f64, mode: F2Imod) -> Option<i64> {
634 let f = n.floor();
635 if n != f {
636 match mode {
637 F2Imod::Eq => return None,
638 F2Imod::Ceil => {
639 let f = f + 1.0;
641 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
643 return Some(f as i64);
644 }
645 return None;
646 }
647 F2Imod::Floor => { }
648 }
649 }
650 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
651 Some(f as i64)
652 } else {
653 None
654 }
655}
656
657pub(crate) fn to_integer_ns(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
659 if let LuaValue::Float(f) = obj {
660 return flt_to_integer(*f, mode);
661 }
662 if let LuaValue::Int(i) = obj {
663 return Some(*i);
664 }
665 None
666}
667
668pub(crate) fn to_integer(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
670 let coerced;
671 let obj = if let Some(v) = str_to_number(obj) {
672 coerced = v;
673 &coerced
674 } else {
675 obj
676 };
677 to_integer_ns(obj, mode)
678}
679
680fn forlimit(
687 state: &mut LuaState,
688 init: i64,
689 lim: &LuaValue,
690 step: i64,
691) -> Result<(bool, i64), LuaError> {
692 let round = if step < 0 { F2Imod::Ceil } else { F2Imod::Floor };
693 if let Some(p) = to_integer(lim, round) {
694 let skip = if step > 0 { init > p } else { init < p };
695 return Ok((skip, p));
696 }
697 let flim = match tonumber(lim) {
698 Some(f) => f,
699 None => return Err(crate::debug::for_error(state, lim, b"limit")),
700 };
701 if 0.0_f64 < flim {
702 if step < 0 {
704 return Ok((true, 0));
705 }
706 Ok((false, i64::MAX))
707 } else {
708 if step > 0 {
710 return Ok((true, 0));
711 }
712 Ok((false, i64::MIN))
713 }
714}
715
716pub(crate) fn forprep(state: &mut LuaState, ra: StackIdx) -> Result<bool, LuaError> {
721 let pinit = state.get_at(ra);
722 let plimit = state.get_at(ra + 1);
723 let pstep = state.get_at(ra + 2);
724
725 if let (LuaValue::Int(init), LuaValue::Int(step)) = (&pinit, &pstep) {
726 let init = *init;
727 let step = *step;
728 if step == 0 {
729 return Err(LuaError::runtime(format_args!("'for' step is zero")));
730 }
731 state.set_at(ra + 3, LuaValue::Int(init));
732
733 let (skip, limit) = forlimit(state, init, &plimit, step)?;
734 if skip {
735 return Ok(true);
736 }
737 let count: u64 = if step > 0 {
738 let c = (limit as u64).wrapping_sub(init as u64);
739 if step != 1 { c / (step as u64) } else { c }
740 } else {
741 let c = (init as u64).wrapping_sub(limit as u64);
742 c / (((-(step + 1)) as u64).wrapping_add(1))
743 };
744 state.set_at(ra + 1, LuaValue::Int(count as i64));
745 Ok(false)
746 } else {
747 let limit_f = match tonumber(&plimit) {
748 Some(f) => f,
749 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
750 };
751 let step_f = match tonumber(&pstep) {
752 Some(f) => f,
753 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
754 };
755 let init_f = match tonumber(&pinit) {
756 Some(f) => f,
757 None => return Err(crate::debug::for_error(state, &pinit, b"initial value")),
758 };
759 if step_f == 0.0 {
760 return Err(LuaError::runtime(format_args!("'for' step is zero")));
761 }
762 let skip = if step_f > 0.0 { limit_f < init_f } else { init_f < limit_f };
763 if skip {
764 return Ok(true);
765 }
766 state.set_at(ra + 1, LuaValue::Float(limit_f));
768 state.set_at(ra + 2, LuaValue::Float(step_f));
769 state.set_at(ra, LuaValue::Float(init_f));
770 state.set_at(ra + 3, LuaValue::Float(init_f));
771 Ok(false)
772 }
773}
774
775fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
777 let step = match state.get_at(ra + 2) {
779 LuaValue::Float(f) => f,
780 _ => return false,
781 };
782 let limit = match state.get_at(ra + 1) {
783 LuaValue::Float(f) => f,
784 _ => return false,
785 };
786 let idx = match state.get_at(ra) {
787 LuaValue::Float(f) => f,
788 _ => return false,
789 };
790 let idx = idx + step;
791 if if step > 0.0 { idx <= limit } else { limit <= idx } {
792 state.set_at(ra, LuaValue::Float(idx));
793 state.set_at(ra + 3, LuaValue::Float(idx));
794 true
795 } else {
796 false
797 }
798}
799
800pub(crate) fn finish_get(
806 state: &mut LuaState,
807 t_val: LuaValue,
808 key: LuaValue,
809 result_idx: StackIdx,
810 slot_empty: bool,
811 t_idx: Option<StackIdx>,
812) -> Result<(), LuaError> {
813 let mut t = t_val;
814 let mut t_idx = t_idx;
815 for _loop in 0..MAX_TAG_LOOP {
816 let tm: LuaValue;
817 if slot_empty && !matches!(t, LuaValue::Table(_)) {
818 tm = state.get_tm_by_obj(&t, TagMethod::Index);
819 if matches!(tm, LuaValue::Nil) {
820 return Err(match t_idx {
821 Some(idx) => crate::debug::type_error(state, &t, idx, b"index"),
822 None => LuaError::type_error(&t, "index"),
823 });
824 }
825 } else {
826 let mt = state.table_metatable(&t);
827 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
828 if matches!(tm, LuaValue::Nil) {
829 state.set_at(result_idx, LuaValue::Nil);
830 return Ok(());
831 }
832 }
833 if matches!(tm, LuaValue::Function(_)) {
834 state.call_tm_res(tm, &t, &key, result_idx)?;
835 return Ok(());
836 }
837 t = tm.clone();
838 t_idx = None;
839 if let Some(v) = state.fast_get(&t, &key)? {
840 state.set_at(result_idx, v);
841 return Ok(());
842 }
843 }
845 Err(LuaError::runtime(format_args!("'__index' chain too long; possible loop")))
846}
847
848pub(crate) fn finish_set(
857 state: &mut LuaState,
858 t_val: LuaValue,
859 key: LuaValue,
860 val: LuaValue,
861 _slot_present: bool,
862 t_idx: Option<StackIdx>,
863 var_hint: Option<(&[u8], &[u8])>,
864) -> Result<(), LuaError> {
865 let mut t = t_val;
866 let mut t_idx = t_idx;
867 for _loop in 0..MAX_TAG_LOOP {
868 let tm: LuaValue;
869 if matches!(t, LuaValue::Table(_)) {
870 let mt = state.table_metatable(&t);
871 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
872 if matches!(tm, LuaValue::Nil) {
873 state.table_raw_set(&t, key, val.clone())?;
874 state.gc_barrier_back(&t, &val);
875 return Ok(());
876 }
877 } else {
878 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
879 if matches!(tm, LuaValue::Nil) {
880 return Err(match (t_idx, var_hint) {
881 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
882 (None, Some((kind, name))) => {
883 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
884 }
885 (None, None) => LuaError::type_error(&t, "index"),
886 });
887 }
888 }
889 if matches!(tm, LuaValue::Function(_)) {
890 state.call_tm(tm, &t, &key, &val)?;
891 return Ok(());
892 }
893 t = tm.clone();
894 t_idx = None;
895 if state.fast_get(&t, &key)?.is_some() {
896 state.table_raw_set(&t, key.clone(), val.clone())?;
897 state.gc_barrier_back(&t, &val);
898 return Ok(());
899 }
900 }
901 Err(LuaError::runtime(format_args!("'__newindex' chain too long; possible loop")))
902}
903
904fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
915 let mut s1 = s1;
918 let mut s2 = s2;
919 loop {
920 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
922 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
923 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
925 if seg_cmp != std::cmp::Ordering::Equal {
926 return seg_cmp;
927 }
928 if z2 == s2.len() {
930 if z1 == s1.len() {
932 return std::cmp::Ordering::Equal;
933 }
934 return std::cmp::Ordering::Greater; }
936 if z1 == s1.len() {
937 return std::cmp::Ordering::Less; }
939 s1 = &s1[z1 + 1..];
941 s2 = &s2[z2 + 1..];
942 }
943}
944
945#[inline]
948fn lt_int_float(i: i64, f: f64) -> bool {
949 if int_fits_float(i) {
950 (i as f64) < f
951 } else {
952 match flt_to_integer(f, F2Imod::Ceil) {
953 Some(fi) => i < fi,
954 None => f > 0.0, }
956 }
957}
958
959#[inline]
960fn le_int_float(i: i64, f: f64) -> bool {
961 if int_fits_float(i) {
962 (i as f64) <= f
963 } else {
964 match flt_to_integer(f, F2Imod::Floor) {
965 Some(fi) => i <= fi,
966 None => f > 0.0,
967 }
968 }
969}
970
971#[inline]
972fn lt_float_int(f: f64, i: i64) -> bool {
973 if int_fits_float(i) {
974 f < (i as f64)
975 } else {
976 match flt_to_integer(f, F2Imod::Floor) {
977 Some(fi) => fi < i,
978 None => f < 0.0,
979 }
980 }
981}
982
983#[inline]
984fn le_float_int(f: f64, i: i64) -> bool {
985 if int_fits_float(i) {
986 f <= (i as f64)
987 } else {
988 match flt_to_integer(f, F2Imod::Ceil) {
989 Some(fi) => fi <= i,
990 None => f < 0.0,
991 }
992 }
993}
994
995#[inline]
996fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
997 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
998 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
999 match (l, r) {
1000 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1001 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1002 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1003 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1004 _ => false,
1005 }
1006}
1007
1008#[inline]
1009fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1010 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1011 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1012 match (l, r) {
1013 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1014 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1015 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1016 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1017 _ => false,
1018 }
1019}
1020
1021fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1023 debug_assert!(!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1024 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))));
1025 match (l, r) {
1026 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1027 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1028 }
1029 _ => state.call_order_tm(l, r, TagMethod::Lt),
1030 }
1031}
1032
1033pub(crate) fn less_than(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1034 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1035 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1036 {
1037 Ok(lt_num(l, r))
1038 } else {
1039 less_than_others(state, l, r)
1040 }
1041}
1042
1043fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1044 match (l, r) {
1045 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1046 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1047 }
1048 _ => state.call_order_tm(l, r, TagMethod::Le),
1049 }
1050}
1051
1052pub(crate) fn less_equal(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1053 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1054 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1055 {
1056 Ok(le_num(l, r))
1057 } else {
1058 less_equal_others(state, l, r)
1059 }
1060}
1061
1062pub(crate) fn equal_obj(
1066 state: Option<&mut LuaState>,
1067 t1: &LuaValue,
1068 t2: &LuaValue,
1069) -> Result<bool, LuaError> {
1070 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1073 if !same_variant {
1074 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1075 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1076 if !(t1_is_num && t2_is_num) {
1077 return Ok(false);
1078 }
1079 let i1 = to_integer_ns(t1, F2Imod::Eq);
1081 let i2 = to_integer_ns(t2, F2Imod::Eq);
1082 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1083 }
1084
1085 match (t1, t2) {
1086 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1087 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1088 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1089 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1090 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1091 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1092 use lua_types::closure::LuaClosure;
1093 let same = match (f1, f2) {
1094 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1095 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1096 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1097 _ => false,
1098 };
1099 Ok(same)
1100 }
1101 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1102 Ok(s1 == s2)
1105 }
1106 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1107 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1110 return Ok(true);
1111 }
1112 let Some(state) = state else { return Ok(false); };
1113 let tm1 = state.fast_tm_ud(u1, TagMethod::Eq);
1114 let tm = if matches!(tm1, LuaValue::Nil) {
1115 state.fast_tm_ud(u2, TagMethod::Eq)
1116 } else {
1117 tm1
1118 };
1119 if matches!(tm, LuaValue::Nil) {
1120 return Ok(false);
1121 }
1122 let result = state.call_tm_res_bool(tm, t1, t2)?;
1123 Ok(result)
1124 }
1125 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1126 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1127 return Ok(true);
1128 }
1129 let Some(state) = state else { return Ok(false); };
1130 let mt1 = h1.metatable();
1132 let mt2 = h2.metatable();
1133 let tm1 = state.fast_tm_table(mt1.as_ref(), TagMethod::Eq);
1134 let tm = if matches!(tm1, LuaValue::Nil) {
1135 state.fast_tm_table(mt2.as_ref(), TagMethod::Eq)
1136 } else {
1137 tm1
1138 };
1139 if matches!(tm, LuaValue::Nil) {
1140 return Ok(false);
1141 }
1142 let result = state.call_tm_res_bool(tm, t1, t2)?;
1143 Ok(result)
1144 }
1145 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1146 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1147 }
1148}
1149
1150fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1154 buf.clear();
1155 let mut remaining = n;
1156 loop {
1157 let idx = top - remaining as i32;
1158 let v = state.get_at(idx);
1159 if let LuaValue::Str(ts) = v {
1160 buf.extend_from_slice(ts.as_bytes());
1161 }
1162 if remaining <= 1 {
1163 break;
1164 }
1165 remaining -= 1;
1166 }
1167}
1168
1169pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1171 if total == 1 {
1172 return Ok(());
1173 }
1174 let mut total = total;
1175 loop {
1176 let top = state.top_idx();
1177 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1182 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1183 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1185 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1186 if !top2_coercible || !top1_stringlike {
1187 state.try_concat_tm(&v_tm1, &v_tm2)?;
1188 total -= 1;
1193 let top = state.top_idx();
1194 state.set_top(top - 1);
1195 if total <= 1 {
1196 break;
1197 }
1198 continue;
1199 }
1200
1201 let is_empty = |v: &LuaValue| -> bool {
1202 matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty())
1203 };
1204
1205 let n: u32;
1206 if is_empty(&v_tm1) {
1207 state.coerce_to_string(top - 2)?;
1208 n = 2;
1209 } else if is_empty(&v_tm2) {
1210 state.coerce_to_string(top - 1)?;
1213 let v = state.get_at(top - 1);
1214 state.set_at(top - 2, v);
1215 n = 2;
1216 } else {
1217 state.coerce_to_string(top - 1)?;
1219 let s1 = match state.get_at(top - 1) {
1220 LuaValue::Str(ts) => ts.as_bytes().len(),
1221 _ => 0,
1222 };
1223 let mut total_len = s1;
1224 let mut count: u32 = 1;
1225 let top = state.top_idx();
1226 loop {
1227 if count as i32 >= total {
1228 break;
1229 }
1230 let idx = top - (count as i32 + 1);
1231 let v = state.get_at(idx);
1232 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1233 break;
1234 }
1235 state.coerce_to_string(idx)?;
1236 let l = match state.get_at(idx) {
1237 LuaValue::Str(ts) => ts.as_bytes().len(),
1238 _ => 0,
1239 };
1240 if l >= usize::MAX - total_len {
1241 state.set_top(top - total as i32);
1243 return Err(LuaError::runtime(format_args!("string length overflow")));
1244 }
1245 total_len += l;
1246 count += 1;
1247 }
1248 n = count;
1249
1250 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1252 let top = state.top_idx();
1253 copy_to_buf(state, top, n, &mut buf);
1254 let ts = state.intern_or_create_str(&buf)?;
1255 state.set_at(top - n as i32, LuaValue::Str(ts));
1256 }
1257 total -= n as i32 - 1;
1258 let top = state.top_idx();
1259 state.set_top(top - ((n - 1) as i32));
1260
1261 if total <= 1 {
1262 break;
1263 }
1264 }
1265 Ok(())
1266}
1267
1268pub(crate) fn obj_len(state: &mut LuaState, ra: StackIdx, rb: LuaValue, rb_idx: StackIdx) -> Result<(), LuaError> {
1272 match &rb {
1273 LuaValue::Table(_) => {
1274 let mt = state.table_metatable(&rb);
1276 let tm = state.fast_tm_table(mt.as_ref(), TagMethod::Len);
1277 if matches!(tm, LuaValue::Nil) {
1278 let n = state.table_length(&rb)?;
1279 state.set_at(ra, LuaValue::Int(n as i64));
1280 return Ok(());
1281 }
1282 state.call_tm_res(tm, &rb, &rb, ra)?;
1284 }
1285 LuaValue::Str(ts) => {
1286 let n = ts.len();
1289 state.set_at(ra, LuaValue::Int(n as i64));
1290 }
1291 other => {
1292 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1294 if matches!(tm, LuaValue::Nil) {
1295 return Err(crate::debug::type_error(state, other, rb_idx, b"get length of"));
1296 }
1297 state.call_tm_res(tm, &rb, &rb, ra)?;
1298 }
1299 }
1300 Ok(())
1301}
1302
1303pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1307 if (n as u64).wrapping_add(1) <= 1 {
1308 if n == 0 {
1309 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1310 }
1311 return Ok(intop_sub(0, m));
1312 }
1313 let q = m / n;
1314 if (m ^ n) < 0 && m % n != 0 {
1316 Ok(q - 1)
1317 } else {
1318 Ok(q)
1319 }
1320}
1321
1322pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1324 if (n as u64).wrapping_add(1) <= 1 {
1325 if n == 0 {
1326 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1327 }
1328 return Ok(0);
1329 }
1330 let r = m % n;
1331 if r != 0 && (r ^ n) < 0 {
1332 Ok(r + n)
1333 } else {
1334 Ok(r)
1335 }
1336}
1337
1338pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1340 let r = m % n;
1341 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1342 if opposite_signs {
1343 r + n
1344 } else {
1345 r
1346 }
1347}
1348
1349pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1352 use TagMethod::*;
1353 match i {
1354 0 => Index, 1 => NewIndex, 2 => Gc, 3 => Mode, 4 => Len, 5 => Eq,
1355 6 => Add, 7 => Sub, 8 => Mul, 9 => Mod, 10 => Pow, 11 => Div,
1356 12 => Idiv, 13 => Band, 14 => Bor, 15 => Bxor, 16 => Shl, 17 => Shr,
1357 18 => Unm, 19 => Bnot, 20 => Lt, 21 => Le, 22 => Concat, 23 => Call,
1358 24 => Close,
1359 _ => Index,
1360 }
1361}
1362
1363pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1366 imod(a, b)
1367}
1368
1369pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1372 idiv(a, b)
1373}
1374
1375pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1378 Ok(fmodf(a, b))
1379}
1380
1381pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1383 if y < 0 {
1384 if y <= -(NBITS as i64) {
1385 0
1386 } else {
1387 intop_shr(x, (-y) as u32)
1388 }
1389 } else {
1390 if y >= NBITS as i64 {
1391 0
1392 } else {
1393 intop_shl(x, y as u32)
1394 }
1395 }
1396}
1397
1398fn push_closure(
1404 state: &mut LuaState,
1405 proto_idx: usize, ci: CallInfoIdx,
1407 base: StackIdx,
1408 ra: StackIdx,
1409) -> Result<(), LuaError> {
1410 state.push_closure(proto_idx, ci, base, ra)
1414}
1415
1416pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1421 let ci = state.current_ci_idx();
1425 let base = state.ci_base(ci);
1426 let inst = state.ci_prev_instruction(ci);
1427 let op = inst.opcode();
1428
1429 match op {
1430 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1432 let prev_inst = state.ci_prev2_instruction(ci);
1433 let a = prev_inst.arg_a();
1434 state.dec_top();
1435 let top = state.top_idx();
1436 let v = state.get_at(top);
1437 state.set_at(base + a, v);
1438 }
1439 OpCode::Unm | OpCode::BNot | OpCode::Len
1441 | OpCode::GetTabUp | OpCode::GetTable | OpCode::GetI
1442 | OpCode::GetField | OpCode::Self_ => {
1443 let a = inst.arg_a();
1444 state.dec_top();
1445 let top = state.top_idx();
1446 let v = state.get_at(top);
1447 state.set_at(base + a, v);
1448 }
1449 OpCode::Lt | OpCode::Le | OpCode::LtI | OpCode::LeI
1453 | OpCode::GtI | OpCode::GeI | OpCode::Eq => {
1454 let top_minus1 = state.top_idx() - 1;
1455 let v = state.get_at(top_minus1);
1456 let res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1457 state.dec_top();
1458 if (res as i32) != inst.arg_k() {
1459 state.ci_skip_next_instruction(ci);
1460 }
1461 }
1463 OpCode::Concat => {
1469 let top = state.top_idx() - 1; let a = inst.arg_a();
1471 let total_concat = (top - 1 - (base + a)) as i32;
1472 let v = state.get_at(top);
1473 state.set_at(top - 2, v);
1474 state.set_top(top - 1);
1475 concat(state, total_concat)?;
1476 }
1477 OpCode::Close => {
1478 state.ci_step_pc_back(ci);
1479 }
1480 OpCode::Return => {
1484 let a = inst.arg_a();
1485 let ra = base + a;
1486 let nres = state.ci_nres(ci);
1487 state.set_top(ra + nres);
1488 state.ci_step_pc_back(ci);
1489 }
1490 other => {
1491 debug_assert!(
1492 matches!(
1493 other,
1494 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1495 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1496 ),
1497 "unexpected opcode in finish_op: {:?}",
1498 other
1499 );
1500 }
1501 }
1502 Ok(())
1503}
1504
1505pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1517 let mut trap: bool;
1518
1519 'startfunc: loop {
1521 trap = state.hook_mask() != 0;
1522
1523 'returning: loop {
1526 let cl = match state.ci_lua_closure(ci) {
1527 Some(c) => c,
1528 None => {
1529 return Err(LuaError::runtime(format_args!(
1530 "internal: execute called on non-Lua frame"
1531 )));
1532 }
1533 };
1534 let mut pc: u32 = state.ci_savedpc(ci);
1536
1537 if trap {
1538 trap = state.trace_call(ci)?;
1539 }
1540 let mut base: StackIdx = state.ci_base(ci);
1541
1542 'dispatch: loop {
1544 if trap {
1545 trap = state.trace_exec(ci, pc)?;
1546 base = state.ci_base(ci); }
1548 let i: Instruction = state.proto_code(&cl, pc);
1549 pc += 1;
1550 let op = i.opcode();
1551
1552 debug_assert!(base == state.ci_base(ci));
1553
1554 #[cfg(debug_assertions)]
1558 {
1559 let op_mode = op_mode_byte(op);
1560 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1561 state.set_top(base);
1562 }
1563 }
1564
1565 match op {
1566 OpCode::Move => {
1568 let ra = base + i.arg_a();
1569 let rb = base + i.arg_b();
1570 let v = state.stack[rb.0 as usize].val;
1571 state.stack[ra.0 as usize].val = v;
1572 }
1573 OpCode::LoadI => {
1575 let ra = base + i.arg_a();
1576 let b = i.arg_s_bx() as i64;
1577 state.set_at(ra, LuaValue::Int(b));
1578 }
1579 OpCode::LoadF => {
1581 let ra = base + i.arg_a();
1582 let b = i.arg_s_bx() as f64;
1583 state.set_at(ra, LuaValue::Float(b));
1584 }
1585 OpCode::LoadK => {
1587 let ra = base + i.arg_a();
1588 let k_idx = i.arg_bx() as usize;
1589 let v = state.proto_const(&cl, k_idx).clone();
1590 state.set_at(ra, v);
1591 }
1592 OpCode::LoadKX => {
1594 let ra = base + i.arg_a();
1595 let extra = state.proto_code(&cl, pc);
1596 pc += 1;
1597 let k_idx = extra.arg_ax() as usize;
1598 let v = state.proto_const(&cl, k_idx).clone();
1599 state.set_at(ra, v);
1600 }
1601 OpCode::LoadFalse => {
1603 let ra = base + i.arg_a();
1604 state.set_at(ra, LuaValue::Bool(false));
1605 }
1606 OpCode::LFalseSkip => {
1608 let ra = base + i.arg_a();
1609 state.set_at(ra, LuaValue::Bool(false));
1610 pc += 1;
1611 }
1612 OpCode::LoadTrue => {
1614 let ra = base + i.arg_a();
1615 state.set_at(ra, LuaValue::Bool(true));
1616 }
1617 OpCode::LoadNil => {
1619 let ra = base + i.arg_a();
1620 let b = i.arg_b();
1621 for k in 0..=b {
1622 state.set_at(ra + k, LuaValue::Nil);
1623 }
1624 }
1625 OpCode::GetUpVal => {
1627 let ra = base + i.arg_a();
1628 let b = i.arg_b() as usize;
1629 let v = state.upvalue_get(&cl, b);
1630 state.set_at(ra, v);
1631 }
1632 OpCode::SetUpVal => {
1635 let ra = base + i.arg_a();
1636 let b = i.arg_b() as usize;
1637 let v = state.stack[ra.0 as usize].val;
1638 let uv = cl.upval(b);
1639 match uv.try_open_payload() {
1640 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1641 state.stack[idx.0 as usize].val = v;
1642 }
1643 _ => {
1644 state.upvalue_set(&cl, b, v)?;
1645 }
1646 }
1647 }
1648 OpCode::GetTabUp => {
1652 let ra = base + i.arg_a();
1653 let b = i.arg_b() as usize;
1654 let k_idx = i.arg_c() as usize;
1655 let upval = state.upvalue_get(&cl, b);
1656 let key = state.proto_const(&cl, k_idx).clone();
1657 match state.fast_get_short_str(&upval, &key)? {
1658 Some(v) => state.set_at(ra, v),
1659 None => {
1660 state.set_ci_savedpc(ci, pc);
1661 state.set_top(state.ci_top(ci));
1662 finish_get(state, upval, key, ra, true, None)?;
1663 trap = state.ci_trap(ci);
1664 }
1665 }
1666 }
1667 OpCode::GetTable => {
1670 let ra = base + i.arg_a();
1671 let rb_idx = base + i.arg_b();
1672 let rb_v = state.get_at(rb_idx);
1673 let rc_v = state.get_at(base + i.arg_c());
1674 let fast_result = if let LuaValue::Int(n) = &rc_v {
1675 state.fast_get_int(&rb_v, *n)?
1676 } else {
1677 state.fast_get(&rb_v, &rc_v)?
1678 };
1679 match fast_result {
1680 Some(v) => state.set_at(ra, v),
1681 None => {
1682 state.set_ci_savedpc(ci, pc);
1683 state.set_top(state.ci_top(ci));
1684 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1685 trap = state.ci_trap(ci);
1686 }
1687 }
1688 }
1689 OpCode::GetI => {
1693 let ra = base + i.arg_a();
1694 let rb_idx = base + i.arg_b();
1695 let rb_v = state.get_at(rb_idx);
1696 let c = i.arg_c() as i64;
1697 match state.fast_get_int(&rb_v, c)? {
1698 Some(v) => state.set_at(ra, v),
1699 None => {
1700 let key = LuaValue::Int(c);
1701 state.set_ci_savedpc(ci, pc);
1702 state.set_top(state.ci_top(ci));
1703 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1704 trap = state.ci_trap(ci);
1705 }
1706 }
1707 }
1708 OpCode::GetField => {
1710 let ra = base + i.arg_a();
1711 let rb_idx = base + i.arg_b();
1712 let rb_v = state.get_at(rb_idx);
1713 let k_idx = i.arg_c() as usize;
1714 let key = state.proto_const(&cl, k_idx).clone();
1715 match state.fast_get_short_str(&rb_v, &key)? {
1716 Some(v) => state.set_at(ra, v),
1717 None => {
1718 state.set_ci_savedpc(ci, pc);
1719 state.set_top(state.ci_top(ci));
1720 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1721 trap = state.ci_trap(ci);
1722 }
1723 }
1724 }
1725 OpCode::SetTabUp => {
1727 let a = i.arg_a() as usize;
1728 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1730 state.proto_const(&cl, i.arg_c() as usize).clone()
1731 } else {
1732 state.get_at(base + i.arg_c())
1733 };
1734 let upval = state.upvalue_get(&cl, a);
1735 let key = state.proto_const(&cl, b_idx).clone();
1736 match state.fast_get_short_str(&upval, &key)? {
1737 Some(_slot) => {
1738 state.table_raw_set(&upval, key, rc_v.clone())?;
1739 state.gc_barrier_back(&upval, &rc_v);
1740 }
1741 None => {
1742 state.set_ci_savedpc(ci, pc);
1743 state.set_top(state.ci_top(ci));
1744 let upval_name: Vec<u8> = cl
1745 .proto
1746 .upvalues
1747 .get(a)
1748 .and_then(|uv| uv.name.as_ref())
1749 .map(|s| s.as_bytes().to_vec())
1750 .unwrap_or_else(|| b"?".to_vec());
1751 let hint: Option<(&[u8], &[u8])> =
1752 Some((b"upvalue", &upval_name));
1753 finish_set(state, upval, key, rc_v, false, None, hint)?;
1754 trap = state.ci_trap(ci);
1755 }
1756 }
1757 }
1758 OpCode::SetTable => {
1760 let ra_idx = base + i.arg_a();
1761 let ra_v = state.get_at(ra_idx);
1762 let rb_v = state.get_at(base + i.arg_b());
1763 let rc_v = if i.test_k() {
1764 state.proto_const(&cl, i.arg_c() as usize).clone()
1765 } else {
1766 state.get_at(base + i.arg_c())
1767 };
1768 let fast = if let LuaValue::Int(n) = &rb_v {
1769 state.fast_get_int(&ra_v, *n)?
1770 } else {
1771 state.fast_get(&ra_v, &rb_v)?
1772 };
1773 if fast.is_some() {
1774 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1775 state.gc_barrier_back(&ra_v, &rc_v);
1776 } else {
1777 state.set_ci_savedpc(ci, pc);
1778 state.set_top(state.ci_top(ci));
1779 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1780 trap = state.ci_trap(ci);
1781 }
1782 }
1783 OpCode::SetI => {
1785 let ra_idx = base + i.arg_a();
1786 let ra_v = state.get_at(ra_idx);
1787 let c = i.arg_b() as i64;
1788 let rc_v = if i.test_k() {
1789 state.proto_const(&cl, i.arg_c() as usize).clone()
1790 } else {
1791 state.get_at(base + i.arg_c())
1792 };
1793 let fast = state.fast_get_int(&ra_v, c)?;
1794 if fast.is_some() {
1795 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1796 state.gc_barrier_back(&ra_v, &rc_v);
1797 } else {
1798 state.set_ci_savedpc(ci, pc);
1799 state.set_top(state.ci_top(ci));
1800 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1801 trap = state.ci_trap(ci);
1802 }
1803 }
1804 OpCode::SetField => {
1806 let ra_idx = base + i.arg_a();
1807 let ra_v = state.get_at(ra_idx);
1808 let b_idx = i.arg_b() as usize;
1809 let key = state.proto_const(&cl, b_idx).clone();
1810 let rc_v = if i.test_k() {
1811 state.proto_const(&cl, i.arg_c() as usize).clone()
1812 } else {
1813 state.get_at(base + i.arg_c())
1814 };
1815 match state.fast_get_short_str(&ra_v, &key)? {
1816 Some(_) => {
1817 state.table_raw_set(&ra_v, key, rc_v.clone())?;
1818 state.gc_barrier_back(&ra_v, &rc_v);
1819 }
1820 None => {
1821 state.set_ci_savedpc(ci, pc);
1822 state.set_top(state.ci_top(ci));
1823 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
1824 trap = state.ci_trap(ci);
1825 }
1826 }
1827 }
1828 OpCode::NewTable => {
1831 let ra = base + i.arg_a();
1832 let mut b = i.arg_b();
1833 let mut c = i.arg_c();
1834 if b > 0 {
1835 b = 1 << (b - 1);
1836 }
1837 if i.test_k() {
1838 let extra = state.proto_code(&cl, pc);
1839 pc += 1;
1840 const MAXARG_C: i32 = (1 << 8) - 1;
1841 c += extra.arg_ax() * (MAXARG_C + 1);
1842 } else {
1843 pc += 1; }
1845 state.set_top(ra + 1);
1846 let t = if b != 0 || c != 0 {
1847 state.new_table_with_sizes(c as u32, b as u32)?
1848 } else {
1849 state.new_table()
1850 };
1851 state.set_at(ra, LuaValue::Table(t.clone()));
1852 state.set_ci_savedpc(ci, pc);
1853 state.set_top(ra + 1);
1854 state.gc_cond_step();
1855 if state.hookmask != 0 {
1856 trap = state.ci_trap(ci);
1857 }
1858 }
1859 OpCode::Self_ => {
1861 let ra = base + i.arg_a();
1862 let rb_idx = base + i.arg_b();
1863 let rb_v = state.get_at(rb_idx);
1864 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
1866 state.proto_const(&cl, k_idx).clone()
1867 } else {
1868 state.get_at(base + i.arg_c())
1869 };
1870 state.set_at(ra + 1, rb_v.clone());
1871 match state.fast_get_short_str(&rb_v, &key)? {
1872 Some(v) => state.set_at(ra, v),
1873 None => {
1874 state.set_ci_savedpc(ci, pc);
1875 state.set_top(state.ci_top(ci));
1876 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1877 trap = state.ci_trap(ci);
1878 }
1879 }
1880 }
1881 OpCode::AddI => {
1883 let ra = base + i.arg_a();
1884 let rb = base + i.arg_b();
1885 let imm = i.arg_s_c() as i64;
1886 let rb_v = state.stack[rb.0 as usize].val;
1887 match rb_v {
1888 LuaValue::Int(iv1) => {
1889 pc += 1;
1890 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
1891 }
1892 LuaValue::Float(nb) => {
1893 pc += 1;
1894 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
1895 }
1896 _ => {}
1897 }
1898 }
1899 OpCode::AddK => {
1901 let ra = base + i.arg_a();
1902 let rb = base + i.arg_b();
1903 let kidx = i.arg_c() as usize;
1904 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1905 pc += 1;
1906 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
1907 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1908 pc += 1;
1909 state.set_at(ra, LuaValue::Float(n1 + n2));
1910 }
1911 }
1912 OpCode::SubK => {
1913 let ra = base + i.arg_a();
1914 let rb = base + i.arg_b();
1915 let kidx = i.arg_c() as usize;
1916 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1917 pc += 1;
1918 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
1919 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1920 pc += 1;
1921 state.set_at(ra, LuaValue::Float(n1 - n2));
1922 }
1923 }
1924 OpCode::MulK => {
1925 let ra = base + i.arg_a();
1926 let rb = base + i.arg_b();
1927 let kidx = i.arg_c() as usize;
1928 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1929 pc += 1;
1930 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1931 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1932 pc += 1;
1933 state.set_at(ra, LuaValue::Float(n1 * n2));
1934 }
1935 }
1936 OpCode::ModK => {
1937 let ra = base + i.arg_a();
1938 let v1 = state.get_at(base + i.arg_b());
1939 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1940 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
1942 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1943 |a, b| imod(a, b), fmodf)?;
1944 }
1945 OpCode::PowK => {
1946 let ra = base + i.arg_a();
1947 let rb = base + i.arg_b();
1948 let kidx = i.arg_c() as usize;
1949 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1950 pc += 1;
1951 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1952 state.set_at(ra, LuaValue::Float(r));
1953 }
1954 }
1955 OpCode::DivK => {
1956 let ra = base + i.arg_a();
1957 let rb = base + i.arg_b();
1958 let kidx = i.arg_c() as usize;
1959 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1960 pc += 1;
1961 state.set_at(ra, LuaValue::Float(n1 / n2));
1962 }
1963 }
1964 OpCode::IDivK => {
1965 let ra = base + i.arg_a();
1966 let v1 = state.get_at(base + i.arg_b());
1967 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1968 state.set_ci_savedpc(ci, pc);
1969 state.set_top(state.ci_top(ci));
1970 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1971 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
1972 }
1973 OpCode::BAndK => {
1974 let ra = base + i.arg_a();
1975 let v1 = state.get_at(base + i.arg_b());
1976 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1977 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
1978 }
1979 OpCode::BOrK => {
1980 let ra = base + i.arg_a();
1981 let v1 = state.get_at(base + i.arg_b());
1982 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1983 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
1984 }
1985 OpCode::BXOrK => {
1986 let ra = base + i.arg_a();
1987 let v1 = state.get_at(base + i.arg_b());
1988 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1989 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
1990 }
1991 OpCode::ShrI => {
1992 let ra = base + i.arg_a();
1993 let v = state.get_at(base + i.arg_b());
1994 let ic = i.arg_s_c() as i64;
1995 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
1996 pc += 1;
1997 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
1998 }
1999 }
2000 OpCode::ShlI => {
2001 let ra = base + i.arg_a();
2002 let v = state.get_at(base + i.arg_b());
2003 let ic = i.arg_s_c() as i64;
2004 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2005 pc += 1;
2006 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2007 }
2008 }
2009 OpCode::Add => {
2011 let ra = base + i.arg_a();
2012 let rb = base + i.arg_b();
2013 let rc = base + i.arg_c();
2014 let ra_u = ra.0 as usize;
2015 let rb_v = state.stack[rb.0 as usize].val;
2016 let rc_v = state.stack[rc.0 as usize].val;
2017 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2018 pc += 1;
2019 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2020 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2021 pc += 1;
2022 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2023 }
2024 }
2025 OpCode::Sub => {
2026 let ra = base + i.arg_a();
2027 let rb = base + i.arg_b();
2028 let rc = base + i.arg_c();
2029 let ra_u = ra.0 as usize;
2030 let rb_v = state.stack[rb.0 as usize].val;
2031 let rc_v = state.stack[rc.0 as usize].val;
2032 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2033 pc += 1;
2034 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2035 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2036 pc += 1;
2037 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2038 }
2039 }
2040 OpCode::Mul => {
2041 let ra = base + i.arg_a();
2042 let rb = base + i.arg_b();
2043 let rc = base + i.arg_c();
2044 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2045 pc += 1;
2046 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2047 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2048 pc += 1;
2049 state.set_at(ra, LuaValue::Float(n1 * n2));
2050 }
2051 }
2052 OpCode::Mod => {
2053 let ra = base + i.arg_a();
2054 let v1 = state.get_at(base + i.arg_b());
2055 let v2 = state.get_at(base + i.arg_c());
2056 state.set_ci_savedpc(ci, pc);
2057 state.set_top(state.ci_top(ci));
2058 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2059 |a, b| imod(a, b), fmodf)?;
2060 }
2061 OpCode::Pow => {
2062 let ra = base + i.arg_a();
2063 let rb = base + i.arg_b();
2064 let rc = base + i.arg_c();
2065 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2066 pc += 1;
2067 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2068 state.set_at(ra, LuaValue::Float(r));
2069 }
2070 }
2071 OpCode::Div => {
2072 let ra = base + i.arg_a();
2073 let rb = base + i.arg_b();
2074 let rc = base + i.arg_c();
2075 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2076 pc += 1;
2077 state.set_at(ra, LuaValue::Float(n1 / n2));
2078 }
2079 }
2080 OpCode::IDiv => {
2081 let ra = base + i.arg_a();
2082 let v1 = state.get_at(base + i.arg_b());
2083 let v2 = state.get_at(base + i.arg_c());
2084 state.set_ci_savedpc(ci, pc);
2085 state.set_top(state.ci_top(ci));
2086 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2087 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2088 }
2089 OpCode::BAnd => {
2092 let ra = base + i.arg_a();
2093 let v1 = state.get_at(base + i.arg_b());
2094 let v2 = state.get_at(base + i.arg_c());
2095 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2096 }
2097 OpCode::BOr => {
2098 let ra = base + i.arg_a();
2099 let v1 = state.get_at(base + i.arg_b());
2100 let v2 = state.get_at(base + i.arg_c());
2101 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2102 }
2103 OpCode::BXOr => {
2104 let ra = base + i.arg_a();
2105 let v1 = state.get_at(base + i.arg_b());
2106 let v2 = state.get_at(base + i.arg_c());
2107 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2108 }
2109 OpCode::Shr => {
2110 let ra = base + i.arg_a();
2111 let v1 = state.get_at(base + i.arg_b());
2112 let v2 = state.get_at(base + i.arg_c());
2113 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2114 }
2115 OpCode::Shl => {
2116 let ra = base + i.arg_a();
2117 let v1 = state.get_at(base + i.arg_b());
2118 let v2 = state.get_at(base + i.arg_c());
2119 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2120 }
2121 OpCode::MmBin => {
2126 let ra_idx = base + i.arg_a();
2127 let rb_idx = base + i.arg_b();
2128 let ra_v = state.get_at(ra_idx);
2129 let rb_v = state.get_at(rb_idx);
2130 let tm = tagmethod_from_index(i.arg_c() as usize);
2131 let prev_inst = state.proto_code(&cl, pc - 2);
2132 let result_idx = base + prev_inst.arg_a();
2133 state.set_ci_savedpc(ci, pc);
2134 state.set_top(state.ci_top(ci));
2135 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2136 trap = state.ci_trap(ci);
2137 }
2138 OpCode::MmBinI => {
2139 let ra_idx = base + i.arg_a();
2140 let ra_v = state.get_at(ra_idx);
2141 let imm = i.arg_s_b() as i64;
2142 let tm = tagmethod_from_index(i.arg_c() as usize);
2143 let flip = i.arg_k() != 0;
2144 let prev_inst = state.proto_code(&cl, pc - 2);
2145 let result_idx = base + prev_inst.arg_a();
2146 state.set_ci_savedpc(ci, pc);
2147 state.set_top(state.ci_top(ci));
2148 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2149 trap = state.ci_trap(ci);
2150 }
2151 OpCode::MmBinK => {
2152 let ra_idx = base + i.arg_a();
2153 let ra_v = state.get_at(ra_idx);
2154 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2155 let tm = tagmethod_from_index(i.arg_c() as usize);
2156 let flip = i.arg_k() != 0;
2157 let prev_inst = state.proto_code(&cl, pc - 2);
2158 let result_idx = base + prev_inst.arg_a();
2159 state.set_ci_savedpc(ci, pc);
2160 state.set_top(state.ci_top(ci));
2161 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2162 trap = state.ci_trap(ci);
2163 }
2164 OpCode::Unm => {
2168 let ra = base + i.arg_a();
2169 let rb_idx = base + i.arg_b();
2170 let rb_v = state.get_at(rb_idx);
2171 match &rb_v {
2172 LuaValue::Int(ib) => {
2173 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2174 }
2175 LuaValue::Float(nb) => {
2176 state.set_at(ra, LuaValue::Float(-nb));
2177 }
2178 _ => {
2179 state.set_ci_savedpc(ci, pc);
2180 state.set_top(state.ci_top(ci));
2181 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2182 trap = state.ci_trap(ci);
2183 }
2184 }
2185 }
2186 OpCode::BNot => {
2188 let ra = base + i.arg_a();
2189 let rb_idx = base + i.arg_b();
2190 let rb_v = state.get_at(rb_idx);
2191 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2192 state.set_at(ra, LuaValue::Int(!ib));
2193 } else {
2194 state.set_ci_savedpc(ci, pc);
2195 state.set_top(state.ci_top(ci));
2196 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2197 trap = state.ci_trap(ci);
2198 }
2199 }
2200 OpCode::Not => {
2202 let ra = base + i.arg_a();
2203 let rb_v = state.get_at(base + i.arg_b());
2204 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2205 state.set_at(ra, LuaValue::Bool(falsy));
2206 }
2207 OpCode::Len => {
2209 let ra = base + i.arg_a();
2210 let rb_idx = base + i.arg_b();
2211 let rb_v = state.get_at(rb_idx);
2212 state.set_ci_savedpc(ci, pc);
2213 state.set_top(state.ci_top(ci));
2214 obj_len(state, ra, rb_v, rb_idx)?;
2215 trap = state.ci_trap(ci);
2216 }
2217 OpCode::Concat => {
2219 let ra = base + i.arg_a();
2220 let n = i.arg_b() as i32;
2221 state.set_top(ra + n as i32);
2222 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2224 let top = state.top_idx();
2225 state.set_ci_savedpc(ci, pc);
2226 state.set_top(top);
2227 state.gc_cond_step();
2228 trap = state.ci_trap(ci);
2229 }
2230 OpCode::Close => {
2232 let ra = base + i.arg_a();
2233 state.set_ci_savedpc(ci, pc);
2234 state.set_top(state.ci_top(ci));
2235 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2236 trap = state.ci_trap(ci);
2237 }
2238 OpCode::Tbc => {
2240 let ra = base + i.arg_a();
2241 state.set_ci_savedpc(ci, pc);
2242 state.set_top(state.ci_top(ci));
2243 state.new_tbc_upval(ra)?;
2244 }
2245 OpCode::Jmp => {
2247 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2248 trap = state.ci_trap(ci);
2249 }
2250 OpCode::Eq => {
2252 let ra_v = state.get_at(base + i.arg_a());
2253 let rb_v = state.get_at(base + i.arg_b());
2254 state.set_ci_savedpc(ci, pc);
2255 state.set_top(state.ci_top(ci));
2256 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2257 trap = state.ci_trap(ci);
2258 if (cond as i32) != i.arg_k() {
2259 pc += 1;
2260 } else {
2261 let next = state.proto_code(&cl, pc);
2262 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2263 trap = state.ci_trap(ci);
2264 }
2265 }
2266 OpCode::Lt => {
2268 let ra_v = state.get_at(base + i.arg_a());
2269 let rb_v = state.get_at(base + i.arg_b());
2270 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2271 *ia < *ib
2272 } else if matches!((&ra_v, &rb_v),
2273 (LuaValue::Int(_) | LuaValue::Float(_),
2274 LuaValue::Int(_) | LuaValue::Float(_))) {
2275 lt_num(&ra_v, &rb_v)
2276 } else {
2277 state.set_ci_savedpc(ci, pc);
2278 state.set_top(state.ci_top(ci));
2279 let r = less_than_others(state, &ra_v, &rb_v)?;
2280 trap = state.ci_trap(ci);
2281 r
2282 };
2283 if (cond as i32) != i.arg_k() {
2284 pc += 1;
2285 } else {
2286 let next = state.proto_code(&cl, pc);
2287 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2288 trap = state.ci_trap(ci);
2289 }
2290 }
2291 OpCode::Le => {
2293 let ra_v = state.get_at(base + i.arg_a());
2294 let rb_v = state.get_at(base + i.arg_b());
2295 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2296 *ia <= *ib
2297 } else if matches!((&ra_v, &rb_v),
2298 (LuaValue::Int(_) | LuaValue::Float(_),
2299 LuaValue::Int(_) | LuaValue::Float(_))) {
2300 le_num(&ra_v, &rb_v)
2301 } else {
2302 state.set_ci_savedpc(ci, pc);
2303 state.set_top(state.ci_top(ci));
2304 let r = less_equal_others(state, &ra_v, &rb_v)?;
2305 trap = state.ci_trap(ci);
2306 r
2307 };
2308 if (cond as i32) != i.arg_k() {
2309 pc += 1;
2310 } else {
2311 let next = state.proto_code(&cl, pc);
2312 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2313 trap = state.ci_trap(ci);
2314 }
2315 }
2316 OpCode::EqK => {
2318 let ra_v = state.get_at(base + i.arg_a());
2319 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2320 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2321 if (cond as i32) != i.arg_k() {
2322 pc += 1;
2323 } else {
2324 let next = state.proto_code(&cl, pc);
2325 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2326 trap = state.ci_trap(ci);
2327 }
2328 }
2329 OpCode::EqI => {
2334 let ra_v = state.get_at(base + i.arg_a());
2335 let im = i.arg_s_b() as i64;
2336 let cond: bool = match &ra_v {
2337 LuaValue::Int(iv) => *iv == im,
2338 LuaValue::Float(fv) => *fv == im as f64,
2339 _ => false,
2340 };
2341 if (cond as i32) != i.arg_k() {
2342 pc += 1;
2343 } else {
2344 let next = state.proto_code(&cl, pc);
2345 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2346 trap = state.ci_trap(ci);
2347 }
2348 }
2349 OpCode::LtI => {
2352 let ra = base + i.arg_a();
2353 let im = i.arg_s_b() as i64;
2354 let fast_cond = match &state.stack[ra.0 as usize].val {
2355 LuaValue::Int(ia) => Some(*ia < im),
2356 LuaValue::Float(fa) => Some(*fa < im as f64),
2357 _ => None,
2358 };
2359 let cond = match fast_cond {
2360 Some(cond) => cond,
2361 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2362 };
2363 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2364 }
2365 OpCode::LeI => {
2366 let ra = base + i.arg_a();
2367 let im = i.arg_s_b() as i64;
2368 let fast_cond = match &state.stack[ra.0 as usize].val {
2369 LuaValue::Int(ia) => Some(*ia <= im),
2370 LuaValue::Float(fa) => Some(*fa <= im as f64),
2371 _ => None,
2372 };
2373 let cond = match fast_cond {
2374 Some(cond) => cond,
2375 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2376 };
2377 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2378 }
2379 OpCode::GtI => {
2380 let ra = base + i.arg_a();
2381 let im = i.arg_s_b() as i64;
2382 let fast_cond = match &state.stack[ra.0 as usize].val {
2383 LuaValue::Int(ia) => Some(*ia > im),
2384 LuaValue::Float(fa) => Some(*fa > im as f64),
2385 _ => None,
2386 };
2387 let cond = match fast_cond {
2388 Some(cond) => cond,
2389 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2390 };
2391 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2392 }
2393 OpCode::GeI => {
2394 let ra = base + i.arg_a();
2395 let im = i.arg_s_b() as i64;
2396 let fast_cond = match &state.stack[ra.0 as usize].val {
2397 LuaValue::Int(ia) => Some(*ia >= im),
2398 LuaValue::Float(fa) => Some(*fa >= im as f64),
2399 _ => None,
2400 };
2401 let cond = match fast_cond {
2402 Some(cond) => cond,
2403 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2404 };
2405 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2406 }
2407 OpCode::Test => {
2409 let ra_v = state.get_at(base + i.arg_a());
2410 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2411 if (cond as i32) != i.arg_k() {
2412 pc += 1;
2413 } else {
2414 let next = state.proto_code(&cl, pc);
2415 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2416 trap = state.ci_trap(ci);
2417 }
2418 }
2419 OpCode::TestSet => {
2422 let ra = base + i.arg_a();
2423 let rb_v = state.get_at(base + i.arg_b());
2424 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2425 if (falsy as i32) == i.arg_k() {
2426 pc += 1;
2427 } else {
2428 state.set_at(ra, rb_v);
2429 let next = state.proto_code(&cl, pc);
2430 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2431 trap = state.ci_trap(ci);
2432 }
2433 }
2434 OpCode::Call => {
2438 let ra = base + i.arg_a();
2439 let b = i.arg_b();
2440 let nresults = i.arg_c() as i32 - 1;
2441 if b != 0 {
2442 state.set_top(ra + b);
2443 }
2444 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2446 match state.precall(ra, nresults)? {
2447 None => {
2448 if had_hook || state.hookmask != 0 {
2452 trap = state.ci_trap(ci); }
2454 }
2455 Some(new_ci) => {
2456 ci = new_ci;
2458 continue 'startfunc;
2459 }
2460 }
2461 }
2462 OpCode::TailCall => {
2467 let ra = base + i.arg_a();
2468 let b = i.arg_b();
2469 let nparams1 = i.arg_c();
2470 let delta = if nparams1 != 0 {
2471 state.ci_nextraargs(ci) + nparams1 as i32
2472 } else {
2473 0
2474 };
2475 let top_b: i32 = if b != 0 {
2476 state.set_top(ra + b);
2477 b
2478 } else {
2479 state.top_idx() - ra
2480 };
2481 state.set_ci_savedpc(ci, pc);
2482 if i.test_k() {
2483 state.close_upvals_from_base(ci)?;
2484 }
2485 let n = state.pretailcall(ci, ra, top_b, delta)?;
2486 if n < 0 {
2487 continue 'startfunc;
2489 } else {
2490 state.ci_adjust_func(ci, delta);
2492 state.poscall(ci, n as u32)?;
2493 if state.hookmask != 0 {
2494 trap = state.ci_trap(ci);
2495 }
2496 break 'dispatch; }
2498 }
2499 OpCode::Return => {
2504 let ra = base + i.arg_a();
2505 let n_raw = i.arg_b() as i32 - 1;
2506 let nparams1 = i.arg_c();
2507 let n: u32 = if n_raw < 0 {
2508 (state.top_idx() - ra) as u32
2509 } else {
2510 n_raw as u32
2511 };
2512 state.set_ci_savedpc(ci, pc);
2513 if i.test_k() {
2514 state.ci_nres_set(ci, n as i32);
2515 let ci_top = state.ci_top(ci);
2516 if state.top_idx().0 < ci_top.0 {
2517 state.set_top(ci_top);
2518 }
2519 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2520 if state.hookmask != 0 {
2521 trap = state.ci_trap(ci);
2522 }
2523 base = state.ci_base(ci); }
2525 if nparams1 != 0 {
2526 let nextraargs = state.ci_nextraargs(ci) as u32;
2527 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2528 }
2529 state.set_top(ra + n as i32);
2530 state.poscall(ci, n)?;
2531 if state.hookmask != 0 {
2532 trap = state.ci_trap(ci);
2533 }
2534 break 'dispatch; }
2536 OpCode::Return0 => {
2542 if state.hookmask == 0 {
2543 let ci_slot = ci.as_usize();
2544 let nres = state.call_info[ci_slot].nresults as i32;
2545 state.ci = state.call_info[ci_slot]
2546 .previous
2547 .expect("RETURN0: returning frame has no previous CallInfo");
2548 state.top = base - 1;
2549 for _ in 0..nres.max(0) {
2550 state.push(LuaValue::Nil);
2551 }
2552 } else {
2553 return0_hook(state, ci, base, i, pc, &mut trap)?;
2554 }
2555 break 'dispatch; }
2557 OpCode::Return1 => {
2561 if state.hookmask == 0 {
2562 let ci_slot = ci.as_usize();
2563 let nres = state.call_info[ci_slot].nresults as i32;
2564 state.ci = state.call_info[ci_slot]
2565 .previous
2566 .expect("RETURN1: returning frame has no previous CallInfo");
2567 if nres == 0 {
2568 state.top = base - 1;
2569 } else {
2570 let ra = base + i.arg_a();
2571 state.stack[(base - 1).0 as usize].val =
2572 state.stack[ra.0 as usize].val; state.top = base;
2574 for _ in 1..nres.max(0) {
2575 state.push(LuaValue::Nil);
2576 }
2577 }
2578 } else {
2579 return1_hook(state, ci, base, i, pc, &mut trap)?;
2580 }
2581 break 'dispatch; }
2583 OpCode::ForLoop => {
2587 let ra = base + i.arg_a();
2588 let ra_u = ra.0 as usize;
2589 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2590 let count = match state.stack[ra_u + 1].val {
2591 LuaValue::Int(c) => c as u64,
2592 _ => 0,
2593 };
2594 if count > 0 {
2595 let idx = match state.stack[ra_u].val {
2596 LuaValue::Int(x) => x,
2597 _ => 0,
2598 };
2599 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2600 let new_idx = intop_add(idx, step);
2601 state.stack[ra_u].val = LuaValue::Int(new_idx);
2602 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2603 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2604 }
2605 } else if float_for_loop(state, ra) {
2606 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2607 }
2608 trap = state.ci_trap(ci);
2609 }
2610 OpCode::ForPrep => {
2612 let ra = base + i.arg_a();
2613 state.set_ci_savedpc(ci, pc);
2614 state.set_top(state.ci_top(ci));
2615 if forprep(state, ra)? {
2616 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2617 }
2618 }
2619 OpCode::TForPrep => {
2623 let ra = base + i.arg_a();
2624 state.set_ci_savedpc(ci, pc);
2625 state.set_top(state.ci_top(ci));
2626 state.new_tbc_upval(ra + 3)?;
2627 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2628 let tfc_i = state.proto_code(&cl, pc);
2629 pc += 1;
2630 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2631 let tfc_ra = base + tfc_i.arg_a();
2633 for k in 0..3u32 {
2634 let v = state.get_at(tfc_ra + k as i32);
2635 state.set_at(tfc_ra + 4 + k as i32, v);
2636 }
2637 state.set_top(tfc_ra + 4 + 3);
2638 state.set_ci_savedpc(ci, pc);
2639 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2640 trap = state.ci_trap(ci);
2641 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2643 pc += 1;
2644 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2645 let tfl_ra = base + tfl_i.arg_a();
2646 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2648 let v = state.get_at(tfl_ra + 4);
2649 state.set_at(tfl_ra + 2, v);
2650 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2651 }
2652 }
2653 OpCode::TForCall => {
2655 let ra = base + i.arg_a();
2656 for k in 0..3u32 {
2657 let v = state.get_at(ra + k as i32);
2658 state.set_at(ra + 4 + k as i32, v);
2659 }
2660 state.set_top(ra + 4 + 3);
2661 state.set_ci_savedpc(ci, pc);
2662 state.call_at(ra + 4, i.arg_c() as i32)?;
2663 trap = state.ci_trap(ci);
2664 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2666 pc += 1;
2667 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2668 let tfl_ra = base + tfl_i.arg_a();
2669 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2670 let v = state.get_at(tfl_ra + 4);
2671 state.set_at(tfl_ra + 2, v);
2672 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2673 }
2674 }
2675 OpCode::TForLoop => {
2677 let ra = base + i.arg_a();
2678 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2679 let v = state.get_at(ra + 4);
2680 state.set_at(ra + 2, v);
2681 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2682 }
2683 }
2684 OpCode::SetList => {
2688 let ra = base + i.arg_a();
2689 let n_raw = i.arg_b();
2690 let mut last = i.arg_c();
2691 let t_val = state.get_at(ra);
2692 let n: i32 = if n_raw == 0 {
2693 state.top_idx() - ra - 1
2694 } else {
2695 state.set_top(state.ci_top(ci));
2696 n_raw
2697 };
2698 last += n;
2699 if i.test_k() {
2700 let extra = state.proto_code(&cl, pc);
2701 pc += 1;
2702 const MAXARG_C: i32 = (1 << 8) - 1;
2703 last += extra.arg_ax() * (MAXARG_C + 1);
2704 }
2705 state.table_ensure_array(&t_val, last as usize)?;
2706 for k in (1..=n).rev() {
2707 let val = state.get_at(ra + k as i32);
2708 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2709 last -= 1;
2710 state.gc_barrier_back(&t_val, &val);
2711 }
2712 }
2713 OpCode::Closure => {
2717 let ra = base + i.arg_a();
2718 let proto_idx = i.arg_bx() as usize;
2719 state.set_ci_savedpc(ci, pc);
2720 state.set_top(state.ci_top(ci));
2721 push_closure(state, proto_idx, ci, base, ra)?;
2722 state.set_ci_savedpc(ci, pc);
2724 state.set_top(ra + 1);
2725 state.gc_cond_step();
2726 trap = state.ci_trap(ci);
2727 }
2728 OpCode::VarArg => {
2730 let ra = base + i.arg_a();
2731 let n = i.arg_c() as i32 - 1;
2732 state.set_ci_savedpc(ci, pc);
2733 state.set_top(state.ci_top(ci));
2734 state.get_varargs(ci, ra, n)?;
2735 trap = state.ci_trap(ci);
2736 }
2737 OpCode::VarArgPrep => {
2741 let nparams = i.arg_a();
2742 state.set_ci_savedpc(ci, pc);
2743 state.adjust_varargs(ci, nparams, &cl)?;
2744 trap = state.ci_trap(ci);
2745 if trap {
2746 state.hook_call(ci)?;
2747 state.set_oldpc(1);
2748 }
2749 base = state.ci_base(ci);
2750 }
2751 OpCode::ExtraArg => {
2753 debug_assert!(false, "OP_EXTRAARG executed directly");
2754 }
2755 } } if state.ci_is_fresh(ci) {
2760 return Ok(());
2761 } else {
2762 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2763 continue 'returning;
2764 }
2765 } } }
2768
2769#[inline(always)]
2772fn number_value(v: LuaValue) -> Option<f64> {
2773 match v {
2774 LuaValue::Float(f) => Some(f),
2775 LuaValue::Int(i) => Some(i as f64),
2776 _ => None,
2777 }
2778}
2779
2780#[allow(dead_code)]
2782#[inline]
2783fn arith_op_aux_rr(
2784 state: &mut LuaState,
2785 ra: StackIdx,
2786 v1: &LuaValue,
2787 v2: &LuaValue,
2788 pc: &mut u32,
2789 iop: fn(i64, i64) -> i64,
2790 fop: fn(f64, f64) -> f64,
2791) {
2792 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2793 *pc += 1;
2794 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
2795 } else {
2796 arith_float_aux(state, ra, v1, v2, pc, fop);
2797 }
2798}
2799
2800#[allow(dead_code)]
2801#[inline]
2802fn arith_float_aux(
2803 state: &mut LuaState,
2804 ra: StackIdx,
2805 v1: &LuaValue,
2806 v2: &LuaValue,
2807 pc: &mut u32,
2808 fop: fn(f64, f64) -> f64,
2809) {
2810 let n1 = match v1 {
2811 LuaValue::Float(f) => Some(*f),
2812 LuaValue::Int(i) => Some(*i as f64),
2813 _ => None,
2814 };
2815 let n2 = match v2 {
2816 LuaValue::Float(f) => Some(*f),
2817 LuaValue::Int(i) => Some(*i as f64),
2818 _ => None,
2819 };
2820 if let (Some(n1), Some(n2)) = (n1, n2) {
2821 *pc += 1;
2822 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
2823 }
2824}
2825
2826#[allow(dead_code)]
2827#[inline]
2828fn arith_op_checked(
2829 state: &mut LuaState,
2830 ra: StackIdx,
2831 v1: &LuaValue,
2832 v2: &LuaValue,
2833 pc: &mut u32,
2834 iop: fn(i64, i64) -> Result<i64, LuaError>,
2835 fop: fn(f64, f64) -> f64,
2836) -> Result<(), LuaError> {
2837 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2838 *pc += 1;
2839 let result = iop(*i1, *i2).map_err(|e| match e {
2840 LuaError::Runtime(LuaValue::Str(s)) => {
2841 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
2842 }
2843 other => other,
2844 })?;
2845 state.set_at(ra, LuaValue::Int(result));
2846 } else {
2847 arith_float_aux(state, ra, v1, v2, pc, fop);
2848 }
2849 Ok(())
2850}
2851
2852#[allow(dead_code)]
2853#[inline]
2854fn bitwise_op_k(
2855 state: &mut LuaState,
2856 ra: StackIdx,
2857 v1: &LuaValue,
2858 v2: &LuaValue, pc: &mut u32,
2860 op: fn(i64, i64) -> i64,
2861) {
2862 let i2 = match v2 {
2863 LuaValue::Int(i) => *i,
2864 _ => return,
2865 };
2866 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
2867 *pc += 1;
2868 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2869 }
2870}
2871
2872#[allow(dead_code)]
2873#[inline]
2874fn bitwise_op_rr(
2875 state: &mut LuaState,
2876 ra: StackIdx,
2877 v1: &LuaValue,
2878 v2: &LuaValue,
2879 pc: &mut u32,
2880 op: fn(i64, i64) -> i64,
2881) {
2882 if let (Some(i1), Some(i2)) = (
2883 to_integer_ns(v1, F2Imod::Eq),
2884 to_integer_ns(v2, F2Imod::Eq),
2885 ) {
2886 *pc += 1;
2887 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2888 }
2889}
2890
2891#[allow(dead_code)]
2893#[inline]
2894fn bitwise_shift_rr(
2895 state: &mut LuaState,
2896 ra: StackIdx,
2897 v1: &LuaValue,
2898 v2: &LuaValue,
2899 pc: &mut u32,
2900 right: bool,
2901) {
2902 if let (Some(i1), Some(i2)) = (
2903 to_integer_ns(v1, F2Imod::Eq),
2904 to_integer_ns(v2, F2Imod::Eq),
2905 ) {
2906 let y = if right { intop_sub(0, i2) } else { i2 };
2907 *pc += 1;
2908 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
2909 }
2910}
2911
2912#[cold]
2915#[inline(never)]
2916#[allow(clippy::too_many_arguments)]
2917fn order_imm_slow(
2918 state: &mut LuaState,
2919 ra: StackIdx,
2920 pc: u32,
2921 trap: &mut bool,
2922 ci: CallInfoIdx,
2923 i: Instruction,
2924 im: i64,
2925 inv: bool,
2926 tm: TagMethod,
2927) -> Result<bool, LuaError> {
2928 let ra_v = state.get_at(ra);
2929 let isf = i.arg_c() != 0;
2930 state.set_ci_savedpc(ci, pc);
2931 state.set_top(state.ci_top(ci));
2932 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
2933 *trap = state.ci_trap(ci);
2934 Ok(r)
2935}
2936
2937#[inline(always)]
2938fn finish_order_imm_jump(
2939 state: &mut LuaState,
2940 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
2941 pc: &mut u32,
2942 trap: &mut bool,
2943 ci: CallInfoIdx,
2944 i: Instruction,
2945 cond: bool,
2946) {
2947 if (cond as i32) != i.arg_k() {
2948 *pc += 1;
2949 } else {
2950 let next = state.proto_code(&cl, *pc);
2951 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2952 *trap = state.ci_trap(ci);
2953 }
2954}
2955
2956#[cold]
2957#[inline(never)]
2958fn return0_hook(
2959 state: &mut LuaState,
2960 ci: CallInfoIdx,
2961 base: StackIdx,
2962 i: Instruction,
2963 pc: u32,
2964 trap: &mut bool,
2965) -> Result<(), LuaError> {
2966 let ra = base + i.arg_a();
2967 state.set_top(ra);
2968 state.set_ci_savedpc(ci, pc);
2969 state.poscall(ci, 0)?;
2970 *trap = true;
2971 Ok(())
2972}
2973
2974#[cold]
2975#[inline(never)]
2976fn return1_hook(
2977 state: &mut LuaState,
2978 ci: CallInfoIdx,
2979 base: StackIdx,
2980 i: Instruction,
2981 pc: u32,
2982 trap: &mut bool,
2983) -> Result<(), LuaError> {
2984 let ra = base + i.arg_a();
2985 state.set_top(ra + 1);
2986 state.set_ci_savedpc(ci, pc);
2987 state.poscall(ci, 1)?;
2988 *trap = true;
2989 Ok(())
2990}
2991
2992