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 ErrNNil = 83,
150 VarArgPack = 84,
158}
159
160#[allow(dead_code)]
164const NUM_OPCODES: u8 = 85;
165
166impl OpCode {
167 #[allow(non_upper_case_globals)]
174 pub const LoadKx: OpCode = OpCode::LoadKX;
175
176 #[allow(non_upper_case_globals)]
178 pub const GetUpval: OpCode = OpCode::GetUpVal;
179
180 pub fn from_u32(v: u32) -> Option<Self> {
184 match v {
185 0 => Some(Self::Move),
186 1 => Some(Self::LoadI),
187 2 => Some(Self::LoadF),
188 3 => Some(Self::LoadK),
189 4 => Some(Self::LoadKX),
190 5 => Some(Self::LoadFalse),
191 6 => Some(Self::LFalseSkip),
192 7 => Some(Self::LoadTrue),
193 8 => Some(Self::LoadNil),
194 9 => Some(Self::GetUpVal),
195 10 => Some(Self::SetUpVal),
196 11 => Some(Self::GetTabUp),
197 12 => Some(Self::GetTable),
198 13 => Some(Self::GetI),
199 14 => Some(Self::GetField),
200 15 => Some(Self::SetTabUp),
201 16 => Some(Self::SetTable),
202 17 => Some(Self::SetI),
203 18 => Some(Self::SetField),
204 19 => Some(Self::NewTable),
205 20 => Some(Self::Self_),
206 21 => Some(Self::AddI),
207 22 => Some(Self::AddK),
208 23 => Some(Self::SubK),
209 24 => Some(Self::MulK),
210 25 => Some(Self::ModK),
211 26 => Some(Self::PowK),
212 27 => Some(Self::DivK),
213 28 => Some(Self::IDivK),
214 29 => Some(Self::BAndK),
215 30 => Some(Self::BOrK),
216 31 => Some(Self::BXOrK),
217 32 => Some(Self::ShrI),
218 33 => Some(Self::ShlI),
219 34 => Some(Self::Add),
220 35 => Some(Self::Sub),
221 36 => Some(Self::Mul),
222 37 => Some(Self::Mod),
223 38 => Some(Self::Pow),
224 39 => Some(Self::Div),
225 40 => Some(Self::IDiv),
226 41 => Some(Self::BAnd),
227 42 => Some(Self::BOr),
228 43 => Some(Self::BXOr),
229 44 => Some(Self::Shl),
230 45 => Some(Self::Shr),
231 46 => Some(Self::MmBin),
232 47 => Some(Self::MmBinI),
233 48 => Some(Self::MmBinK),
234 49 => Some(Self::Unm),
235 50 => Some(Self::BNot),
236 51 => Some(Self::Not),
237 52 => Some(Self::Len),
238 53 => Some(Self::Concat),
239 54 => Some(Self::Close),
240 55 => Some(Self::Tbc),
241 56 => Some(Self::Jmp),
242 57 => Some(Self::Eq),
243 58 => Some(Self::Lt),
244 59 => Some(Self::Le),
245 60 => Some(Self::EqK),
246 61 => Some(Self::EqI),
247 62 => Some(Self::LtI),
248 63 => Some(Self::LeI),
249 64 => Some(Self::GtI),
250 65 => Some(Self::GeI),
251 66 => Some(Self::Test),
252 67 => Some(Self::TestSet),
253 68 => Some(Self::Call),
254 69 => Some(Self::TailCall),
255 70 => Some(Self::Return),
256 71 => Some(Self::Return0),
257 72 => Some(Self::Return1),
258 73 => Some(Self::ForLoop),
259 74 => Some(Self::ForPrep),
260 75 => Some(Self::TForPrep),
261 76 => Some(Self::TForCall),
262 77 => Some(Self::TForLoop),
263 78 => Some(Self::SetList),
264 79 => Some(Self::Closure),
265 80 => Some(Self::VarArg),
266 81 => Some(Self::VarArgPrep),
267 82 => Some(Self::ExtraArg),
268 83 => Some(Self::ErrNNil),
269 84 => Some(Self::VarArgPack),
270 _ => None,
271 }
272 }
273}
274
275pub trait InstructionExt {
279 fn opcode(&self) -> OpCode;
280 fn arg_a(&self) -> i32;
281 fn arg_b(&self) -> i32;
282 fn arg_c(&self) -> i32;
283 fn arg_k(&self) -> i32;
284 fn arg_ax(&self) -> i32;
285 fn arg_bx(&self) -> i32;
286 fn arg_s_b(&self) -> i32;
287 fn arg_s_c(&self) -> i32;
288 fn arg_s_j(&self) -> i32;
289 fn arg_s_bx(&self) -> i32;
290 fn test_k(&self) -> bool;
291 fn test_a_mode(&self) -> bool;
292 fn is_mm_mode(&self) -> bool;
293 fn is_vararg_prep(&self) -> bool;
294 fn is_in_top(&self) -> bool;
295}
296
297impl InstructionExt for Instruction {
298 #[inline(always)]
306 fn opcode(&self) -> OpCode {
307 match (self.raw() & 0x7F) as u8 {
308 0 => OpCode::Move,
309 1 => OpCode::LoadI,
310 2 => OpCode::LoadF,
311 3 => OpCode::LoadK,
312 4 => OpCode::LoadKX,
313 5 => OpCode::LoadFalse,
314 6 => OpCode::LFalseSkip,
315 7 => OpCode::LoadTrue,
316 8 => OpCode::LoadNil,
317 9 => OpCode::GetUpVal,
318 10 => OpCode::SetUpVal,
319 11 => OpCode::GetTabUp,
320 12 => OpCode::GetTable,
321 13 => OpCode::GetI,
322 14 => OpCode::GetField,
323 15 => OpCode::SetTabUp,
324 16 => OpCode::SetTable,
325 17 => OpCode::SetI,
326 18 => OpCode::SetField,
327 19 => OpCode::NewTable,
328 20 => OpCode::Self_,
329 21 => OpCode::AddI,
330 22 => OpCode::AddK,
331 23 => OpCode::SubK,
332 24 => OpCode::MulK,
333 25 => OpCode::ModK,
334 26 => OpCode::PowK,
335 27 => OpCode::DivK,
336 28 => OpCode::IDivK,
337 29 => OpCode::BAndK,
338 30 => OpCode::BOrK,
339 31 => OpCode::BXOrK,
340 32 => OpCode::ShrI,
341 33 => OpCode::ShlI,
342 34 => OpCode::Add,
343 35 => OpCode::Sub,
344 36 => OpCode::Mul,
345 37 => OpCode::Mod,
346 38 => OpCode::Pow,
347 39 => OpCode::Div,
348 40 => OpCode::IDiv,
349 41 => OpCode::BAnd,
350 42 => OpCode::BOr,
351 43 => OpCode::BXOr,
352 44 => OpCode::Shl,
353 45 => OpCode::Shr,
354 46 => OpCode::MmBin,
355 47 => OpCode::MmBinI,
356 48 => OpCode::MmBinK,
357 49 => OpCode::Unm,
358 50 => OpCode::BNot,
359 51 => OpCode::Not,
360 52 => OpCode::Len,
361 53 => OpCode::Concat,
362 54 => OpCode::Close,
363 55 => OpCode::Tbc,
364 56 => OpCode::Jmp,
365 57 => OpCode::Eq,
366 58 => OpCode::Lt,
367 59 => OpCode::Le,
368 60 => OpCode::EqK,
369 61 => OpCode::EqI,
370 62 => OpCode::LtI,
371 63 => OpCode::LeI,
372 64 => OpCode::GtI,
373 65 => OpCode::GeI,
374 66 => OpCode::Test,
375 67 => OpCode::TestSet,
376 68 => OpCode::Call,
377 69 => OpCode::TailCall,
378 70 => OpCode::Return,
379 71 => OpCode::Return0,
380 72 => OpCode::Return1,
381 73 => OpCode::ForLoop,
382 74 => OpCode::ForPrep,
383 75 => OpCode::TForPrep,
384 76 => OpCode::TForCall,
385 77 => OpCode::TForLoop,
386 78 => OpCode::SetList,
387 79 => OpCode::Closure,
388 80 => OpCode::VarArg,
389 81 => OpCode::VarArgPrep,
390 82 => OpCode::ExtraArg,
391 83 => OpCode::ErrNNil,
392 84 => OpCode::VarArgPack,
393 _ => OpCode::ExtraArg,
394 }
395 }
396 #[inline] fn arg_a(&self) -> i32 { ((self.raw() >> 7) & 0xFF) as i32 }
397 #[inline] fn arg_b(&self) -> i32 { ((self.raw() >> 16) & 0xFF) as i32 }
398 #[inline] fn arg_c(&self) -> i32 { ((self.raw() >> 24) & 0xFF) as i32 }
399 #[inline] fn arg_k(&self) -> i32 { ((self.raw() >> 15) & 0x1) as i32 }
400 #[inline] fn arg_ax(&self) -> i32 { (self.raw() >> 7) as i32 }
401 #[inline] fn arg_bx(&self) -> i32 { (self.raw() >> 15) as i32 }
402 #[inline] fn arg_s_b(&self) -> i32 { self.arg_b() - 0x7F }
403 #[inline] fn arg_s_c(&self) -> i32 { self.arg_c() - 0x7F }
404 #[inline] fn arg_s_j(&self) -> i32 { self.arg_ax() - 0xFFFFFF }
405 #[inline] fn arg_s_bx(&self) -> i32 { self.arg_bx() - 0xFFFF }
406 #[inline] fn test_k(&self) -> bool { (self.raw() & (1 << 15)) != 0 }
407 #[inline]
408 fn test_a_mode(&self) -> bool {
409 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
410 }
411 #[inline]
412 fn is_mm_mode(&self) -> bool {
413 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
414 }
415 #[inline]
416 fn is_vararg_prep(&self) -> bool {
417 matches!(self.opcode(), OpCode::VarArgPrep)
418 }
419 #[inline]
420 fn is_in_top(&self) -> bool {
421 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
422 }
423}
424
425const OP_MODE_BYTES: [u8; NUM_OPCODES as usize] = [
438 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, 0x01, 0x08, ];
524
525#[inline(always)]
526fn op_mode_byte(op: OpCode) -> u8 {
527 OP_MODE_BYTES[op as usize]
528}
529
530const MAX_TAG_LOOP: i32 = 2000;
534
535const NBITS: u32 = 64;
536
537#[derive(Debug, Clone, Copy, PartialEq, Eq)]
541pub(crate) enum F2Imod {
542 Eq,
544 Floor,
546 Ceil,
548}
549
550#[inline]
553fn intop_add(a: i64, b: i64) -> i64 {
554 (a as u64).wrapping_add(b as u64) as i64
555}
556
557#[inline]
558fn intop_sub(a: i64, b: i64) -> i64 {
559 (a as u64).wrapping_sub(b as u64) as i64
560}
561
562#[inline]
563fn intop_mul(a: i64, b: i64) -> i64 {
564 (a as u64).wrapping_mul(b as u64) as i64
565}
566
567#[inline]
569fn intop_shr(x: i64, n: u32) -> i64 {
570 (x as u64 >> n) as i64
572}
573
574#[inline]
575fn intop_shl(x: i64, n: u32) -> i64 {
576 (x as u64).wrapping_shl(n) as i64
577}
578
579#[inline]
580fn intop_band(a: i64, b: i64) -> i64 { ((a as u64) & (b as u64)) as i64 }
581#[inline]
582fn intop_bor(a: i64, b: i64) -> i64 { ((a as u64) | (b as u64)) as i64 }
583#[inline]
584fn intop_bxor(a: i64, b: i64) -> i64 { ((a as u64) ^ (b as u64)) as i64 }
585
586#[inline]
591fn int_fits_float(i: i64) -> bool {
592 const MAXINTFITSF: u64 = 1u64 << f64::MANTISSA_DIGITS;
593 (MAXINTFITSF.wrapping_add(i as u64)) <= 2 * MAXINTFITSF
594}
595
596fn str_to_number(obj: &LuaValue) -> Option<LuaValue> {
602 let s = match obj {
604 LuaValue::Str(ts) => ts.as_bytes().to_vec(),
605 _ => return None,
606 };
607 let trimmed = trim_whitespace(&s);
609 if trimmed.is_empty() {
610 return None;
611 }
612 let mut result = LuaValue::Nil;
613 if crate::object::str2num(trimmed, &mut result) != 0 {
614 return Some(result);
615 }
616 None
617}
618
619fn trim_whitespace(s: &[u8]) -> &[u8] {
620 let start = s.iter().position(|&b| !b.is_ascii_whitespace()).unwrap_or(s.len());
621 let end = s.iter().rposition(|&b| !b.is_ascii_whitespace()).map(|i| i + 1).unwrap_or(0);
622 if start <= end { &s[start..end] } else { &s[0..0] }
623}
624
625pub(crate) fn tonumber_(obj: &LuaValue) -> Option<f64> {
631 if let LuaValue::Int(i) = obj {
632 return Some(*i as f64);
633 }
634 if let Some(v) = str_to_number(obj) {
635 return match v {
636 LuaValue::Float(f) => Some(f),
637 LuaValue::Int(i) => Some(i as f64),
638 _ => None,
639 };
640 }
641 None
642}
643
644fn tonumber(obj: &LuaValue) -> Option<f64> {
646 if let LuaValue::Float(f) = obj {
647 return Some(*f);
648 }
649 tonumber_(obj)
650}
651
652pub(crate) fn flt_to_integer(n: f64, mode: F2Imod) -> Option<i64> {
655 let f = n.floor();
656 if n != f {
657 match mode {
658 F2Imod::Eq => return None,
659 F2Imod::Ceil => {
660 let f = f + 1.0;
662 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
664 return Some(f as i64);
665 }
666 return None;
667 }
668 F2Imod::Floor => { }
669 }
670 }
671 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
672 Some(f as i64)
673 } else {
674 None
675 }
676}
677
678pub(crate) fn to_integer_ns(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
680 if let LuaValue::Float(f) = obj {
681 return flt_to_integer(*f, mode);
682 }
683 if let LuaValue::Int(i) = obj {
684 return Some(*i);
685 }
686 None
687}
688
689pub(crate) fn to_integer(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
691 let coerced;
692 let obj = if let Some(v) = str_to_number(obj) {
693 coerced = v;
694 &coerced
695 } else {
696 obj
697 };
698 to_integer_ns(obj, mode)
699}
700
701fn forlimit(
708 state: &mut LuaState,
709 init: i64,
710 lim: &LuaValue,
711 step: i64,
712) -> Result<(bool, i64), LuaError> {
713 let round = if step < 0 { F2Imod::Ceil } else { F2Imod::Floor };
714 if let Some(p) = to_integer(lim, round) {
715 let skip = if step > 0 { init > p } else { init < p };
716 return Ok((skip, p));
717 }
718 let flim = match tonumber(lim) {
719 Some(f) => f,
720 None => return Err(crate::debug::for_error(state, lim, b"limit")),
721 };
722 if 0.0_f64 < flim {
723 if step < 0 {
725 return Ok((true, 0));
726 }
727 Ok((false, i64::MAX))
728 } else {
729 if step > 0 {
731 return Ok((true, 0));
732 }
733 Ok((false, i64::MIN))
734 }
735}
736
737pub(crate) fn forprep(state: &mut LuaState, ra: StackIdx) -> Result<bool, LuaError> {
742 let pinit = state.get_at(ra);
743 let plimit = state.get_at(ra + 1);
744 let pstep = state.get_at(ra + 2);
745
746 if let (LuaValue::Int(init), LuaValue::Int(step)) = (&pinit, &pstep) {
747 let init = *init;
748 let step = *step;
749 if step == 0 {
750 return Err(LuaError::runtime(format_args!("'for' step is zero")));
751 }
752 state.set_at(ra + 3, LuaValue::Int(init));
753
754 let (skip, limit) = forlimit(state, init, &plimit, step)?;
755 if skip {
756 return Ok(true);
757 }
758 let count: u64 = if step > 0 {
759 let c = (limit as u64).wrapping_sub(init as u64);
760 if step != 1 { c / (step as u64) } else { c }
761 } else {
762 let c = (init as u64).wrapping_sub(limit as u64);
763 c / (((-(step + 1)) as u64).wrapping_add(1))
764 };
765 state.set_at(ra + 1, LuaValue::Int(count as i64));
766 Ok(false)
767 } else {
768 let limit_f = match tonumber(&plimit) {
769 Some(f) => f,
770 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
771 };
772 let step_f = match tonumber(&pstep) {
773 Some(f) => f,
774 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
775 };
776 let init_f = match tonumber(&pinit) {
777 Some(f) => f,
778 None => return Err(crate::debug::for_error(state, &pinit, b"initial value")),
779 };
780 if step_f == 0.0 {
781 return Err(LuaError::runtime(format_args!("'for' step is zero")));
782 }
783 let skip = if step_f > 0.0 { limit_f < init_f } else { init_f < limit_f };
784 if skip {
785 return Ok(true);
786 }
787 state.set_at(ra + 1, LuaValue::Float(limit_f));
789 state.set_at(ra + 2, LuaValue::Float(step_f));
790 state.set_at(ra, LuaValue::Float(init_f));
791 state.set_at(ra + 3, LuaValue::Float(init_f));
792 Ok(false)
793 }
794}
795
796fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
798 let step = match state.get_at(ra + 2) {
800 LuaValue::Float(f) => f,
801 _ => return false,
802 };
803 let limit = match state.get_at(ra + 1) {
804 LuaValue::Float(f) => f,
805 _ => return false,
806 };
807 let idx = match state.get_at(ra) {
808 LuaValue::Float(f) => f,
809 _ => return false,
810 };
811 let idx = idx + step;
812 if if step > 0.0 { idx <= limit } else { limit <= idx } {
813 state.set_at(ra, LuaValue::Float(idx));
814 state.set_at(ra + 3, LuaValue::Float(idx));
815 true
816 } else {
817 false
818 }
819}
820
821pub(crate) fn finish_get(
827 state: &mut LuaState,
828 t_val: LuaValue,
829 key: LuaValue,
830 result_idx: StackIdx,
831 slot_empty: bool,
832 t_idx: Option<StackIdx>,
833) -> Result<(), LuaError> {
834 let mut t = t_val;
835 let mut t_idx = t_idx;
836 for _loop in 0..MAX_TAG_LOOP {
837 let tm: LuaValue;
838 if slot_empty && !matches!(t, LuaValue::Table(_)) {
839 tm = state.get_tm_by_obj(&t, TagMethod::Index);
840 if matches!(tm, LuaValue::Nil) {
841 return Err(match t_idx {
842 Some(idx) => crate::debug::type_error(state, &t, idx, b"index"),
843 None => LuaError::type_error(&t, "index"),
844 });
845 }
846 } else {
847 let mt = state.table_metatable(&t);
848 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
849 if matches!(tm, LuaValue::Nil) {
850 state.set_at(result_idx, LuaValue::Nil);
851 return Ok(());
852 }
853 }
854 if matches!(tm, LuaValue::Function(_)) {
855 state.call_tm_res(tm, &t, &key, result_idx)?;
856 return Ok(());
857 }
858 t = tm.clone();
859 t_idx = None;
860 if let Some(v) = state.fast_get(&t, &key)? {
861 state.set_at(result_idx, v);
862 return Ok(());
863 }
864 }
866 Err(LuaError::runtime(format_args!("'__index' chain too long; possible loop")))
867}
868
869pub(crate) fn finish_set(
878 state: &mut LuaState,
879 t_val: LuaValue,
880 key: LuaValue,
881 val: LuaValue,
882 _slot_present: bool,
883 t_idx: Option<StackIdx>,
884 var_hint: Option<(&[u8], &[u8])>,
885) -> Result<(), LuaError> {
886 let mut t = t_val;
887 let mut t_idx = t_idx;
888 for _loop in 0..MAX_TAG_LOOP {
889 let tm: LuaValue;
890 if matches!(t, LuaValue::Table(_)) {
891 let mt = state.table_metatable(&t);
892 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
893 if matches!(tm, LuaValue::Nil) {
894 state.table_raw_set(&t, key, val.clone())?;
895 state.gc_barrier_back(&t, &val);
896 return Ok(());
897 }
898 } else {
899 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
900 if matches!(tm, LuaValue::Nil) {
901 return Err(match (t_idx, var_hint) {
902 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
903 (None, Some((kind, name))) => {
904 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
905 }
906 (None, None) => LuaError::type_error(&t, "index"),
907 });
908 }
909 }
910 if matches!(tm, LuaValue::Function(_)) {
911 state.call_tm(tm, &t, &key, &val)?;
912 return Ok(());
913 }
914 t = tm.clone();
915 t_idx = None;
916 if state.fast_get(&t, &key)?.is_some() {
917 state.table_raw_set(&t, key.clone(), val.clone())?;
918 state.gc_barrier_back(&t, &val);
919 return Ok(());
920 }
921 }
922 Err(LuaError::runtime(format_args!("'__newindex' chain too long; possible loop")))
923}
924
925fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
936 let mut s1 = s1;
939 let mut s2 = s2;
940 loop {
941 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
943 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
944 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
946 if seg_cmp != std::cmp::Ordering::Equal {
947 return seg_cmp;
948 }
949 if z2 == s2.len() {
951 if z1 == s1.len() {
953 return std::cmp::Ordering::Equal;
954 }
955 return std::cmp::Ordering::Greater; }
957 if z1 == s1.len() {
958 return std::cmp::Ordering::Less; }
960 s1 = &s1[z1 + 1..];
962 s2 = &s2[z2 + 1..];
963 }
964}
965
966#[inline]
969fn lt_int_float(i: i64, f: f64) -> bool {
970 if int_fits_float(i) {
971 (i as f64) < f
972 } else {
973 match flt_to_integer(f, F2Imod::Ceil) {
974 Some(fi) => i < fi,
975 None => f > 0.0, }
977 }
978}
979
980#[inline]
981fn le_int_float(i: i64, f: f64) -> bool {
982 if int_fits_float(i) {
983 (i as f64) <= f
984 } else {
985 match flt_to_integer(f, F2Imod::Floor) {
986 Some(fi) => i <= fi,
987 None => f > 0.0,
988 }
989 }
990}
991
992#[inline]
993fn lt_float_int(f: f64, i: i64) -> bool {
994 if int_fits_float(i) {
995 f < (i as f64)
996 } else {
997 match flt_to_integer(f, F2Imod::Floor) {
998 Some(fi) => fi < i,
999 None => f < 0.0,
1000 }
1001 }
1002}
1003
1004#[inline]
1005fn le_float_int(f: f64, i: i64) -> bool {
1006 if int_fits_float(i) {
1007 f <= (i as f64)
1008 } else {
1009 match flt_to_integer(f, F2Imod::Ceil) {
1010 Some(fi) => fi <= i,
1011 None => f < 0.0,
1012 }
1013 }
1014}
1015
1016#[inline]
1017fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
1018 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1019 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1020 match (l, r) {
1021 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1022 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1023 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1024 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1025 _ => false,
1026 }
1027}
1028
1029#[inline]
1030fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1031 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1032 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1033 match (l, r) {
1034 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1035 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1036 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1037 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1038 _ => false,
1039 }
1040}
1041
1042fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1044 debug_assert!(!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1045 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))));
1046 match (l, r) {
1047 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1048 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1049 }
1050 _ => state.call_order_tm(l, r, TagMethod::Lt),
1051 }
1052}
1053
1054pub(crate) fn less_than(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1055 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1056 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1057 {
1058 Ok(lt_num(l, r))
1059 } else {
1060 less_than_others(state, l, r)
1061 }
1062}
1063
1064fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1065 match (l, r) {
1066 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1067 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1068 }
1069 _ => state.call_order_tm(l, r, TagMethod::Le),
1070 }
1071}
1072
1073pub(crate) fn less_equal(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1074 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1075 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1076 {
1077 Ok(le_num(l, r))
1078 } else {
1079 less_equal_others(state, l, r)
1080 }
1081}
1082
1083pub(crate) fn equal_obj(
1087 state: Option<&mut LuaState>,
1088 t1: &LuaValue,
1089 t2: &LuaValue,
1090) -> Result<bool, LuaError> {
1091 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1094 if !same_variant {
1095 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1096 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1097 if !(t1_is_num && t2_is_num) {
1098 return Ok(false);
1099 }
1100 let i1 = to_integer_ns(t1, F2Imod::Eq);
1102 let i2 = to_integer_ns(t2, F2Imod::Eq);
1103 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1104 }
1105
1106 match (t1, t2) {
1107 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1108 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1109 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1110 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1111 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1112 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1113 use lua_types::closure::LuaClosure;
1114 let same = match (f1, f2) {
1115 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1116 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1117 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1118 _ => false,
1119 };
1120 Ok(same)
1121 }
1122 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1123 Ok(s1 == s2)
1126 }
1127 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1128 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1131 return Ok(true);
1132 }
1133 let Some(state) = state else { return Ok(false); };
1134 let tm1 = state.fast_tm_ud(u1, TagMethod::Eq);
1135 let tm = if matches!(tm1, LuaValue::Nil) {
1136 state.fast_tm_ud(u2, TagMethod::Eq)
1137 } else {
1138 tm1
1139 };
1140 if matches!(tm, LuaValue::Nil) {
1141 return Ok(false);
1142 }
1143 let result = state.call_tm_res_bool(tm, t1, t2)?;
1144 Ok(result)
1145 }
1146 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1147 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1148 return Ok(true);
1149 }
1150 let Some(state) = state else { return Ok(false); };
1151 let mt1 = h1.metatable();
1153 let mt2 = h2.metatable();
1154 let tm1 = state.fast_tm_table(mt1.as_ref(), TagMethod::Eq);
1155 let tm = if matches!(tm1, LuaValue::Nil) {
1156 state.fast_tm_table(mt2.as_ref(), TagMethod::Eq)
1157 } else {
1158 tm1
1159 };
1160 if matches!(tm, LuaValue::Nil) {
1161 return Ok(false);
1162 }
1163 let result = state.call_tm_res_bool(tm, t1, t2)?;
1164 Ok(result)
1165 }
1166 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1167 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1168 }
1169}
1170
1171fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1175 buf.clear();
1176 let mut remaining = n;
1177 loop {
1178 let idx = top - remaining as i32;
1179 let v = state.get_at(idx);
1180 if let LuaValue::Str(ts) = v {
1181 buf.extend_from_slice(ts.as_bytes());
1182 }
1183 if remaining <= 1 {
1184 break;
1185 }
1186 remaining -= 1;
1187 }
1188}
1189
1190pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1192 if total == 1 {
1193 return Ok(());
1194 }
1195 let mut total = total;
1196 loop {
1197 let top = state.top_idx();
1198 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1203 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1204 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1206 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1207 if !top2_coercible || !top1_stringlike {
1208 state.try_concat_tm(&v_tm1, &v_tm2)?;
1209 total -= 1;
1214 let top = state.top_idx();
1215 state.set_top(top - 1);
1216 if total <= 1 {
1217 break;
1218 }
1219 continue;
1220 }
1221
1222 let is_empty = |v: &LuaValue| -> bool {
1223 matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty())
1224 };
1225
1226 let n: u32;
1227 if is_empty(&v_tm1) {
1228 state.coerce_to_string(top - 2)?;
1229 n = 2;
1230 } else if is_empty(&v_tm2) {
1231 state.coerce_to_string(top - 1)?;
1234 let v = state.get_at(top - 1);
1235 state.set_at(top - 2, v);
1236 n = 2;
1237 } else {
1238 state.coerce_to_string(top - 1)?;
1240 let s1 = match state.get_at(top - 1) {
1241 LuaValue::Str(ts) => ts.as_bytes().len(),
1242 _ => 0,
1243 };
1244 let mut total_len = s1;
1245 let mut count: u32 = 1;
1246 let top = state.top_idx();
1247 loop {
1248 if count as i32 >= total {
1249 break;
1250 }
1251 let idx = top - (count as i32 + 1);
1252 let v = state.get_at(idx);
1253 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1254 break;
1255 }
1256 state.coerce_to_string(idx)?;
1257 let l = match state.get_at(idx) {
1258 LuaValue::Str(ts) => ts.as_bytes().len(),
1259 _ => 0,
1260 };
1261 if l >= usize::MAX - total_len {
1262 state.set_top(top - total as i32);
1264 return Err(LuaError::runtime(format_args!("string length overflow")));
1265 }
1266 total_len += l;
1267 count += 1;
1268 }
1269 n = count;
1270
1271 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1273 let top = state.top_idx();
1274 copy_to_buf(state, top, n, &mut buf);
1275 let ts = state.intern_or_create_str(&buf)?;
1276 state.set_at(top - n as i32, LuaValue::Str(ts));
1277 }
1278 total -= n as i32 - 1;
1279 let top = state.top_idx();
1280 state.set_top(top - ((n - 1) as i32));
1281
1282 if total <= 1 {
1283 break;
1284 }
1285 }
1286 Ok(())
1287}
1288
1289pub(crate) fn obj_len(state: &mut LuaState, ra: StackIdx, rb: LuaValue, rb_idx: StackIdx) -> Result<(), LuaError> {
1293 match &rb {
1294 LuaValue::Table(_) => {
1295 let consult_len_tm = !matches!(
1300 state.global().lua_version,
1301 lua_types::LuaVersion::V51
1302 );
1303 let tm = if consult_len_tm {
1304 let mt = state.table_metatable(&rb);
1305 state.fast_tm_table(mt.as_ref(), TagMethod::Len)
1306 } else {
1307 LuaValue::Nil
1308 };
1309 if matches!(tm, LuaValue::Nil) {
1310 let n = state.table_length(&rb)?;
1311 state.set_at(ra, LuaValue::Int(n as i64));
1312 return Ok(());
1313 }
1314 state.call_tm_res(tm, &rb, &rb, ra)?;
1316 }
1317 LuaValue::Str(ts) => {
1318 let n = ts.len();
1321 state.set_at(ra, LuaValue::Int(n as i64));
1322 }
1323 other => {
1324 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1326 if matches!(tm, LuaValue::Nil) {
1327 return Err(crate::debug::type_error(state, other, rb_idx, b"get length of"));
1328 }
1329 state.call_tm_res(tm, &rb, &rb, ra)?;
1330 }
1331 }
1332 Ok(())
1333}
1334
1335pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1339 if (n as u64).wrapping_add(1) <= 1 {
1340 if n == 0 {
1341 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1342 }
1343 return Ok(intop_sub(0, m));
1344 }
1345 let q = m / n;
1346 if (m ^ n) < 0 && m % n != 0 {
1348 Ok(q - 1)
1349 } else {
1350 Ok(q)
1351 }
1352}
1353
1354pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1356 if (n as u64).wrapping_add(1) <= 1 {
1357 if n == 0 {
1358 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1359 }
1360 return Ok(0);
1361 }
1362 let r = m % n;
1363 if r != 0 && (r ^ n) < 0 {
1364 Ok(r + n)
1365 } else {
1366 Ok(r)
1367 }
1368}
1369
1370pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1372 let r = m % n;
1373 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1374 if opposite_signs {
1375 r + n
1376 } else {
1377 r
1378 }
1379}
1380
1381pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1384 use TagMethod::*;
1385 match i {
1386 0 => Index, 1 => NewIndex, 2 => Gc, 3 => Mode, 4 => Len, 5 => Eq,
1387 6 => Add, 7 => Sub, 8 => Mul, 9 => Mod, 10 => Pow, 11 => Div,
1388 12 => Idiv, 13 => Band, 14 => Bor, 15 => Bxor, 16 => Shl, 17 => Shr,
1389 18 => Unm, 19 => Bnot, 20 => Lt, 21 => Le, 22 => Concat, 23 => Call,
1390 24 => Close,
1391 _ => Index,
1392 }
1393}
1394
1395pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1398 imod(a, b)
1399}
1400
1401pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1404 idiv(a, b)
1405}
1406
1407pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1410 Ok(fmodf(a, b))
1411}
1412
1413pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1415 if y < 0 {
1416 if y <= -(NBITS as i64) {
1417 0
1418 } else {
1419 intop_shr(x, (-y) as u32)
1420 }
1421 } else {
1422 if y >= NBITS as i64 {
1423 0
1424 } else {
1425 intop_shl(x, y as u32)
1426 }
1427 }
1428}
1429
1430fn push_closure(
1436 state: &mut LuaState,
1437 proto_idx: usize, ci: CallInfoIdx,
1439 base: StackIdx,
1440 ra: StackIdx,
1441) -> Result<(), LuaError> {
1442 state.push_closure(proto_idx, ci, base, ra)
1446}
1447
1448pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1453 let ci = state.current_ci_idx();
1457 let base = state.ci_base(ci);
1458 let inst = state.ci_prev_instruction(ci);
1459 let op = inst.opcode();
1460
1461 match op {
1462 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1464 let prev_inst = state.ci_prev2_instruction(ci);
1465 let a = prev_inst.arg_a();
1466 state.dec_top();
1467 let top = state.top_idx();
1468 let v = state.get_at(top);
1469 state.set_at(base + a, v);
1470 }
1471 OpCode::Unm | OpCode::BNot | OpCode::Len
1473 | OpCode::GetTabUp | OpCode::GetTable | OpCode::GetI
1474 | OpCode::GetField | OpCode::Self_ => {
1475 let a = inst.arg_a();
1476 state.dec_top();
1477 let top = state.top_idx();
1478 let v = state.get_at(top);
1479 state.set_at(base + a, v);
1480 }
1481 OpCode::Lt | OpCode::Le | OpCode::LtI | OpCode::LeI
1485 | OpCode::GtI | OpCode::GeI | OpCode::Eq => {
1486 let top_minus1 = state.top_idx() - 1;
1487 let v = state.get_at(top_minus1);
1488 let res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1489 state.dec_top();
1490 if (res as i32) != inst.arg_k() {
1491 state.ci_skip_next_instruction(ci);
1492 }
1493 }
1495 OpCode::Concat => {
1501 let top = state.top_idx() - 1; let a = inst.arg_a();
1503 let total_concat = (top - 1 - (base + a)) as i32;
1504 let v = state.get_at(top);
1505 state.set_at(top - 2, v);
1506 state.set_top(top - 1);
1507 concat(state, total_concat)?;
1508 }
1509 OpCode::Close => {
1510 state.ci_step_pc_back(ci);
1511 }
1512 OpCode::Return => {
1516 let a = inst.arg_a();
1517 let ra = base + a;
1518 let nres = state.ci_nres(ci);
1519 state.set_top(ra + nres);
1520 state.ci_step_pc_back(ci);
1521 }
1522 other => {
1523 debug_assert!(
1524 matches!(
1525 other,
1526 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1527 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1528 ),
1529 "unexpected opcode in finish_op: {:?}",
1530 other
1531 );
1532 }
1533 }
1534 Ok(())
1535}
1536
1537pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1549 let mut trap: bool;
1550
1551 'startfunc: loop {
1553 trap = state.hook_mask() != 0;
1554
1555 'returning: loop {
1558 let cl = match state.ci_lua_closure(ci) {
1559 Some(c) => c,
1560 None => {
1561 return Err(LuaError::runtime(format_args!(
1562 "internal: execute called on non-Lua frame"
1563 )));
1564 }
1565 };
1566 let mut pc: u32 = state.ci_savedpc(ci);
1568
1569 if trap {
1570 trap = state.trace_call(ci)?;
1571 }
1572 let mut base: StackIdx = state.ci_base(ci);
1573
1574 'dispatch: loop {
1576 if trap {
1577 trap = state.trace_exec(ci, pc)?;
1578 base = state.ci_base(ci); }
1580 let i: Instruction = state.proto_code(&cl, pc);
1581 pc += 1;
1582 let op = i.opcode();
1583
1584 debug_assert!(base == state.ci_base(ci));
1585
1586 #[cfg(debug_assertions)]
1590 {
1591 let op_mode = op_mode_byte(op);
1592 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1593 state.set_top(base);
1594 }
1595 }
1596
1597 match op {
1598 OpCode::Move => {
1600 let ra = base + i.arg_a();
1601 let rb = base + i.arg_b();
1602 let v = state.stack[rb.0 as usize].val;
1603 state.stack[ra.0 as usize].val = v;
1604 }
1605 OpCode::LoadI => {
1607 let ra = base + i.arg_a();
1608 let b = i.arg_s_bx() as i64;
1609 state.set_at(ra, LuaValue::Int(b));
1610 }
1611 OpCode::LoadF => {
1613 let ra = base + i.arg_a();
1614 let b = i.arg_s_bx() as f64;
1615 state.set_at(ra, LuaValue::Float(b));
1616 }
1617 OpCode::LoadK => {
1619 let ra = base + i.arg_a();
1620 let k_idx = i.arg_bx() as usize;
1621 let v = state.proto_const(&cl, k_idx).clone();
1622 state.set_at(ra, v);
1623 }
1624 OpCode::LoadKX => {
1626 let ra = base + i.arg_a();
1627 let extra = state.proto_code(&cl, pc);
1628 pc += 1;
1629 let k_idx = extra.arg_ax() as usize;
1630 let v = state.proto_const(&cl, k_idx).clone();
1631 state.set_at(ra, v);
1632 }
1633 OpCode::LoadFalse => {
1635 let ra = base + i.arg_a();
1636 state.set_at(ra, LuaValue::Bool(false));
1637 }
1638 OpCode::LFalseSkip => {
1640 let ra = base + i.arg_a();
1641 state.set_at(ra, LuaValue::Bool(false));
1642 pc += 1;
1643 }
1644 OpCode::LoadTrue => {
1646 let ra = base + i.arg_a();
1647 state.set_at(ra, LuaValue::Bool(true));
1648 }
1649 OpCode::LoadNil => {
1651 let ra = base + i.arg_a();
1652 let b = i.arg_b();
1653 for k in 0..=b {
1654 state.set_at(ra + k, LuaValue::Nil);
1655 }
1656 }
1657 OpCode::GetUpVal => {
1659 let ra = base + i.arg_a();
1660 let b = i.arg_b() as usize;
1661 let v = state.upvalue_get(&cl, b);
1662 state.set_at(ra, v);
1663 }
1664 OpCode::SetUpVal => {
1667 let ra = base + i.arg_a();
1668 let b = i.arg_b() as usize;
1669 let v = state.stack[ra.0 as usize].val;
1670 let uv = cl.upval(b);
1671 match uv.try_open_payload() {
1672 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1673 state.stack[idx.0 as usize].val = v;
1674 }
1675 _ => {
1676 state.upvalue_set(&cl, b, v)?;
1677 }
1678 }
1679 }
1680 OpCode::GetTabUp => {
1684 let ra = base + i.arg_a();
1685 let b = i.arg_b() as usize;
1686 let k_idx = i.arg_c() as usize;
1687 let upval = state.upvalue_get(&cl, b);
1688 let key = state.proto_const(&cl, k_idx).clone();
1689 match state.fast_get_short_str(&upval, &key)? {
1690 Some(v) => state.set_at(ra, v),
1691 None => {
1692 state.set_ci_savedpc(ci, pc);
1693 state.set_top(state.ci_top(ci));
1694 finish_get(state, upval, key, ra, true, None)?;
1695 trap = state.ci_trap(ci);
1696 }
1697 }
1698 }
1699 OpCode::GetTable => {
1702 let ra = base + i.arg_a();
1703 let rb_idx = base + i.arg_b();
1704 let rb_v = state.get_at(rb_idx);
1705 let rc_v = state.get_at(base + i.arg_c());
1706 let fast_result = if let LuaValue::Int(n) = &rc_v {
1707 state.fast_get_int(&rb_v, *n)?
1708 } else {
1709 state.fast_get(&rb_v, &rc_v)?
1710 };
1711 match fast_result {
1712 Some(v) => state.set_at(ra, v),
1713 None => {
1714 state.set_ci_savedpc(ci, pc);
1715 state.set_top(state.ci_top(ci));
1716 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1717 trap = state.ci_trap(ci);
1718 }
1719 }
1720 }
1721 OpCode::GetI => {
1725 let ra = base + i.arg_a();
1726 let rb_idx = base + i.arg_b();
1727 let rb_v = state.get_at(rb_idx);
1728 let c = i.arg_c() as i64;
1729 match state.fast_get_int(&rb_v, c)? {
1730 Some(v) => state.set_at(ra, v),
1731 None => {
1732 let key = LuaValue::Int(c);
1733 state.set_ci_savedpc(ci, pc);
1734 state.set_top(state.ci_top(ci));
1735 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1736 trap = state.ci_trap(ci);
1737 }
1738 }
1739 }
1740 OpCode::GetField => {
1742 let ra = base + i.arg_a();
1743 let rb_idx = base + i.arg_b();
1744 let rb_v = state.get_at(rb_idx);
1745 let k_idx = i.arg_c() as usize;
1746 let key = state.proto_const(&cl, k_idx).clone();
1747 match state.fast_get_short_str(&rb_v, &key)? {
1748 Some(v) => state.set_at(ra, v),
1749 None => {
1750 state.set_ci_savedpc(ci, pc);
1751 state.set_top(state.ci_top(ci));
1752 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1753 trap = state.ci_trap(ci);
1754 }
1755 }
1756 }
1757 OpCode::SetTabUp => {
1759 let a = i.arg_a() as usize;
1760 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1762 state.proto_const(&cl, i.arg_c() as usize).clone()
1763 } else {
1764 state.get_at(base + i.arg_c())
1765 };
1766 let upval = state.upvalue_get(&cl, a);
1767 let key = state.proto_const(&cl, b_idx).clone();
1768 match state.fast_get_short_str(&upval, &key)? {
1769 Some(_slot) => {
1770 state.table_raw_set(&upval, key, rc_v.clone())?;
1771 state.gc_barrier_back(&upval, &rc_v);
1772 }
1773 None => {
1774 state.set_ci_savedpc(ci, pc);
1775 state.set_top(state.ci_top(ci));
1776 let upval_name: Vec<u8> = cl
1777 .proto
1778 .upvalues
1779 .get(a)
1780 .and_then(|uv| uv.name.as_ref())
1781 .map(|s| s.as_bytes().to_vec())
1782 .unwrap_or_else(|| b"?".to_vec());
1783 let hint: Option<(&[u8], &[u8])> =
1784 Some((b"upvalue", &upval_name));
1785 finish_set(state, upval, key, rc_v, false, None, hint)?;
1786 trap = state.ci_trap(ci);
1787 }
1788 }
1789 }
1790 OpCode::SetTable => {
1792 let ra_idx = base + i.arg_a();
1793 let ra_v = state.get_at(ra_idx);
1794 let rb_v = state.get_at(base + i.arg_b());
1795 let rc_v = if i.test_k() {
1796 state.proto_const(&cl, i.arg_c() as usize).clone()
1797 } else {
1798 state.get_at(base + i.arg_c())
1799 };
1800 let fast = if let LuaValue::Int(n) = &rb_v {
1801 state.fast_get_int(&ra_v, *n)?
1802 } else {
1803 state.fast_get(&ra_v, &rb_v)?
1804 };
1805 if fast.is_some() {
1806 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1807 state.gc_barrier_back(&ra_v, &rc_v);
1808 } else {
1809 state.set_ci_savedpc(ci, pc);
1810 state.set_top(state.ci_top(ci));
1811 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1812 trap = state.ci_trap(ci);
1813 }
1814 }
1815 OpCode::SetI => {
1817 let ra_idx = base + i.arg_a();
1818 let ra_v = state.get_at(ra_idx);
1819 let c = i.arg_b() as i64;
1820 let rc_v = if i.test_k() {
1821 state.proto_const(&cl, i.arg_c() as usize).clone()
1822 } else {
1823 state.get_at(base + i.arg_c())
1824 };
1825 let fast = state.fast_get_int(&ra_v, c)?;
1826 if fast.is_some() {
1827 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1828 state.gc_barrier_back(&ra_v, &rc_v);
1829 } else {
1830 state.set_ci_savedpc(ci, pc);
1831 state.set_top(state.ci_top(ci));
1832 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1833 trap = state.ci_trap(ci);
1834 }
1835 }
1836 OpCode::SetField => {
1838 let ra_idx = base + i.arg_a();
1839 let ra_v = state.get_at(ra_idx);
1840 let b_idx = i.arg_b() as usize;
1841 let key = state.proto_const(&cl, b_idx).clone();
1842 let rc_v = if i.test_k() {
1843 state.proto_const(&cl, i.arg_c() as usize).clone()
1844 } else {
1845 state.get_at(base + i.arg_c())
1846 };
1847 match state.fast_get_short_str(&ra_v, &key)? {
1848 Some(_) => {
1849 state.table_raw_set(&ra_v, key, rc_v.clone())?;
1850 state.gc_barrier_back(&ra_v, &rc_v);
1851 }
1852 None => {
1853 state.set_ci_savedpc(ci, pc);
1854 state.set_top(state.ci_top(ci));
1855 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
1856 trap = state.ci_trap(ci);
1857 }
1858 }
1859 }
1860 OpCode::NewTable => {
1863 let ra = base + i.arg_a();
1864 let mut b = i.arg_b();
1865 let mut c = i.arg_c();
1866 if b > 0 {
1867 b = 1 << (b - 1);
1868 }
1869 if i.test_k() {
1870 let extra = state.proto_code(&cl, pc);
1871 pc += 1;
1872 const MAXARG_C: i32 = (1 << 8) - 1;
1873 c += extra.arg_ax() * (MAXARG_C + 1);
1874 } else {
1875 pc += 1; }
1877 state.set_top(ra + 1);
1878 let t = if b != 0 || c != 0 {
1879 state.new_table_with_sizes(c as u32, b as u32)?
1880 } else {
1881 state.new_table()
1882 };
1883 state.set_at(ra, LuaValue::Table(t.clone()));
1884 state.set_ci_savedpc(ci, pc);
1885 state.set_top(ra + 1);
1886 state.gc_cond_step();
1887 if state.hookmask != 0 {
1888 trap = state.ci_trap(ci);
1889 }
1890 }
1891 OpCode::Self_ => {
1893 let ra = base + i.arg_a();
1894 let rb_idx = base + i.arg_b();
1895 let rb_v = state.get_at(rb_idx);
1896 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
1898 state.proto_const(&cl, k_idx).clone()
1899 } else {
1900 state.get_at(base + i.arg_c())
1901 };
1902 state.set_at(ra + 1, rb_v.clone());
1903 match state.fast_get_short_str(&rb_v, &key)? {
1904 Some(v) => state.set_at(ra, v),
1905 None => {
1906 state.set_ci_savedpc(ci, pc);
1907 state.set_top(state.ci_top(ci));
1908 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1909 trap = state.ci_trap(ci);
1910 }
1911 }
1912 }
1913 OpCode::AddI => {
1915 let ra = base + i.arg_a();
1916 let rb = base + i.arg_b();
1917 let imm = i.arg_s_c() as i64;
1918 let rb_v = state.stack[rb.0 as usize].val;
1919 match rb_v {
1920 LuaValue::Int(iv1) => {
1921 pc += 1;
1922 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
1923 }
1924 LuaValue::Float(nb) => {
1925 pc += 1;
1926 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
1927 }
1928 _ => {}
1929 }
1930 }
1931 OpCode::AddK => {
1933 let ra = base + i.arg_a();
1934 let rb = base + i.arg_b();
1935 let kidx = i.arg_c() as usize;
1936 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1937 pc += 1;
1938 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
1939 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1940 pc += 1;
1941 state.set_at(ra, LuaValue::Float(n1 + n2));
1942 }
1943 }
1944 OpCode::SubK => {
1945 let ra = base + i.arg_a();
1946 let rb = base + i.arg_b();
1947 let kidx = i.arg_c() as usize;
1948 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1949 pc += 1;
1950 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
1951 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1952 pc += 1;
1953 state.set_at(ra, LuaValue::Float(n1 - n2));
1954 }
1955 }
1956 OpCode::MulK => {
1957 let ra = base + i.arg_a();
1958 let rb = base + i.arg_b();
1959 let kidx = i.arg_c() as usize;
1960 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1961 pc += 1;
1962 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1963 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1964 pc += 1;
1965 state.set_at(ra, LuaValue::Float(n1 * n2));
1966 }
1967 }
1968 OpCode::ModK => {
1969 let ra = base + i.arg_a();
1970 let v1 = state.get_at(base + i.arg_b());
1971 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1972 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
1974 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1975 |a, b| imod(a, b), fmodf)?;
1976 }
1977 OpCode::PowK => {
1978 let ra = base + i.arg_a();
1979 let rb = base + i.arg_b();
1980 let kidx = i.arg_c() as usize;
1981 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1982 pc += 1;
1983 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1984 state.set_at(ra, LuaValue::Float(r));
1985 }
1986 }
1987 OpCode::DivK => {
1988 let ra = base + i.arg_a();
1989 let rb = base + i.arg_b();
1990 let kidx = i.arg_c() as usize;
1991 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1992 pc += 1;
1993 state.set_at(ra, LuaValue::Float(n1 / n2));
1994 }
1995 }
1996 OpCode::IDivK => {
1997 let ra = base + i.arg_a();
1998 let v1 = state.get_at(base + i.arg_b());
1999 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2000 state.set_ci_savedpc(ci, pc);
2001 state.set_top(state.ci_top(ci));
2002 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2003 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2004 }
2005 OpCode::BAndK => {
2006 let ra = base + i.arg_a();
2007 let v1 = state.get_at(base + i.arg_b());
2008 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2009 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2010 }
2011 OpCode::BOrK => {
2012 let ra = base + i.arg_a();
2013 let v1 = state.get_at(base + i.arg_b());
2014 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2015 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2016 }
2017 OpCode::BXOrK => {
2018 let ra = base + i.arg_a();
2019 let v1 = state.get_at(base + i.arg_b());
2020 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2021 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2022 }
2023 OpCode::ShrI => {
2024 let ra = base + i.arg_a();
2025 let v = state.get_at(base + i.arg_b());
2026 let ic = i.arg_s_c() as i64;
2027 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2028 pc += 1;
2029 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2030 }
2031 }
2032 OpCode::ShlI => {
2033 let ra = base + i.arg_a();
2034 let v = state.get_at(base + i.arg_b());
2035 let ic = i.arg_s_c() as i64;
2036 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2037 pc += 1;
2038 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2039 }
2040 }
2041 OpCode::Add => {
2043 let ra = base + i.arg_a();
2044 let rb = base + i.arg_b();
2045 let rc = base + i.arg_c();
2046 let ra_u = ra.0 as usize;
2047 let rb_v = state.stack[rb.0 as usize].val;
2048 let rc_v = state.stack[rc.0 as usize].val;
2049 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2050 pc += 1;
2051 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2052 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2053 pc += 1;
2054 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2055 }
2056 }
2057 OpCode::Sub => {
2058 let ra = base + i.arg_a();
2059 let rb = base + i.arg_b();
2060 let rc = base + i.arg_c();
2061 let ra_u = ra.0 as usize;
2062 let rb_v = state.stack[rb.0 as usize].val;
2063 let rc_v = state.stack[rc.0 as usize].val;
2064 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2065 pc += 1;
2066 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2067 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2068 pc += 1;
2069 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2070 }
2071 }
2072 OpCode::Mul => {
2073 let ra = base + i.arg_a();
2074 let rb = base + i.arg_b();
2075 let rc = base + i.arg_c();
2076 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2077 pc += 1;
2078 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2079 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2080 pc += 1;
2081 state.set_at(ra, LuaValue::Float(n1 * n2));
2082 }
2083 }
2084 OpCode::Mod => {
2085 let ra = base + i.arg_a();
2086 let v1 = state.get_at(base + i.arg_b());
2087 let v2 = state.get_at(base + i.arg_c());
2088 state.set_ci_savedpc(ci, pc);
2089 state.set_top(state.ci_top(ci));
2090 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2091 |a, b| imod(a, b), fmodf)?;
2092 }
2093 OpCode::Pow => {
2094 let ra = base + i.arg_a();
2095 let rb = base + i.arg_b();
2096 let rc = base + i.arg_c();
2097 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2098 pc += 1;
2099 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2100 state.set_at(ra, LuaValue::Float(r));
2101 }
2102 }
2103 OpCode::Div => {
2104 let ra = base + i.arg_a();
2105 let rb = base + i.arg_b();
2106 let rc = base + i.arg_c();
2107 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2108 pc += 1;
2109 state.set_at(ra, LuaValue::Float(n1 / n2));
2110 }
2111 }
2112 OpCode::IDiv => {
2113 let ra = base + i.arg_a();
2114 let v1 = state.get_at(base + i.arg_b());
2115 let v2 = state.get_at(base + i.arg_c());
2116 state.set_ci_savedpc(ci, pc);
2117 state.set_top(state.ci_top(ci));
2118 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2119 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2120 }
2121 OpCode::BAnd => {
2124 let ra = base + i.arg_a();
2125 let v1 = state.get_at(base + i.arg_b());
2126 let v2 = state.get_at(base + i.arg_c());
2127 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2128 }
2129 OpCode::BOr => {
2130 let ra = base + i.arg_a();
2131 let v1 = state.get_at(base + i.arg_b());
2132 let v2 = state.get_at(base + i.arg_c());
2133 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2134 }
2135 OpCode::BXOr => {
2136 let ra = base + i.arg_a();
2137 let v1 = state.get_at(base + i.arg_b());
2138 let v2 = state.get_at(base + i.arg_c());
2139 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2140 }
2141 OpCode::Shr => {
2142 let ra = base + i.arg_a();
2143 let v1 = state.get_at(base + i.arg_b());
2144 let v2 = state.get_at(base + i.arg_c());
2145 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2146 }
2147 OpCode::Shl => {
2148 let ra = base + i.arg_a();
2149 let v1 = state.get_at(base + i.arg_b());
2150 let v2 = state.get_at(base + i.arg_c());
2151 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2152 }
2153 OpCode::MmBin => {
2158 let ra_idx = base + i.arg_a();
2159 let rb_idx = base + i.arg_b();
2160 let ra_v = state.get_at(ra_idx);
2161 let rb_v = state.get_at(rb_idx);
2162 let tm = tagmethod_from_index(i.arg_c() as usize);
2163 let prev_inst = state.proto_code(&cl, pc - 2);
2164 let result_idx = base + prev_inst.arg_a();
2165 state.set_ci_savedpc(ci, pc);
2166 state.set_top(state.ci_top(ci));
2167 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2168 trap = state.ci_trap(ci);
2169 }
2170 OpCode::MmBinI => {
2171 let ra_idx = base + i.arg_a();
2172 let ra_v = state.get_at(ra_idx);
2173 let imm = i.arg_s_b() as i64;
2174 let tm = tagmethod_from_index(i.arg_c() as usize);
2175 let flip = i.arg_k() != 0;
2176 let prev_inst = state.proto_code(&cl, pc - 2);
2177 let result_idx = base + prev_inst.arg_a();
2178 state.set_ci_savedpc(ci, pc);
2179 state.set_top(state.ci_top(ci));
2180 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2181 trap = state.ci_trap(ci);
2182 }
2183 OpCode::MmBinK => {
2184 let ra_idx = base + i.arg_a();
2185 let ra_v = state.get_at(ra_idx);
2186 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2187 let tm = tagmethod_from_index(i.arg_c() as usize);
2188 let flip = i.arg_k() != 0;
2189 let prev_inst = state.proto_code(&cl, pc - 2);
2190 let result_idx = base + prev_inst.arg_a();
2191 state.set_ci_savedpc(ci, pc);
2192 state.set_top(state.ci_top(ci));
2193 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2194 trap = state.ci_trap(ci);
2195 }
2196 OpCode::Unm => {
2200 let ra = base + i.arg_a();
2201 let rb_idx = base + i.arg_b();
2202 let rb_v = state.get_at(rb_idx);
2203 match &rb_v {
2204 LuaValue::Int(ib) => {
2205 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2206 }
2207 LuaValue::Float(nb) => {
2208 state.set_at(ra, LuaValue::Float(-nb));
2209 }
2210 _ => {
2211 state.set_ci_savedpc(ci, pc);
2212 state.set_top(state.ci_top(ci));
2213 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2214 trap = state.ci_trap(ci);
2215 }
2216 }
2217 }
2218 OpCode::BNot => {
2220 let ra = base + i.arg_a();
2221 let rb_idx = base + i.arg_b();
2222 let rb_v = state.get_at(rb_idx);
2223 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2224 state.set_at(ra, LuaValue::Int(!ib));
2225 } else {
2226 state.set_ci_savedpc(ci, pc);
2227 state.set_top(state.ci_top(ci));
2228 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2229 trap = state.ci_trap(ci);
2230 }
2231 }
2232 OpCode::Not => {
2234 let ra = base + i.arg_a();
2235 let rb_v = state.get_at(base + i.arg_b());
2236 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2237 state.set_at(ra, LuaValue::Bool(falsy));
2238 }
2239 OpCode::Len => {
2241 let ra = base + i.arg_a();
2242 let rb_idx = base + i.arg_b();
2243 let rb_v = state.get_at(rb_idx);
2244 state.set_ci_savedpc(ci, pc);
2245 state.set_top(state.ci_top(ci));
2246 obj_len(state, ra, rb_v, rb_idx)?;
2247 trap = state.ci_trap(ci);
2248 }
2249 OpCode::Concat => {
2251 let ra = base + i.arg_a();
2252 let n = i.arg_b() as i32;
2253 state.set_top(ra + n as i32);
2254 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2256 let top = state.top_idx();
2257 state.set_ci_savedpc(ci, pc);
2258 state.set_top(top);
2259 state.gc_cond_step();
2260 trap = state.ci_trap(ci);
2261 }
2262 OpCode::Close => {
2264 let ra = base + i.arg_a();
2265 state.set_ci_savedpc(ci, pc);
2266 state.set_top(state.ci_top(ci));
2267 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2268 trap = state.ci_trap(ci);
2269 }
2270 OpCode::Tbc => {
2272 let ra = base + i.arg_a();
2273 state.set_ci_savedpc(ci, pc);
2274 state.set_top(state.ci_top(ci));
2275 state.new_tbc_upval(ra)?;
2276 }
2277 OpCode::Jmp => {
2279 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2280 trap = state.ci_trap(ci);
2281 }
2282 OpCode::Eq => {
2284 let ra_v = state.get_at(base + i.arg_a());
2285 let rb_v = state.get_at(base + i.arg_b());
2286 state.set_ci_savedpc(ci, pc);
2287 state.set_top(state.ci_top(ci));
2288 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2289 trap = state.ci_trap(ci);
2290 if (cond as i32) != i.arg_k() {
2291 pc += 1;
2292 } else {
2293 let next = state.proto_code(&cl, pc);
2294 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2295 trap = state.ci_trap(ci);
2296 }
2297 }
2298 OpCode::Lt => {
2300 let ra_v = state.get_at(base + i.arg_a());
2301 let rb_v = state.get_at(base + i.arg_b());
2302 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2303 *ia < *ib
2304 } else if matches!((&ra_v, &rb_v),
2305 (LuaValue::Int(_) | LuaValue::Float(_),
2306 LuaValue::Int(_) | LuaValue::Float(_))) {
2307 lt_num(&ra_v, &rb_v)
2308 } else {
2309 state.set_ci_savedpc(ci, pc);
2310 state.set_top(state.ci_top(ci));
2311 let r = less_than_others(state, &ra_v, &rb_v)?;
2312 trap = state.ci_trap(ci);
2313 r
2314 };
2315 if (cond as i32) != i.arg_k() {
2316 pc += 1;
2317 } else {
2318 let next = state.proto_code(&cl, pc);
2319 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2320 trap = state.ci_trap(ci);
2321 }
2322 }
2323 OpCode::Le => {
2325 let ra_v = state.get_at(base + i.arg_a());
2326 let rb_v = state.get_at(base + i.arg_b());
2327 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2328 *ia <= *ib
2329 } else if matches!((&ra_v, &rb_v),
2330 (LuaValue::Int(_) | LuaValue::Float(_),
2331 LuaValue::Int(_) | LuaValue::Float(_))) {
2332 le_num(&ra_v, &rb_v)
2333 } else {
2334 state.set_ci_savedpc(ci, pc);
2335 state.set_top(state.ci_top(ci));
2336 let r = less_equal_others(state, &ra_v, &rb_v)?;
2337 trap = state.ci_trap(ci);
2338 r
2339 };
2340 if (cond as i32) != i.arg_k() {
2341 pc += 1;
2342 } else {
2343 let next = state.proto_code(&cl, pc);
2344 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2345 trap = state.ci_trap(ci);
2346 }
2347 }
2348 OpCode::EqK => {
2350 let ra_v = state.get_at(base + i.arg_a());
2351 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2352 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2353 if (cond as i32) != i.arg_k() {
2354 pc += 1;
2355 } else {
2356 let next = state.proto_code(&cl, pc);
2357 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2358 trap = state.ci_trap(ci);
2359 }
2360 }
2361 OpCode::EqI => {
2366 let ra_v = state.get_at(base + i.arg_a());
2367 let im = i.arg_s_b() as i64;
2368 let cond: bool = match &ra_v {
2369 LuaValue::Int(iv) => *iv == im,
2370 LuaValue::Float(fv) => *fv == im as f64,
2371 _ => false,
2372 };
2373 if (cond as i32) != i.arg_k() {
2374 pc += 1;
2375 } else {
2376 let next = state.proto_code(&cl, pc);
2377 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2378 trap = state.ci_trap(ci);
2379 }
2380 }
2381 OpCode::LtI => {
2384 let ra = base + i.arg_a();
2385 let im = i.arg_s_b() as i64;
2386 let fast_cond = match &state.stack[ra.0 as usize].val {
2387 LuaValue::Int(ia) => Some(*ia < im),
2388 LuaValue::Float(fa) => Some(*fa < im as f64),
2389 _ => None,
2390 };
2391 let cond = match fast_cond {
2392 Some(cond) => cond,
2393 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2394 };
2395 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2396 }
2397 OpCode::LeI => {
2398 let ra = base + i.arg_a();
2399 let im = i.arg_s_b() as i64;
2400 let fast_cond = match &state.stack[ra.0 as usize].val {
2401 LuaValue::Int(ia) => Some(*ia <= im),
2402 LuaValue::Float(fa) => Some(*fa <= im as f64),
2403 _ => None,
2404 };
2405 let cond = match fast_cond {
2406 Some(cond) => cond,
2407 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2408 };
2409 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2410 }
2411 OpCode::GtI => {
2412 let ra = base + i.arg_a();
2413 let im = i.arg_s_b() as i64;
2414 let fast_cond = match &state.stack[ra.0 as usize].val {
2415 LuaValue::Int(ia) => Some(*ia > im),
2416 LuaValue::Float(fa) => Some(*fa > im as f64),
2417 _ => None,
2418 };
2419 let cond = match fast_cond {
2420 Some(cond) => cond,
2421 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2422 };
2423 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2424 }
2425 OpCode::GeI => {
2426 let ra = base + i.arg_a();
2427 let im = i.arg_s_b() as i64;
2428 let fast_cond = match &state.stack[ra.0 as usize].val {
2429 LuaValue::Int(ia) => Some(*ia >= im),
2430 LuaValue::Float(fa) => Some(*fa >= im as f64),
2431 _ => None,
2432 };
2433 let cond = match fast_cond {
2434 Some(cond) => cond,
2435 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2436 };
2437 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2438 }
2439 OpCode::Test => {
2441 let ra_v = state.get_at(base + i.arg_a());
2442 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2443 if (cond as i32) != i.arg_k() {
2444 pc += 1;
2445 } else {
2446 let next = state.proto_code(&cl, pc);
2447 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2448 trap = state.ci_trap(ci);
2449 }
2450 }
2451 OpCode::TestSet => {
2454 let ra = base + i.arg_a();
2455 let rb_v = state.get_at(base + i.arg_b());
2456 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2457 if (falsy as i32) == i.arg_k() {
2458 pc += 1;
2459 } else {
2460 state.set_at(ra, rb_v);
2461 let next = state.proto_code(&cl, pc);
2462 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2463 trap = state.ci_trap(ci);
2464 }
2465 }
2466 OpCode::Call => {
2470 let ra = base + i.arg_a();
2471 let b = i.arg_b();
2472 let nresults = i.arg_c() as i32 - 1;
2473 if b != 0 {
2474 state.set_top(ra + b);
2475 }
2476 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2478 match state.precall(ra, nresults)? {
2479 None => {
2480 if had_hook || state.hookmask != 0 {
2484 trap = state.ci_trap(ci); }
2486 }
2487 Some(new_ci) => {
2488 ci = new_ci;
2490 continue 'startfunc;
2491 }
2492 }
2493 }
2494 OpCode::TailCall => {
2499 let ra = base + i.arg_a();
2500 let b = i.arg_b();
2501 let nparams1 = i.arg_c();
2502 let delta = if nparams1 != 0 {
2503 state.ci_nextraargs(ci) + nparams1 as i32
2504 } else {
2505 0
2506 };
2507 let top_b: i32 = if b != 0 {
2508 state.set_top(ra + b);
2509 b
2510 } else {
2511 state.top_idx() - ra
2512 };
2513 state.set_ci_savedpc(ci, pc);
2514 if i.test_k() {
2515 state.close_upvals_from_base(ci)?;
2516 }
2517 let n = state.pretailcall(ci, ra, top_b, delta)?;
2518 if n < 0 {
2519 continue 'startfunc;
2521 } else {
2522 state.ci_adjust_func(ci, delta);
2524 state.poscall(ci, n as u32)?;
2525 if state.hookmask != 0 {
2526 trap = state.ci_trap(ci);
2527 }
2528 break 'dispatch; }
2530 }
2531 OpCode::Return => {
2536 let ra = base + i.arg_a();
2537 let n_raw = i.arg_b() as i32 - 1;
2538 let nparams1 = i.arg_c();
2539 let n: u32 = if n_raw < 0 {
2540 (state.top_idx() - ra) as u32
2541 } else {
2542 n_raw as u32
2543 };
2544 state.set_ci_savedpc(ci, pc);
2545 if i.test_k() {
2546 state.ci_nres_set(ci, n as i32);
2547 let ci_top = state.ci_top(ci);
2548 if state.top_idx().0 < ci_top.0 {
2549 state.set_top(ci_top);
2550 }
2551 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2552 if state.hookmask != 0 {
2553 trap = state.ci_trap(ci);
2554 }
2555 base = state.ci_base(ci); }
2557 if nparams1 != 0 {
2558 let nextraargs = state.ci_nextraargs(ci) as u32;
2559 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2560 }
2561 state.set_top(ra + n as i32);
2562 state.poscall(ci, n)?;
2563 if state.hookmask != 0 {
2564 trap = state.ci_trap(ci);
2565 }
2566 break 'dispatch; }
2568 OpCode::Return0 => {
2574 if state.hookmask == 0 {
2575 let ci_slot = ci.as_usize();
2576 let nres = state.call_info[ci_slot].nresults as i32;
2577 state.ci = state.call_info[ci_slot]
2578 .previous
2579 .expect("RETURN0: returning frame has no previous CallInfo");
2580 state.top = base - 1;
2581 for _ in 0..nres.max(0) {
2582 state.push(LuaValue::Nil);
2583 }
2584 } else {
2585 return0_hook(state, ci, base, i, pc, &mut trap)?;
2586 }
2587 break 'dispatch; }
2589 OpCode::Return1 => {
2593 if state.hookmask == 0 {
2594 let ci_slot = ci.as_usize();
2595 let nres = state.call_info[ci_slot].nresults as i32;
2596 state.ci = state.call_info[ci_slot]
2597 .previous
2598 .expect("RETURN1: returning frame has no previous CallInfo");
2599 if nres == 0 {
2600 state.top = base - 1;
2601 } else {
2602 let ra = base + i.arg_a();
2603 state.stack[(base - 1).0 as usize].val =
2604 state.stack[ra.0 as usize].val; state.top = base;
2606 for _ in 1..nres.max(0) {
2607 state.push(LuaValue::Nil);
2608 }
2609 }
2610 } else {
2611 return1_hook(state, ci, base, i, pc, &mut trap)?;
2612 }
2613 break 'dispatch; }
2615 OpCode::ForLoop => {
2619 let ra = base + i.arg_a();
2620 let ra_u = ra.0 as usize;
2621 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2622 let count = match state.stack[ra_u + 1].val {
2623 LuaValue::Int(c) => c as u64,
2624 _ => 0,
2625 };
2626 if count > 0 {
2627 let idx = match state.stack[ra_u].val {
2628 LuaValue::Int(x) => x,
2629 _ => 0,
2630 };
2631 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2632 let new_idx = intop_add(idx, step);
2633 state.stack[ra_u].val = LuaValue::Int(new_idx);
2634 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2635 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2636 }
2637 } else if float_for_loop(state, ra) {
2638 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2639 }
2640 trap = state.ci_trap(ci);
2641 }
2642 OpCode::ForPrep => {
2644 let ra = base + i.arg_a();
2645 state.set_ci_savedpc(ci, pc);
2646 state.set_top(state.ci_top(ci));
2647 if forprep(state, ra)? {
2648 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2649 }
2650 }
2651 OpCode::TForPrep => {
2655 let ra = base + i.arg_a();
2656 state.set_ci_savedpc(ci, pc);
2657 state.set_top(state.ci_top(ci));
2658 state.new_tbc_upval(ra + 3)?;
2659 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2660 let tfc_i = state.proto_code(&cl, pc);
2661 pc += 1;
2662 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2663 let tfc_ra = base + tfc_i.arg_a();
2665 for k in 0..3u32 {
2666 let v = state.get_at(tfc_ra + k as i32);
2667 state.set_at(tfc_ra + 4 + k as i32, v);
2668 }
2669 state.set_top(tfc_ra + 4 + 3);
2670 state.set_ci_savedpc(ci, pc);
2671 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2672 trap = state.ci_trap(ci);
2673 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2675 pc += 1;
2676 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2677 let tfl_ra = base + tfl_i.arg_a();
2678 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2680 let v = state.get_at(tfl_ra + 4);
2681 state.set_at(tfl_ra + 2, v);
2682 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2683 }
2684 }
2685 OpCode::TForCall => {
2687 let ra = base + i.arg_a();
2688 for k in 0..3u32 {
2689 let v = state.get_at(ra + k as i32);
2690 state.set_at(ra + 4 + k as i32, v);
2691 }
2692 state.set_top(ra + 4 + 3);
2693 state.set_ci_savedpc(ci, pc);
2694 state.call_at(ra + 4, i.arg_c() as i32)?;
2695 trap = state.ci_trap(ci);
2696 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2698 pc += 1;
2699 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2700 let tfl_ra = base + tfl_i.arg_a();
2701 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2702 let v = state.get_at(tfl_ra + 4);
2703 state.set_at(tfl_ra + 2, v);
2704 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2705 }
2706 }
2707 OpCode::TForLoop => {
2709 let ra = base + i.arg_a();
2710 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2711 let v = state.get_at(ra + 4);
2712 state.set_at(ra + 2, v);
2713 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2714 }
2715 }
2716 OpCode::SetList => {
2720 let ra = base + i.arg_a();
2721 let n_raw = i.arg_b();
2722 let mut last = i.arg_c();
2723 let t_val = state.get_at(ra);
2724 let n: i32 = if n_raw == 0 {
2725 state.top_idx() - ra - 1
2726 } else {
2727 state.set_top(state.ci_top(ci));
2728 n_raw
2729 };
2730 last += n;
2731 if i.test_k() {
2732 let extra = state.proto_code(&cl, pc);
2733 pc += 1;
2734 const MAXARG_C: i32 = (1 << 8) - 1;
2735 last += extra.arg_ax() * (MAXARG_C + 1);
2736 }
2737 state.table_ensure_array(&t_val, last as usize)?;
2738 for k in (1..=n).rev() {
2739 let val = state.get_at(ra + k as i32);
2740 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2741 last -= 1;
2742 state.gc_barrier_back(&t_val, &val);
2743 }
2744 }
2745 OpCode::Closure => {
2749 let ra = base + i.arg_a();
2750 let proto_idx = i.arg_bx() as usize;
2751 state.set_ci_savedpc(ci, pc);
2752 state.set_top(state.ci_top(ci));
2753 push_closure(state, proto_idx, ci, base, ra)?;
2754 state.set_ci_savedpc(ci, pc);
2756 state.set_top(ra + 1);
2757 state.gc_cond_step();
2758 trap = state.ci_trap(ci);
2759 }
2760 OpCode::VarArg => {
2762 let ra = base + i.arg_a();
2763 let n = i.arg_c() as i32 - 1;
2764 state.set_ci_savedpc(ci, pc);
2765 state.set_top(state.ci_top(ci));
2766 state.get_varargs(ci, ra, n)?;
2767 trap = state.ci_trap(ci);
2768 }
2769 OpCode::VarArgPrep => {
2773 let nparams = i.arg_a();
2774 state.set_ci_savedpc(ci, pc);
2775 state.adjust_varargs(ci, nparams, &cl)?;
2776 trap = state.ci_trap(ci);
2777 if trap {
2778 state.hook_call(ci)?;
2779 state.set_oldpc(1);
2780 }
2781 base = state.ci_base(ci);
2782 }
2783 OpCode::ExtraArg => {
2785 debug_assert!(false, "OP_EXTRAARG executed directly");
2786 }
2787 OpCode::ErrNNil => {
2792 let ra = base + i.arg_a();
2793 if !matches!(state.get_at(ra), LuaValue::Nil) {
2794 let bx = i.arg_bx();
2795 let name: Vec<u8> = if bx == 0 {
2796 b"?".to_vec()
2797 } else {
2798 match state.proto_const(&cl, (bx - 1) as usize) {
2799 LuaValue::Str(s) => s.as_bytes().to_vec(),
2800 _ => b"?".to_vec(),
2801 }
2802 };
2803 let mut msg = Vec::with_capacity(name.len() + 24);
2804 msg.extend_from_slice(b"global '");
2805 msg.extend_from_slice(&name);
2806 msg.extend_from_slice(b"' already defined");
2807 state.set_ci_savedpc(ci, pc);
2808 return Err(crate::debug::prefixed_runtime_pub(state, msg));
2809 }
2810 }
2811 OpCode::VarArgPack => {
2819 let ra = base + i.arg_a();
2820 let nextra = state.ci_nextraargs(ci);
2821 let ci_func: StackIdx = state.ci_base(ci) - 1;
2822 let t = if nextra > 0 {
2823 state.new_table_with_sizes(nextra as u32, 1)?
2824 } else {
2825 state.new_table()
2826 };
2827 for k in 0..nextra {
2828 let src: StackIdx = ci_func - nextra as i32 + k as i32;
2829 let val = state.get_at(src);
2830 t.raw_set_int(state, (k + 1) as i64, val)?;
2831 }
2832 let n_key = state.intern_str(b"n")?;
2833 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
2834 state.set_at(ra, LuaValue::Table(t));
2835 state.set_ci_savedpc(ci, pc);
2836 state.gc_cond_step();
2837 if state.hookmask != 0 {
2838 trap = state.ci_trap(ci);
2839 }
2840 }
2841 } } if state.ci_is_fresh(ci) {
2846 return Ok(());
2847 } else {
2848 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2849 continue 'returning;
2850 }
2851 } } }
2854
2855#[inline(always)]
2858fn number_value(v: LuaValue) -> Option<f64> {
2859 match v {
2860 LuaValue::Float(f) => Some(f),
2861 LuaValue::Int(i) => Some(i as f64),
2862 _ => None,
2863 }
2864}
2865
2866#[allow(dead_code)]
2868#[inline]
2869fn arith_op_aux_rr(
2870 state: &mut LuaState,
2871 ra: StackIdx,
2872 v1: &LuaValue,
2873 v2: &LuaValue,
2874 pc: &mut u32,
2875 iop: fn(i64, i64) -> i64,
2876 fop: fn(f64, f64) -> f64,
2877) {
2878 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2879 *pc += 1;
2880 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
2881 } else {
2882 arith_float_aux(state, ra, v1, v2, pc, fop);
2883 }
2884}
2885
2886#[allow(dead_code)]
2887#[inline]
2888fn arith_float_aux(
2889 state: &mut LuaState,
2890 ra: StackIdx,
2891 v1: &LuaValue,
2892 v2: &LuaValue,
2893 pc: &mut u32,
2894 fop: fn(f64, f64) -> f64,
2895) {
2896 let n1 = match v1 {
2897 LuaValue::Float(f) => Some(*f),
2898 LuaValue::Int(i) => Some(*i as f64),
2899 _ => None,
2900 };
2901 let n2 = match v2 {
2902 LuaValue::Float(f) => Some(*f),
2903 LuaValue::Int(i) => Some(*i as f64),
2904 _ => None,
2905 };
2906 if let (Some(n1), Some(n2)) = (n1, n2) {
2907 *pc += 1;
2908 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
2909 }
2910}
2911
2912#[allow(dead_code)]
2913#[inline]
2914fn arith_op_checked(
2915 state: &mut LuaState,
2916 ra: StackIdx,
2917 v1: &LuaValue,
2918 v2: &LuaValue,
2919 pc: &mut u32,
2920 iop: fn(i64, i64) -> Result<i64, LuaError>,
2921 fop: fn(f64, f64) -> f64,
2922) -> Result<(), LuaError> {
2923 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2924 *pc += 1;
2925 let result = iop(*i1, *i2).map_err(|e| match e {
2926 LuaError::Runtime(LuaValue::Str(s)) => {
2927 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
2928 }
2929 other => other,
2930 })?;
2931 state.set_at(ra, LuaValue::Int(result));
2932 } else {
2933 arith_float_aux(state, ra, v1, v2, pc, fop);
2934 }
2935 Ok(())
2936}
2937
2938#[allow(dead_code)]
2939#[inline]
2940fn bitwise_op_k(
2941 state: &mut LuaState,
2942 ra: StackIdx,
2943 v1: &LuaValue,
2944 v2: &LuaValue, pc: &mut u32,
2946 op: fn(i64, i64) -> i64,
2947) {
2948 let i2 = match v2 {
2949 LuaValue::Int(i) => *i,
2950 _ => return,
2951 };
2952 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
2953 *pc += 1;
2954 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2955 }
2956}
2957
2958#[allow(dead_code)]
2959#[inline]
2960fn bitwise_op_rr(
2961 state: &mut LuaState,
2962 ra: StackIdx,
2963 v1: &LuaValue,
2964 v2: &LuaValue,
2965 pc: &mut u32,
2966 op: fn(i64, i64) -> i64,
2967) {
2968 if let (Some(i1), Some(i2)) = (
2969 to_integer_ns(v1, F2Imod::Eq),
2970 to_integer_ns(v2, F2Imod::Eq),
2971 ) {
2972 *pc += 1;
2973 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2974 }
2975}
2976
2977#[allow(dead_code)]
2979#[inline]
2980fn bitwise_shift_rr(
2981 state: &mut LuaState,
2982 ra: StackIdx,
2983 v1: &LuaValue,
2984 v2: &LuaValue,
2985 pc: &mut u32,
2986 right: bool,
2987) {
2988 if let (Some(i1), Some(i2)) = (
2989 to_integer_ns(v1, F2Imod::Eq),
2990 to_integer_ns(v2, F2Imod::Eq),
2991 ) {
2992 let y = if right { intop_sub(0, i2) } else { i2 };
2993 *pc += 1;
2994 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
2995 }
2996}
2997
2998#[cold]
3001#[inline(never)]
3002#[allow(clippy::too_many_arguments)]
3003fn order_imm_slow(
3004 state: &mut LuaState,
3005 ra: StackIdx,
3006 pc: u32,
3007 trap: &mut bool,
3008 ci: CallInfoIdx,
3009 i: Instruction,
3010 im: i64,
3011 inv: bool,
3012 tm: TagMethod,
3013) -> Result<bool, LuaError> {
3014 let ra_v = state.get_at(ra);
3015 let isf = i.arg_c() != 0;
3016 state.set_ci_savedpc(ci, pc);
3017 state.set_top(state.ci_top(ci));
3018 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3019 *trap = state.ci_trap(ci);
3020 Ok(r)
3021}
3022
3023#[inline(always)]
3024fn finish_order_imm_jump(
3025 state: &mut LuaState,
3026 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
3027 pc: &mut u32,
3028 trap: &mut bool,
3029 ci: CallInfoIdx,
3030 i: Instruction,
3031 cond: bool,
3032) {
3033 if (cond as i32) != i.arg_k() {
3034 *pc += 1;
3035 } else {
3036 let next = state.proto_code(&cl, *pc);
3037 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3038 *trap = state.ci_trap(ci);
3039 }
3040}
3041
3042#[cold]
3043#[inline(never)]
3044fn return0_hook(
3045 state: &mut LuaState,
3046 ci: CallInfoIdx,
3047 base: StackIdx,
3048 i: Instruction,
3049 pc: u32,
3050 trap: &mut bool,
3051) -> Result<(), LuaError> {
3052 let ra = base + i.arg_a();
3053 state.set_top(ra);
3054 state.set_ci_savedpc(ci, pc);
3055 state.poscall(ci, 0)?;
3056 *trap = true;
3057 Ok(())
3058}
3059
3060#[cold]
3061#[inline(never)]
3062fn return1_hook(
3063 state: &mut LuaState,
3064 ci: CallInfoIdx,
3065 base: StackIdx,
3066 i: Instruction,
3067 pc: u32,
3068 trap: &mut bool,
3069) -> Result<(), LuaError> {
3070 let ra = base + i.arg_a();
3071 state.set_top(ra + 1);
3072 state.set_ci_savedpc(ci, pc);
3073 state.poscall(ci, 1)?;
3074 *trap = true;
3075 Ok(())
3076}
3077
3078