1#[allow(unused_imports)]
23use crate::prelude::*;
24use crate::state::LuaState;
25use lua_types::opcode::Instruction;
26use lua_types::tagmethod::TagMethod;
27use lua_types::{CallInfoIdx, GcRef, LuaError, LuaString, LuaValue, StackIdx};
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
55#[allow(non_camel_case_types)]
56#[repr(u8)]
57pub enum OpCode {
58 Move = 0,
59 LoadI = 1,
60 LoadF = 2,
61 LoadK = 3,
62 LoadKX = 4,
63 LoadFalse = 5,
64 LFalseSkip = 6,
65 LoadTrue = 7,
66 LoadNil = 8,
67 GetUpVal = 9,
68 SetUpVal = 10,
69 GetTabUp = 11,
70 GetTable = 12,
71 GetI = 13,
72 GetField = 14,
73 SetTabUp = 15,
74 SetTable = 16,
75 SetI = 17,
76 SetField = 18,
77 NewTable = 19,
78 Self_ = 20,
79 AddI = 21,
80 AddK = 22,
81 SubK = 23,
82 MulK = 24,
83 ModK = 25,
84 PowK = 26,
85 DivK = 27,
86 IDivK = 28,
87 BAndK = 29,
88 BOrK = 30,
89 BXOrK = 31,
90 ShrI = 32,
91 ShlI = 33,
92 Add = 34,
93 Sub = 35,
94 Mul = 36,
95 Mod = 37,
96 Pow = 38,
97 Div = 39,
98 IDiv = 40,
99 BAnd = 41,
100 BOr = 42,
101 BXOr = 43,
102 Shl = 44,
103 Shr = 45,
104 MmBin = 46,
105 MmBinI = 47,
106 MmBinK = 48,
107 Unm = 49,
108 BNot = 50,
109 Not = 51,
110 Len = 52,
111 Concat = 53,
112 Close = 54,
113 Tbc = 55,
114 Jmp = 56,
115 Eq = 57,
116 Lt = 58,
117 Le = 59,
118 EqK = 60,
119 EqI = 61,
120 LtI = 62,
121 LeI = 63,
122 GtI = 64,
123 GeI = 65,
124 Test = 66,
125 TestSet = 67,
126 Call = 68,
127 TailCall = 69,
128 Return = 70,
129 Return0 = 71,
130 Return1 = 72,
131 ForLoop = 73,
132 ForPrep = 74,
133 TForPrep = 75,
134 TForCall = 76,
135 TForLoop = 77,
136 SetList = 78,
137 Closure = 79,
138 VarArg = 80,
139 VarArgPrep = 81,
140 ExtraArg = 82,
141 ErrNNil = 83,
148 VarArgPack = 84,
156 GetVArg = 85,
159}
160
161#[allow(dead_code)]
165const NUM_OPCODES: u8 = 86;
166
167impl OpCode {
168 #[allow(non_upper_case_globals)]
175 pub const LoadKx: OpCode = OpCode::LoadKX;
176
177 #[allow(non_upper_case_globals)]
179 pub const GetUpval: OpCode = OpCode::GetUpVal;
180
181 pub fn from_u32(v: u32) -> Option<Self> {
185 match v {
186 0 => Some(Self::Move),
187 1 => Some(Self::LoadI),
188 2 => Some(Self::LoadF),
189 3 => Some(Self::LoadK),
190 4 => Some(Self::LoadKX),
191 5 => Some(Self::LoadFalse),
192 6 => Some(Self::LFalseSkip),
193 7 => Some(Self::LoadTrue),
194 8 => Some(Self::LoadNil),
195 9 => Some(Self::GetUpVal),
196 10 => Some(Self::SetUpVal),
197 11 => Some(Self::GetTabUp),
198 12 => Some(Self::GetTable),
199 13 => Some(Self::GetI),
200 14 => Some(Self::GetField),
201 15 => Some(Self::SetTabUp),
202 16 => Some(Self::SetTable),
203 17 => Some(Self::SetI),
204 18 => Some(Self::SetField),
205 19 => Some(Self::NewTable),
206 20 => Some(Self::Self_),
207 21 => Some(Self::AddI),
208 22 => Some(Self::AddK),
209 23 => Some(Self::SubK),
210 24 => Some(Self::MulK),
211 25 => Some(Self::ModK),
212 26 => Some(Self::PowK),
213 27 => Some(Self::DivK),
214 28 => Some(Self::IDivK),
215 29 => Some(Self::BAndK),
216 30 => Some(Self::BOrK),
217 31 => Some(Self::BXOrK),
218 32 => Some(Self::ShrI),
219 33 => Some(Self::ShlI),
220 34 => Some(Self::Add),
221 35 => Some(Self::Sub),
222 36 => Some(Self::Mul),
223 37 => Some(Self::Mod),
224 38 => Some(Self::Pow),
225 39 => Some(Self::Div),
226 40 => Some(Self::IDiv),
227 41 => Some(Self::BAnd),
228 42 => Some(Self::BOr),
229 43 => Some(Self::BXOr),
230 44 => Some(Self::Shl),
231 45 => Some(Self::Shr),
232 46 => Some(Self::MmBin),
233 47 => Some(Self::MmBinI),
234 48 => Some(Self::MmBinK),
235 49 => Some(Self::Unm),
236 50 => Some(Self::BNot),
237 51 => Some(Self::Not),
238 52 => Some(Self::Len),
239 53 => Some(Self::Concat),
240 54 => Some(Self::Close),
241 55 => Some(Self::Tbc),
242 56 => Some(Self::Jmp),
243 57 => Some(Self::Eq),
244 58 => Some(Self::Lt),
245 59 => Some(Self::Le),
246 60 => Some(Self::EqK),
247 61 => Some(Self::EqI),
248 62 => Some(Self::LtI),
249 63 => Some(Self::LeI),
250 64 => Some(Self::GtI),
251 65 => Some(Self::GeI),
252 66 => Some(Self::Test),
253 67 => Some(Self::TestSet),
254 68 => Some(Self::Call),
255 69 => Some(Self::TailCall),
256 70 => Some(Self::Return),
257 71 => Some(Self::Return0),
258 72 => Some(Self::Return1),
259 73 => Some(Self::ForLoop),
260 74 => Some(Self::ForPrep),
261 75 => Some(Self::TForPrep),
262 76 => Some(Self::TForCall),
263 77 => Some(Self::TForLoop),
264 78 => Some(Self::SetList),
265 79 => Some(Self::Closure),
266 80 => Some(Self::VarArg),
267 81 => Some(Self::VarArgPrep),
268 82 => Some(Self::ExtraArg),
269 83 => Some(Self::ErrNNil),
270 84 => Some(Self::VarArgPack),
271 85 => Some(Self::GetVArg),
272 _ => None,
273 }
274 }
275}
276
277pub trait InstructionExt {
281 fn opcode(&self) -> OpCode;
282 fn arg_a(&self) -> i32;
283 fn arg_b(&self) -> i32;
284 fn arg_c(&self) -> i32;
285 fn arg_k(&self) -> i32;
286 fn arg_ax(&self) -> i32;
287 fn arg_bx(&self) -> i32;
288 fn arg_s_b(&self) -> i32;
289 fn arg_s_c(&self) -> i32;
290 fn arg_s_j(&self) -> i32;
291 fn arg_s_bx(&self) -> i32;
292 fn test_k(&self) -> bool;
293 fn test_a_mode(&self) -> bool;
294 fn is_mm_mode(&self) -> bool;
295 fn is_vararg_prep(&self) -> bool;
296 fn is_in_top(&self) -> bool;
297}
298
299impl InstructionExt for Instruction {
300 #[inline(always)]
308 fn opcode(&self) -> OpCode {
309 match (self.raw() & 0x7F) as u8 {
310 0 => OpCode::Move,
311 1 => OpCode::LoadI,
312 2 => OpCode::LoadF,
313 3 => OpCode::LoadK,
314 4 => OpCode::LoadKX,
315 5 => OpCode::LoadFalse,
316 6 => OpCode::LFalseSkip,
317 7 => OpCode::LoadTrue,
318 8 => OpCode::LoadNil,
319 9 => OpCode::GetUpVal,
320 10 => OpCode::SetUpVal,
321 11 => OpCode::GetTabUp,
322 12 => OpCode::GetTable,
323 13 => OpCode::GetI,
324 14 => OpCode::GetField,
325 15 => OpCode::SetTabUp,
326 16 => OpCode::SetTable,
327 17 => OpCode::SetI,
328 18 => OpCode::SetField,
329 19 => OpCode::NewTable,
330 20 => OpCode::Self_,
331 21 => OpCode::AddI,
332 22 => OpCode::AddK,
333 23 => OpCode::SubK,
334 24 => OpCode::MulK,
335 25 => OpCode::ModK,
336 26 => OpCode::PowK,
337 27 => OpCode::DivK,
338 28 => OpCode::IDivK,
339 29 => OpCode::BAndK,
340 30 => OpCode::BOrK,
341 31 => OpCode::BXOrK,
342 32 => OpCode::ShrI,
343 33 => OpCode::ShlI,
344 34 => OpCode::Add,
345 35 => OpCode::Sub,
346 36 => OpCode::Mul,
347 37 => OpCode::Mod,
348 38 => OpCode::Pow,
349 39 => OpCode::Div,
350 40 => OpCode::IDiv,
351 41 => OpCode::BAnd,
352 42 => OpCode::BOr,
353 43 => OpCode::BXOr,
354 44 => OpCode::Shl,
355 45 => OpCode::Shr,
356 46 => OpCode::MmBin,
357 47 => OpCode::MmBinI,
358 48 => OpCode::MmBinK,
359 49 => OpCode::Unm,
360 50 => OpCode::BNot,
361 51 => OpCode::Not,
362 52 => OpCode::Len,
363 53 => OpCode::Concat,
364 54 => OpCode::Close,
365 55 => OpCode::Tbc,
366 56 => OpCode::Jmp,
367 57 => OpCode::Eq,
368 58 => OpCode::Lt,
369 59 => OpCode::Le,
370 60 => OpCode::EqK,
371 61 => OpCode::EqI,
372 62 => OpCode::LtI,
373 63 => OpCode::LeI,
374 64 => OpCode::GtI,
375 65 => OpCode::GeI,
376 66 => OpCode::Test,
377 67 => OpCode::TestSet,
378 68 => OpCode::Call,
379 69 => OpCode::TailCall,
380 70 => OpCode::Return,
381 71 => OpCode::Return0,
382 72 => OpCode::Return1,
383 73 => OpCode::ForLoop,
384 74 => OpCode::ForPrep,
385 75 => OpCode::TForPrep,
386 76 => OpCode::TForCall,
387 77 => OpCode::TForLoop,
388 78 => OpCode::SetList,
389 79 => OpCode::Closure,
390 80 => OpCode::VarArg,
391 81 => OpCode::VarArgPrep,
392 82 => OpCode::ExtraArg,
393 83 => OpCode::ErrNNil,
394 84 => OpCode::VarArgPack,
395 85 => OpCode::GetVArg,
396 _ => OpCode::ExtraArg,
397 }
398 }
399 #[inline]
400 fn arg_a(&self) -> i32 {
401 ((self.raw() >> 7) & 0xFF) as i32
402 }
403 #[inline]
404 fn arg_b(&self) -> i32 {
405 ((self.raw() >> 16) & 0xFF) as i32
406 }
407 #[inline]
408 fn arg_c(&self) -> i32 {
409 ((self.raw() >> 24) & 0xFF) as i32
410 }
411 #[inline]
412 fn arg_k(&self) -> i32 {
413 ((self.raw() >> 15) & 0x1) as i32
414 }
415 #[inline]
416 fn arg_ax(&self) -> i32 {
417 (self.raw() >> 7) as i32
418 }
419 #[inline]
420 fn arg_bx(&self) -> i32 {
421 (self.raw() >> 15) as i32
422 }
423 #[inline]
424 fn arg_s_b(&self) -> i32 {
425 self.arg_b() - 0x7F
426 }
427 #[inline]
428 fn arg_s_c(&self) -> i32 {
429 self.arg_c() - 0x7F
430 }
431 #[inline]
432 fn arg_s_j(&self) -> i32 {
433 self.arg_ax() - 0xFFFFFF
434 }
435 #[inline]
436 fn arg_s_bx(&self) -> i32 {
437 self.arg_bx() - 0xFFFF
438 }
439 #[inline]
440 fn test_k(&self) -> bool {
441 (self.raw() & (1 << 15)) != 0
442 }
443 #[inline]
444 fn test_a_mode(&self) -> bool {
445 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
446 }
447 #[inline]
448 fn is_mm_mode(&self) -> bool {
449 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
450 }
451 #[inline]
452 fn is_vararg_prep(&self) -> bool {
453 matches!(self.opcode(), OpCode::VarArgPrep)
454 }
455 #[inline]
456 fn is_in_top(&self) -> bool {
457 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
458 }
459}
460
461const OP_MODE_BYTES: [u8; NUM_OPCODES as usize] = [
474 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, 0x08, ];
561
562#[inline(always)]
563fn op_mode_byte(op: OpCode) -> u8 {
564 OP_MODE_BYTES[op as usize]
565}
566
567const MAX_TAG_LOOP: i32 = 2000;
571
572const NBITS: u32 = 64;
573
574#[derive(Debug, Clone, Copy, PartialEq, Eq)]
578pub(crate) enum F2Imod {
579 Eq,
581 Floor,
583 Ceil,
585}
586
587#[inline]
590fn intop_add(a: i64, b: i64) -> i64 {
591 (a as u64).wrapping_add(b as u64) as i64
592}
593
594#[inline]
595fn intop_sub(a: i64, b: i64) -> i64 {
596 (a as u64).wrapping_sub(b as u64) as i64
597}
598
599#[inline]
600fn intop_mul(a: i64, b: i64) -> i64 {
601 (a as u64).wrapping_mul(b as u64) as i64
602}
603
604#[inline]
606fn intop_shr(x: i64, n: u32) -> i64 {
607 (x as u64 >> n) as i64
609}
610
611#[inline]
612fn intop_shl(x: i64, n: u32) -> i64 {
613 (x as u64).wrapping_shl(n) as i64
614}
615
616#[inline]
617fn intop_band(a: i64, b: i64) -> i64 {
618 ((a as u64) & (b as u64)) as i64
619}
620#[inline]
621fn intop_bor(a: i64, b: i64) -> i64 {
622 ((a as u64) | (b as u64)) as i64
623}
624#[inline]
625fn intop_bxor(a: i64, b: i64) -> i64 {
626 ((a as u64) ^ (b as u64)) as i64
627}
628
629#[inline]
634fn int_fits_float(i: i64) -> bool {
635 const MAXINTFITSF: u64 = 1u64 << f64::MANTISSA_DIGITS;
636 (MAXINTFITSF.wrapping_add(i as u64)) <= 2 * MAXINTFITSF
637}
638
639fn str_to_number(obj: &LuaValue) -> Option<LuaValue> {
645 let s = match obj {
647 LuaValue::Str(ts) => ts.as_bytes().to_vec(),
648 _ => return None,
649 };
650 let trimmed = trim_whitespace(&s);
652 if trimmed.is_empty() {
653 return None;
654 }
655 let mut result = LuaValue::Nil;
656 if crate::object::str2num(trimmed, &mut result) != 0 {
657 return Some(result);
658 }
659 None
660}
661
662fn trim_whitespace(s: &[u8]) -> &[u8] {
663 let start = s
664 .iter()
665 .position(|&b| !b.is_ascii_whitespace())
666 .unwrap_or(s.len());
667 let end = s
668 .iter()
669 .rposition(|&b| !b.is_ascii_whitespace())
670 .map(|i| i + 1)
671 .unwrap_or(0);
672 if start <= end {
673 &s[start..end]
674 } else {
675 &s[0..0]
676 }
677}
678
679pub(crate) fn tonumber_(obj: &LuaValue) -> Option<f64> {
685 if let LuaValue::Int(i) = obj {
686 return Some(*i as f64);
687 }
688 if let Some(v) = str_to_number(obj) {
689 return match v {
690 LuaValue::Float(f) => Some(f),
691 LuaValue::Int(i) => Some(i as f64),
692 _ => None,
693 };
694 }
695 None
696}
697
698fn tonumber(obj: &LuaValue) -> Option<f64> {
700 if let LuaValue::Float(f) = obj {
701 return Some(*f);
702 }
703 tonumber_(obj)
704}
705
706pub(crate) fn flt_to_integer(n: f64, mode: F2Imod) -> Option<i64> {
709 let f = n.floor();
710 if n != f {
711 match mode {
712 F2Imod::Eq => return None,
713 F2Imod::Ceil => {
714 let f = f + 1.0;
716 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
718 return Some(f as i64);
719 }
720 return None;
721 }
722 F2Imod::Floor => { }
723 }
724 }
725 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
726 Some(f as i64)
727 } else {
728 None
729 }
730}
731
732pub(crate) fn to_integer_ns(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
734 if let LuaValue::Float(f) = obj {
735 return flt_to_integer(*f, mode);
736 }
737 if let LuaValue::Int(i) = obj {
738 return Some(*i);
739 }
740 None
741}
742
743pub(crate) fn to_integer(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
745 let coerced;
746 let obj = if let Some(v) = str_to_number(obj) {
747 coerced = v;
748 &coerced
749 } else {
750 obj
751 };
752 to_integer_ns(obj, mode)
753}
754
755fn forlimit(
762 state: &mut LuaState,
763 init: i64,
764 lim: &LuaValue,
765 step: i64,
766) -> Result<(bool, i64), LuaError> {
767 let round = if step < 0 {
768 F2Imod::Ceil
769 } else {
770 F2Imod::Floor
771 };
772 if let Some(p) = to_integer(lim, round) {
773 let skip = if step > 0 { init > p } else { init < p };
774 return Ok((skip, p));
775 }
776 let flim = match tonumber(lim) {
777 Some(f) => f,
778 None => return Err(crate::debug::for_error(state, lim, b"limit")),
779 };
780 if 0.0_f64 < flim {
781 if step < 0 {
783 return Ok((true, 0));
784 }
785 Ok((false, i64::MAX))
786 } else {
787 if step > 0 {
789 return Ok((true, 0));
790 }
791 Ok((false, i64::MIN))
792 }
793}
794
795pub(crate) fn forprep(state: &mut LuaState, ra: StackIdx) -> Result<bool, LuaError> {
800 let pinit = state.get_at(ra);
801 let plimit = state.get_at(ra + 1);
802 let pstep = state.get_at(ra + 2);
803
804 if let (LuaValue::Int(init), LuaValue::Int(step)) = (&pinit, &pstep) {
805 let init = *init;
806 let step = *step;
807 if step == 0 {
808 return Err(LuaError::runtime(format_args!("'for' step is zero")));
809 }
810 state.set_at(ra + 3, LuaValue::Int(init));
811
812 let (skip, limit) = forlimit(state, init, &plimit, step)?;
813 if skip {
814 return Ok(true);
815 }
816 let count: u64 = if step > 0 {
817 let c = (limit as u64).wrapping_sub(init as u64);
818 if step != 1 {
819 c / (step as u64)
820 } else {
821 c
822 }
823 } else {
824 let c = (init as u64).wrapping_sub(limit as u64);
825 c / (((-(step + 1)) as u64).wrapping_add(1))
826 };
827 state.set_at(ra + 1, LuaValue::Int(count as i64));
828 Ok(false)
829 } else {
830 let limit_f = match tonumber(&plimit) {
831 Some(f) => f,
832 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
833 };
834 let step_f = match tonumber(&pstep) {
835 Some(f) => f,
836 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
837 };
838 let init_f = match tonumber(&pinit) {
839 Some(f) => f,
840 None => return Err(crate::debug::for_error(state, &pinit, b"initial value")),
841 };
842 if step_f == 0.0 {
843 return Err(LuaError::runtime(format_args!("'for' step is zero")));
844 }
845 let skip = if step_f > 0.0 {
846 limit_f < init_f
847 } else {
848 init_f < limit_f
849 };
850 if skip {
851 return Ok(true);
852 }
853 state.set_at(ra + 1, LuaValue::Float(limit_f));
855 state.set_at(ra + 2, LuaValue::Float(step_f));
856 state.set_at(ra, LuaValue::Float(init_f));
857 state.set_at(ra + 3, LuaValue::Float(init_f));
858 Ok(false)
859 }
860}
861
862fn forlimit_legacy(obj: &LuaValue, step: i64) -> Option<(i64, bool)> {
868 let round = if step < 0 {
869 F2Imod::Ceil
870 } else {
871 F2Imod::Floor
872 };
873 if let Some(p) = to_integer(obj, round) {
874 return Some((p, false));
875 }
876 let n = tonumber(obj)?;
877 if 0.0 < n {
878 Some((i64::MAX, step < 0))
879 } else {
880 Some((i64::MIN, step >= 0))
881 }
882}
883
884pub(crate) fn forprep_legacy(state: &mut LuaState, ra: StackIdx) -> Result<(), LuaError> {
892 let init = state.get_at(ra);
893 let plimit = state.get_at(ra + 1);
894 let pstep = state.get_at(ra + 2);
895
896 if let (LuaValue::Int(initv), LuaValue::Int(stepv)) = (&init, &pstep) {
897 let (initv, stepv) = (*initv, *stepv);
898 if let Some((ilimit, stopnow)) = forlimit_legacy(&plimit, stepv) {
899 let base = if stopnow { 0 } else { initv };
900 state.set_at(ra + 1, LuaValue::Int(ilimit));
901 state.set_at(ra, LuaValue::Int(intop_sub(base, stepv)));
902 return Ok(());
903 }
904 }
907
908 let nlimit = match tonumber(&plimit) {
909 Some(f) => f,
910 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
911 };
912 let nstep = match tonumber(&pstep) {
913 Some(f) => f,
914 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
915 };
916 let ninit = match tonumber(&init) {
917 Some(f) => f,
918 None => return Err(crate::debug::for_error(state, &init, b"initial value")),
919 };
920 state.set_at(ra + 1, LuaValue::Float(nlimit));
921 state.set_at(ra + 2, LuaValue::Float(nstep));
922 state.set_at(ra, LuaValue::Float(ninit - nstep));
923 Ok(())
924}
925
926fn forloop_legacy(state: &mut LuaState, ra: StackIdx) -> bool {
931 if let LuaValue::Int(step) = state.get_at(ra + 2) {
932 let idx = intop_add(
933 match state.get_at(ra) {
934 LuaValue::Int(x) => x,
935 _ => 0,
936 },
937 step,
938 );
939 let limit = match state.get_at(ra + 1) {
940 LuaValue::Int(l) => l,
941 _ => 0,
942 };
943 let cont = if step > 0 { idx <= limit } else { limit <= idx };
944 if cont {
945 state.set_at(ra, LuaValue::Int(idx));
946 state.set_at(ra + 3, LuaValue::Int(idx));
947 }
948 cont
949 } else {
950 let step = match state.get_at(ra + 2) {
951 LuaValue::Float(f) => f,
952 _ => return false,
953 };
954 let idx = match state.get_at(ra) {
955 LuaValue::Float(f) => f,
956 _ => return false,
957 } + step;
958 let limit = match state.get_at(ra + 1) {
959 LuaValue::Float(f) => f,
960 _ => return false,
961 };
962 let cont = if step > 0.0 {
963 idx <= limit
964 } else {
965 limit <= idx
966 };
967 if cont {
968 state.set_at(ra, LuaValue::Float(idx));
969 state.set_at(ra + 3, LuaValue::Float(idx));
970 }
971 cont
972 }
973}
974
975fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
977 let step = match state.get_at(ra + 2) {
979 LuaValue::Float(f) => f,
980 _ => return false,
981 };
982 let limit = match state.get_at(ra + 1) {
983 LuaValue::Float(f) => f,
984 _ => return false,
985 };
986 let idx = match state.get_at(ra) {
987 LuaValue::Float(f) => f,
988 _ => return false,
989 };
990 let idx = idx + step;
991 if if step > 0.0 {
992 idx <= limit
993 } else {
994 limit <= idx
995 } {
996 state.set_at(ra, LuaValue::Float(idx));
997 state.set_at(ra + 3, LuaValue::Float(idx));
998 true
999 } else {
1000 false
1001 }
1002}
1003
1004pub(crate) fn finish_get(
1010 state: &mut LuaState,
1011 t_val: LuaValue,
1012 key: LuaValue,
1013 result_idx: StackIdx,
1014 slot_empty: bool,
1015 t_idx: Option<StackIdx>,
1016 var_hint: Option<(&[u8], &[u8])>,
1017) -> Result<(), LuaError> {
1018 let mut t = t_val;
1019 let mut t_idx = t_idx;
1020 for _loop in 0..MAX_TAG_LOOP {
1021 let tm: LuaValue;
1022 if slot_empty && !matches!(t, LuaValue::Table(_)) {
1023 tm = state.get_tm_by_obj(&t, TagMethod::Index);
1024 if matches!(tm, LuaValue::Nil) {
1025 return Err(match (t_idx, var_hint) {
1026 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
1027 (None, Some((kind, name))) => {
1028 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
1029 }
1030 (None, None) => LuaError::type_error(&t, "index"),
1031 });
1032 }
1033 } else {
1034 let mt = state.table_metatable(&t);
1035 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
1036 if matches!(tm, LuaValue::Nil) {
1037 state.set_at(result_idx, LuaValue::Nil);
1038 return Ok(());
1039 }
1040 }
1041 if matches!(tm, LuaValue::Function(_)) {
1042 state.call_tm_res(tm, &t, &key, result_idx)?;
1043 return Ok(());
1044 }
1045 t = tm.clone();
1046 t_idx = None;
1047 if let Some(v) = state.fast_get(&t, &key)? {
1048 state.set_at(result_idx, v);
1049 return Ok(());
1050 }
1051 }
1053 Err(LuaError::runtime(format_args!(
1054 "'__index' chain too long; possible loop"
1055 )))
1056}
1057
1058pub(crate) fn finish_set(
1067 state: &mut LuaState,
1068 t_val: LuaValue,
1069 key: LuaValue,
1070 val: LuaValue,
1071 _slot_present: bool,
1072 t_idx: Option<StackIdx>,
1073 var_hint: Option<(&[u8], &[u8])>,
1074) -> Result<(), LuaError> {
1075 let mut t = t_val;
1076 let mut t_idx = t_idx;
1077 for _loop in 0..MAX_TAG_LOOP {
1078 let tm: LuaValue;
1079 if matches!(t, LuaValue::Table(_)) {
1080 let mt = state.table_metatable(&t);
1081 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
1082 if matches!(tm, LuaValue::Nil) {
1083 state.table_raw_set(&t, key, val.clone())?;
1084 state.gc_value_barrier_back(&t, &val);
1085 return Ok(());
1086 }
1087 } else {
1088 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
1089 if matches!(tm, LuaValue::Nil) {
1090 return Err(match (t_idx, var_hint) {
1091 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
1092 (None, Some((kind, name))) => {
1093 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
1094 }
1095 (None, None) => LuaError::type_error(&t, "index"),
1096 });
1097 }
1098 }
1099 if matches!(tm, LuaValue::Function(_)) {
1100 state.call_tm(tm, &t, &key, &val)?;
1101 return Ok(());
1102 }
1103 t = tm.clone();
1104 t_idx = None;
1105 if state.fast_get(&t, &key)?.is_some() {
1106 state.table_raw_set(&t, key.clone(), val.clone())?;
1107 state.gc_value_barrier_back(&t, &val);
1108 return Ok(());
1109 }
1110 }
1111 Err(LuaError::runtime(format_args!(
1112 "'__newindex' chain too long; possible loop"
1113 )))
1114}
1115
1116fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
1127 let mut s1 = s1;
1130 let mut s2 = s2;
1131 loop {
1132 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
1134 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
1135 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
1137 if seg_cmp != std::cmp::Ordering::Equal {
1138 return seg_cmp;
1139 }
1140 if z2 == s2.len() {
1142 if z1 == s1.len() {
1144 return std::cmp::Ordering::Equal;
1145 }
1146 return std::cmp::Ordering::Greater; }
1148 if z1 == s1.len() {
1149 return std::cmp::Ordering::Less; }
1151 s1 = &s1[z1 + 1..];
1153 s2 = &s2[z2 + 1..];
1154 }
1155}
1156
1157#[inline]
1160fn lt_int_float(i: i64, f: f64) -> bool {
1161 if int_fits_float(i) {
1162 (i as f64) < f
1163 } else {
1164 match flt_to_integer(f, F2Imod::Ceil) {
1165 Some(fi) => i < fi,
1166 None => f > 0.0, }
1168 }
1169}
1170
1171#[inline]
1172fn le_int_float(i: i64, f: f64) -> bool {
1173 if int_fits_float(i) {
1174 (i as f64) <= f
1175 } else {
1176 match flt_to_integer(f, F2Imod::Floor) {
1177 Some(fi) => i <= fi,
1178 None => f > 0.0,
1179 }
1180 }
1181}
1182
1183#[inline]
1184fn lt_float_int(f: f64, i: i64) -> bool {
1185 if int_fits_float(i) {
1186 f < (i as f64)
1187 } else {
1188 match flt_to_integer(f, F2Imod::Floor) {
1189 Some(fi) => fi < i,
1190 None => f < 0.0,
1191 }
1192 }
1193}
1194
1195#[inline]
1196fn le_float_int(f: f64, i: i64) -> bool {
1197 if int_fits_float(i) {
1198 f <= (i as f64)
1199 } else {
1200 match flt_to_integer(f, F2Imod::Ceil) {
1201 Some(fi) => fi <= i,
1202 None => f < 0.0,
1203 }
1204 }
1205}
1206
1207#[inline]
1208fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
1209 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1210 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1211 match (l, r) {
1212 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1213 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1214 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1215 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1216 _ => false,
1217 }
1218}
1219
1220#[inline]
1221fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1222 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1223 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1224 match (l, r) {
1225 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1226 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1227 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1228 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1229 _ => false,
1230 }
1231}
1232
1233fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1235 debug_assert!(
1236 !(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1237 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_)))
1238 );
1239 match (l, r) {
1240 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1241 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1242 }
1243 _ => state.call_order_tm(l, r, TagMethod::Lt),
1244 }
1245}
1246
1247pub(crate) fn less_than(
1248 state: &mut LuaState,
1249 l: &LuaValue,
1250 r: &LuaValue,
1251) -> Result<bool, LuaError> {
1252 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1253 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1254 {
1255 Ok(lt_num(l, r))
1256 } else {
1257 less_than_others(state, l, r)
1258 }
1259}
1260
1261fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1262 match (l, r) {
1263 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1264 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1265 }
1266 _ => state.call_order_tm(l, r, TagMethod::Le),
1267 }
1268}
1269
1270pub(crate) fn less_equal(
1271 state: &mut LuaState,
1272 l: &LuaValue,
1273 r: &LuaValue,
1274) -> Result<bool, LuaError> {
1275 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1276 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1277 {
1278 Ok(le_num(l, r))
1279 } else {
1280 less_equal_others(state, l, r)
1281 }
1282}
1283
1284pub(crate) fn equal_obj(
1288 state: Option<&mut LuaState>,
1289 t1: &LuaValue,
1290 t2: &LuaValue,
1291) -> Result<bool, LuaError> {
1292 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1295 if !same_variant {
1296 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1297 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1298 if !(t1_is_num && t2_is_num) {
1299 return Ok(false);
1300 }
1301 let i1 = to_integer_ns(t1, F2Imod::Eq);
1303 let i2 = to_integer_ns(t2, F2Imod::Eq);
1304 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1305 }
1306
1307 match (t1, t2) {
1308 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1309 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1310 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1311 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1312 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1313 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1314 use lua_types::closure::LuaClosure;
1315 let same = match (f1, f2) {
1316 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1317 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1318 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1319 _ => false,
1320 };
1321 Ok(same)
1322 }
1323 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1324 Ok(s1 == s2)
1327 }
1328 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1329 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1332 return Ok(true);
1333 }
1334 let Some(state) = state else {
1335 return Ok(false);
1336 };
1337 let tm1 = state.fast_tm_ud(u1, TagMethod::Eq);
1338 let tm = if matches!(tm1, LuaValue::Nil) {
1339 state.fast_tm_ud(u2, TagMethod::Eq)
1340 } else {
1341 tm1
1342 };
1343 if matches!(tm, LuaValue::Nil) {
1344 return Ok(false);
1345 }
1346 let result = state.call_tm_res_bool(tm, t1, t2)?;
1347 Ok(result)
1348 }
1349 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1350 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1351 return Ok(true);
1352 }
1353 let Some(state) = state else {
1354 return Ok(false);
1355 };
1356 let mt1 = h1.metatable();
1358 let mt2 = h2.metatable();
1359 let tm1 = state.fast_tm_table(mt1.as_ref(), TagMethod::Eq);
1360 let tm = if matches!(tm1, LuaValue::Nil) {
1361 state.fast_tm_table(mt2.as_ref(), TagMethod::Eq)
1362 } else {
1363 tm1
1364 };
1365 if matches!(tm, LuaValue::Nil) {
1366 return Ok(false);
1367 }
1368 let result = state.call_tm_res_bool(tm, t1, t2)?;
1369 Ok(result)
1370 }
1371 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1372 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1373 }
1374}
1375
1376fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1380 buf.clear();
1381 let mut remaining = n;
1382 loop {
1383 let idx = top - remaining as i32;
1384 let v = state.get_at(idx);
1385 if let LuaValue::Str(ts) = v {
1386 buf.extend_from_slice(ts.as_bytes());
1387 }
1388 if remaining <= 1 {
1389 break;
1390 }
1391 remaining -= 1;
1392 }
1393}
1394
1395pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1397 if total == 1 {
1398 return Ok(());
1399 }
1400 if total == 2 {
1401 let top = state.top_idx();
1402 let v_tm1 = state.get_at(top - 1);
1403 let v_tm2 = state.get_at(top - 2);
1404 if concat_pair_fast(state, top, v_tm2, v_tm1)? {
1405 return Ok(());
1406 }
1407 }
1408 let mut total = total;
1409 loop {
1410 let top = state.top_idx();
1411 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1416 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1417 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1419 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1420 if !top2_coercible || !top1_stringlike {
1421 state.try_concat_tm(&v_tm1, &v_tm2)?;
1422 total -= 1;
1427 let top = state.top_idx();
1428 state.set_top(top - 1);
1429 if total <= 1 {
1430 break;
1431 }
1432 continue;
1433 }
1434
1435 let is_empty =
1436 |v: &LuaValue| -> bool { matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty()) };
1437
1438 let n: u32;
1439 if is_empty(&v_tm1) {
1440 state.coerce_to_string(top - 2)?;
1441 n = 2;
1442 } else if is_empty(&v_tm2) {
1443 state.coerce_to_string(top - 1)?;
1446 let v = state.get_at(top - 1);
1447 state.set_at(top - 2, v);
1448 n = 2;
1449 } else {
1450 state.coerce_to_string(top - 1)?;
1452 let s1 = match state.get_at(top - 1) {
1453 LuaValue::Str(ts) => ts.as_bytes().len(),
1454 _ => 0,
1455 };
1456 let mut total_len = s1;
1457 let mut count: u32 = 1;
1458 let top = state.top_idx();
1459 loop {
1460 if count as i32 >= total {
1461 break;
1462 }
1463 let idx = top - (count as i32 + 1);
1464 let v = state.get_at(idx);
1465 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1466 break;
1467 }
1468 state.coerce_to_string(idx)?;
1469 let l = match state.get_at(idx) {
1470 LuaValue::Str(ts) => ts.as_bytes().len(),
1471 _ => 0,
1472 };
1473 if l >= usize::MAX - total_len {
1474 state.set_top(top - total as i32);
1476 return Err(LuaError::runtime(format_args!("string length overflow")));
1477 }
1478 total_len += l;
1479 count += 1;
1480 }
1481 n = count;
1482
1483 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1485 let top = state.top_idx();
1486 copy_to_buf(state, top, n, &mut buf);
1487 let ts = state.intern_or_create_str(&buf)?;
1488 state.set_at(top - n as i32, LuaValue::Str(ts));
1489 }
1490 total -= n as i32 - 1;
1491 let top = state.top_idx();
1492 state.set_top(top - ((n - 1) as i32));
1493
1494 if total <= 1 {
1495 break;
1496 }
1497 }
1498 Ok(())
1499}
1500
1501enum ConcatPiece {
1502 Str(GcRef<LuaString>),
1503 Num(Vec<u8>),
1504}
1505
1506impl ConcatPiece {
1507 #[inline]
1508 fn len(&self) -> usize {
1509 match self {
1510 ConcatPiece::Str(s) => s.as_bytes().len(),
1511 ConcatPiece::Num(bytes) => bytes.len(),
1512 }
1513 }
1514
1515 #[inline]
1516 fn append_to(&self, out: &mut Vec<u8>) {
1517 match self {
1518 ConcatPiece::Str(s) => out.extend_from_slice(s.as_bytes()),
1519 ConcatPiece::Num(bytes) => out.extend_from_slice(bytes),
1520 }
1521 }
1522}
1523
1524#[inline]
1525fn concat_piece(v: LuaValue, version: lua_types::LuaVersion) -> Option<ConcatPiece> {
1526 match v {
1527 LuaValue::Str(s) => Some(ConcatPiece::Str(s)),
1528 LuaValue::Int(_) | LuaValue::Float(_) => Some(ConcatPiece::Num(
1529 crate::object::number_to_str_buf(&v, version),
1530 )),
1531 _ => None,
1532 }
1533}
1534
1535#[inline]
1536fn concat_pair_fast(
1537 state: &mut LuaState,
1538 top: StackIdx,
1539 left: LuaValue,
1540 right: LuaValue,
1541) -> Result<bool, LuaError> {
1542 let version = state.global().lua_version;
1543 let Some(left) = concat_piece(left, version) else {
1544 return Ok(false);
1545 };
1546 let Some(right) = concat_piece(right, version) else {
1547 return Ok(false);
1548 };
1549 let total_len = left
1550 .len()
1551 .checked_add(right.len())
1552 .ok_or_else(|| LuaError::runtime(format_args!("string length overflow")))?;
1553 let mut buf = Vec::with_capacity(total_len);
1554 left.append_to(&mut buf);
1555 right.append_to(&mut buf);
1556 let ts = state.intern_or_create_str(&buf)?;
1557 state.set_at(top - 2, LuaValue::Str(ts));
1558 state.set_top(top - 1);
1559 Ok(true)
1560}
1561
1562pub(crate) fn obj_len(
1566 state: &mut LuaState,
1567 ra: StackIdx,
1568 rb: LuaValue,
1569 rb_idx: StackIdx,
1570) -> Result<(), LuaError> {
1571 match &rb {
1572 LuaValue::Table(_) => {
1573 let consult_len_tm = !matches!(state.global().lua_version, lua_types::LuaVersion::V51);
1578 let tm = if consult_len_tm {
1579 let mt = state.table_metatable(&rb);
1580 state.fast_tm_table(mt.as_ref(), TagMethod::Len)
1581 } else {
1582 LuaValue::Nil
1583 };
1584 if matches!(tm, LuaValue::Nil) {
1585 let n = state.table_length(&rb)?;
1586 state.set_at(ra, LuaValue::Int(n as i64));
1587 return Ok(());
1588 }
1589 state.call_tm_res(tm, &rb, &rb, ra)?;
1591 }
1592 LuaValue::Str(ts) => {
1593 let n = ts.len();
1596 state.set_at(ra, LuaValue::Int(n as i64));
1597 }
1598 other => {
1599 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1601 if matches!(tm, LuaValue::Nil) {
1602 return Err(crate::debug::type_error(
1603 state,
1604 other,
1605 rb_idx,
1606 b"get length of",
1607 ));
1608 }
1609 state.call_tm_res(tm, &rb, &rb, ra)?;
1610 }
1611 }
1612 Ok(())
1613}
1614
1615pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1619 if (n as u64).wrapping_add(1) <= 1 {
1620 if n == 0 {
1621 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1622 }
1623 return Ok(intop_sub(0, m));
1624 }
1625 let q = m / n;
1626 if (m ^ n) < 0 && m % n != 0 {
1628 Ok(q - 1)
1629 } else {
1630 Ok(q)
1631 }
1632}
1633
1634pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1636 if (n as u64).wrapping_add(1) <= 1 {
1637 if n == 0 {
1638 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1639 }
1640 return Ok(0);
1641 }
1642 let r = m % n;
1643 if r != 0 && (r ^ n) < 0 {
1644 Ok(r + n)
1645 } else {
1646 Ok(r)
1647 }
1648}
1649
1650pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1652 let r = m % n;
1653 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1654 if opposite_signs {
1655 r + n
1656 } else {
1657 r
1658 }
1659}
1660
1661pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1664 use TagMethod::*;
1665 match i {
1666 0 => Index,
1667 1 => NewIndex,
1668 2 => Gc,
1669 3 => Mode,
1670 4 => Len,
1671 5 => Eq,
1672 6 => Add,
1673 7 => Sub,
1674 8 => Mul,
1675 9 => Mod,
1676 10 => Pow,
1677 11 => Div,
1678 12 => Idiv,
1679 13 => Band,
1680 14 => Bor,
1681 15 => Bxor,
1682 16 => Shl,
1683 17 => Shr,
1684 18 => Unm,
1685 19 => Bnot,
1686 20 => Lt,
1687 21 => Le,
1688 22 => Concat,
1689 23 => Call,
1690 24 => Close,
1691 _ => Index,
1692 }
1693}
1694
1695pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1698 imod(a, b)
1699}
1700
1701pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1704 idiv(a, b)
1705}
1706
1707pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1710 Ok(fmodf(a, b))
1711}
1712
1713pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1715 if y < 0 {
1716 if y <= -(NBITS as i64) {
1717 0
1718 } else {
1719 intop_shr(x, (-y) as u32)
1720 }
1721 } else {
1722 if y >= NBITS as i64 {
1723 0
1724 } else {
1725 intop_shl(x, y as u32)
1726 }
1727 }
1728}
1729
1730fn push_closure(
1736 state: &mut LuaState,
1737 proto_idx: usize, ci: CallInfoIdx,
1739 base: StackIdx,
1740 ra: StackIdx,
1741) -> Result<(), LuaError> {
1742 state.push_closure(proto_idx, ci, base, ra)
1746}
1747
1748pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1753 let ci = state.current_ci_idx();
1757 let base = state.ci_base(ci);
1758 let inst = state.ci_prev_instruction(ci);
1759 let op = inst.opcode();
1760
1761 match op {
1762 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1764 let prev_inst = state.ci_prev2_instruction(ci);
1765 let a = prev_inst.arg_a();
1766 state.dec_top();
1767 let top = state.top_idx();
1768 let v = state.get_at(top);
1769 state.set_at(base + a, v);
1770 }
1771 OpCode::Unm
1773 | OpCode::BNot
1774 | OpCode::Len
1775 | OpCode::GetTabUp
1776 | OpCode::GetTable
1777 | OpCode::GetI
1778 | OpCode::GetField
1779 | OpCode::Self_ => {
1780 let a = inst.arg_a();
1781 state.dec_top();
1782 let top = state.top_idx();
1783 let v = state.get_at(top);
1784 state.set_at(base + a, v);
1785 }
1786 OpCode::Lt
1790 | OpCode::Le
1791 | OpCode::LtI
1792 | OpCode::LeI
1793 | OpCode::GtI
1794 | OpCode::GeI
1795 | OpCode::Eq => {
1796 let top_minus1 = state.top_idx() - 1;
1797 let v = state.get_at(top_minus1);
1798 let mut res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1799 state.dec_top();
1800 if (state.get_ci(ci).callstatus & crate::state::CIST_LEQ) != 0 {
1805 state.get_ci_mut(ci).callstatus &= !crate::state::CIST_LEQ;
1806 res = !res;
1807 }
1808 if (res as i32) != inst.arg_k() {
1809 state.ci_skip_next_instruction(ci);
1810 }
1811 }
1812 OpCode::Concat => {
1818 let top = state.top_idx() - 1; let a = inst.arg_a();
1820 let total_concat = (top - 1 - (base + a)) as i32;
1821 let v = state.get_at(top);
1822 state.set_at(top - 2, v);
1823 state.set_top(top - 1);
1824 concat(state, total_concat)?;
1825 }
1826 OpCode::Close => {
1827 state.ci_step_pc_back(ci);
1828 }
1829 OpCode::Return => {
1833 let a = inst.arg_a();
1834 let ra = base + a;
1835 let nres = state.ci_nres(ci);
1836 state.set_top(ra + nres);
1837 state.ci_step_pc_back(ci);
1838 }
1839 other => {
1840 debug_assert!(
1841 matches!(
1842 other,
1843 OpCode::TForCall
1844 | OpCode::Call
1845 | OpCode::TailCall
1846 | OpCode::SetTabUp
1847 | OpCode::SetTable
1848 | OpCode::SetI
1849 | OpCode::SetField
1850 ),
1851 "unexpected opcode in finish_op: {:?}",
1852 other
1853 );
1854 }
1855 }
1856 Ok(())
1857}
1858
1859pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1871 let mut trap: bool;
1872 let legacy_for = matches!(
1879 state.global().lua_version,
1880 lua_types::LuaVersion::V51 | lua_types::LuaVersion::V52 | lua_types::LuaVersion::V53
1881 );
1882 let tfor_55 = state.global().lua_version == lua_types::LuaVersion::V55;
1883
1884 'startfunc: loop {
1886 trap = state.hook_mask() != 0;
1887
1888 'returning: loop {
1891 let ci_slot = ci.as_usize();
1892 let func_idx = state.call_info[ci_slot].func;
1893 let cl = match state.stack.get(func_idx.0 as usize).map(|slot| slot.val) {
1894 Some(LuaValue::Function(lua_types::closure::LuaClosure::Lua(c))) => c,
1895 _ => {
1896 return Err(LuaError::runtime(format_args!(
1897 "internal: execute called on non-Lua frame"
1898 )));
1899 }
1900 };
1901 let code = &cl.proto.code;
1902 let constants = &cl.proto.k;
1903 let mut pc: u32 = state.call_info[ci_slot].saved_pc();
1905
1906 if trap {
1907 trap = state.trace_call(ci)?;
1908 }
1909 let mut base: StackIdx = state.call_info[ci.as_usize()].func + 1;
1910
1911 'dispatch: loop {
1913 if trap {
1914 trap = state.trace_exec(ci, pc)?;
1915 base = state.ci_base(ci); }
1917 let i: Instruction = code[pc as usize];
1918 pc += 1;
1919 let op = i.opcode();
1920 #[cfg(feature = "opcode-profile")]
1921 crate::opcode_profile::record(op);
1922
1923 debug_assert!(base == state.ci_base(ci));
1924
1925 #[cfg(debug_assertions)]
1929 {
1930 let op_mode = op_mode_byte(op);
1931 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1932 state.set_top(base);
1933 }
1934 }
1935
1936 match op {
1937 OpCode::Move => {
1939 let ra = base + i.arg_a();
1940 let rb = base + i.arg_b();
1941 let v = state.stack[rb.0 as usize].val;
1942 state.stack[ra.0 as usize].val = v;
1943 }
1944 OpCode::LoadI => {
1946 let ra = base + i.arg_a();
1947 let b = i.arg_s_bx() as i64;
1948 state.stack[ra.0 as usize].val = LuaValue::Int(b);
1949 }
1950 OpCode::LoadF => {
1952 let ra = base + i.arg_a();
1953 let b = i.arg_s_bx() as f64;
1954 state.stack[ra.0 as usize].val = LuaValue::Float(b);
1955 }
1956 OpCode::LoadK => {
1958 let ra = base + i.arg_a();
1959 let k_idx = i.arg_bx() as usize;
1960 state.stack[ra.0 as usize].val = constants[k_idx];
1961 }
1962 OpCode::LoadKX => {
1964 let ra = base + i.arg_a();
1965 let extra = code[pc as usize];
1966 pc += 1;
1967 let k_idx = extra.arg_ax() as usize;
1968 state.stack[ra.0 as usize].val = constants[k_idx];
1969 }
1970 OpCode::LoadFalse => {
1972 let ra = base + i.arg_a();
1973 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
1974 }
1975 OpCode::LFalseSkip => {
1977 let ra = base + i.arg_a();
1978 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
1979 pc += 1;
1980 }
1981 OpCode::LoadTrue => {
1983 let ra = base + i.arg_a();
1984 state.stack[ra.0 as usize].val = LuaValue::Bool(true);
1985 }
1986 OpCode::LoadNil => {
1988 let ra = base + i.arg_a();
1989 let b = i.arg_b();
1990 for k in 0..=b {
1991 state.stack[(ra + k).0 as usize].val = LuaValue::Nil;
1992 }
1993 }
1994 OpCode::GetUpVal => {
1996 let ra = base + i.arg_a();
1997 let b = i.arg_b() as usize;
1998 let uv = cl.upval(b);
1999 let v = match uv.try_open_payload() {
2000 Some((thread_id, idx))
2001 if thread_id as u64 == state.cached_thread_id =>
2002 {
2003 state.stack[idx.0 as usize].val
2004 }
2005 Some(_) => state.upvalue_get(&cl, b),
2006 None => uv.closed_value(),
2007 };
2008 state.stack[ra.0 as usize].val = v;
2009 }
2010 OpCode::SetUpVal => {
2013 let ra = base + i.arg_a();
2014 let b = i.arg_b() as usize;
2015 let v = state.stack[ra.0 as usize].val;
2016 let uv = cl.upval(b);
2017 match uv.try_open_payload() {
2018 Some((thread_id, idx))
2019 if thread_id as u64 == state.cached_thread_id =>
2020 {
2021 state.stack[idx.0 as usize].val = v;
2022 if v.is_collectable() {
2023 state.gc_barrier_upval(&uv, &v);
2024 }
2025 }
2026 None => {
2027 uv.set_closed_value(v);
2028 if v.is_collectable() {
2029 state.gc_barrier_upval(&uv, &v);
2030 }
2031 }
2032 _ => {
2033 state.upvalue_set(&cl, b, v)?;
2034 }
2035 }
2036 }
2037 OpCode::GetTabUp => {
2041 let ra = base + i.arg_a();
2042 let b = i.arg_b() as usize;
2043 let k_idx = i.arg_c() as usize;
2044 let upval = state.upvalue_get(&cl, b);
2045 let key = constants[k_idx];
2046 match state.fast_get_short_str(&upval, &key)? {
2047 Some(v) => state.set_at(ra, v),
2048 None => {
2049 state.set_ci_savedpc(ci, pc);
2050 state.set_top(state.ci_top(ci));
2051 let upval_name: Vec<u8> =
2052 cl.0.proto
2053 .upvalues
2054 .get(b)
2055 .and_then(|uv| uv.name.as_ref())
2056 .map(|s| s.as_bytes().to_vec())
2057 .unwrap_or_else(|| b"?".to_vec());
2058 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2059 finish_get(state, upval, key, ra, true, None, hint)?;
2060 trap = state.ci_trap(ci);
2061 }
2062 }
2063 }
2064 OpCode::GetTable => {
2067 let ra = base + i.arg_a();
2068 let rb_idx = base + i.arg_b();
2069 let rb_v = state.get_at(rb_idx);
2070 let rc_v = state.get_at(base + i.arg_c());
2071 let fast_result = if let LuaValue::Int(n) = &rc_v {
2072 state.fast_get_int(&rb_v, *n)?
2073 } else {
2074 state.fast_get(&rb_v, &rc_v)?
2075 };
2076 match fast_result {
2077 Some(v) => state.set_at(ra, v),
2078 None => {
2079 state.set_ci_savedpc(ci, pc);
2080 state.set_top(state.ci_top(ci));
2081 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx), None)?;
2082 trap = state.ci_trap(ci);
2083 }
2084 }
2085 }
2086 OpCode::GetI => {
2090 let ra = base + i.arg_a();
2091 let rb_idx = base + i.arg_b();
2092 let rb_v = state.get_at(rb_idx);
2093 let c = i.arg_c() as i64;
2094 match state.fast_get_int(&rb_v, c)? {
2095 Some(v) => state.set_at(ra, v),
2096 None => {
2097 let key = LuaValue::Int(c);
2098 state.set_ci_savedpc(ci, pc);
2099 state.set_top(state.ci_top(ci));
2100 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2101 trap = state.ci_trap(ci);
2102 }
2103 }
2104 }
2105 OpCode::GetField => {
2107 let ra = base + i.arg_a();
2108 let rb_idx = base + i.arg_b();
2109 let rb_v = state.get_at(rb_idx);
2110 let k_idx = i.arg_c() as usize;
2111 let key = constants[k_idx];
2112 match state.fast_get_short_str(&rb_v, &key)? {
2113 Some(v) => state.set_at(ra, v),
2114 None => {
2115 state.set_ci_savedpc(ci, pc);
2116 state.set_top(state.ci_top(ci));
2117 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2118 trap = state.ci_trap(ci);
2119 }
2120 }
2121 }
2122 OpCode::SetTabUp => {
2124 let a = i.arg_a() as usize;
2125 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
2127 constants[i.arg_c() as usize]
2128 } else {
2129 state.get_at(base + i.arg_c())
2130 };
2131 let upval = state.upvalue_get(&cl, a);
2132 let key = constants[b_idx];
2133 match state.fast_get_short_str(&upval, &key)? {
2134 Some(_slot) => {
2135 state.table_raw_set(&upval, key, rc_v.clone())?;
2136 state.gc_value_barrier_back(&upval, &rc_v);
2137 }
2138 None => {
2139 state.set_ci_savedpc(ci, pc);
2140 state.set_top(state.ci_top(ci));
2141 let upval_name: Vec<u8> = cl
2142 .proto
2143 .upvalues
2144 .get(a)
2145 .and_then(|uv| uv.name.as_ref())
2146 .map(|s| s.as_bytes().to_vec())
2147 .unwrap_or_else(|| b"?".to_vec());
2148 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2149 finish_set(state, upval, key, rc_v, false, None, hint)?;
2150 trap = state.ci_trap(ci);
2151 }
2152 }
2153 }
2154 OpCode::SetTable => {
2156 let ra_idx = base + i.arg_a();
2157 let ra_v = state.get_at(ra_idx);
2158 let rb_v = state.get_at(base + i.arg_b());
2159 let rc_v = if i.test_k() {
2160 constants[i.arg_c() as usize]
2161 } else {
2162 state.get_at(base + i.arg_c())
2163 };
2164 if let LuaValue::Table(tbl) = ra_v {
2165 if tbl.metatable().is_none() {
2166 state.gc_table_barrier_back(&tbl, &rc_v);
2167 tbl.raw_set(state, rb_v, rc_v)?;
2168 } else {
2169 let fast = if let LuaValue::Int(n) = &rb_v {
2170 state.fast_get_int(&ra_v, *n)?
2171 } else {
2172 state.fast_get(&ra_v, &rb_v)?
2173 };
2174 if fast.is_some() {
2175 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
2176 state.gc_value_barrier_back(&ra_v, &rc_v);
2177 } else {
2178 state.set_ci_savedpc(ci, pc);
2179 state.set_top(state.ci_top(ci));
2180 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2181 trap = state.ci_trap(ci);
2182 }
2183 }
2184 } else {
2185 state.set_ci_savedpc(ci, pc);
2186 state.set_top(state.ci_top(ci));
2187 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2188 trap = state.ci_trap(ci);
2189 }
2190 }
2191 OpCode::SetI => {
2193 let ra_idx = base + i.arg_a();
2194 let ra_v = state.get_at(ra_idx);
2195 let c = i.arg_b() as i64;
2196 let rc_v = if i.test_k() {
2197 constants[i.arg_c() as usize]
2198 } else {
2199 state.get_at(base + i.arg_c())
2200 };
2201 if let LuaValue::Table(tbl) = ra_v {
2202 if tbl.metatable().is_none() {
2203 state.gc_table_barrier_back(&tbl, &rc_v);
2204 tbl.raw_set_int(state, c, rc_v)?;
2205 } else {
2206 let fast = state.fast_get_int(&ra_v, c)?;
2207 if fast.is_some() {
2208 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
2209 state.gc_value_barrier_back(&ra_v, &rc_v);
2210 } else {
2211 state.set_ci_savedpc(ci, pc);
2212 state.set_top(state.ci_top(ci));
2213 finish_set(
2214 state,
2215 ra_v,
2216 LuaValue::Int(c),
2217 rc_v,
2218 false,
2219 Some(ra_idx),
2220 None,
2221 )?;
2222 trap = state.ci_trap(ci);
2223 }
2224 }
2225 } else {
2226 state.set_ci_savedpc(ci, pc);
2227 state.set_top(state.ci_top(ci));
2228 finish_set(
2229 state,
2230 ra_v,
2231 LuaValue::Int(c),
2232 rc_v,
2233 false,
2234 Some(ra_idx),
2235 None,
2236 )?;
2237 trap = state.ci_trap(ci);
2238 }
2239 }
2240 OpCode::SetField => {
2242 let ra_idx = base + i.arg_a();
2243 let ra_v = state.get_at(ra_idx);
2244 let b_idx = i.arg_b() as usize;
2245 let key = constants[b_idx];
2246 let rc_v = if i.test_k() {
2247 constants[i.arg_c() as usize]
2248 } else {
2249 state.get_at(base + i.arg_c())
2250 };
2251 if let LuaValue::Table(tbl) = ra_v {
2252 if tbl.metatable().is_none() {
2253 state.gc_table_barrier_back(&tbl, &rc_v);
2254 tbl.raw_set(state, key, rc_v)?;
2255 } else {
2256 match state.fast_get_short_str(&ra_v, &key)? {
2257 Some(_) => {
2258 state.table_raw_set(&ra_v, key, rc_v.clone())?;
2259 state.gc_value_barrier_back(&ra_v, &rc_v);
2260 }
2261 None => {
2262 state.set_ci_savedpc(ci, pc);
2263 state.set_top(state.ci_top(ci));
2264 finish_set(
2265 state,
2266 ra_v,
2267 key,
2268 rc_v,
2269 false,
2270 Some(ra_idx),
2271 None,
2272 )?;
2273 trap = state.ci_trap(ci);
2274 }
2275 }
2276 }
2277 } else {
2278 state.set_ci_savedpc(ci, pc);
2279 state.set_top(state.ci_top(ci));
2280 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2281 trap = state.ci_trap(ci);
2282 }
2283 }
2284 OpCode::NewTable => {
2287 let ra = base + i.arg_a();
2288 let mut b = i.arg_b();
2289 let mut c = i.arg_c();
2290 if b > 0 {
2291 b = 1 << (b - 1);
2292 }
2293 if i.test_k() {
2294 let extra = code[pc as usize];
2295 pc += 1;
2296 const MAXARG_C: i32 = (1 << 8) - 1;
2297 c += extra.arg_ax() * (MAXARG_C + 1);
2298 } else {
2299 pc += 1; }
2301 state.set_top(ra + 1);
2302 let t = if b != 0 || c != 0 {
2303 state.new_table_with_sizes(c as u32, b as u32)?
2304 } else {
2305 state.new_table()
2306 };
2307 state.set_at(ra, LuaValue::Table(t.clone()));
2308 state.set_ci_savedpc(ci, pc);
2309 state.set_top(ra + 1);
2310 state.gc_cond_step();
2311 if state.hookmask != 0 {
2312 trap = state.ci_trap(ci);
2313 }
2314 }
2315 OpCode::Self_ => {
2317 let ra = base + i.arg_a();
2318 let rb_idx = base + i.arg_b();
2319 let rb_v = state.get_at(rb_idx);
2320 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2322 constants[k_idx]
2323 } else {
2324 state.get_at(base + i.arg_c())
2325 };
2326 state.set_at(ra + 1, rb_v.clone());
2327 match state.fast_get_short_str(&rb_v, &key)? {
2328 Some(v) => state.set_at(ra, v),
2329 None => {
2330 state.set_ci_savedpc(ci, pc);
2331 state.set_top(state.ci_top(ci));
2332 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2333 trap = state.ci_trap(ci);
2334 }
2335 }
2336 }
2337 OpCode::AddI => {
2339 let ra = base + i.arg_a();
2340 let rb = base + i.arg_b();
2341 let imm = i.arg_s_c() as i64;
2342 let rb_v = state.stack[rb.0 as usize].val;
2343 match rb_v {
2344 LuaValue::Int(iv1) => {
2345 pc += 1;
2346 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2347 }
2348 LuaValue::Float(nb) => {
2349 pc += 1;
2350 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2351 }
2352 _ => {}
2353 }
2354 }
2355 OpCode::AddK => {
2357 let ra = base + i.arg_a();
2358 let rb = base + i.arg_b();
2359 let kidx = i.arg_c() as usize;
2360 if let (Some(i1), Some(i2)) =
2361 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2362 {
2363 pc += 1;
2364 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2365 } else if let (Some(n1), Some(n2)) =
2366 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2367 {
2368 pc += 1;
2369 state.set_at(ra, LuaValue::Float(n1 + n2));
2370 }
2371 }
2372 OpCode::SubK => {
2373 let ra = base + i.arg_a();
2374 let rb = base + i.arg_b();
2375 let kidx = i.arg_c() as usize;
2376 if let (Some(i1), Some(i2)) =
2377 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2378 {
2379 pc += 1;
2380 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2381 } else if let (Some(n1), Some(n2)) =
2382 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2383 {
2384 pc += 1;
2385 state.set_at(ra, LuaValue::Float(n1 - n2));
2386 }
2387 }
2388 OpCode::MulK => {
2389 let ra = base + i.arg_a();
2390 let rb = base + i.arg_b();
2391 let kidx = i.arg_c() as usize;
2392 if let (Some(i1), Some(i2)) =
2393 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2394 {
2395 pc += 1;
2396 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2397 } else if let (Some(n1), Some(n2)) =
2398 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2399 {
2400 pc += 1;
2401 state.set_at(ra, LuaValue::Float(n1 * n2));
2402 }
2403 }
2404 OpCode::ModK => {
2405 let ra = base + i.arg_a();
2406 let v1 = state.get_at(base + i.arg_b());
2407 let v2 = constants[i.arg_c() as usize];
2408 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
2410 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2411 }
2412 OpCode::PowK => {
2413 let ra = base + i.arg_a();
2414 let rb = base + i.arg_b();
2415 let kidx = i.arg_c() as usize;
2416 if let (Some(n1), Some(n2)) =
2417 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2418 {
2419 pc += 1;
2420 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2421 state.set_at(ra, LuaValue::Float(r));
2422 }
2423 }
2424 OpCode::DivK => {
2425 let ra = base + i.arg_a();
2426 let rb = base + i.arg_b();
2427 let kidx = i.arg_c() as usize;
2428 if let (Some(n1), Some(n2)) =
2429 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2430 {
2431 pc += 1;
2432 state.set_at(ra, LuaValue::Float(n1 / n2));
2433 }
2434 }
2435 OpCode::IDivK => {
2436 let ra = base + i.arg_a();
2437 let v1 = state.get_at(base + i.arg_b());
2438 let v2 = constants[i.arg_c() as usize];
2439 state.set_ci_savedpc(ci, pc);
2440 state.set_top(state.ci_top(ci));
2441 arith_op_checked(
2442 state,
2443 ra,
2444 &v1,
2445 &v2,
2446 &mut pc,
2447 |a, b| idiv(a, b),
2448 |a, b| (a / b).floor(),
2449 )?;
2450 }
2451 OpCode::BAndK => {
2452 let ra = base + i.arg_a();
2453 let v1 = state.get_at(base + i.arg_b());
2454 let v2 = constants[i.arg_c() as usize];
2455 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2456 }
2457 OpCode::BOrK => {
2458 let ra = base + i.arg_a();
2459 let v1 = state.get_at(base + i.arg_b());
2460 let v2 = constants[i.arg_c() as usize];
2461 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2462 }
2463 OpCode::BXOrK => {
2464 let ra = base + i.arg_a();
2465 let v1 = state.get_at(base + i.arg_b());
2466 let v2 = constants[i.arg_c() as usize];
2467 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2468 }
2469 OpCode::ShrI => {
2470 let ra = base + i.arg_a();
2471 let v = state.get_at(base + i.arg_b());
2472 let ic = i.arg_s_c() as i64;
2473 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2474 pc += 1;
2475 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2476 }
2477 }
2478 OpCode::ShlI => {
2479 let ra = base + i.arg_a();
2480 let v = state.get_at(base + i.arg_b());
2481 let ic = i.arg_s_c() as i64;
2482 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2483 pc += 1;
2484 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2485 }
2486 }
2487 OpCode::Add => {
2489 let ra = base + i.arg_a();
2490 let rb = base + i.arg_b();
2491 let rc = base + i.arg_c();
2492 let ra_u = ra.0 as usize;
2493 let rb_v = state.stack[rb.0 as usize].val;
2494 let rc_v = state.stack[rc.0 as usize].val;
2495 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2496 pc += 1;
2497 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2498 } else if let (Some(n1), Some(n2)) =
2499 (number_value(rb_v), number_value(rc_v))
2500 {
2501 pc += 1;
2502 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2503 }
2504 }
2505 OpCode::Sub => {
2506 let ra = base + i.arg_a();
2507 let rb = base + i.arg_b();
2508 let rc = base + i.arg_c();
2509 let ra_u = ra.0 as usize;
2510 let rb_v = state.stack[rb.0 as usize].val;
2511 let rc_v = state.stack[rc.0 as usize].val;
2512 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2513 pc += 1;
2514 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2515 } else if let (Some(n1), Some(n2)) =
2516 (number_value(rb_v), number_value(rc_v))
2517 {
2518 pc += 1;
2519 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2520 }
2521 }
2522 OpCode::Mul => {
2523 let ra = base + i.arg_a();
2524 let rb = base + i.arg_b();
2525 let rc = base + i.arg_c();
2526 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2527 pc += 1;
2528 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2529 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2530 pc += 1;
2531 state.set_at(ra, LuaValue::Float(n1 * n2));
2532 }
2533 }
2534 OpCode::Mod => {
2535 let ra = base + i.arg_a();
2536 let v1 = state.get_at(base + i.arg_b());
2537 let v2 = state.get_at(base + i.arg_c());
2538 state.set_ci_savedpc(ci, pc);
2539 state.set_top(state.ci_top(ci));
2540 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2541 }
2542 OpCode::Pow => {
2543 let ra = base + i.arg_a();
2544 let rb = base + i.arg_b();
2545 let rc = base + i.arg_c();
2546 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2547 pc += 1;
2548 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2549 state.set_at(ra, LuaValue::Float(r));
2550 }
2551 }
2552 OpCode::Div => {
2553 let ra = base + i.arg_a();
2554 let rb = base + i.arg_b();
2555 let rc = base + i.arg_c();
2556 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2557 pc += 1;
2558 state.set_at(ra, LuaValue::Float(n1 / n2));
2559 }
2560 }
2561 OpCode::IDiv => {
2562 let ra = base + i.arg_a();
2563 let v1 = state.get_at(base + i.arg_b());
2564 let v2 = state.get_at(base + i.arg_c());
2565 state.set_ci_savedpc(ci, pc);
2566 state.set_top(state.ci_top(ci));
2567 arith_op_checked(
2568 state,
2569 ra,
2570 &v1,
2571 &v2,
2572 &mut pc,
2573 |a, b| idiv(a, b),
2574 |a, b| (a / b).floor(),
2575 )?;
2576 }
2577 OpCode::BAnd => {
2580 let ra = base + i.arg_a();
2581 let v1 = state.get_at(base + i.arg_b());
2582 let v2 = state.get_at(base + i.arg_c());
2583 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2584 }
2585 OpCode::BOr => {
2586 let ra = base + i.arg_a();
2587 let v1 = state.get_at(base + i.arg_b());
2588 let v2 = state.get_at(base + i.arg_c());
2589 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2590 }
2591 OpCode::BXOr => {
2592 let ra = base + i.arg_a();
2593 let v1 = state.get_at(base + i.arg_b());
2594 let v2 = state.get_at(base + i.arg_c());
2595 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2596 }
2597 OpCode::Shr => {
2598 let ra = base + i.arg_a();
2599 let v1 = state.get_at(base + i.arg_b());
2600 let v2 = state.get_at(base + i.arg_c());
2601 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2602 }
2603 OpCode::Shl => {
2604 let ra = base + i.arg_a();
2605 let v1 = state.get_at(base + i.arg_b());
2606 let v2 = state.get_at(base + i.arg_c());
2607 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2608 }
2609 OpCode::MmBin => {
2614 let ra_idx = base + i.arg_a();
2615 let rb_idx = base + i.arg_b();
2616 let ra_v = state.get_at(ra_idx);
2617 let rb_v = state.get_at(rb_idx);
2618 let tm = tagmethod_from_index(i.arg_c() as usize);
2619 let prev_inst = code[(pc - 2) as usize];
2620 let result_idx = base + prev_inst.arg_a();
2621 state.set_ci_savedpc(ci, pc);
2622 state.set_top(state.ci_top(ci));
2623 state.try_bin_tm(
2624 &ra_v,
2625 Some(ra_idx),
2626 &rb_v,
2627 Some(rb_idx),
2628 result_idx,
2629 tm,
2630 )?;
2631 trap = state.ci_trap(ci);
2632 }
2633 OpCode::MmBinI => {
2634 let ra_idx = base + i.arg_a();
2635 let ra_v = state.get_at(ra_idx);
2636 let imm = i.arg_s_b() as i64;
2637 let tm = tagmethod_from_index(i.arg_c() as usize);
2638 let flip = i.arg_k() != 0;
2639 let prev_inst = code[(pc - 2) as usize];
2640 let result_idx = base + prev_inst.arg_a();
2641 state.set_ci_savedpc(ci, pc);
2642 state.set_top(state.ci_top(ci));
2643 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2644 trap = state.ci_trap(ci);
2645 }
2646 OpCode::MmBinK => {
2647 let ra_idx = base + i.arg_a();
2648 let ra_v = state.get_at(ra_idx);
2649 let imm = constants[i.arg_b() as usize];
2650 let tm = tagmethod_from_index(i.arg_c() as usize);
2651 let flip = i.arg_k() != 0;
2652 let prev_inst = code[(pc - 2) as usize];
2653 let result_idx = base + prev_inst.arg_a();
2654 state.set_ci_savedpc(ci, pc);
2655 state.set_top(state.ci_top(ci));
2656 state.try_bin_assoc_tm(
2657 &ra_v,
2658 Some(ra_idx),
2659 &imm,
2660 None,
2661 flip,
2662 result_idx,
2663 tm,
2664 )?;
2665 trap = state.ci_trap(ci);
2666 }
2667 OpCode::Unm => {
2671 let ra = base + i.arg_a();
2672 let rb_idx = base + i.arg_b();
2673 let rb_v = state.get_at(rb_idx);
2674 match &rb_v {
2675 LuaValue::Int(ib) => {
2676 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2677 }
2678 LuaValue::Float(nb) => {
2679 state.set_at(ra, LuaValue::Float(-nb));
2680 }
2681 _ => {
2682 state.set_ci_savedpc(ci, pc);
2683 state.set_top(state.ci_top(ci));
2684 state.try_bin_tm(
2685 &rb_v,
2686 Some(rb_idx),
2687 &rb_v,
2688 Some(rb_idx),
2689 ra,
2690 TagMethod::Unm,
2691 )?;
2692 trap = state.ci_trap(ci);
2693 }
2694 }
2695 }
2696 OpCode::BNot => {
2698 let ra = base + i.arg_a();
2699 let rb_idx = base + i.arg_b();
2700 let rb_v = state.get_at(rb_idx);
2701 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2702 state.set_at(ra, LuaValue::Int(!ib));
2703 } else {
2704 state.set_ci_savedpc(ci, pc);
2705 state.set_top(state.ci_top(ci));
2706 state.try_bin_tm(
2707 &rb_v,
2708 Some(rb_idx),
2709 &rb_v,
2710 Some(rb_idx),
2711 ra,
2712 TagMethod::Bnot,
2713 )?;
2714 trap = state.ci_trap(ci);
2715 }
2716 }
2717 OpCode::Not => {
2719 let ra = base + i.arg_a();
2720 let rb_v = state.get_at(base + i.arg_b());
2721 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2722 state.set_at(ra, LuaValue::Bool(falsy));
2723 }
2724 OpCode::Len => {
2726 let ra = base + i.arg_a();
2727 let rb_idx = base + i.arg_b();
2728 let rb_v = state.get_at(rb_idx);
2729 state.set_ci_savedpc(ci, pc);
2730 state.set_top(state.ci_top(ci));
2731 obj_len(state, ra, rb_v, rb_idx)?;
2732 trap = state.ci_trap(ci);
2733 }
2734 OpCode::Concat => {
2736 let ra = base + i.arg_a();
2737 let n = i.arg_b() as i32;
2738 state.set_top(ra + n as i32);
2739 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2741 let top = state.top_idx();
2742 state.set_ci_savedpc(ci, pc);
2743 state.set_top(top);
2744 state.gc_cond_step();
2745 trap = state.ci_trap(ci);
2746 }
2747 OpCode::Close => {
2749 let ra = base + i.arg_a();
2750 state.set_ci_savedpc(ci, pc);
2751 state.set_top(state.ci_top(ci));
2752 crate::func::close(
2753 state,
2754 ra,
2755 lua_types::status::LuaStatus::Ok as i32,
2756 true,
2757 )?;
2758 trap = state.ci_trap(ci);
2759 }
2760 OpCode::Tbc => {
2762 let ra = base + i.arg_a();
2763 state.set_ci_savedpc(ci, pc);
2764 state.set_top(state.ci_top(ci));
2765 state.new_tbc_upval(ra)?;
2766 }
2767 OpCode::Jmp => {
2769 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2770 trap = state.ci_trap(ci);
2771 }
2772 OpCode::Eq => {
2774 let ra_v = state.get_at(base + i.arg_a());
2775 let rb_v = state.get_at(base + i.arg_b());
2776 state.set_ci_savedpc(ci, pc);
2777 state.set_top(state.ci_top(ci));
2778 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2779 trap = state.ci_trap(ci);
2780 if (cond as i32) != i.arg_k() {
2781 pc += 1;
2782 } else {
2783 let next = code[pc as usize];
2784 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2785 trap = state.ci_trap(ci);
2786 }
2787 }
2788 OpCode::Lt => {
2790 let ra_v = state.get_at(base + i.arg_a());
2791 let rb_v = state.get_at(base + i.arg_b());
2792 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2793 *ia < *ib
2794 } else if matches!(
2795 (&ra_v, &rb_v),
2796 (
2797 LuaValue::Int(_) | LuaValue::Float(_),
2798 LuaValue::Int(_) | LuaValue::Float(_)
2799 )
2800 ) {
2801 lt_num(&ra_v, &rb_v)
2802 } else {
2803 state.set_ci_savedpc(ci, pc);
2804 state.set_top(state.ci_top(ci));
2805 let r = less_than_others(state, &ra_v, &rb_v)?;
2806 trap = state.ci_trap(ci);
2807 r
2808 };
2809 if (cond as i32) != i.arg_k() {
2810 pc += 1;
2811 } else {
2812 let next = code[pc as usize];
2813 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2814 trap = state.ci_trap(ci);
2815 }
2816 }
2817 OpCode::Le => {
2819 let ra_v = state.get_at(base + i.arg_a());
2820 let rb_v = state.get_at(base + i.arg_b());
2821 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2822 *ia <= *ib
2823 } else if matches!(
2824 (&ra_v, &rb_v),
2825 (
2826 LuaValue::Int(_) | LuaValue::Float(_),
2827 LuaValue::Int(_) | LuaValue::Float(_)
2828 )
2829 ) {
2830 le_num(&ra_v, &rb_v)
2831 } else {
2832 state.set_ci_savedpc(ci, pc);
2833 state.set_top(state.ci_top(ci));
2834 let r = less_equal_others(state, &ra_v, &rb_v)?;
2835 trap = state.ci_trap(ci);
2836 r
2837 };
2838 if (cond as i32) != i.arg_k() {
2839 pc += 1;
2840 } else {
2841 let next = code[pc as usize];
2842 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2843 trap = state.ci_trap(ci);
2844 }
2845 }
2846 OpCode::EqK => {
2848 let ra_v = state.get_at(base + i.arg_a());
2849 let rb_v = constants[i.arg_b() as usize];
2850 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2851 if (cond as i32) != i.arg_k() {
2852 pc += 1;
2853 } else {
2854 let next = code[pc as usize];
2855 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2856 trap = state.ci_trap(ci);
2857 }
2858 }
2859 OpCode::EqI => {
2864 let ra_v = state.get_at(base + i.arg_a());
2865 let im = i.arg_s_b() as i64;
2866 let cond: bool = match &ra_v {
2867 LuaValue::Int(iv) => *iv == im,
2868 LuaValue::Float(fv) => *fv == im as f64,
2869 _ => false,
2870 };
2871 if (cond as i32) != i.arg_k() {
2872 pc += 1;
2873 } else {
2874 let next = code[pc as usize];
2875 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2876 trap = state.ci_trap(ci);
2877 }
2878 }
2879 OpCode::LtI => {
2882 let ra = base + i.arg_a();
2883 let im = i.arg_s_b() as i64;
2884 let fast_cond = match &state.stack[ra.0 as usize].val {
2885 LuaValue::Int(ia) => Some(*ia < im),
2886 LuaValue::Float(fa) => Some(*fa < im as f64),
2887 _ => None,
2888 };
2889 let cond = match fast_cond {
2890 Some(cond) => cond,
2891 None => order_imm_slow(
2892 state,
2893 ra,
2894 pc,
2895 &mut trap,
2896 ci,
2897 i,
2898 im,
2899 false,
2900 TagMethod::Lt,
2901 )?,
2902 };
2903 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2904 }
2905 OpCode::LeI => {
2906 let ra = base + i.arg_a();
2907 let im = i.arg_s_b() as i64;
2908 let fast_cond = match &state.stack[ra.0 as usize].val {
2909 LuaValue::Int(ia) => Some(*ia <= im),
2910 LuaValue::Float(fa) => Some(*fa <= im as f64),
2911 _ => None,
2912 };
2913 let cond = match fast_cond {
2914 Some(cond) => cond,
2915 None => order_imm_slow(
2916 state,
2917 ra,
2918 pc,
2919 &mut trap,
2920 ci,
2921 i,
2922 im,
2923 false,
2924 TagMethod::Le,
2925 )?,
2926 };
2927 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2928 }
2929 OpCode::GtI => {
2930 let ra = base + i.arg_a();
2931 let im = i.arg_s_b() as i64;
2932 let fast_cond = match &state.stack[ra.0 as usize].val {
2933 LuaValue::Int(ia) => Some(*ia > im),
2934 LuaValue::Float(fa) => Some(*fa > im as f64),
2935 _ => None,
2936 };
2937 let cond = match fast_cond {
2938 Some(cond) => cond,
2939 None => order_imm_slow(
2940 state,
2941 ra,
2942 pc,
2943 &mut trap,
2944 ci,
2945 i,
2946 im,
2947 true,
2948 TagMethod::Lt,
2949 )?,
2950 };
2951 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2952 }
2953 OpCode::GeI => {
2954 let ra = base + i.arg_a();
2955 let im = i.arg_s_b() as i64;
2956 let fast_cond = match &state.stack[ra.0 as usize].val {
2957 LuaValue::Int(ia) => Some(*ia >= im),
2958 LuaValue::Float(fa) => Some(*fa >= im as f64),
2959 _ => None,
2960 };
2961 let cond = match fast_cond {
2962 Some(cond) => cond,
2963 None => order_imm_slow(
2964 state,
2965 ra,
2966 pc,
2967 &mut trap,
2968 ci,
2969 i,
2970 im,
2971 true,
2972 TagMethod::Le,
2973 )?,
2974 };
2975 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2976 }
2977 OpCode::Test => {
2979 let ra_v = state.get_at(base + i.arg_a());
2980 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2981 if (cond as i32) != i.arg_k() {
2982 pc += 1;
2983 } else {
2984 let next = code[pc as usize];
2985 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2986 trap = state.ci_trap(ci);
2987 }
2988 }
2989 OpCode::TestSet => {
2992 let ra = base + i.arg_a();
2993 let rb_v = state.get_at(base + i.arg_b());
2994 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2995 if (falsy as i32) == i.arg_k() {
2996 pc += 1;
2997 } else {
2998 state.set_at(ra, rb_v);
2999 let next = code[pc as usize];
3000 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3001 trap = state.ci_trap(ci);
3002 }
3003 }
3004 OpCode::Call => {
3008 let ra = base + i.arg_a();
3009 let b = i.arg_b();
3010 let nresults = i.arg_c() as i32 - 1;
3011 if b != 0 {
3012 state.set_top(ra + b);
3013 }
3014 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
3016 match state.precall(ra, nresults)? {
3017 None => {
3018 if had_hook || state.hookmask != 0 {
3022 trap = state.ci_trap(ci); }
3024 }
3025 Some(new_ci) => {
3026 ci = new_ci;
3028 continue 'startfunc;
3029 }
3030 }
3031 }
3032 OpCode::TailCall => {
3037 let ra = base + i.arg_a();
3038 let b = i.arg_b();
3039 let nparams1 = i.arg_c();
3040 let delta = if nparams1 != 0 {
3041 state.ci_nextraargs(ci) + nparams1 as i32
3042 } else {
3043 0
3044 };
3045 let top_b: i32 = if b != 0 {
3046 state.set_top(ra + b);
3047 b
3048 } else {
3049 state.top_idx() - ra
3050 };
3051 state.set_ci_savedpc(ci, pc);
3052 if i.test_k() {
3053 state.close_upvals_from_base(ci)?;
3054 }
3055 let n = state.pretailcall(ci, ra, top_b, delta)?;
3056 if n < 0 {
3057 continue 'startfunc;
3059 } else {
3060 state.ci_adjust_func(ci, delta);
3062 state.poscall(ci, n as u32)?;
3063 if state.hookmask != 0 {
3064 trap = state.ci_trap(ci);
3065 }
3066 break 'dispatch; }
3068 }
3069 OpCode::Return => {
3074 let ra = base + i.arg_a();
3075 let n_raw = i.arg_b() as i32 - 1;
3076 let nparams1 = i.arg_c();
3077 let n: u32 = if n_raw < 0 {
3078 (state.top_idx() - ra) as u32
3079 } else {
3080 n_raw as u32
3081 };
3082 state.set_ci_savedpc(ci, pc);
3083 if i.test_k() {
3084 state.ci_nres_set(ci, n as i32);
3085 let ci_top = state.ci_top(ci);
3086 if state.top_idx().0 < ci_top.0 {
3087 state.set_top(ci_top);
3088 }
3089 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
3090 if state.hookmask != 0 {
3091 trap = state.ci_trap(ci);
3092 }
3093 base = state.ci_base(ci); }
3095 if nparams1 != 0 {
3096 let nextraargs = state.ci_nextraargs(ci) as u32;
3097 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
3098 }
3099 state.set_top(ra + n as i32);
3100 state.poscall(ci, n)?;
3101 if state.hookmask != 0 {
3102 trap = state.ci_trap(ci);
3103 }
3104 break 'dispatch; }
3106 OpCode::Return0 => {
3112 if state.hookmask == 0 {
3113 let ci_slot = ci.as_usize();
3114 let nres = state.call_info[ci_slot].nresults as i32;
3115 state.ci = state.call_info[ci_slot]
3116 .previous
3117 .expect("RETURN0: returning frame has no previous CallInfo");
3118 state.top = base - 1;
3119 for _ in 0..nres.max(0) {
3120 state.push(LuaValue::Nil);
3121 }
3122 } else {
3123 return0_hook(state, ci, base, i, pc, &mut trap)?;
3124 }
3125 break 'dispatch; }
3127 OpCode::Return1 => {
3131 if state.hookmask == 0 {
3132 let ci_slot = ci.as_usize();
3133 let nres = state.call_info[ci_slot].nresults as i32;
3134 state.ci = state.call_info[ci_slot]
3135 .previous
3136 .expect("RETURN1: returning frame has no previous CallInfo");
3137 if nres == 0 {
3138 state.top = base - 1;
3139 } else {
3140 let ra = base + i.arg_a();
3141 state.stack[(base - 1).0 as usize].val =
3142 state.stack[ra.0 as usize].val; state.top = base;
3144 for _ in 1..nres.max(0) {
3145 state.push(LuaValue::Nil);
3146 }
3147 }
3148 } else {
3149 return1_hook(state, ci, base, i, pc, &mut trap)?;
3150 }
3151 break 'dispatch; }
3153 OpCode::ForLoop => {
3157 let ra = base + i.arg_a();
3158 if legacy_for {
3159 if forloop_legacy(state, ra) {
3160 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3161 }
3162 trap = state.ci_trap(ci);
3163 } else {
3164 let ra_u = ra.0 as usize;
3165 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
3166 let count = match state.stack[ra_u + 1].val {
3167 LuaValue::Int(c) => c as u64,
3168 _ => 0,
3169 };
3170 if count > 0 {
3171 let idx = match state.stack[ra_u].val {
3172 LuaValue::Int(x) => x,
3173 _ => 0,
3174 };
3175 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
3176 let new_idx = intop_add(idx, step);
3177 state.stack[ra_u].val = LuaValue::Int(new_idx);
3178 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
3179 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3180 }
3181 } else if float_for_loop(state, ra) {
3182 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3183 }
3184 trap = state.ci_trap(ci);
3185 }
3186 }
3187 OpCode::ForPrep => {
3189 let ra = base + i.arg_a();
3190 state.set_ci_savedpc(ci, pc);
3191 state.set_top(state.ci_top(ci));
3192 if legacy_for {
3193 forprep_legacy(state, ra)?;
3196 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3197 } else if forprep(state, ra)? {
3198 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
3199 }
3200 }
3201 OpCode::TForPrep => {
3205 let ra = base + i.arg_a();
3206 state.set_ci_savedpc(ci, pc);
3207 state.set_top(state.ci_top(ci));
3208 if tfor_55 {
3209 let closing = state.get_at(ra + 3);
3210 let control = state.get_at(ra + 2);
3211 state.set_at(ra + 2, closing);
3212 state.set_at(ra + 3, control);
3213 state.new_tbc_upval(ra + 2)?;
3214 } else {
3215 state.new_tbc_upval(ra + 3)?;
3216 }
3217 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3218 let tfc_i = code[pc as usize];
3219 pc += 1;
3220 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
3221 let tfc_ra = base + tfc_i.arg_a();
3223 if tfor_55 {
3224 let func = state.get_at(tfc_ra);
3225 let state_val = state.get_at(tfc_ra + 1);
3226 let control = state.get_at(tfc_ra + 3);
3227 state.set_at(tfc_ra + 3, func);
3228 state.set_at(tfc_ra + 4, state_val);
3229 state.set_at(tfc_ra + 5, control);
3230 state.set_top(tfc_ra + 6);
3231 state.set_ci_savedpc(ci, pc);
3232 state.call_at(tfc_ra + 3, tfc_i.arg_c() as i32)?;
3233 } else {
3234 for k in 0..3u32 {
3235 let v = state.get_at(tfc_ra + k as i32);
3236 state.set_at(tfc_ra + 4 + k as i32, v);
3237 }
3238 state.set_top(tfc_ra + 4 + 3);
3239 state.set_ci_savedpc(ci, pc);
3240 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
3241 }
3242 trap = state.ci_trap(ci);
3243 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3245 pc += 1;
3246 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3247 let tfl_ra = base + tfl_i.arg_a();
3248 if tfor_55 {
3250 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3251 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3252 }
3253 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3254 let v = state.get_at(tfl_ra + 4);
3255 state.set_at(tfl_ra + 2, v);
3256 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3257 }
3258 }
3259 OpCode::TForCall => {
3261 let ra = base + i.arg_a();
3262 if tfor_55 {
3263 let func = state.get_at(ra);
3264 let state_val = state.get_at(ra + 1);
3265 let control = state.get_at(ra + 3);
3266 state.set_at(ra + 3, func);
3267 state.set_at(ra + 4, state_val);
3268 state.set_at(ra + 5, control);
3269 state.set_top(ra + 6);
3270 state.set_ci_savedpc(ci, pc);
3271 state.call_at(ra + 3, i.arg_c() as i32)?;
3272 } else {
3273 for k in 0..3u32 {
3274 let v = state.get_at(ra + k as i32);
3275 state.set_at(ra + 4 + k as i32, v);
3276 }
3277 state.set_top(ra + 4 + 3);
3278 state.set_ci_savedpc(ci, pc);
3279 state.call_at(ra + 4, i.arg_c() as i32)?;
3280 }
3281 trap = state.ci_trap(ci);
3282 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3284 pc += 1;
3285 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3286 let tfl_ra = base + tfl_i.arg_a();
3287 if tfor_55 {
3288 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3289 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3290 }
3291 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3292 let v = state.get_at(tfl_ra + 4);
3293 state.set_at(tfl_ra + 2, v);
3294 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3295 }
3296 }
3297 OpCode::TForLoop => {
3299 let ra = base + i.arg_a();
3300 if tfor_55 {
3301 if !matches!(state.get_at(ra + 3), LuaValue::Nil) {
3302 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3303 }
3304 } else if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
3305 let v = state.get_at(ra + 4);
3306 state.set_at(ra + 2, v);
3307 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3308 }
3309 }
3310 OpCode::SetList => {
3314 let ra = base + i.arg_a();
3315 let n_raw = i.arg_b();
3316 let mut last = i.arg_c();
3317 let t_val = state.get_at(ra);
3318 let n: i32 = if n_raw == 0 {
3319 state.top_idx() - ra - 1
3320 } else {
3321 state.set_top(state.ci_top(ci));
3322 n_raw
3323 };
3324 last += n;
3325 if i.test_k() {
3326 let extra = code[pc as usize];
3327 pc += 1;
3328 const MAXARG_C: i32 = (1 << 8) - 1;
3329 last += extra.arg_ax() * (MAXARG_C + 1);
3330 }
3331 state.table_ensure_array(&t_val, last as usize)?;
3332 for k in (1..=n).rev() {
3333 let val = state.get_at(ra + k as i32);
3334 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
3335 last -= 1;
3336 state.gc_value_barrier_back(&t_val, &val);
3337 }
3338 }
3339 OpCode::Closure => {
3343 let ra = base + i.arg_a();
3344 let proto_idx = i.arg_bx() as usize;
3345 state.set_ci_savedpc(ci, pc);
3346 state.set_top(state.ci_top(ci));
3347 push_closure(state, proto_idx, ci, base, ra)?;
3348 state.set_ci_savedpc(ci, pc);
3350 state.set_top(ra + 1);
3351 state.gc_cond_step();
3352 trap = state.ci_trap(ci);
3353 }
3354 OpCode::VarArg => {
3356 let ra = base + i.arg_a();
3357 let n = i.arg_c() as i32 - 1;
3358 state.set_ci_savedpc(ci, pc);
3359 state.set_top(state.ci_top(ci));
3360 state.get_varargs(ci, ra, n)?;
3361 trap = state.ci_trap(ci);
3362 }
3363 OpCode::VarArgPrep => {
3367 let nparams = i.arg_a();
3368 state.set_ci_savedpc(ci, pc);
3369 state.adjust_varargs(ci, nparams, &cl)?;
3370 trap = state.ci_trap(ci);
3371 if trap {
3372 state.hook_call(ci)?;
3373 state.set_oldpc(1);
3374 }
3375 base = state.ci_base(ci);
3376 }
3377 OpCode::GetVArg => {
3379 let ra = base + i.arg_a();
3380 let vararg_reg = base + i.arg_b();
3381 let key = state.get_at(base + i.arg_c()).clone();
3382 let val = if let LuaValue::Table(t) = state.get_at(vararg_reg) {
3383 t.get(&key)
3384 } else {
3385 let nextra = state.ci_nextraargs(ci);
3386 match key {
3387 LuaValue::Int(n) if n >= 1 && n <= nextra as i64 => {
3388 let ci_func = state.ci_base(ci) - 1;
3389 state.get_at(ci_func - nextra + n as i32 - 1)
3390 }
3391 LuaValue::Float(f)
3392 if f.is_finite()
3393 && f.fract() == 0.0
3394 && f >= 1.0
3395 && f <= nextra as f64 =>
3396 {
3397 let ci_func = state.ci_base(ci) - 1;
3398 state.get_at(ci_func - nextra + f as i32 - 1)
3399 }
3400 LuaValue::Str(s) if s.as_bytes() == b"n" => {
3401 LuaValue::Int(nextra as i64)
3402 }
3403 _ => LuaValue::Nil,
3404 }
3405 };
3406 state.set_at(ra, val);
3407 }
3408 OpCode::ExtraArg => {
3410 debug_assert!(false, "OP_EXTRAARG executed directly");
3411 }
3412 OpCode::ErrNNil => {
3417 let ra = base + i.arg_a();
3418 if !matches!(state.get_at(ra), LuaValue::Nil) {
3419 let bx = i.arg_bx();
3420 let name: Vec<u8> = if bx == 0 {
3421 b"?".to_vec()
3422 } else {
3423 match constants[(bx - 1) as usize] {
3424 LuaValue::Str(s) => s.as_bytes().to_vec(),
3425 _ => b"?".to_vec(),
3426 }
3427 };
3428 let mut msg = Vec::with_capacity(name.len() + 24);
3429 msg.extend_from_slice(b"global '");
3430 msg.extend_from_slice(&name);
3431 msg.extend_from_slice(b"' already defined");
3432 state.set_ci_savedpc(ci, pc);
3433 return Err(crate::debug::prefixed_runtime_pub(state, msg));
3434 }
3435 }
3436 OpCode::VarArgPack => {
3444 if !cl.proto.vararg_table_needed && !i.test_k() {
3445 state.set_ci_savedpc(ci, pc);
3446 continue;
3447 }
3448 let ra = base + i.arg_a();
3449 let nextra = state.ci_nextraargs(ci);
3450 let ci_func: StackIdx = state.ci_base(ci) - 1;
3451 let t = if nextra > 0 {
3452 state.new_table_with_sizes(nextra as u32, 1)?
3453 } else {
3454 state.new_table()
3455 };
3456 for k in 0..nextra {
3457 let src: StackIdx = ci_func - nextra as i32 + k as i32;
3458 let val = state.get_at(src);
3459 t.raw_set_int(state, (k + 1) as i64, val)?;
3460 }
3461 let n_key = state.intern_str(b"n")?;
3462 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
3463 state.set_at(ra, LuaValue::Table(t));
3464 state.set_ci_savedpc(ci, pc);
3465 state.gc_cond_step();
3466 if state.hookmask != 0 {
3467 trap = state.ci_trap(ci);
3468 }
3469 }
3470 } } if state.ci_is_fresh(ci) {
3475 return Ok(());
3476 } else {
3477 ci = state
3478 .ci_previous(ci)
3479 .expect("ci_previous: not fresh frame must have previous");
3480 continue 'returning;
3481 }
3482 } } }
3485
3486#[inline(always)]
3489fn number_value(v: LuaValue) -> Option<f64> {
3490 match v {
3491 LuaValue::Float(f) => Some(f),
3492 LuaValue::Int(i) => Some(i as f64),
3493 _ => None,
3494 }
3495}
3496
3497#[allow(dead_code)]
3499#[inline]
3500fn arith_op_aux_rr(
3501 state: &mut LuaState,
3502 ra: StackIdx,
3503 v1: &LuaValue,
3504 v2: &LuaValue,
3505 pc: &mut u32,
3506 iop: fn(i64, i64) -> i64,
3507 fop: fn(f64, f64) -> f64,
3508) {
3509 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3510 *pc += 1;
3511 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3512 } else {
3513 arith_float_aux(state, ra, v1, v2, pc, fop);
3514 }
3515}
3516
3517#[allow(dead_code)]
3518#[inline]
3519fn arith_float_aux(
3520 state: &mut LuaState,
3521 ra: StackIdx,
3522 v1: &LuaValue,
3523 v2: &LuaValue,
3524 pc: &mut u32,
3525 fop: fn(f64, f64) -> f64,
3526) {
3527 let n1 = match v1 {
3528 LuaValue::Float(f) => Some(*f),
3529 LuaValue::Int(i) => Some(*i as f64),
3530 _ => None,
3531 };
3532 let n2 = match v2 {
3533 LuaValue::Float(f) => Some(*f),
3534 LuaValue::Int(i) => Some(*i as f64),
3535 _ => None,
3536 };
3537 if let (Some(n1), Some(n2)) = (n1, n2) {
3538 *pc += 1;
3539 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3540 }
3541}
3542
3543#[allow(dead_code)]
3544#[inline]
3545fn arith_op_checked(
3546 state: &mut LuaState,
3547 ra: StackIdx,
3548 v1: &LuaValue,
3549 v2: &LuaValue,
3550 pc: &mut u32,
3551 iop: fn(i64, i64) -> Result<i64, LuaError>,
3552 fop: fn(f64, f64) -> f64,
3553) -> Result<(), LuaError> {
3554 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3555 *pc += 1;
3556 let result = iop(*i1, *i2).map_err(|e| match e {
3557 LuaError::Runtime(LuaValue::Str(s)) => {
3558 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3559 }
3560 other => other,
3561 })?;
3562 state.set_at(ra, LuaValue::Int(result));
3563 } else {
3564 arith_float_aux(state, ra, v1, v2, pc, fop);
3565 }
3566 Ok(())
3567}
3568
3569#[allow(dead_code)]
3570#[inline]
3571fn bitwise_op_k(
3572 state: &mut LuaState,
3573 ra: StackIdx,
3574 v1: &LuaValue,
3575 v2: &LuaValue, pc: &mut u32,
3577 op: fn(i64, i64) -> i64,
3578) {
3579 let i2 = match v2 {
3580 LuaValue::Int(i) => *i,
3581 _ => return,
3582 };
3583 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3584 *pc += 1;
3585 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3586 }
3587}
3588
3589#[allow(dead_code)]
3590#[inline]
3591fn bitwise_op_rr(
3592 state: &mut LuaState,
3593 ra: StackIdx,
3594 v1: &LuaValue,
3595 v2: &LuaValue,
3596 pc: &mut u32,
3597 op: fn(i64, i64) -> i64,
3598) {
3599 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3600 *pc += 1;
3601 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3602 }
3603}
3604
3605#[allow(dead_code)]
3607#[inline]
3608fn bitwise_shift_rr(
3609 state: &mut LuaState,
3610 ra: StackIdx,
3611 v1: &LuaValue,
3612 v2: &LuaValue,
3613 pc: &mut u32,
3614 right: bool,
3615) {
3616 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3617 let y = if right { intop_sub(0, i2) } else { i2 };
3618 *pc += 1;
3619 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3620 }
3621}
3622
3623#[cold]
3626#[inline(never)]
3627#[allow(clippy::too_many_arguments)]
3628fn order_imm_slow(
3629 state: &mut LuaState,
3630 ra: StackIdx,
3631 pc: u32,
3632 trap: &mut bool,
3633 ci: CallInfoIdx,
3634 i: Instruction,
3635 im: i64,
3636 inv: bool,
3637 tm: TagMethod,
3638) -> Result<bool, LuaError> {
3639 let ra_v = state.get_at(ra);
3640 let isf = i.arg_c() != 0;
3641 state.set_ci_savedpc(ci, pc);
3642 state.set_top(state.ci_top(ci));
3643 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3644 *trap = state.ci_trap(ci);
3645 Ok(r)
3646}
3647
3648#[inline(always)]
3649fn finish_order_imm_jump(
3650 state: &mut LuaState,
3651 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
3652 pc: &mut u32,
3653 trap: &mut bool,
3654 ci: CallInfoIdx,
3655 i: Instruction,
3656 cond: bool,
3657) {
3658 if (cond as i32) != i.arg_k() {
3659 *pc += 1;
3660 } else {
3661 let next = state.proto_code(&cl, *pc);
3662 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3663 *trap = state.ci_trap(ci);
3664 }
3665}
3666
3667#[cold]
3668#[inline(never)]
3669fn return0_hook(
3670 state: &mut LuaState,
3671 ci: CallInfoIdx,
3672 base: StackIdx,
3673 i: Instruction,
3674 pc: u32,
3675 trap: &mut bool,
3676) -> Result<(), LuaError> {
3677 let ra = base + i.arg_a();
3678 state.set_top(ra);
3679 state.set_ci_savedpc(ci, pc);
3680 state.poscall(ci, 0)?;
3681 *trap = true;
3682 Ok(())
3683}
3684
3685#[cold]
3686#[inline(never)]
3687fn return1_hook(
3688 state: &mut LuaState,
3689 ci: CallInfoIdx,
3690 base: StackIdx,
3691 i: Instruction,
3692 pc: u32,
3693 trap: &mut bool,
3694) -> Result<(), LuaError> {
3695 let ra = base + i.arg_a();
3696 state.set_top(ra + 1);
3697 state.set_ci_savedpc(ci, pc);
3698 state.poscall(ci, 1)?;
3699 *trap = true;
3700 Ok(())
3701}
3702
3703