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 matches!(
902 state.global().lua_version,
903 lua_types::LuaVersion::V51 | lua_types::LuaVersion::V52
904 ) && !matches!(init, LuaValue::Int(_))
905 && tonumber(&init).is_none()
906 {
907 return Err(crate::debug::for_error(state, &init, b"initial value"));
908 }
909
910 if let (LuaValue::Int(initv), LuaValue::Int(stepv)) = (&init, &pstep) {
911 let (initv, stepv) = (*initv, *stepv);
912 if let Some((ilimit, stopnow)) = forlimit_legacy(&plimit, stepv) {
913 let base = if stopnow { 0 } else { initv };
914 state.set_at(ra + 1, LuaValue::Int(ilimit));
915 state.set_at(ra, LuaValue::Int(intop_sub(base, stepv)));
916 return Ok(());
917 }
918 }
921
922 let nlimit = match tonumber(&plimit) {
923 Some(f) => f,
924 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
925 };
926 let nstep = match tonumber(&pstep) {
927 Some(f) => f,
928 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
929 };
930 let ninit = match tonumber(&init) {
931 Some(f) => f,
932 None => return Err(crate::debug::for_error(state, &init, b"initial value")),
933 };
934 state.set_at(ra + 1, LuaValue::Float(nlimit));
935 state.set_at(ra + 2, LuaValue::Float(nstep));
936 state.set_at(ra, LuaValue::Float(ninit - nstep));
937 Ok(())
938}
939
940fn forloop_legacy(state: &mut LuaState, ra: StackIdx) -> bool {
945 if let LuaValue::Int(step) = state.get_at(ra + 2) {
946 let idx = intop_add(
947 match state.get_at(ra) {
948 LuaValue::Int(x) => x,
949 _ => 0,
950 },
951 step,
952 );
953 let limit = match state.get_at(ra + 1) {
954 LuaValue::Int(l) => l,
955 _ => 0,
956 };
957 let cont = if step > 0 { idx <= limit } else { limit <= idx };
958 if cont {
959 state.set_at(ra, LuaValue::Int(idx));
960 state.set_at(ra + 3, LuaValue::Int(idx));
961 }
962 cont
963 } else {
964 let step = match state.get_at(ra + 2) {
965 LuaValue::Float(f) => f,
966 _ => return false,
967 };
968 let idx = match state.get_at(ra) {
969 LuaValue::Float(f) => f,
970 _ => return false,
971 } + step;
972 let limit = match state.get_at(ra + 1) {
973 LuaValue::Float(f) => f,
974 _ => return false,
975 };
976 let cont = if step > 0.0 {
977 idx <= limit
978 } else {
979 limit <= idx
980 };
981 if cont {
982 state.set_at(ra, LuaValue::Float(idx));
983 state.set_at(ra + 3, LuaValue::Float(idx));
984 }
985 cont
986 }
987}
988
989fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
991 let step = match state.get_at(ra + 2) {
993 LuaValue::Float(f) => f,
994 _ => return false,
995 };
996 let limit = match state.get_at(ra + 1) {
997 LuaValue::Float(f) => f,
998 _ => return false,
999 };
1000 let idx = match state.get_at(ra) {
1001 LuaValue::Float(f) => f,
1002 _ => return false,
1003 };
1004 let idx = idx + step;
1005 if if step > 0.0 {
1006 idx <= limit
1007 } else {
1008 limit <= idx
1009 } {
1010 state.set_at(ra, LuaValue::Float(idx));
1011 state.set_at(ra + 3, LuaValue::Float(idx));
1012 true
1013 } else {
1014 false
1015 }
1016}
1017
1018pub(crate) fn finish_get(
1024 state: &mut LuaState,
1025 t_val: LuaValue,
1026 key: LuaValue,
1027 result_idx: StackIdx,
1028 slot_empty: bool,
1029 t_idx: Option<StackIdx>,
1030 var_hint: Option<(&[u8], &[u8])>,
1031) -> Result<(), LuaError> {
1032 let mut t = t_val;
1033 let mut t_idx = t_idx;
1034 for _loop in 0..MAX_TAG_LOOP {
1035 let tm: LuaValue;
1036 if slot_empty && !matches!(t, LuaValue::Table(_)) {
1037 tm = state.get_tm_by_obj(&t, TagMethod::Index);
1038 if matches!(tm, LuaValue::Nil) {
1039 return Err(match (t_idx, var_hint) {
1040 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
1041 (None, Some((kind, name))) => {
1042 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
1043 }
1044 (None, None) => LuaError::type_error(&t, "index"),
1045 });
1046 }
1047 } else {
1048 let mt = state.table_metatable(&t);
1049 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
1050 if matches!(tm, LuaValue::Nil) {
1051 state.set_at(result_idx, LuaValue::Nil);
1052 return Ok(());
1053 }
1054 }
1055 if matches!(tm, LuaValue::Function(_)) {
1056 state.call_tm_res(tm, &t, &key, result_idx)?;
1057 return Ok(());
1058 }
1059 t = tm.clone();
1060 t_idx = None;
1061 if let Some(v) = state.fast_get(&t, &key)? {
1062 state.set_at(result_idx, v);
1063 return Ok(());
1064 }
1065 }
1067 Err(LuaError::runtime(format_args!(
1068 "'__index' chain too long; possible loop"
1069 )))
1070}
1071
1072pub(crate) fn finish_set(
1081 state: &mut LuaState,
1082 t_val: LuaValue,
1083 key: LuaValue,
1084 val: LuaValue,
1085 _slot_present: bool,
1086 t_idx: Option<StackIdx>,
1087 var_hint: Option<(&[u8], &[u8])>,
1088) -> Result<(), LuaError> {
1089 let mut t = t_val;
1090 let mut t_idx = t_idx;
1091 for _loop in 0..MAX_TAG_LOOP {
1092 let tm: LuaValue;
1093 if matches!(t, LuaValue::Table(_)) {
1094 let mt = state.table_metatable(&t);
1095 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
1096 if matches!(tm, LuaValue::Nil) {
1097 state.table_raw_set(&t, key, val.clone())?;
1098 state.gc_value_barrier_back(&t, &val);
1099 return Ok(());
1100 }
1101 } else {
1102 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
1103 if matches!(tm, LuaValue::Nil) {
1104 return Err(match (t_idx, var_hint) {
1105 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
1106 (None, Some((kind, name))) => {
1107 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
1108 }
1109 (None, None) => LuaError::type_error(&t, "index"),
1110 });
1111 }
1112 }
1113 if matches!(tm, LuaValue::Function(_)) {
1114 state.call_tm(tm, &t, &key, &val)?;
1115 return Ok(());
1116 }
1117 t = tm.clone();
1118 t_idx = None;
1119 if state.fast_get(&t, &key)?.is_some() {
1120 state.table_raw_set(&t, key.clone(), val.clone())?;
1121 state.gc_value_barrier_back(&t, &val);
1122 return Ok(());
1123 }
1124 }
1125 Err(LuaError::runtime(format_args!(
1126 "'__newindex' chain too long; possible loop"
1127 )))
1128}
1129
1130fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
1141 let mut s1 = s1;
1144 let mut s2 = s2;
1145 loop {
1146 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
1148 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
1149 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
1151 if seg_cmp != std::cmp::Ordering::Equal {
1152 return seg_cmp;
1153 }
1154 if z2 == s2.len() {
1156 if z1 == s1.len() {
1158 return std::cmp::Ordering::Equal;
1159 }
1160 return std::cmp::Ordering::Greater; }
1162 if z1 == s1.len() {
1163 return std::cmp::Ordering::Less; }
1165 s1 = &s1[z1 + 1..];
1167 s2 = &s2[z2 + 1..];
1168 }
1169}
1170
1171#[inline]
1174fn lt_int_float(i: i64, f: f64) -> bool {
1175 if int_fits_float(i) {
1176 (i as f64) < f
1177 } else {
1178 match flt_to_integer(f, F2Imod::Ceil) {
1179 Some(fi) => i < fi,
1180 None => f > 0.0, }
1182 }
1183}
1184
1185#[inline]
1186fn le_int_float(i: i64, f: f64) -> bool {
1187 if int_fits_float(i) {
1188 (i as f64) <= f
1189 } else {
1190 match flt_to_integer(f, F2Imod::Floor) {
1191 Some(fi) => i <= fi,
1192 None => f > 0.0,
1193 }
1194 }
1195}
1196
1197#[inline]
1198fn lt_float_int(f: f64, i: i64) -> bool {
1199 if int_fits_float(i) {
1200 f < (i as f64)
1201 } else {
1202 match flt_to_integer(f, F2Imod::Floor) {
1203 Some(fi) => fi < i,
1204 None => f < 0.0,
1205 }
1206 }
1207}
1208
1209#[inline]
1210fn le_float_int(f: f64, i: i64) -> bool {
1211 if int_fits_float(i) {
1212 f <= (i as f64)
1213 } else {
1214 match flt_to_integer(f, F2Imod::Ceil) {
1215 Some(fi) => fi <= i,
1216 None => f < 0.0,
1217 }
1218 }
1219}
1220
1221#[inline]
1222fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
1223 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1224 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1225 match (l, r) {
1226 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1227 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1228 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1229 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1230 _ => false,
1231 }
1232}
1233
1234#[inline]
1235fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1236 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1237 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1238 match (l, r) {
1239 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1240 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1241 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1242 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1243 _ => false,
1244 }
1245}
1246
1247fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1249 debug_assert!(
1250 !(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1251 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_)))
1252 );
1253 match (l, r) {
1254 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1255 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1256 }
1257 _ => state.call_order_tm(l, r, TagMethod::Lt),
1258 }
1259}
1260
1261pub(crate) fn less_than(
1262 state: &mut LuaState,
1263 l: &LuaValue,
1264 r: &LuaValue,
1265) -> Result<bool, LuaError> {
1266 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1267 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1268 {
1269 Ok(lt_num(l, r))
1270 } else {
1271 less_than_others(state, l, r)
1272 }
1273}
1274
1275fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1276 match (l, r) {
1277 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1278 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1279 }
1280 _ => state.call_order_tm(l, r, TagMethod::Le),
1281 }
1282}
1283
1284pub(crate) fn less_equal(
1285 state: &mut LuaState,
1286 l: &LuaValue,
1287 r: &LuaValue,
1288) -> Result<bool, LuaError> {
1289 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1290 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1291 {
1292 Ok(le_num(l, r))
1293 } else {
1294 less_equal_others(state, l, r)
1295 }
1296}
1297
1298pub(crate) fn raw_equal_values(t1: &LuaValue, t2: &LuaValue) -> bool {
1307 matches!(equal_obj(None, t1, t2), Ok(true))
1308}
1309
1310fn equal_tm(state: &mut LuaState, t1: &LuaValue, t2: &LuaValue) -> LuaValue {
1318 let eq = crate::tagmethods::TagMethod::Eq;
1319 if state.global().lua_version == lua_types::LuaVersion::V51 {
1320 return crate::tagmethods::get_comp_tm_51(state, t1, t2, eq);
1321 }
1322 let tm1 = crate::tagmethods::get_tm_by_obj(state, t1, eq);
1323 if tm1.is_nil() {
1324 crate::tagmethods::get_tm_by_obj(state, t2, eq)
1325 } else {
1326 tm1
1327 }
1328}
1329
1330pub(crate) fn equal_obj(
1332 state: Option<&mut LuaState>,
1333 t1: &LuaValue,
1334 t2: &LuaValue,
1335) -> Result<bool, LuaError> {
1336 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1339 if !same_variant {
1340 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1341 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1342 if !(t1_is_num && t2_is_num) {
1343 return Ok(false);
1344 }
1345 let i1 = to_integer_ns(t1, F2Imod::Eq);
1347 let i2 = to_integer_ns(t2, F2Imod::Eq);
1348 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1349 }
1350
1351 match (t1, t2) {
1352 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1353 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1354 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1355 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1356 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1357 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1358 use lua_types::closure::LuaClosure;
1359 let same = match (f1, f2) {
1360 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1361 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1362 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1363 _ => false,
1364 };
1365 Ok(same)
1366 }
1367 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1368 Ok(s1 == s2)
1371 }
1372 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1373 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1376 return Ok(true);
1377 }
1378 let Some(state) = state else {
1379 return Ok(false);
1380 };
1381 let tm = equal_tm(state, t1, t2);
1382 if matches!(tm, LuaValue::Nil) {
1383 return Ok(false);
1384 }
1385 let result = state.call_tm_res_bool(tm, t1, t2)?;
1386 Ok(result)
1387 }
1388 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1389 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1390 return Ok(true);
1391 }
1392 let Some(state) = state else {
1393 return Ok(false);
1394 };
1395 let tm = equal_tm(state, t1, t2);
1396 if matches!(tm, LuaValue::Nil) {
1397 return Ok(false);
1398 }
1399 let result = state.call_tm_res_bool(tm, t1, t2)?;
1400 Ok(result)
1401 }
1402 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1403 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1404 }
1405}
1406
1407fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1411 buf.clear();
1412 let mut remaining = n;
1413 loop {
1414 let idx = top - remaining as i32;
1415 let v = state.get_at(idx);
1416 if let LuaValue::Str(ts) = v {
1417 buf.extend_from_slice(ts.as_bytes());
1418 }
1419 if remaining <= 1 {
1420 break;
1421 }
1422 remaining -= 1;
1423 }
1424}
1425
1426pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1428 if total == 1 {
1429 return Ok(());
1430 }
1431 if total == 2 {
1432 let top = state.top_idx();
1433 let v_tm1 = state.get_at(top - 1);
1434 let v_tm2 = state.get_at(top - 2);
1435 if concat_pair_fast(state, top, v_tm2, v_tm1)? {
1436 return Ok(());
1437 }
1438 }
1439 let mut total = total;
1440 loop {
1441 let top = state.top_idx();
1442 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1447 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1448 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1450 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1451 if !top2_coercible || !top1_stringlike {
1452 state.try_concat_tm(&v_tm1, &v_tm2)?;
1453 total -= 1;
1458 let top = state.top_idx();
1459 state.set_top(top - 1);
1460 if total <= 1 {
1461 break;
1462 }
1463 continue;
1464 }
1465
1466 let is_empty =
1467 |v: &LuaValue| -> bool { matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty()) };
1468
1469 let n: u32;
1470 if is_empty(&v_tm1) {
1471 state.coerce_to_string(top - 2)?;
1472 n = 2;
1473 } else if is_empty(&v_tm2) {
1474 state.coerce_to_string(top - 1)?;
1477 let v = state.get_at(top - 1);
1478 state.set_at(top - 2, v);
1479 n = 2;
1480 } else {
1481 state.coerce_to_string(top - 1)?;
1483 let s1 = match state.get_at(top - 1) {
1484 LuaValue::Str(ts) => ts.as_bytes().len(),
1485 _ => 0,
1486 };
1487 let mut total_len = s1;
1488 let mut count: u32 = 1;
1489 let top = state.top_idx();
1490 loop {
1491 if count as i32 >= total {
1492 break;
1493 }
1494 let idx = top - (count as i32 + 1);
1495 let v = state.get_at(idx);
1496 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1497 break;
1498 }
1499 state.coerce_to_string(idx)?;
1500 let l = match state.get_at(idx) {
1501 LuaValue::Str(ts) => ts.as_bytes().len(),
1502 _ => 0,
1503 };
1504 if l >= usize::MAX - total_len {
1505 state.set_top(top - total as i32);
1507 return Err(LuaError::runtime(format_args!("string length overflow")));
1508 }
1509 total_len += l;
1510 count += 1;
1511 }
1512 n = count;
1513
1514 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1516 let top = state.top_idx();
1517 copy_to_buf(state, top, n, &mut buf);
1518 let ts = state.intern_or_create_str(&buf)?;
1519 state.set_at(top - n as i32, LuaValue::Str(ts));
1520 }
1521 total -= n as i32 - 1;
1522 let top = state.top_idx();
1523 state.set_top(top - ((n - 1) as i32));
1524
1525 if total <= 1 {
1526 break;
1527 }
1528 }
1529 Ok(())
1530}
1531
1532enum ConcatPiece {
1533 Str(GcRef<LuaString>),
1534 Num(Vec<u8>),
1535}
1536
1537impl ConcatPiece {
1538 #[inline]
1539 fn len(&self) -> usize {
1540 match self {
1541 ConcatPiece::Str(s) => s.as_bytes().len(),
1542 ConcatPiece::Num(bytes) => bytes.len(),
1543 }
1544 }
1545
1546 #[inline]
1547 fn append_to(&self, out: &mut Vec<u8>) {
1548 match self {
1549 ConcatPiece::Str(s) => out.extend_from_slice(s.as_bytes()),
1550 ConcatPiece::Num(bytes) => out.extend_from_slice(bytes),
1551 }
1552 }
1553}
1554
1555#[inline]
1556fn concat_piece(v: LuaValue, version: lua_types::LuaVersion) -> Option<ConcatPiece> {
1557 match v {
1558 LuaValue::Str(s) => Some(ConcatPiece::Str(s)),
1559 LuaValue::Int(_) | LuaValue::Float(_) => Some(ConcatPiece::Num(
1560 crate::object::number_to_str_buf(&v, version),
1561 )),
1562 _ => None,
1563 }
1564}
1565
1566#[inline]
1567fn concat_pair_fast(
1568 state: &mut LuaState,
1569 top: StackIdx,
1570 left: LuaValue,
1571 right: LuaValue,
1572) -> Result<bool, LuaError> {
1573 let version = state.global().lua_version;
1574 let Some(left) = concat_piece(left, version) else {
1575 return Ok(false);
1576 };
1577 let Some(right) = concat_piece(right, version) else {
1578 return Ok(false);
1579 };
1580 let total_len = left
1581 .len()
1582 .checked_add(right.len())
1583 .ok_or_else(|| LuaError::runtime(format_args!("string length overflow")))?;
1584 let mut buf = Vec::with_capacity(total_len);
1585 left.append_to(&mut buf);
1586 right.append_to(&mut buf);
1587 let ts = state.intern_or_create_str(&buf)?;
1588 state.set_at(top - 2, LuaValue::Str(ts));
1589 state.set_top(top - 1);
1590 Ok(true)
1591}
1592
1593pub(crate) fn obj_len(
1597 state: &mut LuaState,
1598 ra: StackIdx,
1599 rb: LuaValue,
1600 rb_idx: StackIdx,
1601) -> Result<(), LuaError> {
1602 match &rb {
1603 LuaValue::Table(_) => {
1604 let consult_len_tm = !matches!(state.global().lua_version, lua_types::LuaVersion::V51);
1609 let tm = if consult_len_tm {
1610 let mt = state.table_metatable(&rb);
1611 state.fast_tm_table(mt.as_ref(), TagMethod::Len)
1612 } else {
1613 LuaValue::Nil
1614 };
1615 if matches!(tm, LuaValue::Nil) {
1616 let n = state.table_length(&rb)?;
1617 state.set_at(ra, LuaValue::Int(n as i64));
1618 return Ok(());
1619 }
1620 state.call_tm_res(tm, &rb, &rb, ra)?;
1622 }
1623 LuaValue::Str(ts) => {
1624 let n = ts.len();
1627 state.set_at(ra, LuaValue::Int(n as i64));
1628 }
1629 other => {
1630 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1632 if matches!(tm, LuaValue::Nil) {
1633 return Err(crate::debug::type_error(
1634 state,
1635 other,
1636 rb_idx,
1637 b"get length of",
1638 ));
1639 }
1640 state.call_tm_res(tm, &rb, &rb, ra)?;
1641 }
1642 }
1643 Ok(())
1644}
1645
1646pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1650 if (n as u64).wrapping_add(1) <= 1 {
1651 if n == 0 {
1652 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1653 }
1654 return Ok(intop_sub(0, m));
1655 }
1656 let q = m / n;
1657 if (m ^ n) < 0 && m % n != 0 {
1659 Ok(q - 1)
1660 } else {
1661 Ok(q)
1662 }
1663}
1664
1665pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1667 if (n as u64).wrapping_add(1) <= 1 {
1668 if n == 0 {
1669 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1670 }
1671 return Ok(0);
1672 }
1673 let r = m % n;
1674 if r != 0 && (r ^ n) < 0 {
1675 Ok(r + n)
1676 } else {
1677 Ok(r)
1678 }
1679}
1680
1681pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1683 let r = m % n;
1684 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1685 if opposite_signs {
1686 r + n
1687 } else {
1688 r
1689 }
1690}
1691
1692pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1695 use TagMethod::*;
1696 match i {
1697 0 => Index,
1698 1 => NewIndex,
1699 2 => Gc,
1700 3 => Mode,
1701 4 => Len,
1702 5 => Eq,
1703 6 => Add,
1704 7 => Sub,
1705 8 => Mul,
1706 9 => Mod,
1707 10 => Pow,
1708 11 => Div,
1709 12 => Idiv,
1710 13 => Band,
1711 14 => Bor,
1712 15 => Bxor,
1713 16 => Shl,
1714 17 => Shr,
1715 18 => Unm,
1716 19 => Bnot,
1717 20 => Lt,
1718 21 => Le,
1719 22 => Concat,
1720 23 => Call,
1721 24 => Close,
1722 _ => Index,
1723 }
1724}
1725
1726pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1729 imod(a, b)
1730}
1731
1732pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1735 idiv(a, b)
1736}
1737
1738pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1741 Ok(fmodf(a, b))
1742}
1743
1744pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1746 if y < 0 {
1747 if y <= -(NBITS as i64) {
1748 0
1749 } else {
1750 intop_shr(x, (-y) as u32)
1751 }
1752 } else {
1753 if y >= NBITS as i64 {
1754 0
1755 } else {
1756 intop_shl(x, y as u32)
1757 }
1758 }
1759}
1760
1761fn push_closure(
1767 state: &mut LuaState,
1768 proto_idx: usize, ci: CallInfoIdx,
1770 base: StackIdx,
1771 ra: StackIdx,
1772) -> Result<(), LuaError> {
1773 state.push_closure(proto_idx, ci, base, ra)
1777}
1778
1779pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1784 let ci = state.current_ci_idx();
1788 let base = state.ci_base(ci);
1789 let inst = state.ci_prev_instruction(ci);
1790 let op = inst.opcode();
1791
1792 match op {
1793 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1795 let prev_inst = state.ci_prev2_instruction(ci);
1796 let a = prev_inst.arg_a();
1797 state.dec_top();
1798 let top = state.top_idx();
1799 let v = state.get_at(top);
1800 state.set_at(base + a, v);
1801 }
1802 OpCode::Unm
1804 | OpCode::BNot
1805 | OpCode::Len
1806 | OpCode::GetTabUp
1807 | OpCode::GetTable
1808 | OpCode::GetI
1809 | OpCode::GetField
1810 | OpCode::Self_ => {
1811 let a = inst.arg_a();
1812 state.dec_top();
1813 let top = state.top_idx();
1814 let v = state.get_at(top);
1815 state.set_at(base + a, v);
1816 }
1817 OpCode::Lt
1821 | OpCode::Le
1822 | OpCode::LtI
1823 | OpCode::LeI
1824 | OpCode::GtI
1825 | OpCode::GeI
1826 | OpCode::Eq => {
1827 let top_minus1 = state.top_idx() - 1;
1828 let v = state.get_at(top_minus1);
1829 let mut res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1830 state.dec_top();
1831 if (state.get_ci(ci).callstatus & crate::state::CIST_LEQ) != 0 {
1836 state.get_ci_mut(ci).callstatus &= !crate::state::CIST_LEQ;
1837 res = !res;
1838 }
1839 if (res as i32) != inst.arg_k() {
1840 state.ci_skip_next_instruction(ci);
1841 }
1842 }
1843 OpCode::Concat => {
1849 let top = state.top_idx() - 1; let a = inst.arg_a();
1851 let total_concat = (top - 1 - (base + a)) as i32;
1852 let v = state.get_at(top);
1853 state.set_at(top - 2, v);
1854 state.set_top(top - 1);
1855 concat(state, total_concat)?;
1856 }
1857 OpCode::Close => {
1858 state.ci_step_pc_back(ci);
1859 }
1860 OpCode::Return => {
1864 let a = inst.arg_a();
1865 let ra = base + a;
1866 let nres = state.ci_nres(ci);
1867 state.set_top(ra + nres);
1868 state.ci_step_pc_back(ci);
1869 }
1870 other => {
1871 debug_assert!(
1872 matches!(
1873 other,
1874 OpCode::TForCall
1875 | OpCode::Call
1876 | OpCode::TailCall
1877 | OpCode::SetTabUp
1878 | OpCode::SetTable
1879 | OpCode::SetI
1880 | OpCode::SetField
1881 ),
1882 "unexpected opcode in finish_op: {:?}",
1883 other
1884 );
1885 }
1886 }
1887 Ok(())
1888}
1889
1890pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1902 let mut trap: bool;
1903 let legacy_for = matches!(
1910 state.global().lua_version,
1911 lua_types::LuaVersion::V51 | lua_types::LuaVersion::V52 | lua_types::LuaVersion::V53
1912 );
1913 let tfor_55 = state.global().lua_version == lua_types::LuaVersion::V55;
1914
1915 'startfunc: loop {
1917 trap = state.hook_mask() != 0;
1918
1919 'returning: loop {
1922 let ci_slot = ci.as_usize();
1923 let func_idx = state.call_info[ci_slot].func;
1924 let cl = match state.stack[func_idx.0 as usize].val {
1925 LuaValue::Function(lua_types::closure::LuaClosure::Lua(c)) => c,
1926 _ => {
1927 return Err(LuaError::runtime(format_args!(
1928 "internal: execute called on non-Lua frame"
1929 )));
1930 }
1931 };
1932 let code = &cl.proto.code;
1933 let constants = &cl.proto.k;
1934 let mut pc: u32 = state.call_info[ci_slot].saved_pc();
1936
1937 if trap {
1938 trap = state.trace_call(ci)?;
1939 }
1940 let mut base: StackIdx = state.call_info[ci.as_usize()].func + 1;
1941
1942 'dispatch: loop {
1944 if trap {
1945 trap = state.trace_exec(ci, pc)?;
1946 base = state.ci_base(ci); }
1948 let i: Instruction = code[pc as usize];
1949 pc += 1;
1950 let op = i.opcode();
1951 #[cfg(feature = "opcode-profile")]
1952 crate::opcode_profile::record(op);
1953
1954 debug_assert!(base == state.ci_base(ci));
1955
1956 #[cfg(debug_assertions)]
1960 {
1961 let op_mode = op_mode_byte(op);
1962 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1963 state.set_top(base);
1964 }
1965 }
1966
1967 match op {
1968 OpCode::Move => {
1970 let ra = base + i.arg_a();
1971 let rb = base + i.arg_b();
1972 let v = state.stack[rb.0 as usize].val;
1973 state.stack[ra.0 as usize].val = v;
1974 }
1975 OpCode::LoadI => {
1977 let ra = base + i.arg_a();
1978 let b = i.arg_s_bx() as i64;
1979 state.stack[ra.0 as usize].val = LuaValue::Int(b);
1980 }
1981 OpCode::LoadF => {
1983 let ra = base + i.arg_a();
1984 let b = i.arg_s_bx() as f64;
1985 state.stack[ra.0 as usize].val = LuaValue::Float(b);
1986 }
1987 OpCode::LoadK => {
1989 let ra = base + i.arg_a();
1990 let k_idx = i.arg_bx() as usize;
1991 state.stack[ra.0 as usize].val = constants[k_idx];
1992 }
1993 OpCode::LoadKX => {
1995 let ra = base + i.arg_a();
1996 let extra = code[pc as usize];
1997 pc += 1;
1998 let k_idx = extra.arg_ax() as usize;
1999 state.stack[ra.0 as usize].val = constants[k_idx];
2000 }
2001 OpCode::LoadFalse => {
2003 let ra = base + i.arg_a();
2004 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
2005 }
2006 OpCode::LFalseSkip => {
2008 let ra = base + i.arg_a();
2009 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
2010 pc += 1;
2011 }
2012 OpCode::LoadTrue => {
2014 let ra = base + i.arg_a();
2015 state.stack[ra.0 as usize].val = LuaValue::Bool(true);
2016 }
2017 OpCode::LoadNil => {
2019 let ra = base + i.arg_a();
2020 let b = i.arg_b();
2021 for k in 0..=b {
2022 state.stack[(ra + k).0 as usize].val = LuaValue::Nil;
2023 }
2024 }
2025 OpCode::GetUpVal => {
2027 let ra = base + i.arg_a();
2028 let b = i.arg_b() as usize;
2029 let uv = cl.upval(b);
2030 let v = match uv.try_open_payload() {
2031 Some((thread_id, idx))
2032 if thread_id as u64 == state.cached_thread_id =>
2033 {
2034 state.stack[idx.0 as usize].val
2035 }
2036 Some(_) => state.upvalue_get(&cl, b),
2037 None => uv.closed_value(),
2038 };
2039 state.stack[ra.0 as usize].val = v;
2040 }
2041 OpCode::SetUpVal => {
2044 let ra = base + i.arg_a();
2045 let b = i.arg_b() as usize;
2046 let v = state.stack[ra.0 as usize].val;
2047 let uv = cl.upval(b);
2048 match uv.try_open_payload() {
2049 Some((thread_id, idx))
2050 if thread_id as u64 == state.cached_thread_id =>
2051 {
2052 state.stack[idx.0 as usize].val = v;
2053 if v.is_collectable() {
2054 state.gc_barrier_upval(&uv, &v);
2055 }
2056 }
2057 None => {
2058 uv.set_closed_value(v);
2059 if v.is_collectable() {
2060 state.gc_barrier_upval(&uv, &v);
2061 }
2062 }
2063 _ => {
2064 state.upvalue_set(&cl, b, v)?;
2065 }
2066 }
2067 }
2068 OpCode::GetTabUp => {
2072 let ra = base + i.arg_a();
2073 let b = i.arg_b() as usize;
2074 let k_idx = i.arg_c() as usize;
2075 let upval = state.upvalue_get(&cl, b);
2076 let key = constants[k_idx];
2077 match state.fast_get_short_str(&upval, &key)? {
2078 Some(v) => state.set_at(ra, v),
2079 None => {
2080 state.set_ci_savedpc(ci, pc);
2081 state.set_top(state.ci_top(ci));
2082 let upval_name: Vec<u8> =
2083 cl.0.proto
2084 .upvalues
2085 .get(b)
2086 .and_then(|uv| uv.name.as_ref())
2087 .map(|s| s.as_bytes().to_vec())
2088 .unwrap_or_else(|| b"?".to_vec());
2089 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2090 finish_get(state, upval, key, ra, true, None, hint)?;
2091 trap = state.ci_trap(ci);
2092 }
2093 }
2094 }
2095 OpCode::GetTable => {
2098 let ra = base + i.arg_a();
2099 let rb_idx = base + i.arg_b();
2100 let rb_v = state.get_at(rb_idx);
2101 let rc_v = state.get_at(base + i.arg_c());
2102 let fast_result = if let LuaValue::Int(n) = &rc_v {
2103 state.fast_get_int(&rb_v, *n)?
2104 } else {
2105 state.fast_get(&rb_v, &rc_v)?
2106 };
2107 match fast_result {
2108 Some(v) => state.set_at(ra, v),
2109 None => {
2110 state.set_ci_savedpc(ci, pc);
2111 state.set_top(state.ci_top(ci));
2112 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx), None)?;
2113 trap = state.ci_trap(ci);
2114 }
2115 }
2116 }
2117 OpCode::GetI => {
2121 let ra = base + i.arg_a();
2122 let rb_idx = base + i.arg_b();
2123 let rb_v = state.get_at(rb_idx);
2124 let c = i.arg_c() as i64;
2125 match state.fast_get_int(&rb_v, c)? {
2126 Some(v) => state.set_at(ra, v),
2127 None => {
2128 let key = LuaValue::Int(c);
2129 state.set_ci_savedpc(ci, pc);
2130 state.set_top(state.ci_top(ci));
2131 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2132 trap = state.ci_trap(ci);
2133 }
2134 }
2135 }
2136 OpCode::GetField => {
2138 let ra = base + i.arg_a();
2139 let rb_idx = base + i.arg_b();
2140 let rb_v = state.get_at(rb_idx);
2141 let k_idx = i.arg_c() as usize;
2142 let key = constants[k_idx];
2143 match state.fast_get_short_str(&rb_v, &key)? {
2144 Some(v) => state.set_at(ra, v),
2145 None => {
2146 state.set_ci_savedpc(ci, pc);
2147 state.set_top(state.ci_top(ci));
2148 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2149 trap = state.ci_trap(ci);
2150 }
2151 }
2152 }
2153 OpCode::SetTabUp => {
2155 let a = i.arg_a() as usize;
2156 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
2158 constants[i.arg_c() as usize]
2159 } else {
2160 state.get_at(base + i.arg_c())
2161 };
2162 let upval = state.upvalue_get(&cl, a);
2163 let key = constants[b_idx];
2164 if let LuaValue::Table(tbl) = upval {
2165 if !tbl.has_metatable() {
2166 if rc_v.is_collectable() {
2167 state.gc_table_barrier_back(&tbl, &rc_v);
2168 }
2169 if let LuaValue::Str(s) = key {
2170 tbl.raw_set_short_str(state, s, rc_v)?;
2171 } else {
2172 tbl.raw_set(state, key, rc_v)?;
2173 }
2174 continue 'dispatch;
2175 }
2176 }
2177 match state.fast_get_short_str(&upval, &key)? {
2178 Some(_slot) => {
2179 state.gc_value_barrier_back(&upval, &rc_v);
2180 if let LuaValue::Table(tbl) = upval {
2181 if let LuaValue::Str(s) = key {
2182 tbl.raw_set_short_str(state, s, rc_v)?;
2183 } else {
2184 tbl.raw_set(state, key, rc_v)?;
2185 }
2186 } else {
2187 state.table_raw_set(&upval, key, rc_v)?;
2188 }
2189 }
2190 None => {
2191 state.set_ci_savedpc(ci, pc);
2192 state.set_top(state.ci_top(ci));
2193 let upval_name: Vec<u8> = cl
2194 .proto
2195 .upvalues
2196 .get(a)
2197 .and_then(|uv| uv.name.as_ref())
2198 .map(|s| s.as_bytes().to_vec())
2199 .unwrap_or_else(|| b"?".to_vec());
2200 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2201 finish_set(state, upval, key, rc_v, false, None, hint)?;
2202 trap = state.ci_trap(ci);
2203 }
2204 }
2205 }
2206 OpCode::SetTable => {
2208 let ra_idx = base + i.arg_a();
2209 let ra_v = state.get_at(ra_idx);
2210 let rb_v = state.get_at(base + i.arg_b());
2211 let rc_v = if i.test_k() {
2212 constants[i.arg_c() as usize]
2213 } else {
2214 state.get_at(base + i.arg_c())
2215 };
2216 if let LuaValue::Table(tbl) = ra_v {
2217 if !tbl.has_metatable() {
2218 if rc_v.is_collectable() {
2219 state.gc_table_barrier_back(&tbl, &rc_v);
2220 }
2221 match rb_v {
2222 LuaValue::Int(n) => tbl.raw_set_int(state, n, rc_v)?,
2223 LuaValue::Str(s) if s.is_short() => {
2224 tbl.raw_set_short_str(state, s, rc_v)?
2225 }
2226 _ => tbl.raw_set(state, rb_v, rc_v)?,
2227 }
2228 } else {
2229 let fast = if let LuaValue::Int(n) = &rb_v {
2230 state.fast_get_int(&ra_v, *n)?
2231 } else {
2232 state.fast_get(&ra_v, &rb_v)?
2233 };
2234 if fast.is_some() {
2235 state.gc_value_barrier_back(&ra_v, &rc_v);
2236 match rb_v {
2237 LuaValue::Int(n) => tbl.raw_set_int(state, n, rc_v)?,
2238 LuaValue::Str(s) if s.is_short() => {
2239 tbl.raw_set_short_str(state, s, rc_v)?
2240 }
2241 _ => tbl.raw_set(state, rb_v, rc_v)?,
2242 }
2243 } else {
2244 state.set_ci_savedpc(ci, pc);
2245 state.set_top(state.ci_top(ci));
2246 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2247 trap = state.ci_trap(ci);
2248 }
2249 }
2250 } else {
2251 state.set_ci_savedpc(ci, pc);
2252 state.set_top(state.ci_top(ci));
2253 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2254 trap = state.ci_trap(ci);
2255 }
2256 }
2257 OpCode::SetI => {
2259 let ra_idx = base + i.arg_a();
2260 let ra_v = state.get_at(ra_idx);
2261 let c = i.arg_b() as i64;
2262 let rc_v = if i.test_k() {
2263 constants[i.arg_c() as usize]
2264 } else {
2265 state.get_at(base + i.arg_c())
2266 };
2267 if let LuaValue::Table(tbl) = ra_v {
2268 if !tbl.has_metatable() {
2269 if rc_v.is_collectable() {
2270 state.gc_table_barrier_back(&tbl, &rc_v);
2271 }
2272 tbl.raw_set_int(state, c, rc_v)?;
2273 } else {
2274 let fast = state.fast_get_int(&ra_v, c)?;
2275 if fast.is_some() {
2276 state.gc_value_barrier_back(&ra_v, &rc_v);
2277 tbl.raw_set_int(state, c, rc_v)?;
2278 } else {
2279 state.set_ci_savedpc(ci, pc);
2280 state.set_top(state.ci_top(ci));
2281 finish_set(
2282 state,
2283 ra_v,
2284 LuaValue::Int(c),
2285 rc_v,
2286 false,
2287 Some(ra_idx),
2288 None,
2289 )?;
2290 trap = state.ci_trap(ci);
2291 }
2292 }
2293 } else {
2294 state.set_ci_savedpc(ci, pc);
2295 state.set_top(state.ci_top(ci));
2296 finish_set(
2297 state,
2298 ra_v,
2299 LuaValue::Int(c),
2300 rc_v,
2301 false,
2302 Some(ra_idx),
2303 None,
2304 )?;
2305 trap = state.ci_trap(ci);
2306 }
2307 }
2308 OpCode::SetField => {
2310 let ra_idx = base + i.arg_a();
2311 let ra_v = state.get_at(ra_idx);
2312 let b_idx = i.arg_b() as usize;
2313 let key = constants[b_idx];
2314 let rc_v = if i.test_k() {
2315 constants[i.arg_c() as usize]
2316 } else {
2317 state.get_at(base + i.arg_c())
2318 };
2319 if let LuaValue::Table(tbl) = ra_v {
2320 if !tbl.has_metatable() {
2321 if rc_v.is_collectable() {
2322 state.gc_table_barrier_back(&tbl, &rc_v);
2323 }
2324 if let LuaValue::Str(s) = key {
2325 tbl.raw_set_short_str(state, s, rc_v)?;
2326 } else {
2327 tbl.raw_set(state, key, rc_v)?;
2328 }
2329 } else {
2330 match state.fast_get_short_str(&ra_v, &key)? {
2331 Some(_) => {
2332 state.gc_value_barrier_back(&ra_v, &rc_v);
2333 if let LuaValue::Str(s) = key {
2334 tbl.raw_set_short_str(state, s, rc_v)?;
2335 } else {
2336 tbl.raw_set(state, key, rc_v)?;
2337 }
2338 }
2339 None => {
2340 state.set_ci_savedpc(ci, pc);
2341 state.set_top(state.ci_top(ci));
2342 finish_set(
2343 state,
2344 ra_v,
2345 key,
2346 rc_v,
2347 false,
2348 Some(ra_idx),
2349 None,
2350 )?;
2351 trap = state.ci_trap(ci);
2352 }
2353 }
2354 }
2355 } else {
2356 state.set_ci_savedpc(ci, pc);
2357 state.set_top(state.ci_top(ci));
2358 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2359 trap = state.ci_trap(ci);
2360 }
2361 }
2362 OpCode::NewTable => {
2365 let ra = base + i.arg_a();
2366 let mut b = i.arg_b();
2367 let mut c = i.arg_c();
2368 if b > 0 {
2369 b = 1 << (b - 1);
2370 }
2371 if i.test_k() {
2372 let extra = code[pc as usize];
2373 pc += 1;
2374 const MAXARG_C: i32 = (1 << 8) - 1;
2375 c += extra.arg_ax() * (MAXARG_C + 1);
2376 } else {
2377 pc += 1; }
2379 state.set_top(ra + 1);
2380 let t = if b != 0 || c != 0 {
2381 state.new_table_with_sizes(c as u32, b as u32)?
2382 } else {
2383 state.new_table()
2384 };
2385 state.set_at(ra, LuaValue::Table(t.clone()));
2386 state.set_ci_savedpc(ci, pc);
2387 state.set_top(ra + 1);
2388 state.gc_cond_step();
2389 if state.hookmask != 0 {
2390 trap = state.ci_trap(ci);
2391 }
2392 }
2393 OpCode::Self_ => {
2395 let ra = base + i.arg_a();
2396 let rb_idx = base + i.arg_b();
2397 let rb_v = state.get_at(rb_idx);
2398 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2400 constants[k_idx]
2401 } else {
2402 state.get_at(base + i.arg_c())
2403 };
2404 state.set_at(ra + 1, rb_v.clone());
2405 match state.fast_get_short_str(&rb_v, &key)? {
2406 Some(v) => state.set_at(ra, v),
2407 None => {
2408 state.set_ci_savedpc(ci, pc);
2409 state.set_top(state.ci_top(ci));
2410 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2411 trap = state.ci_trap(ci);
2412 }
2413 }
2414 }
2415 OpCode::AddI => {
2417 let ra = base + i.arg_a();
2418 let rb = base + i.arg_b();
2419 let imm = i.arg_s_c() as i64;
2420 let rb_v = state.stack[rb.0 as usize].val;
2421 match rb_v {
2422 LuaValue::Int(iv1) => {
2423 pc += 1;
2424 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2425 }
2426 LuaValue::Float(nb) => {
2427 pc += 1;
2428 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2429 }
2430 _ => {}
2431 }
2432 }
2433 OpCode::AddK => {
2435 let ra = base + i.arg_a();
2436 let rb = base + i.arg_b();
2437 let kidx = i.arg_c() as usize;
2438 if let (Some(i1), Some(i2)) =
2439 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2440 {
2441 pc += 1;
2442 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2443 } else if let (Some(n1), Some(n2)) =
2444 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2445 {
2446 pc += 1;
2447 state.set_at(ra, LuaValue::Float(n1 + n2));
2448 }
2449 }
2450 OpCode::SubK => {
2451 let ra = base + i.arg_a();
2452 let rb = base + i.arg_b();
2453 let kidx = i.arg_c() as usize;
2454 if let (Some(i1), Some(i2)) =
2455 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2456 {
2457 pc += 1;
2458 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2459 } else if let (Some(n1), Some(n2)) =
2460 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2461 {
2462 pc += 1;
2463 state.set_at(ra, LuaValue::Float(n1 - n2));
2464 }
2465 }
2466 OpCode::MulK => {
2467 let ra = base + i.arg_a();
2468 let rb = base + i.arg_b();
2469 let kidx = i.arg_c() as usize;
2470 if let (Some(i1), Some(i2)) =
2471 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2472 {
2473 pc += 1;
2474 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2475 } else 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::ModK => {
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); state.set_top(state.ci_top(ci));
2488 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2489 }
2490 OpCode::PowK => {
2491 let ra = base + i.arg_a();
2492 let rb = base + i.arg_b();
2493 let kidx = i.arg_c() as usize;
2494 if let (Some(n1), Some(n2)) =
2495 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2496 {
2497 pc += 1;
2498 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2499 state.set_at(ra, LuaValue::Float(r));
2500 }
2501 }
2502 OpCode::DivK => {
2503 let ra = base + i.arg_a();
2504 let rb = base + i.arg_b();
2505 let kidx = i.arg_c() as usize;
2506 if let (Some(n1), Some(n2)) =
2507 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2508 {
2509 pc += 1;
2510 state.set_at(ra, LuaValue::Float(n1 / n2));
2511 }
2512 }
2513 OpCode::IDivK => {
2514 let ra = base + i.arg_a();
2515 let v1 = state.get_at(base + i.arg_b());
2516 let v2 = constants[i.arg_c() as usize];
2517 state.set_ci_savedpc(ci, pc);
2518 state.set_top(state.ci_top(ci));
2519 arith_op_checked(
2520 state,
2521 ra,
2522 &v1,
2523 &v2,
2524 &mut pc,
2525 |a, b| idiv(a, b),
2526 |a, b| (a / b).floor(),
2527 )?;
2528 }
2529 OpCode::BAndK => {
2530 let ra = base + i.arg_a();
2531 let v1 = state.get_at(base + i.arg_b());
2532 let v2 = constants[i.arg_c() as usize];
2533 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2534 }
2535 OpCode::BOrK => {
2536 let ra = base + i.arg_a();
2537 let v1 = state.get_at(base + i.arg_b());
2538 let v2 = constants[i.arg_c() as usize];
2539 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2540 }
2541 OpCode::BXOrK => {
2542 let ra = base + i.arg_a();
2543 let v1 = state.get_at(base + i.arg_b());
2544 let v2 = constants[i.arg_c() as usize];
2545 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2546 }
2547 OpCode::ShrI => {
2548 let ra = base + i.arg_a();
2549 let v = state.get_at(base + i.arg_b());
2550 let ic = i.arg_s_c() as i64;
2551 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2552 pc += 1;
2553 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2554 }
2555 }
2556 OpCode::ShlI => {
2557 let ra = base + i.arg_a();
2558 let v = state.get_at(base + i.arg_b());
2559 let ic = i.arg_s_c() as i64;
2560 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2561 pc += 1;
2562 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2563 }
2564 }
2565 OpCode::Add => {
2567 let ra = base + i.arg_a();
2568 let rb = base + i.arg_b();
2569 let rc = base + i.arg_c();
2570 let ra_u = ra.0 as usize;
2571 let rb_v = state.stack[rb.0 as usize].val;
2572 let rc_v = state.stack[rc.0 as usize].val;
2573 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2574 pc += 1;
2575 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2576 } else if let (Some(n1), Some(n2)) =
2577 (number_value(rb_v), number_value(rc_v))
2578 {
2579 pc += 1;
2580 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2581 }
2582 }
2583 OpCode::Sub => {
2584 let ra = base + i.arg_a();
2585 let rb = base + i.arg_b();
2586 let rc = base + i.arg_c();
2587 let ra_u = ra.0 as usize;
2588 let rb_v = state.stack[rb.0 as usize].val;
2589 let rc_v = state.stack[rc.0 as usize].val;
2590 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2591 pc += 1;
2592 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2593 } else if let (Some(n1), Some(n2)) =
2594 (number_value(rb_v), number_value(rc_v))
2595 {
2596 pc += 1;
2597 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2598 }
2599 }
2600 OpCode::Mul => {
2601 let ra = base + i.arg_a();
2602 let rb = base + i.arg_b();
2603 let rc = base + i.arg_c();
2604 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2605 pc += 1;
2606 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2607 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2608 pc += 1;
2609 state.set_at(ra, LuaValue::Float(n1 * n2));
2610 }
2611 }
2612 OpCode::Mod => {
2613 let ra = base + i.arg_a();
2614 let v1 = state.get_at(base + i.arg_b());
2615 let v2 = state.get_at(base + i.arg_c());
2616 state.set_ci_savedpc(ci, pc);
2617 state.set_top(state.ci_top(ci));
2618 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2619 }
2620 OpCode::Pow => {
2621 let ra = base + i.arg_a();
2622 let rb = base + i.arg_b();
2623 let rc = base + i.arg_c();
2624 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2625 pc += 1;
2626 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2627 state.set_at(ra, LuaValue::Float(r));
2628 }
2629 }
2630 OpCode::Div => {
2631 let ra = base + i.arg_a();
2632 let rb = base + i.arg_b();
2633 let rc = base + i.arg_c();
2634 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2635 pc += 1;
2636 state.set_at(ra, LuaValue::Float(n1 / n2));
2637 }
2638 }
2639 OpCode::IDiv => {
2640 let ra = base + i.arg_a();
2641 let v1 = state.get_at(base + i.arg_b());
2642 let v2 = state.get_at(base + i.arg_c());
2643 state.set_ci_savedpc(ci, pc);
2644 state.set_top(state.ci_top(ci));
2645 arith_op_checked(
2646 state,
2647 ra,
2648 &v1,
2649 &v2,
2650 &mut pc,
2651 |a, b| idiv(a, b),
2652 |a, b| (a / b).floor(),
2653 )?;
2654 }
2655 OpCode::BAnd => {
2658 let ra = base + i.arg_a();
2659 let v1 = state.get_at(base + i.arg_b());
2660 let v2 = state.get_at(base + i.arg_c());
2661 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2662 }
2663 OpCode::BOr => {
2664 let ra = base + i.arg_a();
2665 let v1 = state.get_at(base + i.arg_b());
2666 let v2 = state.get_at(base + i.arg_c());
2667 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2668 }
2669 OpCode::BXOr => {
2670 let ra = base + i.arg_a();
2671 let v1 = state.get_at(base + i.arg_b());
2672 let v2 = state.get_at(base + i.arg_c());
2673 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2674 }
2675 OpCode::Shr => {
2676 let ra = base + i.arg_a();
2677 let v1 = state.get_at(base + i.arg_b());
2678 let v2 = state.get_at(base + i.arg_c());
2679 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2680 }
2681 OpCode::Shl => {
2682 let ra = base + i.arg_a();
2683 let v1 = state.get_at(base + i.arg_b());
2684 let v2 = state.get_at(base + i.arg_c());
2685 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2686 }
2687 OpCode::MmBin => {
2692 let ra_idx = base + i.arg_a();
2693 let rb_idx = base + i.arg_b();
2694 let ra_v = state.get_at(ra_idx);
2695 let rb_v = state.get_at(rb_idx);
2696 let tm = tagmethod_from_index(i.arg_c() as usize);
2697 let prev_inst = code[(pc - 2) as usize];
2698 let result_idx = base + prev_inst.arg_a();
2699 state.set_ci_savedpc(ci, pc);
2700 state.set_top(state.ci_top(ci));
2701 state.try_bin_tm(
2702 &ra_v,
2703 Some(ra_idx),
2704 &rb_v,
2705 Some(rb_idx),
2706 result_idx,
2707 tm,
2708 )?;
2709 trap = state.ci_trap(ci);
2710 }
2711 OpCode::MmBinI => {
2712 let ra_idx = base + i.arg_a();
2713 let ra_v = state.get_at(ra_idx);
2714 let imm = i.arg_s_b() as i64;
2715 let tm = tagmethod_from_index(i.arg_c() as usize);
2716 let flip = i.arg_k() != 0;
2717 let prev_inst = code[(pc - 2) as usize];
2718 let result_idx = base + prev_inst.arg_a();
2719 state.set_ci_savedpc(ci, pc);
2720 state.set_top(state.ci_top(ci));
2721 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2722 trap = state.ci_trap(ci);
2723 }
2724 OpCode::MmBinK => {
2725 let ra_idx = base + i.arg_a();
2726 let ra_v = state.get_at(ra_idx);
2727 let imm = constants[i.arg_b() as usize];
2728 let tm = tagmethod_from_index(i.arg_c() as usize);
2729 let flip = i.arg_k() != 0;
2730 let prev_inst = code[(pc - 2) as usize];
2731 let result_idx = base + prev_inst.arg_a();
2732 state.set_ci_savedpc(ci, pc);
2733 state.set_top(state.ci_top(ci));
2734 state.try_bin_assoc_tm(
2735 &ra_v,
2736 Some(ra_idx),
2737 &imm,
2738 None,
2739 flip,
2740 result_idx,
2741 tm,
2742 )?;
2743 trap = state.ci_trap(ci);
2744 }
2745 OpCode::Unm => {
2749 let ra = base + i.arg_a();
2750 let rb_idx = base + i.arg_b();
2751 let rb_v = state.get_at(rb_idx);
2752 match &rb_v {
2753 LuaValue::Int(ib) => {
2754 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2755 }
2756 LuaValue::Float(nb) => {
2757 state.set_at(ra, LuaValue::Float(-nb));
2758 }
2759 _ => {
2760 state.set_ci_savedpc(ci, pc);
2761 state.set_top(state.ci_top(ci));
2762 state.try_bin_tm(
2763 &rb_v,
2764 Some(rb_idx),
2765 &rb_v,
2766 Some(rb_idx),
2767 ra,
2768 TagMethod::Unm,
2769 )?;
2770 trap = state.ci_trap(ci);
2771 }
2772 }
2773 }
2774 OpCode::BNot => {
2776 let ra = base + i.arg_a();
2777 let rb_idx = base + i.arg_b();
2778 let rb_v = state.get_at(rb_idx);
2779 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2780 state.set_at(ra, LuaValue::Int(!ib));
2781 } else {
2782 state.set_ci_savedpc(ci, pc);
2783 state.set_top(state.ci_top(ci));
2784 state.try_bin_tm(
2785 &rb_v,
2786 Some(rb_idx),
2787 &rb_v,
2788 Some(rb_idx),
2789 ra,
2790 TagMethod::Bnot,
2791 )?;
2792 trap = state.ci_trap(ci);
2793 }
2794 }
2795 OpCode::Not => {
2797 let ra = base + i.arg_a();
2798 let rb_v = state.get_at(base + i.arg_b());
2799 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2800 state.set_at(ra, LuaValue::Bool(falsy));
2801 }
2802 OpCode::Len => {
2804 let ra = base + i.arg_a();
2805 let rb_idx = base + i.arg_b();
2806 let rb_v = state.get_at(rb_idx);
2807 state.set_ci_savedpc(ci, pc);
2808 state.set_top(state.ci_top(ci));
2809 obj_len(state, ra, rb_v, rb_idx)?;
2810 trap = state.ci_trap(ci);
2811 }
2812 OpCode::Concat => {
2814 let ra = base + i.arg_a();
2815 let n = i.arg_b() as i32;
2816 state.set_top(ra + n as i32);
2817 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2819 let top = state.top_idx();
2820 state.set_ci_savedpc(ci, pc);
2821 state.set_top(top);
2822 state.gc_cond_step();
2823 trap = state.ci_trap(ci);
2824 }
2825 OpCode::Close => {
2827 let ra = base + i.arg_a();
2828 state.set_ci_savedpc(ci, pc);
2829 state.set_top(state.ci_top(ci));
2830 crate::func::close(
2831 state,
2832 ra,
2833 lua_types::status::LuaStatus::Ok as i32,
2834 true,
2835 )?;
2836 trap = state.ci_trap(ci);
2837 }
2838 OpCode::Tbc => {
2840 let ra = base + i.arg_a();
2841 state.set_ci_savedpc(ci, pc);
2842 state.set_top(state.ci_top(ci));
2843 state.new_tbc_upval(ra)?;
2844 }
2845 OpCode::Jmp => {
2847 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2848 trap = state.ci_trap(ci);
2849 }
2850 OpCode::Eq => {
2852 let ra_v = state.get_at(base + i.arg_a());
2853 let rb_v = state.get_at(base + i.arg_b());
2854 state.set_ci_savedpc(ci, pc);
2855 state.set_top(state.ci_top(ci));
2856 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2857 trap = state.ci_trap(ci);
2858 if (cond as i32) != i.arg_k() {
2859 pc += 1;
2860 } else {
2861 let next = code[pc as usize];
2862 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2863 trap = state.ci_trap(ci);
2864 }
2865 }
2866 OpCode::Lt => {
2868 let ra_v = state.get_at(base + i.arg_a());
2869 let rb_v = state.get_at(base + i.arg_b());
2870 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2871 *ia < *ib
2872 } else if matches!(
2873 (&ra_v, &rb_v),
2874 (
2875 LuaValue::Int(_) | LuaValue::Float(_),
2876 LuaValue::Int(_) | LuaValue::Float(_)
2877 )
2878 ) {
2879 lt_num(&ra_v, &rb_v)
2880 } else {
2881 state.set_ci_savedpc(ci, pc);
2882 state.set_top(state.ci_top(ci));
2883 let r = less_than_others(state, &ra_v, &rb_v)?;
2884 trap = state.ci_trap(ci);
2885 r
2886 };
2887 if (cond as i32) != i.arg_k() {
2888 pc += 1;
2889 } else {
2890 let next = code[pc as usize];
2891 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2892 trap = state.ci_trap(ci);
2893 }
2894 }
2895 OpCode::Le => {
2897 let ra_v = state.get_at(base + i.arg_a());
2898 let rb_v = state.get_at(base + i.arg_b());
2899 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2900 *ia <= *ib
2901 } else if matches!(
2902 (&ra_v, &rb_v),
2903 (
2904 LuaValue::Int(_) | LuaValue::Float(_),
2905 LuaValue::Int(_) | LuaValue::Float(_)
2906 )
2907 ) {
2908 le_num(&ra_v, &rb_v)
2909 } else {
2910 state.set_ci_savedpc(ci, pc);
2911 state.set_top(state.ci_top(ci));
2912 let r = less_equal_others(state, &ra_v, &rb_v)?;
2913 trap = state.ci_trap(ci);
2914 r
2915 };
2916 if (cond as i32) != i.arg_k() {
2917 pc += 1;
2918 } else {
2919 let next = code[pc as usize];
2920 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2921 trap = state.ci_trap(ci);
2922 }
2923 }
2924 OpCode::EqK => {
2926 let ra_v = state.get_at(base + i.arg_a());
2927 let rb_v = constants[i.arg_b() as usize];
2928 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2929 if (cond as i32) != i.arg_k() {
2930 pc += 1;
2931 } else {
2932 let next = code[pc as usize];
2933 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2934 trap = state.ci_trap(ci);
2935 }
2936 }
2937 OpCode::EqI => {
2942 let ra_v = state.get_at(base + i.arg_a());
2943 let im = i.arg_s_b() as i64;
2944 let cond: bool = match &ra_v {
2945 LuaValue::Int(iv) => *iv == im,
2946 LuaValue::Float(fv) => *fv == im as f64,
2947 _ => false,
2948 };
2949 if (cond as i32) != i.arg_k() {
2950 pc += 1;
2951 } else {
2952 let next = code[pc as usize];
2953 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2954 trap = state.ci_trap(ci);
2955 }
2956 }
2957 OpCode::LtI => {
2960 let ra = base + i.arg_a();
2961 let im = i.arg_s_b() as i64;
2962 let fast_cond = match &state.stack[ra.0 as usize].val {
2963 LuaValue::Int(ia) => Some(*ia < im),
2964 LuaValue::Float(fa) => Some(*fa < im as f64),
2965 _ => None,
2966 };
2967 let cond = match fast_cond {
2968 Some(cond) => cond,
2969 None => order_imm_slow(
2970 state,
2971 ra,
2972 pc,
2973 &mut trap,
2974 ci,
2975 i,
2976 im,
2977 false,
2978 TagMethod::Lt,
2979 )?,
2980 };
2981 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
2982 }
2983 OpCode::LeI => {
2984 let ra = base + i.arg_a();
2985 let im = i.arg_s_b() as i64;
2986 let fast_cond = match &state.stack[ra.0 as usize].val {
2987 LuaValue::Int(ia) => Some(*ia <= im),
2988 LuaValue::Float(fa) => Some(*fa <= im as f64),
2989 _ => None,
2990 };
2991 let cond = match fast_cond {
2992 Some(cond) => cond,
2993 None => order_imm_slow(
2994 state,
2995 ra,
2996 pc,
2997 &mut trap,
2998 ci,
2999 i,
3000 im,
3001 false,
3002 TagMethod::Le,
3003 )?,
3004 };
3005 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3006 }
3007 OpCode::GtI => {
3008 let ra = base + i.arg_a();
3009 let im = i.arg_s_b() as i64;
3010 let fast_cond = match &state.stack[ra.0 as usize].val {
3011 LuaValue::Int(ia) => Some(*ia > im),
3012 LuaValue::Float(fa) => Some(*fa > im as f64),
3013 _ => None,
3014 };
3015 let cond = match fast_cond {
3016 Some(cond) => cond,
3017 None => order_imm_slow(
3018 state,
3019 ra,
3020 pc,
3021 &mut trap,
3022 ci,
3023 i,
3024 im,
3025 true,
3026 TagMethod::Lt,
3027 )?,
3028 };
3029 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3030 }
3031 OpCode::GeI => {
3032 let ra = base + i.arg_a();
3033 let im = i.arg_s_b() as i64;
3034 let fast_cond = match &state.stack[ra.0 as usize].val {
3035 LuaValue::Int(ia) => Some(*ia >= im),
3036 LuaValue::Float(fa) => Some(*fa >= im as f64),
3037 _ => None,
3038 };
3039 let cond = match fast_cond {
3040 Some(cond) => cond,
3041 None => order_imm_slow(
3042 state,
3043 ra,
3044 pc,
3045 &mut trap,
3046 ci,
3047 i,
3048 im,
3049 true,
3050 TagMethod::Le,
3051 )?,
3052 };
3053 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3054 }
3055 OpCode::Test => {
3057 let ra_v = state.get_at(base + i.arg_a());
3058 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
3059 if (cond as i32) != i.arg_k() {
3060 pc += 1;
3061 } else {
3062 let next = code[pc as usize];
3063 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3064 trap = state.ci_trap(ci);
3065 }
3066 }
3067 OpCode::TestSet => {
3070 let ra = base + i.arg_a();
3071 let rb_v = state.get_at(base + i.arg_b());
3072 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
3073 if (falsy as i32) == i.arg_k() {
3074 pc += 1;
3075 } else {
3076 state.set_at(ra, rb_v);
3077 let next = code[pc as usize];
3078 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3079 trap = state.ci_trap(ci);
3080 }
3081 }
3082 OpCode::Call => {
3086 let ra = base + i.arg_a();
3087 let b = i.arg_b();
3088 let nresults = i.arg_c() as i32 - 1;
3089 if b != 0 {
3090 state.set_top(ra + b);
3091 }
3092 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
3094 match state.precall(ra, nresults)? {
3095 None => {
3096 if had_hook || state.hookmask != 0 {
3100 trap = state.ci_trap(ci); }
3102 }
3103 Some(new_ci) => {
3104 ci = new_ci;
3106 continue 'startfunc;
3107 }
3108 }
3109 }
3110 OpCode::TailCall => {
3115 let ra = base + i.arg_a();
3116 let b = i.arg_b();
3117 let nparams1 = i.arg_c();
3118 let delta = if nparams1 != 0 {
3119 state.ci_nextraargs(ci) + nparams1 as i32
3120 } else {
3121 0
3122 };
3123 let top_b: i32 = if b != 0 {
3124 state.set_top(ra + b);
3125 b
3126 } else {
3127 state.top_idx() - ra
3128 };
3129 state.set_ci_savedpc(ci, pc);
3130 if i.test_k() {
3131 state.close_upvals_from_base(ci)?;
3132 }
3133 let n = state.pretailcall(ci, ra, top_b, delta)?;
3134 if n < 0 {
3135 state.note_lua_tailcall(ci);
3137 continue 'startfunc;
3138 } else {
3139 state.ci_adjust_func(ci, delta);
3141 state.poscall(ci, n as u32)?;
3142 if state.hookmask != 0 {
3143 trap = state.ci_trap(ci);
3144 }
3145 break 'dispatch; }
3147 }
3148 OpCode::Return => {
3153 let ra = base + i.arg_a();
3154 let n_raw = i.arg_b() as i32 - 1;
3155 let nparams1 = i.arg_c();
3156 let n: u32 = if n_raw < 0 {
3157 (state.top_idx() - ra) as u32
3158 } else {
3159 n_raw as u32
3160 };
3161 state.set_ci_savedpc(ci, pc);
3162 if i.test_k() {
3163 state.ci_nres_set(ci, n as i32);
3164 let ci_top = state.ci_top(ci);
3165 if state.top_idx().0 < ci_top.0 {
3166 state.set_top(ci_top);
3167 }
3168 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
3169 if state.hookmask != 0 {
3170 trap = state.ci_trap(ci);
3171 }
3172 base = state.ci_base(ci); }
3174 if nparams1 != 0 {
3175 let nextraargs = state.ci_nextraargs(ci) as u32;
3176 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
3177 }
3178 state.set_top(ra + n as i32);
3179 state.poscall(ci, n)?;
3180 if state.hookmask != 0 {
3181 trap = state.ci_trap(ci);
3182 }
3183 break 'dispatch; }
3185 OpCode::Return0 => {
3191 if state.hookmask == 0 {
3192 let ci_slot = ci.as_usize();
3193 let nres = state.call_info[ci_slot].nresults as i32;
3194 state.ci = state.call_info[ci_slot]
3195 .previous
3196 .expect("RETURN0: returning frame has no previous CallInfo");
3197 state.top = base - 1;
3198 for _ in 0..nres.max(0) {
3199 state.push(LuaValue::Nil);
3200 }
3201 } else {
3202 return0_hook(state, ci, base, i, pc, &mut trap)?;
3203 }
3204 break 'dispatch; }
3206 OpCode::Return1 => {
3210 if state.hookmask == 0 {
3211 let ci_slot = ci.as_usize();
3212 let nres = state.call_info[ci_slot].nresults as i32;
3213 state.ci = state.call_info[ci_slot]
3214 .previous
3215 .expect("RETURN1: returning frame has no previous CallInfo");
3216 if nres == 0 {
3217 state.top = base - 1;
3218 } else {
3219 let ra = base + i.arg_a();
3220 state.stack[(base - 1).0 as usize].val =
3221 state.stack[ra.0 as usize].val; state.top = base;
3223 for _ in 1..nres.max(0) {
3224 state.push(LuaValue::Nil);
3225 }
3226 }
3227 } else {
3228 return1_hook(state, ci, base, i, pc, &mut trap)?;
3229 }
3230 break 'dispatch; }
3232 OpCode::ForLoop => {
3236 let ra = base + i.arg_a();
3237 if legacy_for {
3238 if forloop_legacy(state, ra) {
3239 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3240 }
3241 if state.hookmask != 0 {
3242 trap = state.ci_trap(ci);
3243 }
3244 } else {
3245 let ra_u = ra.0 as usize;
3246 let window: &mut [crate::state::StackValue; 4] = (&mut state.stack
3247 [ra_u..ra_u + 4])
3248 .try_into()
3249 .expect("FORLOOP register window");
3250 if let LuaValue::Int(step) = window[2].val {
3251 let count = match window[1].val {
3252 LuaValue::Int(c) => c as u64,
3253 _ => 0,
3254 };
3255 if count > 0 {
3256 let idx = match window[0].val {
3257 LuaValue::Int(x) => x,
3258 _ => 0,
3259 };
3260 window[1].val = LuaValue::Int((count - 1) as i64);
3261 let new_idx = intop_add(idx, step);
3262 window[0].val = LuaValue::Int(new_idx);
3263 window[3].val = LuaValue::Int(new_idx);
3264 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3265 }
3266 } else if float_for_loop(state, ra) {
3267 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3268 }
3269 if state.hookmask != 0 {
3270 trap = state.ci_trap(ci);
3271 }
3272 }
3273 }
3274 OpCode::ForPrep => {
3276 let ra = base + i.arg_a();
3277 state.set_ci_savedpc(ci, pc);
3278 state.set_top(state.ci_top(ci));
3279 if legacy_for {
3280 forprep_legacy(state, ra)?;
3283 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3284 } else if forprep(state, ra)? {
3285 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
3286 }
3287 }
3288 OpCode::TForPrep => {
3292 let ra = base + i.arg_a();
3293 state.set_ci_savedpc(ci, pc);
3294 state.set_top(state.ci_top(ci));
3295 if tfor_55 {
3296 let closing = state.get_at(ra + 3);
3297 let control = state.get_at(ra + 2);
3298 state.set_at(ra + 2, closing);
3299 state.set_at(ra + 3, control);
3300 state.new_tbc_upval(ra + 2)?;
3301 } else {
3302 state.new_tbc_upval(ra + 3)?;
3303 }
3304 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3305 let tfc_i = code[pc as usize];
3306 pc += 1;
3307 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
3308 let tfc_ra = base + tfc_i.arg_a();
3310 if tfor_55 {
3311 let src = tfc_ra.0 as usize;
3312 let func = state.stack[src].val.clone();
3313 let state_val = state.stack[src + 1].val.clone();
3314 let control = state.stack[src + 3].val.clone();
3315 state.stack[src + 3].val = func;
3316 state.stack[src + 4].val = state_val;
3317 state.stack[src + 5].val = control;
3318 state.set_top(tfc_ra + 6);
3319 state.set_ci_savedpc(ci, pc);
3320 if !state.call_known_c_at(tfc_ra + 3, tfc_i.arg_c() as i32)? {
3321 state.call_at(tfc_ra + 3, tfc_i.arg_c() as i32)?;
3322 }
3323 } else {
3324 let src = tfc_ra.0 as usize;
3325 let dst = src + 4;
3326 for k in 0..3usize {
3327 state.stack[dst + k].val = state.stack[src + k].val.clone();
3328 }
3329 state.set_top(tfc_ra + 4 + 3);
3330 state.set_ci_savedpc(ci, pc);
3331 if !state.call_known_c_at(tfc_ra + 4, tfc_i.arg_c() as i32)? {
3332 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
3333 }
3334 }
3335 trap = state.ci_trap(ci);
3336 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3338 pc += 1;
3339 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3340 let tfl_ra = base + tfl_i.arg_a();
3341 if tfor_55 {
3343 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3344 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3345 }
3346 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3347 let v = state.get_at(tfl_ra + 4);
3348 state.set_at(tfl_ra + 2, v);
3349 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3350 }
3351 }
3352 OpCode::TForCall => {
3354 let ra = base + i.arg_a();
3355 if tfor_55 {
3356 let src = ra.0 as usize;
3357 let func = state.stack[src].val.clone();
3358 let state_val = state.stack[src + 1].val.clone();
3359 let control = state.stack[src + 3].val.clone();
3360 state.stack[src + 3].val = func;
3361 state.stack[src + 4].val = state_val;
3362 state.stack[src + 5].val = control;
3363 state.set_top(ra + 6);
3364 state.set_ci_savedpc(ci, pc);
3365 if !state.call_known_c_at(ra + 3, i.arg_c() as i32)? {
3366 state.call_at(ra + 3, i.arg_c() as i32)?;
3367 }
3368 } else {
3369 let src = ra.0 as usize;
3370 let dst = src + 4;
3371 for k in 0..3usize {
3372 state.stack[dst + k].val = state.stack[src + k].val.clone();
3373 }
3374 state.set_top(ra + 4 + 3);
3375 state.set_ci_savedpc(ci, pc);
3376 if !state.call_known_c_at(ra + 4, i.arg_c() as i32)? {
3377 state.call_at(ra + 4, i.arg_c() as i32)?;
3378 }
3379 }
3380 trap = state.ci_trap(ci);
3381 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3383 pc += 1;
3384 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3385 let tfl_ra = base + tfl_i.arg_a();
3386 if tfor_55 {
3387 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3388 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3389 }
3390 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3391 let v = state.get_at(tfl_ra + 4);
3392 state.set_at(tfl_ra + 2, v);
3393 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3394 }
3395 }
3396 OpCode::TForLoop => {
3398 let ra = base + i.arg_a();
3399 if tfor_55 {
3400 if !matches!(state.get_at(ra + 3), LuaValue::Nil) {
3401 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3402 }
3403 } else if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
3404 let v = state.get_at(ra + 4);
3405 state.set_at(ra + 2, v);
3406 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3407 }
3408 }
3409 OpCode::SetList => {
3413 let ra = base + i.arg_a();
3414 let n_raw = i.arg_b();
3415 let mut last = i.arg_c();
3416 let t_val = state.get_at(ra);
3417 let n: i32 = if n_raw == 0 {
3418 state.top_idx() - ra - 1
3419 } else {
3420 state.set_top(state.ci_top(ci));
3421 n_raw
3422 };
3423 last += n;
3424 if i.test_k() {
3425 let extra = code[pc as usize];
3426 pc += 1;
3427 const MAXARG_C: i32 = (1 << 8) - 1;
3428 last += extra.arg_ax() * (MAXARG_C + 1);
3429 }
3430 state.table_ensure_array(&t_val, last as usize)?;
3431 for k in (1..=n).rev() {
3432 let val = state.get_at(ra + k as i32);
3433 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
3434 last -= 1;
3435 state.gc_value_barrier_back(&t_val, &val);
3436 }
3437 }
3438 OpCode::Closure => {
3442 let ra = base + i.arg_a();
3443 let proto_idx = i.arg_bx() as usize;
3444 state.set_ci_savedpc(ci, pc);
3445 state.set_top(state.ci_top(ci));
3446 push_closure(state, proto_idx, ci, base, ra)?;
3447 state.set_ci_savedpc(ci, pc);
3449 state.set_top(ra + 1);
3450 state.gc_cond_step();
3451 trap = state.ci_trap(ci);
3452 }
3453 OpCode::VarArg => {
3455 let ra = base + i.arg_a();
3456 let n = i.arg_c() as i32 - 1;
3457 state.set_ci_savedpc(ci, pc);
3458 state.set_top(state.ci_top(ci));
3459 state.get_varargs(ci, ra, n)?;
3460 trap = state.ci_trap(ci);
3461 }
3462 OpCode::VarArgPrep => {
3466 let nparams = i.arg_a();
3467 state.set_ci_savedpc(ci, pc);
3468 state.adjust_varargs(ci, nparams, &cl)?;
3469 trap = state.ci_trap(ci);
3470 if trap {
3471 state.hook_call(ci)?;
3472 state.set_oldpc(1);
3473 }
3474 base = state.ci_base(ci);
3475 }
3476 OpCode::GetVArg => {
3478 let ra = base + i.arg_a();
3479 let vararg_reg = base + i.arg_b();
3480 let key = state.get_at(base + i.arg_c()).clone();
3481 let val = if let LuaValue::Table(t) = state.get_at(vararg_reg) {
3482 t.get(&key)
3483 } else {
3484 let nextra = state.ci_nextraargs(ci);
3485 match key {
3486 LuaValue::Int(n) if n >= 1 && n <= nextra as i64 => {
3487 let ci_func = state.ci_base(ci) - 1;
3488 state.get_at(ci_func - nextra + n as i32 - 1)
3489 }
3490 LuaValue::Float(f)
3491 if f.is_finite()
3492 && f.fract() == 0.0
3493 && f >= 1.0
3494 && f <= nextra as f64 =>
3495 {
3496 let ci_func = state.ci_base(ci) - 1;
3497 state.get_at(ci_func - nextra + f as i32 - 1)
3498 }
3499 LuaValue::Str(s) if s.as_bytes() == b"n" => {
3500 LuaValue::Int(nextra as i64)
3501 }
3502 _ => LuaValue::Nil,
3503 }
3504 };
3505 state.set_at(ra, val);
3506 }
3507 OpCode::ExtraArg => {
3509 debug_assert!(false, "OP_EXTRAARG executed directly");
3510 }
3511 OpCode::ErrNNil => {
3516 let ra = base + i.arg_a();
3517 if !matches!(state.get_at(ra), LuaValue::Nil) {
3518 let bx = i.arg_bx();
3519 let name: Vec<u8> = if bx == 0 {
3520 b"?".to_vec()
3521 } else {
3522 match constants[(bx - 1) as usize] {
3523 LuaValue::Str(s) => s.as_bytes().to_vec(),
3524 _ => b"?".to_vec(),
3525 }
3526 };
3527 let mut msg = Vec::with_capacity(name.len() + 24);
3528 msg.extend_from_slice(b"global '");
3529 msg.extend_from_slice(&name);
3530 msg.extend_from_slice(b"' already defined");
3531 state.set_ci_savedpc(ci, pc);
3532 return Err(crate::debug::prefixed_runtime_pub(state, msg));
3533 }
3534 }
3535 OpCode::VarArgPack => {
3543 if !cl.proto.vararg_table_needed && !i.test_k() {
3544 state.set_ci_savedpc(ci, pc);
3545 continue;
3546 }
3547 let ra = base + i.arg_a();
3548 let nextra = state.ci_nextraargs(ci);
3549 let ci_func: StackIdx = state.ci_base(ci) - 1;
3550 let t = if nextra > 0 {
3551 state.new_table_with_sizes(nextra as u32, 1)?
3552 } else {
3553 state.new_table()
3554 };
3555 for k in 0..nextra {
3556 let src: StackIdx = ci_func - nextra as i32 + k as i32;
3557 let val = state.get_at(src);
3558 t.raw_set_int(state, (k + 1) as i64, val)?;
3559 }
3560 let n_key = state.intern_str(b"n")?;
3561 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
3562 state.set_at(ra, LuaValue::Table(t));
3563 state.set_ci_savedpc(ci, pc);
3564 state.set_top(ra + 1);
3565 state.gc_cond_step();
3566 if state.hookmask != 0 {
3567 trap = state.ci_trap(ci);
3568 }
3569 }
3570 } } if state.ci_is_fresh(ci) {
3575 return Ok(());
3576 } else {
3577 ci = state
3578 .ci_previous(ci)
3579 .expect("ci_previous: not fresh frame must have previous");
3580 continue 'returning;
3581 }
3582 } } }
3585
3586#[inline(always)]
3589fn number_value(v: LuaValue) -> Option<f64> {
3590 match v {
3591 LuaValue::Float(f) => Some(f),
3592 LuaValue::Int(i) => Some(i as f64),
3593 _ => None,
3594 }
3595}
3596
3597#[allow(dead_code)]
3599#[inline]
3600fn arith_op_aux_rr(
3601 state: &mut LuaState,
3602 ra: StackIdx,
3603 v1: &LuaValue,
3604 v2: &LuaValue,
3605 pc: &mut u32,
3606 iop: fn(i64, i64) -> i64,
3607 fop: fn(f64, f64) -> f64,
3608) {
3609 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3610 *pc += 1;
3611 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3612 } else {
3613 arith_float_aux(state, ra, v1, v2, pc, fop);
3614 }
3615}
3616
3617#[allow(dead_code)]
3618#[inline]
3619fn arith_float_aux(
3620 state: &mut LuaState,
3621 ra: StackIdx,
3622 v1: &LuaValue,
3623 v2: &LuaValue,
3624 pc: &mut u32,
3625 fop: fn(f64, f64) -> f64,
3626) {
3627 let n1 = match v1 {
3628 LuaValue::Float(f) => Some(*f),
3629 LuaValue::Int(i) => Some(*i as f64),
3630 _ => None,
3631 };
3632 let n2 = match v2 {
3633 LuaValue::Float(f) => Some(*f),
3634 LuaValue::Int(i) => Some(*i as f64),
3635 _ => None,
3636 };
3637 if let (Some(n1), Some(n2)) = (n1, n2) {
3638 *pc += 1;
3639 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3640 }
3641}
3642
3643#[allow(dead_code)]
3644#[inline]
3645fn arith_op_checked(
3646 state: &mut LuaState,
3647 ra: StackIdx,
3648 v1: &LuaValue,
3649 v2: &LuaValue,
3650 pc: &mut u32,
3651 iop: fn(i64, i64) -> Result<i64, LuaError>,
3652 fop: fn(f64, f64) -> f64,
3653) -> Result<(), LuaError> {
3654 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3655 *pc += 1;
3656 let result = iop(*i1, *i2).map_err(|e| match e {
3657 LuaError::Runtime(LuaValue::Str(s)) => {
3658 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3659 }
3660 LuaError::RuntimeMsg(b) => crate::debug::prefixed_runtime_pub(state, b.into_vec()),
3661 other => other,
3662 })?;
3663 state.set_at(ra, LuaValue::Int(result));
3664 } else {
3665 arith_float_aux(state, ra, v1, v2, pc, fop);
3666 }
3667 Ok(())
3668}
3669
3670#[allow(dead_code)]
3671#[inline]
3672fn bitwise_op_k(
3673 state: &mut LuaState,
3674 ra: StackIdx,
3675 v1: &LuaValue,
3676 v2: &LuaValue, pc: &mut u32,
3678 op: fn(i64, i64) -> i64,
3679) {
3680 let i2 = match v2 {
3681 LuaValue::Int(i) => *i,
3682 _ => return,
3683 };
3684 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3685 *pc += 1;
3686 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3687 }
3688}
3689
3690#[allow(dead_code)]
3691#[inline]
3692fn bitwise_op_rr(
3693 state: &mut LuaState,
3694 ra: StackIdx,
3695 v1: &LuaValue,
3696 v2: &LuaValue,
3697 pc: &mut u32,
3698 op: fn(i64, i64) -> i64,
3699) {
3700 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3701 *pc += 1;
3702 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3703 }
3704}
3705
3706#[allow(dead_code)]
3708#[inline]
3709fn bitwise_shift_rr(
3710 state: &mut LuaState,
3711 ra: StackIdx,
3712 v1: &LuaValue,
3713 v2: &LuaValue,
3714 pc: &mut u32,
3715 right: bool,
3716) {
3717 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3718 let y = if right { intop_sub(0, i2) } else { i2 };
3719 *pc += 1;
3720 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3721 }
3722}
3723
3724#[cold]
3727#[inline(never)]
3728#[allow(clippy::too_many_arguments)]
3729fn order_imm_slow(
3730 state: &mut LuaState,
3731 ra: StackIdx,
3732 pc: u32,
3733 trap: &mut bool,
3734 ci: CallInfoIdx,
3735 i: Instruction,
3736 im: i64,
3737 inv: bool,
3738 tm: TagMethod,
3739) -> Result<bool, LuaError> {
3740 let ra_v = state.get_at(ra);
3741 let isf = i.arg_c() != 0;
3742 state.set_ci_savedpc(ci, pc);
3743 state.set_top(state.ci_top(ci));
3744 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3745 *trap = state.ci_trap(ci);
3746 Ok(r)
3747}
3748
3749#[inline(always)]
3750fn finish_order_imm_jump(
3751 state: &mut LuaState,
3752 code: &[Instruction],
3753 pc: &mut u32,
3754 trap: &mut bool,
3755 ci: CallInfoIdx,
3756 i: Instruction,
3757 cond: bool,
3758) {
3759 if (cond as i32) != i.arg_k() {
3760 *pc += 1;
3761 } else {
3762 let next = code[*pc as usize];
3763 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3764 if state.hookmask != 0 {
3765 *trap = state.ci_trap(ci);
3766 }
3767 }
3768}
3769
3770#[cold]
3771#[inline(never)]
3772fn return0_hook(
3773 state: &mut LuaState,
3774 ci: CallInfoIdx,
3775 base: StackIdx,
3776 i: Instruction,
3777 pc: u32,
3778 trap: &mut bool,
3779) -> Result<(), LuaError> {
3780 let ra = base + i.arg_a();
3781 state.set_top(ra);
3782 state.set_ci_savedpc(ci, pc);
3783 state.poscall(ci, 0)?;
3784 *trap = true;
3785 Ok(())
3786}
3787
3788#[cold]
3789#[inline(never)]
3790fn return1_hook(
3791 state: &mut LuaState,
3792 ci: CallInfoIdx,
3793 base: StackIdx,
3794 i: Instruction,
3795 pc: u32,
3796 trap: &mut bool,
3797) -> Result<(), LuaError> {
3798 let ra = base + i.arg_a();
3799 state.set_top(ra + 1);
3800 state.set_ci_savedpc(ci, pc);
3801 state.poscall(ci, 1)?;
3802 *trap = true;
3803 Ok(())
3804}
3805
3806