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 mut res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1489 state.dec_top();
1490 if (state.get_ci(ci).callstatus & crate::state::CIST_LEQ) != 0 {
1495 state.get_ci_mut(ci).callstatus &= !crate::state::CIST_LEQ;
1496 res = !res;
1497 }
1498 if (res as i32) != inst.arg_k() {
1499 state.ci_skip_next_instruction(ci);
1500 }
1501 }
1502 OpCode::Concat => {
1508 let top = state.top_idx() - 1; let a = inst.arg_a();
1510 let total_concat = (top - 1 - (base + a)) as i32;
1511 let v = state.get_at(top);
1512 state.set_at(top - 2, v);
1513 state.set_top(top - 1);
1514 concat(state, total_concat)?;
1515 }
1516 OpCode::Close => {
1517 state.ci_step_pc_back(ci);
1518 }
1519 OpCode::Return => {
1523 let a = inst.arg_a();
1524 let ra = base + a;
1525 let nres = state.ci_nres(ci);
1526 state.set_top(ra + nres);
1527 state.ci_step_pc_back(ci);
1528 }
1529 other => {
1530 debug_assert!(
1531 matches!(
1532 other,
1533 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1534 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1535 ),
1536 "unexpected opcode in finish_op: {:?}",
1537 other
1538 );
1539 }
1540 }
1541 Ok(())
1542}
1543
1544pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1556 let mut trap: bool;
1557
1558 'startfunc: loop {
1560 trap = state.hook_mask() != 0;
1561
1562 'returning: loop {
1565 let cl = match state.ci_lua_closure(ci) {
1566 Some(c) => c,
1567 None => {
1568 return Err(LuaError::runtime(format_args!(
1569 "internal: execute called on non-Lua frame"
1570 )));
1571 }
1572 };
1573 let mut pc: u32 = state.ci_savedpc(ci);
1575
1576 if trap {
1577 trap = state.trace_call(ci)?;
1578 }
1579 let mut base: StackIdx = state.ci_base(ci);
1580
1581 'dispatch: loop {
1583 if trap {
1584 trap = state.trace_exec(ci, pc)?;
1585 base = state.ci_base(ci); }
1587 let i: Instruction = state.proto_code(&cl, pc);
1588 pc += 1;
1589 let op = i.opcode();
1590
1591 debug_assert!(base == state.ci_base(ci));
1592
1593 #[cfg(debug_assertions)]
1597 {
1598 let op_mode = op_mode_byte(op);
1599 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1600 state.set_top(base);
1601 }
1602 }
1603
1604 match op {
1605 OpCode::Move => {
1607 let ra = base + i.arg_a();
1608 let rb = base + i.arg_b();
1609 let v = state.stack[rb.0 as usize].val;
1610 state.stack[ra.0 as usize].val = v;
1611 }
1612 OpCode::LoadI => {
1614 let ra = base + i.arg_a();
1615 let b = i.arg_s_bx() as i64;
1616 state.set_at(ra, LuaValue::Int(b));
1617 }
1618 OpCode::LoadF => {
1620 let ra = base + i.arg_a();
1621 let b = i.arg_s_bx() as f64;
1622 state.set_at(ra, LuaValue::Float(b));
1623 }
1624 OpCode::LoadK => {
1626 let ra = base + i.arg_a();
1627 let k_idx = i.arg_bx() as usize;
1628 let v = state.proto_const(&cl, k_idx).clone();
1629 state.set_at(ra, v);
1630 }
1631 OpCode::LoadKX => {
1633 let ra = base + i.arg_a();
1634 let extra = state.proto_code(&cl, pc);
1635 pc += 1;
1636 let k_idx = extra.arg_ax() as usize;
1637 let v = state.proto_const(&cl, k_idx).clone();
1638 state.set_at(ra, v);
1639 }
1640 OpCode::LoadFalse => {
1642 let ra = base + i.arg_a();
1643 state.set_at(ra, LuaValue::Bool(false));
1644 }
1645 OpCode::LFalseSkip => {
1647 let ra = base + i.arg_a();
1648 state.set_at(ra, LuaValue::Bool(false));
1649 pc += 1;
1650 }
1651 OpCode::LoadTrue => {
1653 let ra = base + i.arg_a();
1654 state.set_at(ra, LuaValue::Bool(true));
1655 }
1656 OpCode::LoadNil => {
1658 let ra = base + i.arg_a();
1659 let b = i.arg_b();
1660 for k in 0..=b {
1661 state.set_at(ra + k, LuaValue::Nil);
1662 }
1663 }
1664 OpCode::GetUpVal => {
1666 let ra = base + i.arg_a();
1667 let b = i.arg_b() as usize;
1668 let v = state.upvalue_get(&cl, b);
1669 state.set_at(ra, v);
1670 }
1671 OpCode::SetUpVal => {
1674 let ra = base + i.arg_a();
1675 let b = i.arg_b() as usize;
1676 let v = state.stack[ra.0 as usize].val;
1677 let uv = cl.upval(b);
1678 match uv.try_open_payload() {
1679 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1680 state.stack[idx.0 as usize].val = v;
1681 }
1682 _ => {
1683 state.upvalue_set(&cl, b, v)?;
1684 }
1685 }
1686 }
1687 OpCode::GetTabUp => {
1691 let ra = base + i.arg_a();
1692 let b = i.arg_b() as usize;
1693 let k_idx = i.arg_c() as usize;
1694 let upval = state.upvalue_get(&cl, b);
1695 let key = state.proto_const(&cl, k_idx).clone();
1696 match state.fast_get_short_str(&upval, &key)? {
1697 Some(v) => state.set_at(ra, v),
1698 None => {
1699 state.set_ci_savedpc(ci, pc);
1700 state.set_top(state.ci_top(ci));
1701 finish_get(state, upval, key, ra, true, None)?;
1702 trap = state.ci_trap(ci);
1703 }
1704 }
1705 }
1706 OpCode::GetTable => {
1709 let ra = base + i.arg_a();
1710 let rb_idx = base + i.arg_b();
1711 let rb_v = state.get_at(rb_idx);
1712 let rc_v = state.get_at(base + i.arg_c());
1713 let fast_result = if let LuaValue::Int(n) = &rc_v {
1714 state.fast_get_int(&rb_v, *n)?
1715 } else {
1716 state.fast_get(&rb_v, &rc_v)?
1717 };
1718 match fast_result {
1719 Some(v) => state.set_at(ra, v),
1720 None => {
1721 state.set_ci_savedpc(ci, pc);
1722 state.set_top(state.ci_top(ci));
1723 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1724 trap = state.ci_trap(ci);
1725 }
1726 }
1727 }
1728 OpCode::GetI => {
1732 let ra = base + i.arg_a();
1733 let rb_idx = base + i.arg_b();
1734 let rb_v = state.get_at(rb_idx);
1735 let c = i.arg_c() as i64;
1736 match state.fast_get_int(&rb_v, c)? {
1737 Some(v) => state.set_at(ra, v),
1738 None => {
1739 let key = LuaValue::Int(c);
1740 state.set_ci_savedpc(ci, pc);
1741 state.set_top(state.ci_top(ci));
1742 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1743 trap = state.ci_trap(ci);
1744 }
1745 }
1746 }
1747 OpCode::GetField => {
1749 let ra = base + i.arg_a();
1750 let rb_idx = base + i.arg_b();
1751 let rb_v = state.get_at(rb_idx);
1752 let k_idx = i.arg_c() as usize;
1753 let key = state.proto_const(&cl, k_idx).clone();
1754 match state.fast_get_short_str(&rb_v, &key)? {
1755 Some(v) => state.set_at(ra, v),
1756 None => {
1757 state.set_ci_savedpc(ci, pc);
1758 state.set_top(state.ci_top(ci));
1759 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1760 trap = state.ci_trap(ci);
1761 }
1762 }
1763 }
1764 OpCode::SetTabUp => {
1766 let a = i.arg_a() as usize;
1767 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1769 state.proto_const(&cl, i.arg_c() as usize).clone()
1770 } else {
1771 state.get_at(base + i.arg_c())
1772 };
1773 let upval = state.upvalue_get(&cl, a);
1774 let key = state.proto_const(&cl, b_idx).clone();
1775 match state.fast_get_short_str(&upval, &key)? {
1776 Some(_slot) => {
1777 state.table_raw_set(&upval, key, rc_v.clone())?;
1778 state.gc_barrier_back(&upval, &rc_v);
1779 }
1780 None => {
1781 state.set_ci_savedpc(ci, pc);
1782 state.set_top(state.ci_top(ci));
1783 let upval_name: Vec<u8> = cl
1784 .proto
1785 .upvalues
1786 .get(a)
1787 .and_then(|uv| uv.name.as_ref())
1788 .map(|s| s.as_bytes().to_vec())
1789 .unwrap_or_else(|| b"?".to_vec());
1790 let hint: Option<(&[u8], &[u8])> =
1791 Some((b"upvalue", &upval_name));
1792 finish_set(state, upval, key, rc_v, false, None, hint)?;
1793 trap = state.ci_trap(ci);
1794 }
1795 }
1796 }
1797 OpCode::SetTable => {
1799 let ra_idx = base + i.arg_a();
1800 let ra_v = state.get_at(ra_idx);
1801 let rb_v = state.get_at(base + i.arg_b());
1802 let rc_v = if i.test_k() {
1803 state.proto_const(&cl, i.arg_c() as usize).clone()
1804 } else {
1805 state.get_at(base + i.arg_c())
1806 };
1807 let fast = if let LuaValue::Int(n) = &rb_v {
1808 state.fast_get_int(&ra_v, *n)?
1809 } else {
1810 state.fast_get(&ra_v, &rb_v)?
1811 };
1812 if fast.is_some() {
1813 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1814 state.gc_barrier_back(&ra_v, &rc_v);
1815 } else {
1816 state.set_ci_savedpc(ci, pc);
1817 state.set_top(state.ci_top(ci));
1818 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1819 trap = state.ci_trap(ci);
1820 }
1821 }
1822 OpCode::SetI => {
1824 let ra_idx = base + i.arg_a();
1825 let ra_v = state.get_at(ra_idx);
1826 let c = i.arg_b() as i64;
1827 let rc_v = if i.test_k() {
1828 state.proto_const(&cl, i.arg_c() as usize).clone()
1829 } else {
1830 state.get_at(base + i.arg_c())
1831 };
1832 let fast = state.fast_get_int(&ra_v, c)?;
1833 if fast.is_some() {
1834 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1835 state.gc_barrier_back(&ra_v, &rc_v);
1836 } else {
1837 state.set_ci_savedpc(ci, pc);
1838 state.set_top(state.ci_top(ci));
1839 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1840 trap = state.ci_trap(ci);
1841 }
1842 }
1843 OpCode::SetField => {
1845 let ra_idx = base + i.arg_a();
1846 let ra_v = state.get_at(ra_idx);
1847 let b_idx = i.arg_b() as usize;
1848 let key = state.proto_const(&cl, b_idx).clone();
1849 let rc_v = if i.test_k() {
1850 state.proto_const(&cl, i.arg_c() as usize).clone()
1851 } else {
1852 state.get_at(base + i.arg_c())
1853 };
1854 match state.fast_get_short_str(&ra_v, &key)? {
1855 Some(_) => {
1856 state.table_raw_set(&ra_v, key, rc_v.clone())?;
1857 state.gc_barrier_back(&ra_v, &rc_v);
1858 }
1859 None => {
1860 state.set_ci_savedpc(ci, pc);
1861 state.set_top(state.ci_top(ci));
1862 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
1863 trap = state.ci_trap(ci);
1864 }
1865 }
1866 }
1867 OpCode::NewTable => {
1870 let ra = base + i.arg_a();
1871 let mut b = i.arg_b();
1872 let mut c = i.arg_c();
1873 if b > 0 {
1874 b = 1 << (b - 1);
1875 }
1876 if i.test_k() {
1877 let extra = state.proto_code(&cl, pc);
1878 pc += 1;
1879 const MAXARG_C: i32 = (1 << 8) - 1;
1880 c += extra.arg_ax() * (MAXARG_C + 1);
1881 } else {
1882 pc += 1; }
1884 state.set_top(ra + 1);
1885 let t = if b != 0 || c != 0 {
1886 state.new_table_with_sizes(c as u32, b as u32)?
1887 } else {
1888 state.new_table()
1889 };
1890 state.set_at(ra, LuaValue::Table(t.clone()));
1891 state.set_ci_savedpc(ci, pc);
1892 state.set_top(ra + 1);
1893 state.gc_cond_step();
1894 if state.hookmask != 0 {
1895 trap = state.ci_trap(ci);
1896 }
1897 }
1898 OpCode::Self_ => {
1900 let ra = base + i.arg_a();
1901 let rb_idx = base + i.arg_b();
1902 let rb_v = state.get_at(rb_idx);
1903 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
1905 state.proto_const(&cl, k_idx).clone()
1906 } else {
1907 state.get_at(base + i.arg_c())
1908 };
1909 state.set_at(ra + 1, rb_v.clone());
1910 match state.fast_get_short_str(&rb_v, &key)? {
1911 Some(v) => state.set_at(ra, v),
1912 None => {
1913 state.set_ci_savedpc(ci, pc);
1914 state.set_top(state.ci_top(ci));
1915 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1916 trap = state.ci_trap(ci);
1917 }
1918 }
1919 }
1920 OpCode::AddI => {
1922 let ra = base + i.arg_a();
1923 let rb = base + i.arg_b();
1924 let imm = i.arg_s_c() as i64;
1925 let rb_v = state.stack[rb.0 as usize].val;
1926 match rb_v {
1927 LuaValue::Int(iv1) => {
1928 pc += 1;
1929 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
1930 }
1931 LuaValue::Float(nb) => {
1932 pc += 1;
1933 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
1934 }
1935 _ => {}
1936 }
1937 }
1938 OpCode::AddK => {
1940 let ra = base + i.arg_a();
1941 let rb = base + i.arg_b();
1942 let kidx = i.arg_c() as usize;
1943 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1944 pc += 1;
1945 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
1946 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1947 pc += 1;
1948 state.set_at(ra, LuaValue::Float(n1 + n2));
1949 }
1950 }
1951 OpCode::SubK => {
1952 let ra = base + i.arg_a();
1953 let rb = base + i.arg_b();
1954 let kidx = i.arg_c() as usize;
1955 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1956 pc += 1;
1957 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
1958 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1959 pc += 1;
1960 state.set_at(ra, LuaValue::Float(n1 - n2));
1961 }
1962 }
1963 OpCode::MulK => {
1964 let ra = base + i.arg_a();
1965 let rb = base + i.arg_b();
1966 let kidx = i.arg_c() as usize;
1967 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1968 pc += 1;
1969 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1970 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1971 pc += 1;
1972 state.set_at(ra, LuaValue::Float(n1 * n2));
1973 }
1974 }
1975 OpCode::ModK => {
1976 let ra = base + i.arg_a();
1977 let v1 = state.get_at(base + i.arg_b());
1978 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1979 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
1981 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1982 |a, b| imod(a, b), fmodf)?;
1983 }
1984 OpCode::PowK => {
1985 let ra = base + i.arg_a();
1986 let rb = base + i.arg_b();
1987 let kidx = i.arg_c() as usize;
1988 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1989 pc += 1;
1990 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1991 state.set_at(ra, LuaValue::Float(r));
1992 }
1993 }
1994 OpCode::DivK => {
1995 let ra = base + i.arg_a();
1996 let rb = base + i.arg_b();
1997 let kidx = i.arg_c() as usize;
1998 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1999 pc += 1;
2000 state.set_at(ra, LuaValue::Float(n1 / n2));
2001 }
2002 }
2003 OpCode::IDivK => {
2004 let ra = base + i.arg_a();
2005 let v1 = state.get_at(base + i.arg_b());
2006 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2007 state.set_ci_savedpc(ci, pc);
2008 state.set_top(state.ci_top(ci));
2009 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2010 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2011 }
2012 OpCode::BAndK => {
2013 let ra = base + i.arg_a();
2014 let v1 = state.get_at(base + i.arg_b());
2015 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2016 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2017 }
2018 OpCode::BOrK => {
2019 let ra = base + i.arg_a();
2020 let v1 = state.get_at(base + i.arg_b());
2021 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2022 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2023 }
2024 OpCode::BXOrK => {
2025 let ra = base + i.arg_a();
2026 let v1 = state.get_at(base + i.arg_b());
2027 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2028 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2029 }
2030 OpCode::ShrI => {
2031 let ra = base + i.arg_a();
2032 let v = state.get_at(base + i.arg_b());
2033 let ic = i.arg_s_c() as i64;
2034 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2035 pc += 1;
2036 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2037 }
2038 }
2039 OpCode::ShlI => {
2040 let ra = base + i.arg_a();
2041 let v = state.get_at(base + i.arg_b());
2042 let ic = i.arg_s_c() as i64;
2043 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2044 pc += 1;
2045 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2046 }
2047 }
2048 OpCode::Add => {
2050 let ra = base + i.arg_a();
2051 let rb = base + i.arg_b();
2052 let rc = base + i.arg_c();
2053 let ra_u = ra.0 as usize;
2054 let rb_v = state.stack[rb.0 as usize].val;
2055 let rc_v = state.stack[rc.0 as usize].val;
2056 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2057 pc += 1;
2058 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2059 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2060 pc += 1;
2061 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2062 }
2063 }
2064 OpCode::Sub => {
2065 let ra = base + i.arg_a();
2066 let rb = base + i.arg_b();
2067 let rc = base + i.arg_c();
2068 let ra_u = ra.0 as usize;
2069 let rb_v = state.stack[rb.0 as usize].val;
2070 let rc_v = state.stack[rc.0 as usize].val;
2071 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2072 pc += 1;
2073 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2074 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2075 pc += 1;
2076 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2077 }
2078 }
2079 OpCode::Mul => {
2080 let ra = base + i.arg_a();
2081 let rb = base + i.arg_b();
2082 let rc = base + i.arg_c();
2083 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2084 pc += 1;
2085 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2086 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2087 pc += 1;
2088 state.set_at(ra, LuaValue::Float(n1 * n2));
2089 }
2090 }
2091 OpCode::Mod => {
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 state.set_ci_savedpc(ci, pc);
2096 state.set_top(state.ci_top(ci));
2097 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2098 |a, b| imod(a, b), fmodf)?;
2099 }
2100 OpCode::Pow => {
2101 let ra = base + i.arg_a();
2102 let rb = base + i.arg_b();
2103 let rc = base + i.arg_c();
2104 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2105 pc += 1;
2106 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2107 state.set_at(ra, LuaValue::Float(r));
2108 }
2109 }
2110 OpCode::Div => {
2111 let ra = base + i.arg_a();
2112 let rb = base + i.arg_b();
2113 let rc = base + i.arg_c();
2114 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2115 pc += 1;
2116 state.set_at(ra, LuaValue::Float(n1 / n2));
2117 }
2118 }
2119 OpCode::IDiv => {
2120 let ra = base + i.arg_a();
2121 let v1 = state.get_at(base + i.arg_b());
2122 let v2 = state.get_at(base + i.arg_c());
2123 state.set_ci_savedpc(ci, pc);
2124 state.set_top(state.ci_top(ci));
2125 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2126 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2127 }
2128 OpCode::BAnd => {
2131 let ra = base + i.arg_a();
2132 let v1 = state.get_at(base + i.arg_b());
2133 let v2 = state.get_at(base + i.arg_c());
2134 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2135 }
2136 OpCode::BOr => {
2137 let ra = base + i.arg_a();
2138 let v1 = state.get_at(base + i.arg_b());
2139 let v2 = state.get_at(base + i.arg_c());
2140 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2141 }
2142 OpCode::BXOr => {
2143 let ra = base + i.arg_a();
2144 let v1 = state.get_at(base + i.arg_b());
2145 let v2 = state.get_at(base + i.arg_c());
2146 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2147 }
2148 OpCode::Shr => {
2149 let ra = base + i.arg_a();
2150 let v1 = state.get_at(base + i.arg_b());
2151 let v2 = state.get_at(base + i.arg_c());
2152 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2153 }
2154 OpCode::Shl => {
2155 let ra = base + i.arg_a();
2156 let v1 = state.get_at(base + i.arg_b());
2157 let v2 = state.get_at(base + i.arg_c());
2158 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2159 }
2160 OpCode::MmBin => {
2165 let ra_idx = base + i.arg_a();
2166 let rb_idx = base + i.arg_b();
2167 let ra_v = state.get_at(ra_idx);
2168 let rb_v = state.get_at(rb_idx);
2169 let tm = tagmethod_from_index(i.arg_c() as usize);
2170 let prev_inst = state.proto_code(&cl, pc - 2);
2171 let result_idx = base + prev_inst.arg_a();
2172 state.set_ci_savedpc(ci, pc);
2173 state.set_top(state.ci_top(ci));
2174 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2175 trap = state.ci_trap(ci);
2176 }
2177 OpCode::MmBinI => {
2178 let ra_idx = base + i.arg_a();
2179 let ra_v = state.get_at(ra_idx);
2180 let imm = i.arg_s_b() as i64;
2181 let tm = tagmethod_from_index(i.arg_c() as usize);
2182 let flip = i.arg_k() != 0;
2183 let prev_inst = state.proto_code(&cl, pc - 2);
2184 let result_idx = base + prev_inst.arg_a();
2185 state.set_ci_savedpc(ci, pc);
2186 state.set_top(state.ci_top(ci));
2187 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2188 trap = state.ci_trap(ci);
2189 }
2190 OpCode::MmBinK => {
2191 let ra_idx = base + i.arg_a();
2192 let ra_v = state.get_at(ra_idx);
2193 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2194 let tm = tagmethod_from_index(i.arg_c() as usize);
2195 let flip = i.arg_k() != 0;
2196 let prev_inst = state.proto_code(&cl, pc - 2);
2197 let result_idx = base + prev_inst.arg_a();
2198 state.set_ci_savedpc(ci, pc);
2199 state.set_top(state.ci_top(ci));
2200 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2201 trap = state.ci_trap(ci);
2202 }
2203 OpCode::Unm => {
2207 let ra = base + i.arg_a();
2208 let rb_idx = base + i.arg_b();
2209 let rb_v = state.get_at(rb_idx);
2210 match &rb_v {
2211 LuaValue::Int(ib) => {
2212 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2213 }
2214 LuaValue::Float(nb) => {
2215 state.set_at(ra, LuaValue::Float(-nb));
2216 }
2217 _ => {
2218 state.set_ci_savedpc(ci, pc);
2219 state.set_top(state.ci_top(ci));
2220 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2221 trap = state.ci_trap(ci);
2222 }
2223 }
2224 }
2225 OpCode::BNot => {
2227 let ra = base + i.arg_a();
2228 let rb_idx = base + i.arg_b();
2229 let rb_v = state.get_at(rb_idx);
2230 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2231 state.set_at(ra, LuaValue::Int(!ib));
2232 } else {
2233 state.set_ci_savedpc(ci, pc);
2234 state.set_top(state.ci_top(ci));
2235 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2236 trap = state.ci_trap(ci);
2237 }
2238 }
2239 OpCode::Not => {
2241 let ra = base + i.arg_a();
2242 let rb_v = state.get_at(base + i.arg_b());
2243 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2244 state.set_at(ra, LuaValue::Bool(falsy));
2245 }
2246 OpCode::Len => {
2248 let ra = base + i.arg_a();
2249 let rb_idx = base + i.arg_b();
2250 let rb_v = state.get_at(rb_idx);
2251 state.set_ci_savedpc(ci, pc);
2252 state.set_top(state.ci_top(ci));
2253 obj_len(state, ra, rb_v, rb_idx)?;
2254 trap = state.ci_trap(ci);
2255 }
2256 OpCode::Concat => {
2258 let ra = base + i.arg_a();
2259 let n = i.arg_b() as i32;
2260 state.set_top(ra + n as i32);
2261 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2263 let top = state.top_idx();
2264 state.set_ci_savedpc(ci, pc);
2265 state.set_top(top);
2266 state.gc_cond_step();
2267 trap = state.ci_trap(ci);
2268 }
2269 OpCode::Close => {
2271 let ra = base + i.arg_a();
2272 state.set_ci_savedpc(ci, pc);
2273 state.set_top(state.ci_top(ci));
2274 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2275 trap = state.ci_trap(ci);
2276 }
2277 OpCode::Tbc => {
2279 let ra = base + i.arg_a();
2280 state.set_ci_savedpc(ci, pc);
2281 state.set_top(state.ci_top(ci));
2282 state.new_tbc_upval(ra)?;
2283 }
2284 OpCode::Jmp => {
2286 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2287 trap = state.ci_trap(ci);
2288 }
2289 OpCode::Eq => {
2291 let ra_v = state.get_at(base + i.arg_a());
2292 let rb_v = state.get_at(base + i.arg_b());
2293 state.set_ci_savedpc(ci, pc);
2294 state.set_top(state.ci_top(ci));
2295 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2296 trap = state.ci_trap(ci);
2297 if (cond as i32) != i.arg_k() {
2298 pc += 1;
2299 } else {
2300 let next = state.proto_code(&cl, pc);
2301 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2302 trap = state.ci_trap(ci);
2303 }
2304 }
2305 OpCode::Lt => {
2307 let ra_v = state.get_at(base + i.arg_a());
2308 let rb_v = state.get_at(base + i.arg_b());
2309 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2310 *ia < *ib
2311 } else if matches!((&ra_v, &rb_v),
2312 (LuaValue::Int(_) | LuaValue::Float(_),
2313 LuaValue::Int(_) | LuaValue::Float(_))) {
2314 lt_num(&ra_v, &rb_v)
2315 } else {
2316 state.set_ci_savedpc(ci, pc);
2317 state.set_top(state.ci_top(ci));
2318 let r = less_than_others(state, &ra_v, &rb_v)?;
2319 trap = state.ci_trap(ci);
2320 r
2321 };
2322 if (cond as i32) != i.arg_k() {
2323 pc += 1;
2324 } else {
2325 let next = state.proto_code(&cl, pc);
2326 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2327 trap = state.ci_trap(ci);
2328 }
2329 }
2330 OpCode::Le => {
2332 let ra_v = state.get_at(base + i.arg_a());
2333 let rb_v = state.get_at(base + i.arg_b());
2334 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2335 *ia <= *ib
2336 } else if matches!((&ra_v, &rb_v),
2337 (LuaValue::Int(_) | LuaValue::Float(_),
2338 LuaValue::Int(_) | LuaValue::Float(_))) {
2339 le_num(&ra_v, &rb_v)
2340 } else {
2341 state.set_ci_savedpc(ci, pc);
2342 state.set_top(state.ci_top(ci));
2343 let r = less_equal_others(state, &ra_v, &rb_v)?;
2344 trap = state.ci_trap(ci);
2345 r
2346 };
2347 if (cond as i32) != i.arg_k() {
2348 pc += 1;
2349 } else {
2350 let next = state.proto_code(&cl, pc);
2351 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2352 trap = state.ci_trap(ci);
2353 }
2354 }
2355 OpCode::EqK => {
2357 let ra_v = state.get_at(base + i.arg_a());
2358 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2359 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2360 if (cond as i32) != i.arg_k() {
2361 pc += 1;
2362 } else {
2363 let next = state.proto_code(&cl, pc);
2364 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2365 trap = state.ci_trap(ci);
2366 }
2367 }
2368 OpCode::EqI => {
2373 let ra_v = state.get_at(base + i.arg_a());
2374 let im = i.arg_s_b() as i64;
2375 let cond: bool = match &ra_v {
2376 LuaValue::Int(iv) => *iv == im,
2377 LuaValue::Float(fv) => *fv == im as f64,
2378 _ => false,
2379 };
2380 if (cond as i32) != i.arg_k() {
2381 pc += 1;
2382 } else {
2383 let next = state.proto_code(&cl, pc);
2384 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2385 trap = state.ci_trap(ci);
2386 }
2387 }
2388 OpCode::LtI => {
2391 let ra = base + i.arg_a();
2392 let im = i.arg_s_b() as i64;
2393 let fast_cond = match &state.stack[ra.0 as usize].val {
2394 LuaValue::Int(ia) => Some(*ia < im),
2395 LuaValue::Float(fa) => Some(*fa < im as f64),
2396 _ => None,
2397 };
2398 let cond = match fast_cond {
2399 Some(cond) => cond,
2400 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2401 };
2402 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2403 }
2404 OpCode::LeI => {
2405 let ra = base + i.arg_a();
2406 let im = i.arg_s_b() as i64;
2407 let fast_cond = match &state.stack[ra.0 as usize].val {
2408 LuaValue::Int(ia) => Some(*ia <= im),
2409 LuaValue::Float(fa) => Some(*fa <= im as f64),
2410 _ => None,
2411 };
2412 let cond = match fast_cond {
2413 Some(cond) => cond,
2414 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2415 };
2416 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2417 }
2418 OpCode::GtI => {
2419 let ra = base + i.arg_a();
2420 let im = i.arg_s_b() as i64;
2421 let fast_cond = match &state.stack[ra.0 as usize].val {
2422 LuaValue::Int(ia) => Some(*ia > im),
2423 LuaValue::Float(fa) => Some(*fa > im as f64),
2424 _ => None,
2425 };
2426 let cond = match fast_cond {
2427 Some(cond) => cond,
2428 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2429 };
2430 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2431 }
2432 OpCode::GeI => {
2433 let ra = base + i.arg_a();
2434 let im = i.arg_s_b() as i64;
2435 let fast_cond = match &state.stack[ra.0 as usize].val {
2436 LuaValue::Int(ia) => Some(*ia >= im),
2437 LuaValue::Float(fa) => Some(*fa >= im as f64),
2438 _ => None,
2439 };
2440 let cond = match fast_cond {
2441 Some(cond) => cond,
2442 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2443 };
2444 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2445 }
2446 OpCode::Test => {
2448 let ra_v = state.get_at(base + i.arg_a());
2449 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2450 if (cond as i32) != i.arg_k() {
2451 pc += 1;
2452 } else {
2453 let next = state.proto_code(&cl, pc);
2454 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2455 trap = state.ci_trap(ci);
2456 }
2457 }
2458 OpCode::TestSet => {
2461 let ra = base + i.arg_a();
2462 let rb_v = state.get_at(base + i.arg_b());
2463 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2464 if (falsy as i32) == i.arg_k() {
2465 pc += 1;
2466 } else {
2467 state.set_at(ra, rb_v);
2468 let next = state.proto_code(&cl, pc);
2469 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2470 trap = state.ci_trap(ci);
2471 }
2472 }
2473 OpCode::Call => {
2477 let ra = base + i.arg_a();
2478 let b = i.arg_b();
2479 let nresults = i.arg_c() as i32 - 1;
2480 if b != 0 {
2481 state.set_top(ra + b);
2482 }
2483 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2485 match state.precall(ra, nresults)? {
2486 None => {
2487 if had_hook || state.hookmask != 0 {
2491 trap = state.ci_trap(ci); }
2493 }
2494 Some(new_ci) => {
2495 ci = new_ci;
2497 continue 'startfunc;
2498 }
2499 }
2500 }
2501 OpCode::TailCall => {
2506 let ra = base + i.arg_a();
2507 let b = i.arg_b();
2508 let nparams1 = i.arg_c();
2509 let delta = if nparams1 != 0 {
2510 state.ci_nextraargs(ci) + nparams1 as i32
2511 } else {
2512 0
2513 };
2514 let top_b: i32 = if b != 0 {
2515 state.set_top(ra + b);
2516 b
2517 } else {
2518 state.top_idx() - ra
2519 };
2520 state.set_ci_savedpc(ci, pc);
2521 if i.test_k() {
2522 state.close_upvals_from_base(ci)?;
2523 }
2524 let n = state.pretailcall(ci, ra, top_b, delta)?;
2525 if n < 0 {
2526 continue 'startfunc;
2528 } else {
2529 state.ci_adjust_func(ci, delta);
2531 state.poscall(ci, n as u32)?;
2532 if state.hookmask != 0 {
2533 trap = state.ci_trap(ci);
2534 }
2535 break 'dispatch; }
2537 }
2538 OpCode::Return => {
2543 let ra = base + i.arg_a();
2544 let n_raw = i.arg_b() as i32 - 1;
2545 let nparams1 = i.arg_c();
2546 let n: u32 = if n_raw < 0 {
2547 (state.top_idx() - ra) as u32
2548 } else {
2549 n_raw as u32
2550 };
2551 state.set_ci_savedpc(ci, pc);
2552 if i.test_k() {
2553 state.ci_nres_set(ci, n as i32);
2554 let ci_top = state.ci_top(ci);
2555 if state.top_idx().0 < ci_top.0 {
2556 state.set_top(ci_top);
2557 }
2558 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2559 if state.hookmask != 0 {
2560 trap = state.ci_trap(ci);
2561 }
2562 base = state.ci_base(ci); }
2564 if nparams1 != 0 {
2565 let nextraargs = state.ci_nextraargs(ci) as u32;
2566 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2567 }
2568 state.set_top(ra + n as i32);
2569 state.poscall(ci, n)?;
2570 if state.hookmask != 0 {
2571 trap = state.ci_trap(ci);
2572 }
2573 break 'dispatch; }
2575 OpCode::Return0 => {
2581 if state.hookmask == 0 {
2582 let ci_slot = ci.as_usize();
2583 let nres = state.call_info[ci_slot].nresults as i32;
2584 state.ci = state.call_info[ci_slot]
2585 .previous
2586 .expect("RETURN0: returning frame has no previous CallInfo");
2587 state.top = base - 1;
2588 for _ in 0..nres.max(0) {
2589 state.push(LuaValue::Nil);
2590 }
2591 } else {
2592 return0_hook(state, ci, base, i, pc, &mut trap)?;
2593 }
2594 break 'dispatch; }
2596 OpCode::Return1 => {
2600 if state.hookmask == 0 {
2601 let ci_slot = ci.as_usize();
2602 let nres = state.call_info[ci_slot].nresults as i32;
2603 state.ci = state.call_info[ci_slot]
2604 .previous
2605 .expect("RETURN1: returning frame has no previous CallInfo");
2606 if nres == 0 {
2607 state.top = base - 1;
2608 } else {
2609 let ra = base + i.arg_a();
2610 state.stack[(base - 1).0 as usize].val =
2611 state.stack[ra.0 as usize].val; state.top = base;
2613 for _ in 1..nres.max(0) {
2614 state.push(LuaValue::Nil);
2615 }
2616 }
2617 } else {
2618 return1_hook(state, ci, base, i, pc, &mut trap)?;
2619 }
2620 break 'dispatch; }
2622 OpCode::ForLoop => {
2626 let ra = base + i.arg_a();
2627 let ra_u = ra.0 as usize;
2628 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2629 let count = match state.stack[ra_u + 1].val {
2630 LuaValue::Int(c) => c as u64,
2631 _ => 0,
2632 };
2633 if count > 0 {
2634 let idx = match state.stack[ra_u].val {
2635 LuaValue::Int(x) => x,
2636 _ => 0,
2637 };
2638 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2639 let new_idx = intop_add(idx, step);
2640 state.stack[ra_u].val = LuaValue::Int(new_idx);
2641 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2642 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2643 }
2644 } else if float_for_loop(state, ra) {
2645 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2646 }
2647 trap = state.ci_trap(ci);
2648 }
2649 OpCode::ForPrep => {
2651 let ra = base + i.arg_a();
2652 state.set_ci_savedpc(ci, pc);
2653 state.set_top(state.ci_top(ci));
2654 if forprep(state, ra)? {
2655 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2656 }
2657 }
2658 OpCode::TForPrep => {
2662 let ra = base + i.arg_a();
2663 state.set_ci_savedpc(ci, pc);
2664 state.set_top(state.ci_top(ci));
2665 state.new_tbc_upval(ra + 3)?;
2666 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2667 let tfc_i = state.proto_code(&cl, pc);
2668 pc += 1;
2669 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2670 let tfc_ra = base + tfc_i.arg_a();
2672 for k in 0..3u32 {
2673 let v = state.get_at(tfc_ra + k as i32);
2674 state.set_at(tfc_ra + 4 + k as i32, v);
2675 }
2676 state.set_top(tfc_ra + 4 + 3);
2677 state.set_ci_savedpc(ci, pc);
2678 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2679 trap = state.ci_trap(ci);
2680 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2682 pc += 1;
2683 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2684 let tfl_ra = base + tfl_i.arg_a();
2685 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2687 let v = state.get_at(tfl_ra + 4);
2688 state.set_at(tfl_ra + 2, v);
2689 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2690 }
2691 }
2692 OpCode::TForCall => {
2694 let ra = base + i.arg_a();
2695 for k in 0..3u32 {
2696 let v = state.get_at(ra + k as i32);
2697 state.set_at(ra + 4 + k as i32, v);
2698 }
2699 state.set_top(ra + 4 + 3);
2700 state.set_ci_savedpc(ci, pc);
2701 state.call_at(ra + 4, i.arg_c() as i32)?;
2702 trap = state.ci_trap(ci);
2703 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2705 pc += 1;
2706 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2707 let tfl_ra = base + tfl_i.arg_a();
2708 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2709 let v = state.get_at(tfl_ra + 4);
2710 state.set_at(tfl_ra + 2, v);
2711 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2712 }
2713 }
2714 OpCode::TForLoop => {
2716 let ra = base + i.arg_a();
2717 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2718 let v = state.get_at(ra + 4);
2719 state.set_at(ra + 2, v);
2720 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2721 }
2722 }
2723 OpCode::SetList => {
2727 let ra = base + i.arg_a();
2728 let n_raw = i.arg_b();
2729 let mut last = i.arg_c();
2730 let t_val = state.get_at(ra);
2731 let n: i32 = if n_raw == 0 {
2732 state.top_idx() - ra - 1
2733 } else {
2734 state.set_top(state.ci_top(ci));
2735 n_raw
2736 };
2737 last += n;
2738 if i.test_k() {
2739 let extra = state.proto_code(&cl, pc);
2740 pc += 1;
2741 const MAXARG_C: i32 = (1 << 8) - 1;
2742 last += extra.arg_ax() * (MAXARG_C + 1);
2743 }
2744 state.table_ensure_array(&t_val, last as usize)?;
2745 for k in (1..=n).rev() {
2746 let val = state.get_at(ra + k as i32);
2747 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2748 last -= 1;
2749 state.gc_barrier_back(&t_val, &val);
2750 }
2751 }
2752 OpCode::Closure => {
2756 let ra = base + i.arg_a();
2757 let proto_idx = i.arg_bx() as usize;
2758 state.set_ci_savedpc(ci, pc);
2759 state.set_top(state.ci_top(ci));
2760 push_closure(state, proto_idx, ci, base, ra)?;
2761 state.set_ci_savedpc(ci, pc);
2763 state.set_top(ra + 1);
2764 state.gc_cond_step();
2765 trap = state.ci_trap(ci);
2766 }
2767 OpCode::VarArg => {
2769 let ra = base + i.arg_a();
2770 let n = i.arg_c() as i32 - 1;
2771 state.set_ci_savedpc(ci, pc);
2772 state.set_top(state.ci_top(ci));
2773 state.get_varargs(ci, ra, n)?;
2774 trap = state.ci_trap(ci);
2775 }
2776 OpCode::VarArgPrep => {
2780 let nparams = i.arg_a();
2781 state.set_ci_savedpc(ci, pc);
2782 state.adjust_varargs(ci, nparams, &cl)?;
2783 trap = state.ci_trap(ci);
2784 if trap {
2785 state.hook_call(ci)?;
2786 state.set_oldpc(1);
2787 }
2788 base = state.ci_base(ci);
2789 }
2790 OpCode::ExtraArg => {
2792 debug_assert!(false, "OP_EXTRAARG executed directly");
2793 }
2794 OpCode::ErrNNil => {
2799 let ra = base + i.arg_a();
2800 if !matches!(state.get_at(ra), LuaValue::Nil) {
2801 let bx = i.arg_bx();
2802 let name: Vec<u8> = if bx == 0 {
2803 b"?".to_vec()
2804 } else {
2805 match state.proto_const(&cl, (bx - 1) as usize) {
2806 LuaValue::Str(s) => s.as_bytes().to_vec(),
2807 _ => b"?".to_vec(),
2808 }
2809 };
2810 let mut msg = Vec::with_capacity(name.len() + 24);
2811 msg.extend_from_slice(b"global '");
2812 msg.extend_from_slice(&name);
2813 msg.extend_from_slice(b"' already defined");
2814 state.set_ci_savedpc(ci, pc);
2815 return Err(crate::debug::prefixed_runtime_pub(state, msg));
2816 }
2817 }
2818 OpCode::VarArgPack => {
2826 let ra = base + i.arg_a();
2827 let nextra = state.ci_nextraargs(ci);
2828 let ci_func: StackIdx = state.ci_base(ci) - 1;
2829 let t = if nextra > 0 {
2830 state.new_table_with_sizes(nextra as u32, 1)?
2831 } else {
2832 state.new_table()
2833 };
2834 for k in 0..nextra {
2835 let src: StackIdx = ci_func - nextra as i32 + k as i32;
2836 let val = state.get_at(src);
2837 t.raw_set_int(state, (k + 1) as i64, val)?;
2838 }
2839 let n_key = state.intern_str(b"n")?;
2840 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
2841 state.set_at(ra, LuaValue::Table(t));
2842 state.set_ci_savedpc(ci, pc);
2843 state.gc_cond_step();
2844 if state.hookmask != 0 {
2845 trap = state.ci_trap(ci);
2846 }
2847 }
2848 } } if state.ci_is_fresh(ci) {
2853 return Ok(());
2854 } else {
2855 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2856 continue 'returning;
2857 }
2858 } } }
2861
2862#[inline(always)]
2865fn number_value(v: LuaValue) -> Option<f64> {
2866 match v {
2867 LuaValue::Float(f) => Some(f),
2868 LuaValue::Int(i) => Some(i as f64),
2869 _ => None,
2870 }
2871}
2872
2873#[allow(dead_code)]
2875#[inline]
2876fn arith_op_aux_rr(
2877 state: &mut LuaState,
2878 ra: StackIdx,
2879 v1: &LuaValue,
2880 v2: &LuaValue,
2881 pc: &mut u32,
2882 iop: fn(i64, i64) -> i64,
2883 fop: fn(f64, f64) -> f64,
2884) {
2885 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2886 *pc += 1;
2887 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
2888 } else {
2889 arith_float_aux(state, ra, v1, v2, pc, fop);
2890 }
2891}
2892
2893#[allow(dead_code)]
2894#[inline]
2895fn arith_float_aux(
2896 state: &mut LuaState,
2897 ra: StackIdx,
2898 v1: &LuaValue,
2899 v2: &LuaValue,
2900 pc: &mut u32,
2901 fop: fn(f64, f64) -> f64,
2902) {
2903 let n1 = match v1 {
2904 LuaValue::Float(f) => Some(*f),
2905 LuaValue::Int(i) => Some(*i as f64),
2906 _ => None,
2907 };
2908 let n2 = match v2 {
2909 LuaValue::Float(f) => Some(*f),
2910 LuaValue::Int(i) => Some(*i as f64),
2911 _ => None,
2912 };
2913 if let (Some(n1), Some(n2)) = (n1, n2) {
2914 *pc += 1;
2915 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
2916 }
2917}
2918
2919#[allow(dead_code)]
2920#[inline]
2921fn arith_op_checked(
2922 state: &mut LuaState,
2923 ra: StackIdx,
2924 v1: &LuaValue,
2925 v2: &LuaValue,
2926 pc: &mut u32,
2927 iop: fn(i64, i64) -> Result<i64, LuaError>,
2928 fop: fn(f64, f64) -> f64,
2929) -> Result<(), LuaError> {
2930 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2931 *pc += 1;
2932 let result = iop(*i1, *i2).map_err(|e| match e {
2933 LuaError::Runtime(LuaValue::Str(s)) => {
2934 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
2935 }
2936 other => other,
2937 })?;
2938 state.set_at(ra, LuaValue::Int(result));
2939 } else {
2940 arith_float_aux(state, ra, v1, v2, pc, fop);
2941 }
2942 Ok(())
2943}
2944
2945#[allow(dead_code)]
2946#[inline]
2947fn bitwise_op_k(
2948 state: &mut LuaState,
2949 ra: StackIdx,
2950 v1: &LuaValue,
2951 v2: &LuaValue, pc: &mut u32,
2953 op: fn(i64, i64) -> i64,
2954) {
2955 let i2 = match v2 {
2956 LuaValue::Int(i) => *i,
2957 _ => return,
2958 };
2959 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
2960 *pc += 1;
2961 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2962 }
2963}
2964
2965#[allow(dead_code)]
2966#[inline]
2967fn bitwise_op_rr(
2968 state: &mut LuaState,
2969 ra: StackIdx,
2970 v1: &LuaValue,
2971 v2: &LuaValue,
2972 pc: &mut u32,
2973 op: fn(i64, i64) -> i64,
2974) {
2975 if let (Some(i1), Some(i2)) = (
2976 to_integer_ns(v1, F2Imod::Eq),
2977 to_integer_ns(v2, F2Imod::Eq),
2978 ) {
2979 *pc += 1;
2980 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2981 }
2982}
2983
2984#[allow(dead_code)]
2986#[inline]
2987fn bitwise_shift_rr(
2988 state: &mut LuaState,
2989 ra: StackIdx,
2990 v1: &LuaValue,
2991 v2: &LuaValue,
2992 pc: &mut u32,
2993 right: bool,
2994) {
2995 if let (Some(i1), Some(i2)) = (
2996 to_integer_ns(v1, F2Imod::Eq),
2997 to_integer_ns(v2, F2Imod::Eq),
2998 ) {
2999 let y = if right { intop_sub(0, i2) } else { i2 };
3000 *pc += 1;
3001 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3002 }
3003}
3004
3005#[cold]
3008#[inline(never)]
3009#[allow(clippy::too_many_arguments)]
3010fn order_imm_slow(
3011 state: &mut LuaState,
3012 ra: StackIdx,
3013 pc: u32,
3014 trap: &mut bool,
3015 ci: CallInfoIdx,
3016 i: Instruction,
3017 im: i64,
3018 inv: bool,
3019 tm: TagMethod,
3020) -> Result<bool, LuaError> {
3021 let ra_v = state.get_at(ra);
3022 let isf = i.arg_c() != 0;
3023 state.set_ci_savedpc(ci, pc);
3024 state.set_top(state.ci_top(ci));
3025 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3026 *trap = state.ci_trap(ci);
3027 Ok(r)
3028}
3029
3030#[inline(always)]
3031fn finish_order_imm_jump(
3032 state: &mut LuaState,
3033 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
3034 pc: &mut u32,
3035 trap: &mut bool,
3036 ci: CallInfoIdx,
3037 i: Instruction,
3038 cond: bool,
3039) {
3040 if (cond as i32) != i.arg_k() {
3041 *pc += 1;
3042 } else {
3043 let next = state.proto_code(&cl, *pc);
3044 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3045 *trap = state.ci_trap(ci);
3046 }
3047}
3048
3049#[cold]
3050#[inline(never)]
3051fn return0_hook(
3052 state: &mut LuaState,
3053 ci: CallInfoIdx,
3054 base: StackIdx,
3055 i: Instruction,
3056 pc: u32,
3057 trap: &mut bool,
3058) -> Result<(), LuaError> {
3059 let ra = base + i.arg_a();
3060 state.set_top(ra);
3061 state.set_ci_savedpc(ci, pc);
3062 state.poscall(ci, 0)?;
3063 *trap = true;
3064 Ok(())
3065}
3066
3067#[cold]
3068#[inline(never)]
3069fn return1_hook(
3070 state: &mut LuaState,
3071 ci: CallInfoIdx,
3072 base: StackIdx,
3073 i: Instruction,
3074 pc: u32,
3075 trap: &mut bool,
3076) -> Result<(), LuaError> {
3077 let ra = base + i.arg_a();
3078 state.set_top(ra + 1);
3079 state.set_ci_savedpc(ci, pc);
3080 state.poscall(ci, 1)?;
3081 *trap = true;
3082 Ok(())
3083}
3084
3085