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[func_idx.0 as usize].val {
1894 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 if let LuaValue::Table(tbl) = upval {
2134 if !tbl.has_metatable() {
2135 if rc_v.is_collectable() {
2136 state.gc_table_barrier_back(&tbl, &rc_v);
2137 }
2138 if let LuaValue::Str(s) = key {
2139 tbl.raw_set_short_str(state, s, rc_v)?;
2140 } else {
2141 tbl.raw_set(state, key, rc_v)?;
2142 }
2143 continue 'dispatch;
2144 }
2145 }
2146 match state.fast_get_short_str(&upval, &key)? {
2147 Some(_slot) => {
2148 state.gc_value_barrier_back(&upval, &rc_v);
2149 if let LuaValue::Table(tbl) = upval {
2150 if let LuaValue::Str(s) = key {
2151 tbl.raw_set_short_str(state, s, rc_v)?;
2152 } else {
2153 tbl.raw_set(state, key, rc_v)?;
2154 }
2155 } else {
2156 state.table_raw_set(&upval, key, rc_v)?;
2157 }
2158 }
2159 None => {
2160 state.set_ci_savedpc(ci, pc);
2161 state.set_top(state.ci_top(ci));
2162 let upval_name: Vec<u8> = cl
2163 .proto
2164 .upvalues
2165 .get(a)
2166 .and_then(|uv| uv.name.as_ref())
2167 .map(|s| s.as_bytes().to_vec())
2168 .unwrap_or_else(|| b"?".to_vec());
2169 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2170 finish_set(state, upval, key, rc_v, false, None, hint)?;
2171 trap = state.ci_trap(ci);
2172 }
2173 }
2174 }
2175 OpCode::SetTable => {
2177 let ra_idx = base + i.arg_a();
2178 let ra_v = state.get_at(ra_idx);
2179 let rb_v = state.get_at(base + i.arg_b());
2180 let rc_v = if i.test_k() {
2181 constants[i.arg_c() as usize]
2182 } else {
2183 state.get_at(base + i.arg_c())
2184 };
2185 if let LuaValue::Table(tbl) = ra_v {
2186 if !tbl.has_metatable() {
2187 if rc_v.is_collectable() {
2188 state.gc_table_barrier_back(&tbl, &rc_v);
2189 }
2190 match rb_v {
2191 LuaValue::Int(n) => tbl.raw_set_int(state, n, rc_v)?,
2192 LuaValue::Str(s) if s.is_short() => {
2193 tbl.raw_set_short_str(state, s, rc_v)?
2194 }
2195 _ => tbl.raw_set(state, rb_v, rc_v)?,
2196 }
2197 } else {
2198 let fast = if let LuaValue::Int(n) = &rb_v {
2199 state.fast_get_int(&ra_v, *n)?
2200 } else {
2201 state.fast_get(&ra_v, &rb_v)?
2202 };
2203 if fast.is_some() {
2204 state.gc_value_barrier_back(&ra_v, &rc_v);
2205 match rb_v {
2206 LuaValue::Int(n) => tbl.raw_set_int(state, n, rc_v)?,
2207 LuaValue::Str(s) if s.is_short() => {
2208 tbl.raw_set_short_str(state, s, rc_v)?
2209 }
2210 _ => tbl.raw_set(state, rb_v, rc_v)?,
2211 }
2212 } else {
2213 state.set_ci_savedpc(ci, pc);
2214 state.set_top(state.ci_top(ci));
2215 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2216 trap = state.ci_trap(ci);
2217 }
2218 }
2219 } else {
2220 state.set_ci_savedpc(ci, pc);
2221 state.set_top(state.ci_top(ci));
2222 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2223 trap = state.ci_trap(ci);
2224 }
2225 }
2226 OpCode::SetI => {
2228 let ra_idx = base + i.arg_a();
2229 let ra_v = state.get_at(ra_idx);
2230 let c = i.arg_b() as i64;
2231 let rc_v = if i.test_k() {
2232 constants[i.arg_c() as usize]
2233 } else {
2234 state.get_at(base + i.arg_c())
2235 };
2236 if let LuaValue::Table(tbl) = ra_v {
2237 if !tbl.has_metatable() {
2238 if rc_v.is_collectable() {
2239 state.gc_table_barrier_back(&tbl, &rc_v);
2240 }
2241 tbl.raw_set_int(state, c, rc_v)?;
2242 } else {
2243 let fast = state.fast_get_int(&ra_v, c)?;
2244 if fast.is_some() {
2245 state.gc_value_barrier_back(&ra_v, &rc_v);
2246 tbl.raw_set_int(state, c, rc_v)?;
2247 } else {
2248 state.set_ci_savedpc(ci, pc);
2249 state.set_top(state.ci_top(ci));
2250 finish_set(
2251 state,
2252 ra_v,
2253 LuaValue::Int(c),
2254 rc_v,
2255 false,
2256 Some(ra_idx),
2257 None,
2258 )?;
2259 trap = state.ci_trap(ci);
2260 }
2261 }
2262 } else {
2263 state.set_ci_savedpc(ci, pc);
2264 state.set_top(state.ci_top(ci));
2265 finish_set(
2266 state,
2267 ra_v,
2268 LuaValue::Int(c),
2269 rc_v,
2270 false,
2271 Some(ra_idx),
2272 None,
2273 )?;
2274 trap = state.ci_trap(ci);
2275 }
2276 }
2277 OpCode::SetField => {
2279 let ra_idx = base + i.arg_a();
2280 let ra_v = state.get_at(ra_idx);
2281 let b_idx = i.arg_b() as usize;
2282 let key = constants[b_idx];
2283 let rc_v = if i.test_k() {
2284 constants[i.arg_c() as usize]
2285 } else {
2286 state.get_at(base + i.arg_c())
2287 };
2288 if let LuaValue::Table(tbl) = ra_v {
2289 if !tbl.has_metatable() {
2290 if rc_v.is_collectable() {
2291 state.gc_table_barrier_back(&tbl, &rc_v);
2292 }
2293 if let LuaValue::Str(s) = key {
2294 tbl.raw_set_short_str(state, s, rc_v)?;
2295 } else {
2296 tbl.raw_set(state, key, rc_v)?;
2297 }
2298 } else {
2299 match state.fast_get_short_str(&ra_v, &key)? {
2300 Some(_) => {
2301 state.gc_value_barrier_back(&ra_v, &rc_v);
2302 if let LuaValue::Str(s) = key {
2303 tbl.raw_set_short_str(state, s, rc_v)?;
2304 } else {
2305 tbl.raw_set(state, key, rc_v)?;
2306 }
2307 }
2308 None => {
2309 state.set_ci_savedpc(ci, pc);
2310 state.set_top(state.ci_top(ci));
2311 finish_set(
2312 state,
2313 ra_v,
2314 key,
2315 rc_v,
2316 false,
2317 Some(ra_idx),
2318 None,
2319 )?;
2320 trap = state.ci_trap(ci);
2321 }
2322 }
2323 }
2324 } else {
2325 state.set_ci_savedpc(ci, pc);
2326 state.set_top(state.ci_top(ci));
2327 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2328 trap = state.ci_trap(ci);
2329 }
2330 }
2331 OpCode::NewTable => {
2334 let ra = base + i.arg_a();
2335 let mut b = i.arg_b();
2336 let mut c = i.arg_c();
2337 if b > 0 {
2338 b = 1 << (b - 1);
2339 }
2340 if i.test_k() {
2341 let extra = code[pc as usize];
2342 pc += 1;
2343 const MAXARG_C: i32 = (1 << 8) - 1;
2344 c += extra.arg_ax() * (MAXARG_C + 1);
2345 } else {
2346 pc += 1; }
2348 state.set_top(ra + 1);
2349 let t = if b != 0 || c != 0 {
2350 state.new_table_with_sizes(c as u32, b as u32)?
2351 } else {
2352 state.new_table()
2353 };
2354 state.set_at(ra, LuaValue::Table(t.clone()));
2355 state.set_ci_savedpc(ci, pc);
2356 state.set_top(ra + 1);
2357 state.gc_cond_step();
2358 if state.hookmask != 0 {
2359 trap = state.ci_trap(ci);
2360 }
2361 }
2362 OpCode::Self_ => {
2364 let ra = base + i.arg_a();
2365 let rb_idx = base + i.arg_b();
2366 let rb_v = state.get_at(rb_idx);
2367 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2369 constants[k_idx]
2370 } else {
2371 state.get_at(base + i.arg_c())
2372 };
2373 state.set_at(ra + 1, rb_v.clone());
2374 match state.fast_get_short_str(&rb_v, &key)? {
2375 Some(v) => state.set_at(ra, v),
2376 None => {
2377 state.set_ci_savedpc(ci, pc);
2378 state.set_top(state.ci_top(ci));
2379 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2380 trap = state.ci_trap(ci);
2381 }
2382 }
2383 }
2384 OpCode::AddI => {
2386 let ra = base + i.arg_a();
2387 let rb = base + i.arg_b();
2388 let imm = i.arg_s_c() as i64;
2389 let rb_v = state.stack[rb.0 as usize].val;
2390 match rb_v {
2391 LuaValue::Int(iv1) => {
2392 pc += 1;
2393 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2394 }
2395 LuaValue::Float(nb) => {
2396 pc += 1;
2397 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2398 }
2399 _ => {}
2400 }
2401 }
2402 OpCode::AddK => {
2404 let ra = base + i.arg_a();
2405 let rb = base + i.arg_b();
2406 let kidx = i.arg_c() as usize;
2407 if let (Some(i1), Some(i2)) =
2408 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2409 {
2410 pc += 1;
2411 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2412 } else if let (Some(n1), Some(n2)) =
2413 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2414 {
2415 pc += 1;
2416 state.set_at(ra, LuaValue::Float(n1 + n2));
2417 }
2418 }
2419 OpCode::SubK => {
2420 let ra = base + i.arg_a();
2421 let rb = base + i.arg_b();
2422 let kidx = i.arg_c() as usize;
2423 if let (Some(i1), Some(i2)) =
2424 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2425 {
2426 pc += 1;
2427 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2428 } else 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::MulK => {
2436 let ra = base + i.arg_a();
2437 let rb = base + i.arg_b();
2438 let kidx = i.arg_c() as usize;
2439 if let (Some(i1), Some(i2)) =
2440 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2441 {
2442 pc += 1;
2443 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2444 } else if let (Some(n1), Some(n2)) =
2445 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2446 {
2447 pc += 1;
2448 state.set_at(ra, LuaValue::Float(n1 * n2));
2449 }
2450 }
2451 OpCode::ModK => {
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 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
2457 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2458 }
2459 OpCode::PowK => {
2460 let ra = base + i.arg_a();
2461 let rb = base + i.arg_b();
2462 let kidx = i.arg_c() as usize;
2463 if let (Some(n1), Some(n2)) =
2464 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2465 {
2466 pc += 1;
2467 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2468 state.set_at(ra, LuaValue::Float(r));
2469 }
2470 }
2471 OpCode::DivK => {
2472 let ra = base + i.arg_a();
2473 let rb = base + i.arg_b();
2474 let kidx = i.arg_c() as usize;
2475 if let (Some(n1), Some(n2)) =
2476 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2477 {
2478 pc += 1;
2479 state.set_at(ra, LuaValue::Float(n1 / n2));
2480 }
2481 }
2482 OpCode::IDivK => {
2483 let ra = base + i.arg_a();
2484 let v1 = state.get_at(base + i.arg_b());
2485 let v2 = constants[i.arg_c() as usize];
2486 state.set_ci_savedpc(ci, pc);
2487 state.set_top(state.ci_top(ci));
2488 arith_op_checked(
2489 state,
2490 ra,
2491 &v1,
2492 &v2,
2493 &mut pc,
2494 |a, b| idiv(a, b),
2495 |a, b| (a / b).floor(),
2496 )?;
2497 }
2498 OpCode::BAndK => {
2499 let ra = base + i.arg_a();
2500 let v1 = state.get_at(base + i.arg_b());
2501 let v2 = constants[i.arg_c() as usize];
2502 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2503 }
2504 OpCode::BOrK => {
2505 let ra = base + i.arg_a();
2506 let v1 = state.get_at(base + i.arg_b());
2507 let v2 = constants[i.arg_c() as usize];
2508 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2509 }
2510 OpCode::BXOrK => {
2511 let ra = base + i.arg_a();
2512 let v1 = state.get_at(base + i.arg_b());
2513 let v2 = constants[i.arg_c() as usize];
2514 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2515 }
2516 OpCode::ShrI => {
2517 let ra = base + i.arg_a();
2518 let v = state.get_at(base + i.arg_b());
2519 let ic = i.arg_s_c() as i64;
2520 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2521 pc += 1;
2522 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2523 }
2524 }
2525 OpCode::ShlI => {
2526 let ra = base + i.arg_a();
2527 let v = state.get_at(base + i.arg_b());
2528 let ic = i.arg_s_c() as i64;
2529 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2530 pc += 1;
2531 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2532 }
2533 }
2534 OpCode::Add => {
2536 let ra = base + i.arg_a();
2537 let rb = base + i.arg_b();
2538 let rc = base + i.arg_c();
2539 let ra_u = ra.0 as usize;
2540 let rb_v = state.stack[rb.0 as usize].val;
2541 let rc_v = state.stack[rc.0 as usize].val;
2542 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2543 pc += 1;
2544 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2545 } else if let (Some(n1), Some(n2)) =
2546 (number_value(rb_v), number_value(rc_v))
2547 {
2548 pc += 1;
2549 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2550 }
2551 }
2552 OpCode::Sub => {
2553 let ra = base + i.arg_a();
2554 let rb = base + i.arg_b();
2555 let rc = base + i.arg_c();
2556 let ra_u = ra.0 as usize;
2557 let rb_v = state.stack[rb.0 as usize].val;
2558 let rc_v = state.stack[rc.0 as usize].val;
2559 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2560 pc += 1;
2561 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2562 } else if let (Some(n1), Some(n2)) =
2563 (number_value(rb_v), number_value(rc_v))
2564 {
2565 pc += 1;
2566 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2567 }
2568 }
2569 OpCode::Mul => {
2570 let ra = base + i.arg_a();
2571 let rb = base + i.arg_b();
2572 let rc = base + i.arg_c();
2573 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2574 pc += 1;
2575 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2576 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2577 pc += 1;
2578 state.set_at(ra, LuaValue::Float(n1 * n2));
2579 }
2580 }
2581 OpCode::Mod => {
2582 let ra = base + i.arg_a();
2583 let v1 = state.get_at(base + i.arg_b());
2584 let v2 = state.get_at(base + i.arg_c());
2585 state.set_ci_savedpc(ci, pc);
2586 state.set_top(state.ci_top(ci));
2587 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2588 }
2589 OpCode::Pow => {
2590 let ra = base + i.arg_a();
2591 let rb = base + i.arg_b();
2592 let rc = base + i.arg_c();
2593 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2594 pc += 1;
2595 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2596 state.set_at(ra, LuaValue::Float(r));
2597 }
2598 }
2599 OpCode::Div => {
2600 let ra = base + i.arg_a();
2601 let rb = base + i.arg_b();
2602 let rc = base + i.arg_c();
2603 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2604 pc += 1;
2605 state.set_at(ra, LuaValue::Float(n1 / n2));
2606 }
2607 }
2608 OpCode::IDiv => {
2609 let ra = base + i.arg_a();
2610 let v1 = state.get_at(base + i.arg_b());
2611 let v2 = state.get_at(base + i.arg_c());
2612 state.set_ci_savedpc(ci, pc);
2613 state.set_top(state.ci_top(ci));
2614 arith_op_checked(
2615 state,
2616 ra,
2617 &v1,
2618 &v2,
2619 &mut pc,
2620 |a, b| idiv(a, b),
2621 |a, b| (a / b).floor(),
2622 )?;
2623 }
2624 OpCode::BAnd => {
2627 let ra = base + i.arg_a();
2628 let v1 = state.get_at(base + i.arg_b());
2629 let v2 = state.get_at(base + i.arg_c());
2630 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2631 }
2632 OpCode::BOr => {
2633 let ra = base + i.arg_a();
2634 let v1 = state.get_at(base + i.arg_b());
2635 let v2 = state.get_at(base + i.arg_c());
2636 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2637 }
2638 OpCode::BXOr => {
2639 let ra = base + i.arg_a();
2640 let v1 = state.get_at(base + i.arg_b());
2641 let v2 = state.get_at(base + i.arg_c());
2642 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2643 }
2644 OpCode::Shr => {
2645 let ra = base + i.arg_a();
2646 let v1 = state.get_at(base + i.arg_b());
2647 let v2 = state.get_at(base + i.arg_c());
2648 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2649 }
2650 OpCode::Shl => {
2651 let ra = base + i.arg_a();
2652 let v1 = state.get_at(base + i.arg_b());
2653 let v2 = state.get_at(base + i.arg_c());
2654 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2655 }
2656 OpCode::MmBin => {
2661 let ra_idx = base + i.arg_a();
2662 let rb_idx = base + i.arg_b();
2663 let ra_v = state.get_at(ra_idx);
2664 let rb_v = state.get_at(rb_idx);
2665 let tm = tagmethod_from_index(i.arg_c() as usize);
2666 let prev_inst = code[(pc - 2) as usize];
2667 let result_idx = base + prev_inst.arg_a();
2668 state.set_ci_savedpc(ci, pc);
2669 state.set_top(state.ci_top(ci));
2670 state.try_bin_tm(
2671 &ra_v,
2672 Some(ra_idx),
2673 &rb_v,
2674 Some(rb_idx),
2675 result_idx,
2676 tm,
2677 )?;
2678 trap = state.ci_trap(ci);
2679 }
2680 OpCode::MmBinI => {
2681 let ra_idx = base + i.arg_a();
2682 let ra_v = state.get_at(ra_idx);
2683 let imm = i.arg_s_b() as i64;
2684 let tm = tagmethod_from_index(i.arg_c() as usize);
2685 let flip = i.arg_k() != 0;
2686 let prev_inst = code[(pc - 2) as usize];
2687 let result_idx = base + prev_inst.arg_a();
2688 state.set_ci_savedpc(ci, pc);
2689 state.set_top(state.ci_top(ci));
2690 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2691 trap = state.ci_trap(ci);
2692 }
2693 OpCode::MmBinK => {
2694 let ra_idx = base + i.arg_a();
2695 let ra_v = state.get_at(ra_idx);
2696 let imm = constants[i.arg_b() as usize];
2697 let tm = tagmethod_from_index(i.arg_c() as usize);
2698 let flip = i.arg_k() != 0;
2699 let prev_inst = code[(pc - 2) as usize];
2700 let result_idx = base + prev_inst.arg_a();
2701 state.set_ci_savedpc(ci, pc);
2702 state.set_top(state.ci_top(ci));
2703 state.try_bin_assoc_tm(
2704 &ra_v,
2705 Some(ra_idx),
2706 &imm,
2707 None,
2708 flip,
2709 result_idx,
2710 tm,
2711 )?;
2712 trap = state.ci_trap(ci);
2713 }
2714 OpCode::Unm => {
2718 let ra = base + i.arg_a();
2719 let rb_idx = base + i.arg_b();
2720 let rb_v = state.get_at(rb_idx);
2721 match &rb_v {
2722 LuaValue::Int(ib) => {
2723 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2724 }
2725 LuaValue::Float(nb) => {
2726 state.set_at(ra, LuaValue::Float(-nb));
2727 }
2728 _ => {
2729 state.set_ci_savedpc(ci, pc);
2730 state.set_top(state.ci_top(ci));
2731 state.try_bin_tm(
2732 &rb_v,
2733 Some(rb_idx),
2734 &rb_v,
2735 Some(rb_idx),
2736 ra,
2737 TagMethod::Unm,
2738 )?;
2739 trap = state.ci_trap(ci);
2740 }
2741 }
2742 }
2743 OpCode::BNot => {
2745 let ra = base + i.arg_a();
2746 let rb_idx = base + i.arg_b();
2747 let rb_v = state.get_at(rb_idx);
2748 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2749 state.set_at(ra, LuaValue::Int(!ib));
2750 } else {
2751 state.set_ci_savedpc(ci, pc);
2752 state.set_top(state.ci_top(ci));
2753 state.try_bin_tm(
2754 &rb_v,
2755 Some(rb_idx),
2756 &rb_v,
2757 Some(rb_idx),
2758 ra,
2759 TagMethod::Bnot,
2760 )?;
2761 trap = state.ci_trap(ci);
2762 }
2763 }
2764 OpCode::Not => {
2766 let ra = base + i.arg_a();
2767 let rb_v = state.get_at(base + i.arg_b());
2768 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2769 state.set_at(ra, LuaValue::Bool(falsy));
2770 }
2771 OpCode::Len => {
2773 let ra = base + i.arg_a();
2774 let rb_idx = base + i.arg_b();
2775 let rb_v = state.get_at(rb_idx);
2776 state.set_ci_savedpc(ci, pc);
2777 state.set_top(state.ci_top(ci));
2778 obj_len(state, ra, rb_v, rb_idx)?;
2779 trap = state.ci_trap(ci);
2780 }
2781 OpCode::Concat => {
2783 let ra = base + i.arg_a();
2784 let n = i.arg_b() as i32;
2785 state.set_top(ra + n as i32);
2786 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2788 let top = state.top_idx();
2789 state.set_ci_savedpc(ci, pc);
2790 state.set_top(top);
2791 state.gc_cond_step();
2792 trap = state.ci_trap(ci);
2793 }
2794 OpCode::Close => {
2796 let ra = base + i.arg_a();
2797 state.set_ci_savedpc(ci, pc);
2798 state.set_top(state.ci_top(ci));
2799 crate::func::close(
2800 state,
2801 ra,
2802 lua_types::status::LuaStatus::Ok as i32,
2803 true,
2804 )?;
2805 trap = state.ci_trap(ci);
2806 }
2807 OpCode::Tbc => {
2809 let ra = base + i.arg_a();
2810 state.set_ci_savedpc(ci, pc);
2811 state.set_top(state.ci_top(ci));
2812 state.new_tbc_upval(ra)?;
2813 }
2814 OpCode::Jmp => {
2816 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2817 trap = state.ci_trap(ci);
2818 }
2819 OpCode::Eq => {
2821 let ra_v = state.get_at(base + i.arg_a());
2822 let rb_v = state.get_at(base + i.arg_b());
2823 state.set_ci_savedpc(ci, pc);
2824 state.set_top(state.ci_top(ci));
2825 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2826 trap = state.ci_trap(ci);
2827 if (cond as i32) != i.arg_k() {
2828 pc += 1;
2829 } else {
2830 let next = code[pc as usize];
2831 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2832 trap = state.ci_trap(ci);
2833 }
2834 }
2835 OpCode::Lt => {
2837 let ra_v = state.get_at(base + i.arg_a());
2838 let rb_v = state.get_at(base + i.arg_b());
2839 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2840 *ia < *ib
2841 } else if matches!(
2842 (&ra_v, &rb_v),
2843 (
2844 LuaValue::Int(_) | LuaValue::Float(_),
2845 LuaValue::Int(_) | LuaValue::Float(_)
2846 )
2847 ) {
2848 lt_num(&ra_v, &rb_v)
2849 } else {
2850 state.set_ci_savedpc(ci, pc);
2851 state.set_top(state.ci_top(ci));
2852 let r = less_than_others(state, &ra_v, &rb_v)?;
2853 trap = state.ci_trap(ci);
2854 r
2855 };
2856 if (cond as i32) != i.arg_k() {
2857 pc += 1;
2858 } else {
2859 let next = code[pc as usize];
2860 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2861 trap = state.ci_trap(ci);
2862 }
2863 }
2864 OpCode::Le => {
2866 let ra_v = state.get_at(base + i.arg_a());
2867 let rb_v = state.get_at(base + i.arg_b());
2868 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2869 *ia <= *ib
2870 } else if matches!(
2871 (&ra_v, &rb_v),
2872 (
2873 LuaValue::Int(_) | LuaValue::Float(_),
2874 LuaValue::Int(_) | LuaValue::Float(_)
2875 )
2876 ) {
2877 le_num(&ra_v, &rb_v)
2878 } else {
2879 state.set_ci_savedpc(ci, pc);
2880 state.set_top(state.ci_top(ci));
2881 let r = less_equal_others(state, &ra_v, &rb_v)?;
2882 trap = state.ci_trap(ci);
2883 r
2884 };
2885 if (cond as i32) != i.arg_k() {
2886 pc += 1;
2887 } else {
2888 let next = code[pc as usize];
2889 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2890 trap = state.ci_trap(ci);
2891 }
2892 }
2893 OpCode::EqK => {
2895 let ra_v = state.get_at(base + i.arg_a());
2896 let rb_v = constants[i.arg_b() as usize];
2897 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2898 if (cond as i32) != i.arg_k() {
2899 pc += 1;
2900 } else {
2901 let next = code[pc as usize];
2902 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2903 trap = state.ci_trap(ci);
2904 }
2905 }
2906 OpCode::EqI => {
2911 let ra_v = state.get_at(base + i.arg_a());
2912 let im = i.arg_s_b() as i64;
2913 let cond: bool = match &ra_v {
2914 LuaValue::Int(iv) => *iv == im,
2915 LuaValue::Float(fv) => *fv == im as f64,
2916 _ => false,
2917 };
2918 if (cond as i32) != i.arg_k() {
2919 pc += 1;
2920 } else {
2921 let next = code[pc as usize];
2922 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2923 trap = state.ci_trap(ci);
2924 }
2925 }
2926 OpCode::LtI => {
2929 let ra = base + i.arg_a();
2930 let im = i.arg_s_b() as i64;
2931 let fast_cond = match &state.stack[ra.0 as usize].val {
2932 LuaValue::Int(ia) => Some(*ia < im),
2933 LuaValue::Float(fa) => Some(*fa < im as f64),
2934 _ => None,
2935 };
2936 let cond = match fast_cond {
2937 Some(cond) => cond,
2938 None => order_imm_slow(
2939 state,
2940 ra,
2941 pc,
2942 &mut trap,
2943 ci,
2944 i,
2945 im,
2946 false,
2947 TagMethod::Lt,
2948 )?,
2949 };
2950 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
2951 }
2952 OpCode::LeI => {
2953 let ra = base + i.arg_a();
2954 let im = i.arg_s_b() as i64;
2955 let fast_cond = match &state.stack[ra.0 as usize].val {
2956 LuaValue::Int(ia) => Some(*ia <= im),
2957 LuaValue::Float(fa) => Some(*fa <= im as f64),
2958 _ => None,
2959 };
2960 let cond = match fast_cond {
2961 Some(cond) => cond,
2962 None => order_imm_slow(
2963 state,
2964 ra,
2965 pc,
2966 &mut trap,
2967 ci,
2968 i,
2969 im,
2970 false,
2971 TagMethod::Le,
2972 )?,
2973 };
2974 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
2975 }
2976 OpCode::GtI => {
2977 let ra = base + i.arg_a();
2978 let im = i.arg_s_b() as i64;
2979 let fast_cond = match &state.stack[ra.0 as usize].val {
2980 LuaValue::Int(ia) => Some(*ia > im),
2981 LuaValue::Float(fa) => Some(*fa > im as f64),
2982 _ => None,
2983 };
2984 let cond = match fast_cond {
2985 Some(cond) => cond,
2986 None => order_imm_slow(
2987 state,
2988 ra,
2989 pc,
2990 &mut trap,
2991 ci,
2992 i,
2993 im,
2994 true,
2995 TagMethod::Lt,
2996 )?,
2997 };
2998 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
2999 }
3000 OpCode::GeI => {
3001 let ra = base + i.arg_a();
3002 let im = i.arg_s_b() as i64;
3003 let fast_cond = match &state.stack[ra.0 as usize].val {
3004 LuaValue::Int(ia) => Some(*ia >= im),
3005 LuaValue::Float(fa) => Some(*fa >= im as f64),
3006 _ => None,
3007 };
3008 let cond = match fast_cond {
3009 Some(cond) => cond,
3010 None => order_imm_slow(
3011 state,
3012 ra,
3013 pc,
3014 &mut trap,
3015 ci,
3016 i,
3017 im,
3018 true,
3019 TagMethod::Le,
3020 )?,
3021 };
3022 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3023 }
3024 OpCode::Test => {
3026 let ra_v = state.get_at(base + i.arg_a());
3027 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
3028 if (cond as i32) != i.arg_k() {
3029 pc += 1;
3030 } else {
3031 let next = code[pc as usize];
3032 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3033 trap = state.ci_trap(ci);
3034 }
3035 }
3036 OpCode::TestSet => {
3039 let ra = base + i.arg_a();
3040 let rb_v = state.get_at(base + i.arg_b());
3041 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
3042 if (falsy as i32) == i.arg_k() {
3043 pc += 1;
3044 } else {
3045 state.set_at(ra, rb_v);
3046 let next = code[pc as usize];
3047 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3048 trap = state.ci_trap(ci);
3049 }
3050 }
3051 OpCode::Call => {
3055 let ra = base + i.arg_a();
3056 let b = i.arg_b();
3057 let nresults = i.arg_c() as i32 - 1;
3058 if b != 0 {
3059 state.set_top(ra + b);
3060 }
3061 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
3063 match state.precall(ra, nresults)? {
3064 None => {
3065 if had_hook || state.hookmask != 0 {
3069 trap = state.ci_trap(ci); }
3071 }
3072 Some(new_ci) => {
3073 ci = new_ci;
3075 continue 'startfunc;
3076 }
3077 }
3078 }
3079 OpCode::TailCall => {
3084 let ra = base + i.arg_a();
3085 let b = i.arg_b();
3086 let nparams1 = i.arg_c();
3087 let delta = if nparams1 != 0 {
3088 state.ci_nextraargs(ci) + nparams1 as i32
3089 } else {
3090 0
3091 };
3092 let top_b: i32 = if b != 0 {
3093 state.set_top(ra + b);
3094 b
3095 } else {
3096 state.top_idx() - ra
3097 };
3098 state.set_ci_savedpc(ci, pc);
3099 if i.test_k() {
3100 state.close_upvals_from_base(ci)?;
3101 }
3102 let n = state.pretailcall(ci, ra, top_b, delta)?;
3103 if n < 0 {
3104 continue 'startfunc;
3106 } else {
3107 state.ci_adjust_func(ci, delta);
3109 state.poscall(ci, n as u32)?;
3110 if state.hookmask != 0 {
3111 trap = state.ci_trap(ci);
3112 }
3113 break 'dispatch; }
3115 }
3116 OpCode::Return => {
3121 let ra = base + i.arg_a();
3122 let n_raw = i.arg_b() as i32 - 1;
3123 let nparams1 = i.arg_c();
3124 let n: u32 = if n_raw < 0 {
3125 (state.top_idx() - ra) as u32
3126 } else {
3127 n_raw as u32
3128 };
3129 state.set_ci_savedpc(ci, pc);
3130 if i.test_k() {
3131 state.ci_nres_set(ci, n as i32);
3132 let ci_top = state.ci_top(ci);
3133 if state.top_idx().0 < ci_top.0 {
3134 state.set_top(ci_top);
3135 }
3136 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
3137 if state.hookmask != 0 {
3138 trap = state.ci_trap(ci);
3139 }
3140 base = state.ci_base(ci); }
3142 if nparams1 != 0 {
3143 let nextraargs = state.ci_nextraargs(ci) as u32;
3144 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
3145 }
3146 state.set_top(ra + n as i32);
3147 state.poscall(ci, n)?;
3148 if state.hookmask != 0 {
3149 trap = state.ci_trap(ci);
3150 }
3151 break 'dispatch; }
3153 OpCode::Return0 => {
3159 if state.hookmask == 0 {
3160 let ci_slot = ci.as_usize();
3161 let nres = state.call_info[ci_slot].nresults as i32;
3162 state.ci = state.call_info[ci_slot]
3163 .previous
3164 .expect("RETURN0: returning frame has no previous CallInfo");
3165 state.top = base - 1;
3166 for _ in 0..nres.max(0) {
3167 state.push(LuaValue::Nil);
3168 }
3169 } else {
3170 return0_hook(state, ci, base, i, pc, &mut trap)?;
3171 }
3172 break 'dispatch; }
3174 OpCode::Return1 => {
3178 if state.hookmask == 0 {
3179 let ci_slot = ci.as_usize();
3180 let nres = state.call_info[ci_slot].nresults as i32;
3181 state.ci = state.call_info[ci_slot]
3182 .previous
3183 .expect("RETURN1: returning frame has no previous CallInfo");
3184 if nres == 0 {
3185 state.top = base - 1;
3186 } else {
3187 let ra = base + i.arg_a();
3188 state.stack[(base - 1).0 as usize].val =
3189 state.stack[ra.0 as usize].val; state.top = base;
3191 for _ in 1..nres.max(0) {
3192 state.push(LuaValue::Nil);
3193 }
3194 }
3195 } else {
3196 return1_hook(state, ci, base, i, pc, &mut trap)?;
3197 }
3198 break 'dispatch; }
3200 OpCode::ForLoop => {
3204 let ra = base + i.arg_a();
3205 if legacy_for {
3206 if forloop_legacy(state, ra) {
3207 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3208 }
3209 if state.hookmask != 0 {
3210 trap = state.ci_trap(ci);
3211 }
3212 } else {
3213 let ra_u = ra.0 as usize;
3214 let window: &mut [crate::state::StackValue; 4] = (&mut state.stack
3215 [ra_u..ra_u + 4])
3216 .try_into()
3217 .expect("FORLOOP register window");
3218 if let LuaValue::Int(step) = window[2].val {
3219 let count = match window[1].val {
3220 LuaValue::Int(c) => c as u64,
3221 _ => 0,
3222 };
3223 if count > 0 {
3224 let idx = match window[0].val {
3225 LuaValue::Int(x) => x,
3226 _ => 0,
3227 };
3228 window[1].val = LuaValue::Int((count - 1) as i64);
3229 let new_idx = intop_add(idx, step);
3230 window[0].val = LuaValue::Int(new_idx);
3231 window[3].val = LuaValue::Int(new_idx);
3232 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3233 }
3234 } else if float_for_loop(state, ra) {
3235 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3236 }
3237 if state.hookmask != 0 {
3238 trap = state.ci_trap(ci);
3239 }
3240 }
3241 }
3242 OpCode::ForPrep => {
3244 let ra = base + i.arg_a();
3245 state.set_ci_savedpc(ci, pc);
3246 state.set_top(state.ci_top(ci));
3247 if legacy_for {
3248 forprep_legacy(state, ra)?;
3251 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3252 } else if forprep(state, ra)? {
3253 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
3254 }
3255 }
3256 OpCode::TForPrep => {
3260 let ra = base + i.arg_a();
3261 state.set_ci_savedpc(ci, pc);
3262 state.set_top(state.ci_top(ci));
3263 if tfor_55 {
3264 let closing = state.get_at(ra + 3);
3265 let control = state.get_at(ra + 2);
3266 state.set_at(ra + 2, closing);
3267 state.set_at(ra + 3, control);
3268 state.new_tbc_upval(ra + 2)?;
3269 } else {
3270 state.new_tbc_upval(ra + 3)?;
3271 }
3272 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3273 let tfc_i = code[pc as usize];
3274 pc += 1;
3275 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
3276 let tfc_ra = base + tfc_i.arg_a();
3278 if tfor_55 {
3279 let src = tfc_ra.0 as usize;
3280 let func = state.stack[src].val.clone();
3281 let state_val = state.stack[src + 1].val.clone();
3282 let control = state.stack[src + 3].val.clone();
3283 state.stack[src + 3].val = func;
3284 state.stack[src + 4].val = state_val;
3285 state.stack[src + 5].val = control;
3286 state.set_top(tfc_ra + 6);
3287 state.set_ci_savedpc(ci, pc);
3288 if !state.call_known_c_at(tfc_ra + 3, tfc_i.arg_c() as i32)? {
3289 state.call_at(tfc_ra + 3, tfc_i.arg_c() as i32)?;
3290 }
3291 } else {
3292 let src = tfc_ra.0 as usize;
3293 let dst = src + 4;
3294 for k in 0..3usize {
3295 state.stack[dst + k].val = state.stack[src + k].val.clone();
3296 }
3297 state.set_top(tfc_ra + 4 + 3);
3298 state.set_ci_savedpc(ci, pc);
3299 if !state.call_known_c_at(tfc_ra + 4, tfc_i.arg_c() as i32)? {
3300 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
3301 }
3302 }
3303 trap = state.ci_trap(ci);
3304 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3306 pc += 1;
3307 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3308 let tfl_ra = base + tfl_i.arg_a();
3309 if tfor_55 {
3311 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3312 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3313 }
3314 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3315 let v = state.get_at(tfl_ra + 4);
3316 state.set_at(tfl_ra + 2, v);
3317 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3318 }
3319 }
3320 OpCode::TForCall => {
3322 let ra = base + i.arg_a();
3323 if tfor_55 {
3324 let src = ra.0 as usize;
3325 let func = state.stack[src].val.clone();
3326 let state_val = state.stack[src + 1].val.clone();
3327 let control = state.stack[src + 3].val.clone();
3328 state.stack[src + 3].val = func;
3329 state.stack[src + 4].val = state_val;
3330 state.stack[src + 5].val = control;
3331 state.set_top(ra + 6);
3332 state.set_ci_savedpc(ci, pc);
3333 if !state.call_known_c_at(ra + 3, i.arg_c() as i32)? {
3334 state.call_at(ra + 3, i.arg_c() as i32)?;
3335 }
3336 } else {
3337 let src = ra.0 as usize;
3338 let dst = src + 4;
3339 for k in 0..3usize {
3340 state.stack[dst + k].val = state.stack[src + k].val.clone();
3341 }
3342 state.set_top(ra + 4 + 3);
3343 state.set_ci_savedpc(ci, pc);
3344 if !state.call_known_c_at(ra + 4, i.arg_c() as i32)? {
3345 state.call_at(ra + 4, i.arg_c() as i32)?;
3346 }
3347 }
3348 trap = state.ci_trap(ci);
3349 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3351 pc += 1;
3352 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3353 let tfl_ra = base + tfl_i.arg_a();
3354 if tfor_55 {
3355 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3356 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3357 }
3358 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3359 let v = state.get_at(tfl_ra + 4);
3360 state.set_at(tfl_ra + 2, v);
3361 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3362 }
3363 }
3364 OpCode::TForLoop => {
3366 let ra = base + i.arg_a();
3367 if tfor_55 {
3368 if !matches!(state.get_at(ra + 3), LuaValue::Nil) {
3369 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3370 }
3371 } else if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
3372 let v = state.get_at(ra + 4);
3373 state.set_at(ra + 2, v);
3374 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3375 }
3376 }
3377 OpCode::SetList => {
3381 let ra = base + i.arg_a();
3382 let n_raw = i.arg_b();
3383 let mut last = i.arg_c();
3384 let t_val = state.get_at(ra);
3385 let n: i32 = if n_raw == 0 {
3386 state.top_idx() - ra - 1
3387 } else {
3388 state.set_top(state.ci_top(ci));
3389 n_raw
3390 };
3391 last += n;
3392 if i.test_k() {
3393 let extra = code[pc as usize];
3394 pc += 1;
3395 const MAXARG_C: i32 = (1 << 8) - 1;
3396 last += extra.arg_ax() * (MAXARG_C + 1);
3397 }
3398 state.table_ensure_array(&t_val, last as usize)?;
3399 for k in (1..=n).rev() {
3400 let val = state.get_at(ra + k as i32);
3401 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
3402 last -= 1;
3403 state.gc_value_barrier_back(&t_val, &val);
3404 }
3405 }
3406 OpCode::Closure => {
3410 let ra = base + i.arg_a();
3411 let proto_idx = i.arg_bx() as usize;
3412 state.set_ci_savedpc(ci, pc);
3413 state.set_top(state.ci_top(ci));
3414 push_closure(state, proto_idx, ci, base, ra)?;
3415 state.set_ci_savedpc(ci, pc);
3417 state.set_top(ra + 1);
3418 state.gc_cond_step();
3419 trap = state.ci_trap(ci);
3420 }
3421 OpCode::VarArg => {
3423 let ra = base + i.arg_a();
3424 let n = i.arg_c() as i32 - 1;
3425 state.set_ci_savedpc(ci, pc);
3426 state.set_top(state.ci_top(ci));
3427 state.get_varargs(ci, ra, n)?;
3428 trap = state.ci_trap(ci);
3429 }
3430 OpCode::VarArgPrep => {
3434 let nparams = i.arg_a();
3435 state.set_ci_savedpc(ci, pc);
3436 state.adjust_varargs(ci, nparams, &cl)?;
3437 trap = state.ci_trap(ci);
3438 if trap {
3439 state.hook_call(ci)?;
3440 state.set_oldpc(1);
3441 }
3442 base = state.ci_base(ci);
3443 }
3444 OpCode::GetVArg => {
3446 let ra = base + i.arg_a();
3447 let vararg_reg = base + i.arg_b();
3448 let key = state.get_at(base + i.arg_c()).clone();
3449 let val = if let LuaValue::Table(t) = state.get_at(vararg_reg) {
3450 t.get(&key)
3451 } else {
3452 let nextra = state.ci_nextraargs(ci);
3453 match key {
3454 LuaValue::Int(n) if n >= 1 && n <= nextra as i64 => {
3455 let ci_func = state.ci_base(ci) - 1;
3456 state.get_at(ci_func - nextra + n as i32 - 1)
3457 }
3458 LuaValue::Float(f)
3459 if f.is_finite()
3460 && f.fract() == 0.0
3461 && f >= 1.0
3462 && f <= nextra as f64 =>
3463 {
3464 let ci_func = state.ci_base(ci) - 1;
3465 state.get_at(ci_func - nextra + f as i32 - 1)
3466 }
3467 LuaValue::Str(s) if s.as_bytes() == b"n" => {
3468 LuaValue::Int(nextra as i64)
3469 }
3470 _ => LuaValue::Nil,
3471 }
3472 };
3473 state.set_at(ra, val);
3474 }
3475 OpCode::ExtraArg => {
3477 debug_assert!(false, "OP_EXTRAARG executed directly");
3478 }
3479 OpCode::ErrNNil => {
3484 let ra = base + i.arg_a();
3485 if !matches!(state.get_at(ra), LuaValue::Nil) {
3486 let bx = i.arg_bx();
3487 let name: Vec<u8> = if bx == 0 {
3488 b"?".to_vec()
3489 } else {
3490 match constants[(bx - 1) as usize] {
3491 LuaValue::Str(s) => s.as_bytes().to_vec(),
3492 _ => b"?".to_vec(),
3493 }
3494 };
3495 let mut msg = Vec::with_capacity(name.len() + 24);
3496 msg.extend_from_slice(b"global '");
3497 msg.extend_from_slice(&name);
3498 msg.extend_from_slice(b"' already defined");
3499 state.set_ci_savedpc(ci, pc);
3500 return Err(crate::debug::prefixed_runtime_pub(state, msg));
3501 }
3502 }
3503 OpCode::VarArgPack => {
3511 if !cl.proto.vararg_table_needed && !i.test_k() {
3512 state.set_ci_savedpc(ci, pc);
3513 continue;
3514 }
3515 let ra = base + i.arg_a();
3516 let nextra = state.ci_nextraargs(ci);
3517 let ci_func: StackIdx = state.ci_base(ci) - 1;
3518 let t = if nextra > 0 {
3519 state.new_table_with_sizes(nextra as u32, 1)?
3520 } else {
3521 state.new_table()
3522 };
3523 for k in 0..nextra {
3524 let src: StackIdx = ci_func - nextra as i32 + k as i32;
3525 let val = state.get_at(src);
3526 t.raw_set_int(state, (k + 1) as i64, val)?;
3527 }
3528 let n_key = state.intern_str(b"n")?;
3529 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
3530 state.set_at(ra, LuaValue::Table(t));
3531 state.set_ci_savedpc(ci, pc);
3532 state.set_top(ra + 1);
3533 state.gc_cond_step();
3534 if state.hookmask != 0 {
3535 trap = state.ci_trap(ci);
3536 }
3537 }
3538 } } if state.ci_is_fresh(ci) {
3543 return Ok(());
3544 } else {
3545 ci = state
3546 .ci_previous(ci)
3547 .expect("ci_previous: not fresh frame must have previous");
3548 continue 'returning;
3549 }
3550 } } }
3553
3554#[inline(always)]
3557fn number_value(v: LuaValue) -> Option<f64> {
3558 match v {
3559 LuaValue::Float(f) => Some(f),
3560 LuaValue::Int(i) => Some(i as f64),
3561 _ => None,
3562 }
3563}
3564
3565#[allow(dead_code)]
3567#[inline]
3568fn arith_op_aux_rr(
3569 state: &mut LuaState,
3570 ra: StackIdx,
3571 v1: &LuaValue,
3572 v2: &LuaValue,
3573 pc: &mut u32,
3574 iop: fn(i64, i64) -> i64,
3575 fop: fn(f64, f64) -> f64,
3576) {
3577 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3578 *pc += 1;
3579 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3580 } else {
3581 arith_float_aux(state, ra, v1, v2, pc, fop);
3582 }
3583}
3584
3585#[allow(dead_code)]
3586#[inline]
3587fn arith_float_aux(
3588 state: &mut LuaState,
3589 ra: StackIdx,
3590 v1: &LuaValue,
3591 v2: &LuaValue,
3592 pc: &mut u32,
3593 fop: fn(f64, f64) -> f64,
3594) {
3595 let n1 = match v1 {
3596 LuaValue::Float(f) => Some(*f),
3597 LuaValue::Int(i) => Some(*i as f64),
3598 _ => None,
3599 };
3600 let n2 = match v2 {
3601 LuaValue::Float(f) => Some(*f),
3602 LuaValue::Int(i) => Some(*i as f64),
3603 _ => None,
3604 };
3605 if let (Some(n1), Some(n2)) = (n1, n2) {
3606 *pc += 1;
3607 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3608 }
3609}
3610
3611#[allow(dead_code)]
3612#[inline]
3613fn arith_op_checked(
3614 state: &mut LuaState,
3615 ra: StackIdx,
3616 v1: &LuaValue,
3617 v2: &LuaValue,
3618 pc: &mut u32,
3619 iop: fn(i64, i64) -> Result<i64, LuaError>,
3620 fop: fn(f64, f64) -> f64,
3621) -> Result<(), LuaError> {
3622 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3623 *pc += 1;
3624 let result = iop(*i1, *i2).map_err(|e| match e {
3625 LuaError::Runtime(LuaValue::Str(s)) => {
3626 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3627 }
3628 other => other,
3629 })?;
3630 state.set_at(ra, LuaValue::Int(result));
3631 } else {
3632 arith_float_aux(state, ra, v1, v2, pc, fop);
3633 }
3634 Ok(())
3635}
3636
3637#[allow(dead_code)]
3638#[inline]
3639fn bitwise_op_k(
3640 state: &mut LuaState,
3641 ra: StackIdx,
3642 v1: &LuaValue,
3643 v2: &LuaValue, pc: &mut u32,
3645 op: fn(i64, i64) -> i64,
3646) {
3647 let i2 = match v2 {
3648 LuaValue::Int(i) => *i,
3649 _ => return,
3650 };
3651 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3652 *pc += 1;
3653 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3654 }
3655}
3656
3657#[allow(dead_code)]
3658#[inline]
3659fn bitwise_op_rr(
3660 state: &mut LuaState,
3661 ra: StackIdx,
3662 v1: &LuaValue,
3663 v2: &LuaValue,
3664 pc: &mut u32,
3665 op: fn(i64, i64) -> i64,
3666) {
3667 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3668 *pc += 1;
3669 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3670 }
3671}
3672
3673#[allow(dead_code)]
3675#[inline]
3676fn bitwise_shift_rr(
3677 state: &mut LuaState,
3678 ra: StackIdx,
3679 v1: &LuaValue,
3680 v2: &LuaValue,
3681 pc: &mut u32,
3682 right: bool,
3683) {
3684 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3685 let y = if right { intop_sub(0, i2) } else { i2 };
3686 *pc += 1;
3687 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3688 }
3689}
3690
3691#[cold]
3694#[inline(never)]
3695#[allow(clippy::too_many_arguments)]
3696fn order_imm_slow(
3697 state: &mut LuaState,
3698 ra: StackIdx,
3699 pc: u32,
3700 trap: &mut bool,
3701 ci: CallInfoIdx,
3702 i: Instruction,
3703 im: i64,
3704 inv: bool,
3705 tm: TagMethod,
3706) -> Result<bool, LuaError> {
3707 let ra_v = state.get_at(ra);
3708 let isf = i.arg_c() != 0;
3709 state.set_ci_savedpc(ci, pc);
3710 state.set_top(state.ci_top(ci));
3711 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3712 *trap = state.ci_trap(ci);
3713 Ok(r)
3714}
3715
3716#[inline(always)]
3717fn finish_order_imm_jump(
3718 state: &mut LuaState,
3719 code: &[Instruction],
3720 pc: &mut u32,
3721 trap: &mut bool,
3722 ci: CallInfoIdx,
3723 i: Instruction,
3724 cond: bool,
3725) {
3726 if (cond as i32) != i.arg_k() {
3727 *pc += 1;
3728 } else {
3729 let next = code[*pc as usize];
3730 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3731 if state.hookmask != 0 {
3732 *trap = state.ci_trap(ci);
3733 }
3734 }
3735}
3736
3737#[cold]
3738#[inline(never)]
3739fn return0_hook(
3740 state: &mut LuaState,
3741 ci: CallInfoIdx,
3742 base: StackIdx,
3743 i: Instruction,
3744 pc: u32,
3745 trap: &mut bool,
3746) -> Result<(), LuaError> {
3747 let ra = base + i.arg_a();
3748 state.set_top(ra);
3749 state.set_ci_savedpc(ci, pc);
3750 state.poscall(ci, 0)?;
3751 *trap = true;
3752 Ok(())
3753}
3754
3755#[cold]
3756#[inline(never)]
3757fn return1_hook(
3758 state: &mut LuaState,
3759 ci: CallInfoIdx,
3760 base: StackIdx,
3761 i: Instruction,
3762 pc: u32,
3763 trap: &mut bool,
3764) -> Result<(), LuaError> {
3765 let ra = base + i.arg_a();
3766 state.set_top(ra + 1);
3767 state.set_ci_savedpc(ci, pc);
3768 state.poscall(ci, 1)?;
3769 *trap = true;
3770 Ok(())
3771}
3772
3773