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 {
280 fn opcode(&self) -> OpCode;
281 fn arg_a(&self) -> i32;
282 fn arg_b(&self) -> i32;
283 fn arg_c(&self) -> i32;
284 fn arg_k(&self) -> i32;
285 fn arg_ax(&self) -> i32;
286 fn arg_bx(&self) -> i32;
287 fn arg_s_b(&self) -> i32;
288 fn arg_s_c(&self) -> i32;
289 fn arg_s_j(&self) -> i32;
290 fn arg_s_bx(&self) -> i32;
291 fn test_k(&self) -> bool;
292 fn test_a_mode(&self) -> bool;
293 fn is_mm_mode(&self) -> bool;
294 fn is_vararg_prep(&self) -> bool;
295 fn is_in_top(&self) -> bool;
296}
297
298impl InstructionExt for Instruction {
299 #[inline(always)]
307 fn opcode(&self) -> OpCode {
308 match (self.raw() & 0x7F) as u8 {
309 0 => OpCode::Move,
310 1 => OpCode::LoadI,
311 2 => OpCode::LoadF,
312 3 => OpCode::LoadK,
313 4 => OpCode::LoadKX,
314 5 => OpCode::LoadFalse,
315 6 => OpCode::LFalseSkip,
316 7 => OpCode::LoadTrue,
317 8 => OpCode::LoadNil,
318 9 => OpCode::GetUpVal,
319 10 => OpCode::SetUpVal,
320 11 => OpCode::GetTabUp,
321 12 => OpCode::GetTable,
322 13 => OpCode::GetI,
323 14 => OpCode::GetField,
324 15 => OpCode::SetTabUp,
325 16 => OpCode::SetTable,
326 17 => OpCode::SetI,
327 18 => OpCode::SetField,
328 19 => OpCode::NewTable,
329 20 => OpCode::Self_,
330 21 => OpCode::AddI,
331 22 => OpCode::AddK,
332 23 => OpCode::SubK,
333 24 => OpCode::MulK,
334 25 => OpCode::ModK,
335 26 => OpCode::PowK,
336 27 => OpCode::DivK,
337 28 => OpCode::IDivK,
338 29 => OpCode::BAndK,
339 30 => OpCode::BOrK,
340 31 => OpCode::BXOrK,
341 32 => OpCode::ShrI,
342 33 => OpCode::ShlI,
343 34 => OpCode::Add,
344 35 => OpCode::Sub,
345 36 => OpCode::Mul,
346 37 => OpCode::Mod,
347 38 => OpCode::Pow,
348 39 => OpCode::Div,
349 40 => OpCode::IDiv,
350 41 => OpCode::BAnd,
351 42 => OpCode::BOr,
352 43 => OpCode::BXOr,
353 44 => OpCode::Shl,
354 45 => OpCode::Shr,
355 46 => OpCode::MmBin,
356 47 => OpCode::MmBinI,
357 48 => OpCode::MmBinK,
358 49 => OpCode::Unm,
359 50 => OpCode::BNot,
360 51 => OpCode::Not,
361 52 => OpCode::Len,
362 53 => OpCode::Concat,
363 54 => OpCode::Close,
364 55 => OpCode::Tbc,
365 56 => OpCode::Jmp,
366 57 => OpCode::Eq,
367 58 => OpCode::Lt,
368 59 => OpCode::Le,
369 60 => OpCode::EqK,
370 61 => OpCode::EqI,
371 62 => OpCode::LtI,
372 63 => OpCode::LeI,
373 64 => OpCode::GtI,
374 65 => OpCode::GeI,
375 66 => OpCode::Test,
376 67 => OpCode::TestSet,
377 68 => OpCode::Call,
378 69 => OpCode::TailCall,
379 70 => OpCode::Return,
380 71 => OpCode::Return0,
381 72 => OpCode::Return1,
382 73 => OpCode::ForLoop,
383 74 => OpCode::ForPrep,
384 75 => OpCode::TForPrep,
385 76 => OpCode::TForCall,
386 77 => OpCode::TForLoop,
387 78 => OpCode::SetList,
388 79 => OpCode::Closure,
389 80 => OpCode::VarArg,
390 81 => OpCode::VarArgPrep,
391 82 => OpCode::ExtraArg,
392 83 => OpCode::ErrNNil,
393 84 => OpCode::VarArgPack,
394 85 => OpCode::GetVArg,
395 _ => OpCode::ExtraArg,
396 }
397 }
398 #[inline]
399 fn arg_a(&self) -> i32 {
400 ((self.raw() >> 7) & 0xFF) as i32
401 }
402 #[inline]
403 fn arg_b(&self) -> i32 {
404 ((self.raw() >> 16) & 0xFF) as i32
405 }
406 #[inline]
407 fn arg_c(&self) -> i32 {
408 ((self.raw() >> 24) & 0xFF) as i32
409 }
410 #[inline]
411 fn arg_k(&self) -> i32 {
412 ((self.raw() >> 15) & 0x1) as i32
413 }
414 #[inline]
415 fn arg_ax(&self) -> i32 {
416 (self.raw() >> 7) as i32
417 }
418 #[inline]
419 fn arg_bx(&self) -> i32 {
420 (self.raw() >> 15) as i32
421 }
422 #[inline]
423 fn arg_s_b(&self) -> i32 {
424 self.arg_b() - 0x7F
425 }
426 #[inline]
427 fn arg_s_c(&self) -> i32 {
428 self.arg_c() - 0x7F
429 }
430 #[inline]
431 fn arg_s_j(&self) -> i32 {
432 self.arg_ax() - 0xFFFFFF
433 }
434 #[inline]
435 fn arg_s_bx(&self) -> i32 {
436 self.arg_bx() - 0xFFFF
437 }
438 #[inline]
439 fn test_k(&self) -> bool {
440 (self.raw() & (1 << 15)) != 0
441 }
442 #[inline]
443 fn test_a_mode(&self) -> bool {
444 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
445 }
446 #[inline]
447 fn is_mm_mode(&self) -> bool {
448 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
449 }
450 #[inline]
451 fn is_vararg_prep(&self) -> bool {
452 matches!(self.opcode(), OpCode::VarArgPrep)
453 }
454 #[inline]
455 fn is_in_top(&self) -> bool {
456 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
457 }
458}
459
460const 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;
1142 let mut s2 = s2;
1143 loop {
1144 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
1146 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
1147 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
1149 if seg_cmp != std::cmp::Ordering::Equal {
1150 return seg_cmp;
1151 }
1152 if z2 == s2.len() {
1154 if z1 == s1.len() {
1156 return std::cmp::Ordering::Equal;
1157 }
1158 return std::cmp::Ordering::Greater; }
1160 if z1 == s1.len() {
1161 return std::cmp::Ordering::Less; }
1163 s1 = &s1[z1 + 1..];
1165 s2 = &s2[z2 + 1..];
1166 }
1167}
1168
1169#[inline]
1172fn lt_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::Ceil) {
1177 Some(fi) => i < fi,
1178 None => f > 0.0, }
1180 }
1181}
1182
1183#[inline]
1184fn le_int_float(i: i64, f: f64) -> bool {
1185 if int_fits_float(i) {
1186 (i as f64) <= f
1187 } else {
1188 match flt_to_integer(f, F2Imod::Floor) {
1189 Some(fi) => i <= fi,
1190 None => f > 0.0,
1191 }
1192 }
1193}
1194
1195#[inline]
1196fn lt_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::Floor) {
1201 Some(fi) => fi < i,
1202 None => f < 0.0,
1203 }
1204 }
1205}
1206
1207#[inline]
1208fn le_float_int(f: f64, i: i64) -> bool {
1209 if int_fits_float(i) {
1210 f <= (i as f64)
1211 } else {
1212 match flt_to_integer(f, F2Imod::Ceil) {
1213 Some(fi) => fi <= i,
1214 None => f < 0.0,
1215 }
1216 }
1217}
1218
1219#[inline]
1220fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
1221 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1222 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1223 match (l, r) {
1224 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1225 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1226 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1227 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1228 _ => false,
1229 }
1230}
1231
1232#[inline]
1233fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1234 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1235 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1236 match (l, r) {
1237 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1238 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1239 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1240 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1241 _ => false,
1242 }
1243}
1244
1245fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1247 debug_assert!(
1248 !(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1249 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_)))
1250 );
1251 match (l, r) {
1252 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1253 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1254 }
1255 _ => state.call_order_tm(l, r, TagMethod::Lt),
1256 }
1257}
1258
1259pub(crate) fn less_than(
1260 state: &mut LuaState,
1261 l: &LuaValue,
1262 r: &LuaValue,
1263) -> Result<bool, LuaError> {
1264 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1265 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1266 {
1267 Ok(lt_num(l, r))
1268 } else {
1269 less_than_others(state, l, r)
1270 }
1271}
1272
1273fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1274 match (l, r) {
1275 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1276 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1277 }
1278 _ => state.call_order_tm(l, r, TagMethod::Le),
1279 }
1280}
1281
1282pub(crate) fn less_equal(
1283 state: &mut LuaState,
1284 l: &LuaValue,
1285 r: &LuaValue,
1286) -> Result<bool, LuaError> {
1287 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1288 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1289 {
1290 Ok(le_num(l, r))
1291 } else {
1292 less_equal_others(state, l, r)
1293 }
1294}
1295
1296pub(crate) fn raw_equal_values(t1: &LuaValue, t2: &LuaValue) -> bool {
1305 matches!(equal_obj(None, t1, t2), Ok(true))
1306}
1307
1308fn equal_tm(state: &mut LuaState, t1: &LuaValue, t2: &LuaValue) -> LuaValue {
1316 let eq = crate::tagmethods::TagMethod::Eq;
1317 if state.global().lua_version == lua_types::LuaVersion::V51 {
1318 return crate::tagmethods::get_comp_tm_51(state, t1, t2, eq);
1319 }
1320 let tm1 = crate::tagmethods::get_tm_by_obj(state, t1, eq);
1321 if tm1.is_nil() {
1322 crate::tagmethods::get_tm_by_obj(state, t2, eq)
1323 } else {
1324 tm1
1325 }
1326}
1327
1328pub(crate) fn equal_obj(
1330 state: Option<&mut LuaState>,
1331 t1: &LuaValue,
1332 t2: &LuaValue,
1333) -> Result<bool, LuaError> {
1334 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1337 if !same_variant {
1338 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1339 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1340 if !(t1_is_num && t2_is_num) {
1341 return Ok(false);
1342 }
1343 let i1 = to_integer_ns(t1, F2Imod::Eq);
1345 let i2 = to_integer_ns(t2, F2Imod::Eq);
1346 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1347 }
1348
1349 match (t1, t2) {
1350 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1351 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1352 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1353 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1354 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1355 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1356 use lua_types::closure::LuaClosure;
1357 let same = match (f1, f2) {
1358 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1359 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1360 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1361 _ => false,
1362 };
1363 Ok(same)
1364 }
1365 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1366 Ok(s1 == s2)
1369 }
1370 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1371 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1374 return Ok(true);
1375 }
1376 let Some(state) = state else {
1377 return Ok(false);
1378 };
1379 let tm = equal_tm(state, t1, t2);
1380 if matches!(tm, LuaValue::Nil) {
1381 return Ok(false);
1382 }
1383 let result = state.call_tm_res_bool(tm, t1, t2)?;
1384 Ok(result)
1385 }
1386 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1387 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1388 return Ok(true);
1389 }
1390 let Some(state) = state else {
1391 return Ok(false);
1392 };
1393 let tm = equal_tm(state, t1, t2);
1394 if matches!(tm, LuaValue::Nil) {
1395 return Ok(false);
1396 }
1397 let result = state.call_tm_res_bool(tm, t1, t2)?;
1398 Ok(result)
1399 }
1400 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1401 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1402 }
1403}
1404
1405fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1409 buf.clear();
1410 let mut remaining = n;
1411 loop {
1412 let idx = top - remaining as i32;
1413 let v = state.get_at(idx);
1414 if let LuaValue::Str(ts) = v {
1415 buf.extend_from_slice(ts.as_bytes());
1416 }
1417 if remaining <= 1 {
1418 break;
1419 }
1420 remaining -= 1;
1421 }
1422}
1423
1424pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1426 if total == 1 {
1427 return Ok(());
1428 }
1429 if total == 2 {
1430 let top = state.top_idx();
1431 let v_tm1 = state.get_at(top - 1);
1432 let v_tm2 = state.get_at(top - 2);
1433 if concat_pair_fast(state, top, v_tm2, v_tm1)? {
1434 return Ok(());
1435 }
1436 }
1437 let mut total = total;
1438 loop {
1439 let top = state.top_idx();
1440 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1445 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1446 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1448 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1449 if !top2_coercible || !top1_stringlike {
1450 state.try_concat_tm(&v_tm1, &v_tm2)?;
1451 total -= 1;
1456 let top = state.top_idx();
1457 state.set_top(top - 1);
1458 if total <= 1 {
1459 break;
1460 }
1461 continue;
1462 }
1463
1464 let is_empty =
1465 |v: &LuaValue| -> bool { matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty()) };
1466
1467 let n: u32;
1468 if is_empty(&v_tm1) {
1469 state.coerce_to_string(top - 2)?;
1470 n = 2;
1471 } else if is_empty(&v_tm2) {
1472 state.coerce_to_string(top - 1)?;
1475 let v = state.get_at(top - 1);
1476 state.set_at(top - 2, v);
1477 n = 2;
1478 } else {
1479 state.coerce_to_string(top - 1)?;
1481 let s1 = match state.get_at(top - 1) {
1482 LuaValue::Str(ts) => ts.as_bytes().len(),
1483 _ => 0,
1484 };
1485 let mut total_len = s1;
1486 let mut count: u32 = 1;
1487 let top = state.top_idx();
1488 loop {
1489 if count as i32 >= total {
1490 break;
1491 }
1492 let idx = top - (count as i32 + 1);
1493 let v = state.get_at(idx);
1494 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1495 break;
1496 }
1497 state.coerce_to_string(idx)?;
1498 let l = match state.get_at(idx) {
1499 LuaValue::Str(ts) => ts.as_bytes().len(),
1500 _ => 0,
1501 };
1502 if l >= usize::MAX - total_len {
1503 state.set_top(top - total as i32);
1505 return Err(LuaError::runtime(format_args!("string length overflow")));
1506 }
1507 total_len += l;
1508 count += 1;
1509 }
1510 n = count;
1511
1512 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1514 let top = state.top_idx();
1515 copy_to_buf(state, top, n, &mut buf);
1516 let ts = state.intern_or_create_str(&buf)?;
1517 state.set_at(top - n as i32, LuaValue::Str(ts));
1518 }
1519 total -= n as i32 - 1;
1520 let top = state.top_idx();
1521 state.set_top(top - ((n - 1) as i32));
1522
1523 if total <= 1 {
1524 break;
1525 }
1526 }
1527 Ok(())
1528}
1529
1530enum ConcatPiece {
1531 Str(GcRef<LuaString>),
1532 Num(Vec<u8>),
1533}
1534
1535impl ConcatPiece {
1536 #[inline]
1537 fn len(&self) -> usize {
1538 match self {
1539 ConcatPiece::Str(s) => s.as_bytes().len(),
1540 ConcatPiece::Num(bytes) => bytes.len(),
1541 }
1542 }
1543
1544 #[inline]
1545 fn append_to(&self, out: &mut Vec<u8>) {
1546 match self {
1547 ConcatPiece::Str(s) => out.extend_from_slice(s.as_bytes()),
1548 ConcatPiece::Num(bytes) => out.extend_from_slice(bytes),
1549 }
1550 }
1551}
1552
1553#[inline]
1554fn concat_piece(v: LuaValue, version: lua_types::LuaVersion) -> Option<ConcatPiece> {
1555 match v {
1556 LuaValue::Str(s) => Some(ConcatPiece::Str(s)),
1557 LuaValue::Int(_) | LuaValue::Float(_) => Some(ConcatPiece::Num(
1558 crate::object::number_to_str_buf(&v, version),
1559 )),
1560 _ => None,
1561 }
1562}
1563
1564#[inline]
1565fn concat_pair_fast(
1566 state: &mut LuaState,
1567 top: StackIdx,
1568 left: LuaValue,
1569 right: LuaValue,
1570) -> Result<bool, LuaError> {
1571 let version = state.global().lua_version;
1572 let Some(left) = concat_piece(left, version) else {
1573 return Ok(false);
1574 };
1575 let Some(right) = concat_piece(right, version) else {
1576 return Ok(false);
1577 };
1578 let total_len = left
1579 .len()
1580 .checked_add(right.len())
1581 .ok_or_else(|| LuaError::runtime(format_args!("string length overflow")))?;
1582 let mut buf = Vec::with_capacity(total_len);
1583 left.append_to(&mut buf);
1584 right.append_to(&mut buf);
1585 let ts = state.intern_or_create_str(&buf)?;
1586 state.set_at(top - 2, LuaValue::Str(ts));
1587 state.set_top(top - 1);
1588 Ok(true)
1589}
1590
1591pub(crate) fn obj_len(
1595 state: &mut LuaState,
1596 ra: StackIdx,
1597 rb: LuaValue,
1598 rb_idx: StackIdx,
1599) -> Result<(), LuaError> {
1600 match &rb {
1601 LuaValue::Table(_) => {
1602 let consult_len_tm = !matches!(state.global().lua_version, lua_types::LuaVersion::V51);
1607 let tm = if consult_len_tm {
1608 let mt = state.table_metatable(&rb);
1609 state.fast_tm_table(mt.as_ref(), TagMethod::Len)
1610 } else {
1611 LuaValue::Nil
1612 };
1613 if matches!(tm, LuaValue::Nil) {
1614 let n = state.table_length(&rb)?;
1615 state.set_at(ra, LuaValue::Int(n as i64));
1616 return Ok(());
1617 }
1618 state.call_tm_res(tm, &rb, &rb, ra)?;
1620 }
1621 LuaValue::Str(ts) => {
1622 let n = ts.len();
1625 state.set_at(ra, LuaValue::Int(n as i64));
1626 }
1627 other => {
1628 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1630 if matches!(tm, LuaValue::Nil) {
1631 return Err(crate::debug::type_error(
1632 state,
1633 other,
1634 rb_idx,
1635 b"get length of",
1636 ));
1637 }
1638 state.call_tm_res(tm, &rb, &rb, ra)?;
1639 }
1640 }
1641 Ok(())
1642}
1643
1644pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1648 if (n as u64).wrapping_add(1) <= 1 {
1649 if n == 0 {
1650 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1651 }
1652 return Ok(intop_sub(0, m));
1653 }
1654 let q = m / n;
1655 if (m ^ n) < 0 && m % n != 0 {
1657 Ok(q - 1)
1658 } else {
1659 Ok(q)
1660 }
1661}
1662
1663pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1665 if (n as u64).wrapping_add(1) <= 1 {
1666 if n == 0 {
1667 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1668 }
1669 return Ok(0);
1670 }
1671 let r = m % n;
1672 if r != 0 && (r ^ n) < 0 {
1673 Ok(r + n)
1674 } else {
1675 Ok(r)
1676 }
1677}
1678
1679pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1681 let r = m % n;
1682 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1683 if opposite_signs {
1684 r + n
1685 } else {
1686 r
1687 }
1688}
1689
1690pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1693 use TagMethod::*;
1694 match i {
1695 0 => Index,
1696 1 => NewIndex,
1697 2 => Gc,
1698 3 => Mode,
1699 4 => Len,
1700 5 => Eq,
1701 6 => Add,
1702 7 => Sub,
1703 8 => Mul,
1704 9 => Mod,
1705 10 => Pow,
1706 11 => Div,
1707 12 => Idiv,
1708 13 => Band,
1709 14 => Bor,
1710 15 => Bxor,
1711 16 => Shl,
1712 17 => Shr,
1713 18 => Unm,
1714 19 => Bnot,
1715 20 => Lt,
1716 21 => Le,
1717 22 => Concat,
1718 23 => Call,
1719 24 => Close,
1720 _ => Index,
1721 }
1722}
1723
1724pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1727 imod(a, b)
1728}
1729
1730pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1733 idiv(a, b)
1734}
1735
1736pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1739 Ok(fmodf(a, b))
1740}
1741
1742pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1744 if y < 0 {
1745 if y <= -(NBITS as i64) {
1746 0
1747 } else {
1748 intop_shr(x, (-y) as u32)
1749 }
1750 } else {
1751 if y >= NBITS as i64 {
1752 0
1753 } else {
1754 intop_shl(x, y as u32)
1755 }
1756 }
1757}
1758
1759fn 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)
1774}
1775
1776pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1781 let ci = state.current_ci_idx();
1785 let base = state.ci_base(ci);
1786 let inst = state.ci_prev_instruction(ci);
1787 let op = inst.opcode();
1788
1789 match op {
1790 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1792 let prev_inst = state.ci_prev2_instruction(ci);
1793 let a = prev_inst.arg_a();
1794 state.dec_top();
1795 let top = state.top_idx();
1796 let v = state.get_at(top);
1797 state.set_at(base + a, v);
1798 }
1799 OpCode::Unm
1801 | OpCode::BNot
1802 | OpCode::Len
1803 | OpCode::GetTabUp
1804 | OpCode::GetTable
1805 | OpCode::GetI
1806 | OpCode::GetField
1807 | OpCode::Self_ => {
1808 let a = inst.arg_a();
1809 state.dec_top();
1810 let top = state.top_idx();
1811 let v = state.get_at(top);
1812 state.set_at(base + a, v);
1813 }
1814 OpCode::Lt
1818 | OpCode::Le
1819 | OpCode::LtI
1820 | OpCode::LeI
1821 | OpCode::GtI
1822 | OpCode::GeI
1823 | OpCode::Eq => {
1824 let top_minus1 = state.top_idx() - 1;
1825 let v = state.get_at(top_minus1);
1826 let mut res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1827 state.dec_top();
1828 if (state.get_ci(ci).callstatus & crate::state::CIST_LEQ) != 0 {
1833 state.get_ci_mut(ci).callstatus &= !crate::state::CIST_LEQ;
1834 res = !res;
1835 }
1836 if (res as i32) != inst.arg_k() {
1837 state.ci_skip_next_instruction(ci);
1838 }
1839 }
1840 OpCode::Concat => {
1846 let top = state.top_idx() - 1; let a = inst.arg_a();
1848 let total_concat = (top - 1 - (base + a)) as i32;
1849 let v = state.get_at(top);
1850 state.set_at(top - 2, v);
1851 state.set_top(top - 1);
1852 concat(state, total_concat)?;
1853 }
1854 OpCode::Close => {
1855 state.ci_step_pc_back(ci);
1856 }
1857 OpCode::Return => {
1861 let a = inst.arg_a();
1862 let ra = base + a;
1863 let nres = state.ci_nres(ci);
1864 state.set_top(ra + nres);
1865 state.ci_step_pc_back(ci);
1866 }
1867 other => {
1868 debug_assert!(
1869 matches!(
1870 other,
1871 OpCode::TForCall
1872 | OpCode::Call
1873 | OpCode::TailCall
1874 | OpCode::SetTabUp
1875 | OpCode::SetTable
1876 | OpCode::SetI
1877 | OpCode::SetField
1878 ),
1879 "unexpected opcode in finish_op: {:?}",
1880 other
1881 );
1882 }
1883 }
1884 Ok(())
1885}
1886
1887pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1899 let mut trap: bool;
1900 let legacy_for = matches!(
1907 state.global().lua_version,
1908 lua_types::LuaVersion::V51 | lua_types::LuaVersion::V52 | lua_types::LuaVersion::V53
1909 );
1910 let tfor_55 = state.global().lua_version == lua_types::LuaVersion::V55;
1911
1912 'startfunc: loop {
1914 trap = state.hook_mask() != 0;
1915
1916 'returning: loop {
1919 let ci_slot = ci.as_usize();
1920 let func_idx = state.call_info[ci_slot].func;
1921 let cl = match state.stack[func_idx.0 as usize].val {
1922 LuaValue::Function(lua_types::closure::LuaClosure::Lua(c)) => c,
1923 _ => {
1924 return Err(LuaError::runtime(format_args!(
1925 "internal: execute called on non-Lua frame"
1926 )));
1927 }
1928 };
1929 let code = &cl.proto.code;
1930 let constants = &cl.proto.k;
1931 let mut pc: u32 = state.call_info[ci_slot].saved_pc();
1933
1934 if trap {
1935 trap = state.trace_call(ci)?;
1936 }
1937 let mut base: StackIdx = state.call_info[ci.as_usize()].func + 1;
1938
1939 'dispatch: loop {
1941 if trap {
1942 trap = state.trace_exec(ci, pc)?;
1943 base = state.ci_base(ci); }
1945 let i: Instruction = code[pc as usize];
1946 pc += 1;
1947 let op = i.opcode();
1948 #[cfg(feature = "opcode-profile")]
1949 crate::opcode_profile::record(op);
1950
1951 debug_assert!(base == state.ci_base(ci));
1952
1953 #[cfg(debug_assertions)]
1957 {
1958 let op_mode = op_mode_byte(op);
1959 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1960 state.set_top(base);
1961 }
1962 }
1963
1964 match op {
1965 OpCode::Move => {
1967 let ra = base + i.arg_a();
1968 let rb = base + i.arg_b();
1969 let v = state.stack[rb.0 as usize].val;
1970 state.stack[ra.0 as usize].val = v;
1971 }
1972 OpCode::LoadI => {
1974 let ra = base + i.arg_a();
1975 let b = i.arg_s_bx() as i64;
1976 state.stack[ra.0 as usize].val = LuaValue::Int(b);
1977 }
1978 OpCode::LoadF => {
1980 let ra = base + i.arg_a();
1981 let b = i.arg_s_bx() as f64;
1982 state.stack[ra.0 as usize].val = LuaValue::Float(b);
1983 }
1984 OpCode::LoadK => {
1986 let ra = base + i.arg_a();
1987 let k_idx = i.arg_bx() as usize;
1988 state.stack[ra.0 as usize].val = constants[k_idx];
1989 }
1990 OpCode::LoadKX => {
1992 let ra = base + i.arg_a();
1993 let extra = code[pc as usize];
1994 pc += 1;
1995 let k_idx = extra.arg_ax() as usize;
1996 state.stack[ra.0 as usize].val = constants[k_idx];
1997 }
1998 OpCode::LoadFalse => {
2000 let ra = base + i.arg_a();
2001 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
2002 }
2003 OpCode::LFalseSkip => {
2005 let ra = base + i.arg_a();
2006 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
2007 pc += 1;
2008 }
2009 OpCode::LoadTrue => {
2011 let ra = base + i.arg_a();
2012 state.stack[ra.0 as usize].val = LuaValue::Bool(true);
2013 }
2014 OpCode::LoadNil => {
2016 let ra = base + i.arg_a();
2017 let b = i.arg_b();
2018 for k in 0..=b {
2019 state.stack[(ra + k).0 as usize].val = LuaValue::Nil;
2020 }
2021 }
2022 OpCode::GetUpVal => {
2024 let ra = base + i.arg_a();
2025 let b = i.arg_b() as usize;
2026 let uv = cl.upval(b);
2027 let v = match uv.try_open_payload() {
2028 Some((thread_id, idx))
2029 if thread_id == state.cached_thread_id =>
2030 {
2031 state.stack[idx.0 as usize].val
2032 }
2033 Some(_) => state.upvalue_get(&cl, b),
2034 None => uv.closed_value(),
2035 };
2036 state.stack[ra.0 as usize].val = v;
2037 }
2038 OpCode::SetUpVal => {
2041 let ra = base + i.arg_a();
2042 let b = i.arg_b() as usize;
2043 let v = state.stack[ra.0 as usize].val;
2044 let uv = cl.upval(b);
2045 match uv.try_open_payload() {
2046 Some((thread_id, idx))
2047 if thread_id == state.cached_thread_id =>
2048 {
2049 state.stack[idx.0 as usize].val = v;
2050 if v.is_collectable() {
2051 state.gc_barrier_upval(&uv, &v);
2052 }
2053 }
2054 None => {
2055 uv.set_closed_value(v);
2056 if v.is_collectable() {
2057 state.gc_barrier_upval(&uv, &v);
2058 }
2059 }
2060 _ => {
2061 state.upvalue_set(&cl, b, v)?;
2062 }
2063 }
2064 }
2065 OpCode::GetTabUp => {
2069 let ra = base + i.arg_a();
2070 let b = i.arg_b() as usize;
2071 let k_idx = i.arg_c() as usize;
2072 let upval = state.upvalue_get(&cl, b);
2073 let key = constants[k_idx];
2074 match state.fast_get_short_str(&upval, &key)? {
2075 Some(v) => state.set_at(ra, v),
2076 None => {
2077 state.set_ci_savedpc(ci, pc);
2078 state.set_top(state.ci_top(ci));
2079 let upval_name: Vec<u8> =
2080 cl.0.proto
2081 .upvalues
2082 .get(b)
2083 .and_then(|uv| uv.name.as_ref())
2084 .map(|s| s.as_bytes().to_vec())
2085 .unwrap_or_else(|| b"?".to_vec());
2086 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2087 finish_get(state, upval, key, ra, true, None, hint)?;
2088 trap = state.ci_trap(ci);
2089 }
2090 }
2091 }
2092 OpCode::GetTable => {
2095 let ra = base + i.arg_a();
2096 let rb_idx = base + i.arg_b();
2097 let rb_v = state.get_at(rb_idx);
2098 let rc_v = state.get_at(base + i.arg_c());
2099 let fast_result = if let LuaValue::Int(n) = &rc_v {
2100 state.fast_get_int(&rb_v, *n)?
2101 } else {
2102 state.fast_get(&rb_v, &rc_v)?
2103 };
2104 match fast_result {
2105 Some(v) => state.set_at(ra, v),
2106 None => {
2107 state.set_ci_savedpc(ci, pc);
2108 state.set_top(state.ci_top(ci));
2109 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx), None)?;
2110 trap = state.ci_trap(ci);
2111 }
2112 }
2113 }
2114 OpCode::GetI => {
2118 let ra = base + i.arg_a();
2119 let rb_idx = base + i.arg_b();
2120 let rb_v = state.get_at(rb_idx);
2121 let c = i.arg_c() as i64;
2122 match state.fast_get_int(&rb_v, c)? {
2123 Some(v) => state.set_at(ra, v),
2124 None => {
2125 let key = LuaValue::Int(c);
2126 state.set_ci_savedpc(ci, pc);
2127 state.set_top(state.ci_top(ci));
2128 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2129 trap = state.ci_trap(ci);
2130 }
2131 }
2132 }
2133 OpCode::GetField => {
2135 let ra = base + i.arg_a();
2136 let rb_idx = base + i.arg_b();
2137 let rb_v = state.get_at(rb_idx);
2138 let k_idx = i.arg_c() as usize;
2139 let key = constants[k_idx];
2140 match state.fast_get_short_str(&rb_v, &key)? {
2141 Some(v) => state.set_at(ra, v),
2142 None => {
2143 state.set_ci_savedpc(ci, pc);
2144 state.set_top(state.ci_top(ci));
2145 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2146 trap = state.ci_trap(ci);
2147 }
2148 }
2149 }
2150 OpCode::SetTabUp => {
2152 let a = i.arg_a() as usize;
2153 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
2155 constants[i.arg_c() as usize]
2156 } else {
2157 state.get_at(base + i.arg_c())
2158 };
2159 let upval = state.upvalue_get(&cl, a);
2160 let key = constants[b_idx];
2161 if let LuaValue::Table(tbl) = upval {
2162 if !tbl.has_metatable() {
2163 if rc_v.is_collectable() {
2164 state.gc_table_barrier_back(&tbl, &rc_v);
2165 }
2166 if let LuaValue::Str(s) = key {
2167 tbl.raw_set_short_str(state, s, rc_v)?;
2168 } else {
2169 tbl.raw_set(state, key, rc_v)?;
2170 }
2171 continue 'dispatch;
2172 }
2173 }
2174 match state.fast_get_short_str(&upval, &key)? {
2175 Some(_slot) => {
2176 state.gc_value_barrier_back(&upval, &rc_v);
2177 if let LuaValue::Table(tbl) = upval {
2178 if let LuaValue::Str(s) = key {
2179 tbl.raw_set_short_str(state, s, rc_v)?;
2180 } else {
2181 tbl.raw_set(state, key, rc_v)?;
2182 }
2183 } else {
2184 state.table_raw_set(&upval, key, rc_v)?;
2185 }
2186 }
2187 None => {
2188 state.set_ci_savedpc(ci, pc);
2189 state.set_top(state.ci_top(ci));
2190 let upval_name: Vec<u8> = cl
2191 .proto
2192 .upvalues
2193 .get(a)
2194 .and_then(|uv| uv.name.as_ref())
2195 .map(|s| s.as_bytes().to_vec())
2196 .unwrap_or_else(|| b"?".to_vec());
2197 let hint: Option<(&[u8], &[u8])> = Some((b"upvalue", &upval_name));
2198 finish_set(state, upval, key, rc_v, false, None, hint)?;
2199 trap = state.ci_trap(ci);
2200 }
2201 }
2202 }
2203 OpCode::SetTable => {
2205 let ra_idx = base + i.arg_a();
2206 let ra_v = state.get_at(ra_idx);
2207 let rb_v = state.get_at(base + i.arg_b());
2208 let rc_v = if i.test_k() {
2209 constants[i.arg_c() as usize]
2210 } else {
2211 state.get_at(base + i.arg_c())
2212 };
2213 if let LuaValue::Table(tbl) = ra_v {
2214 if !tbl.has_metatable() {
2215 if rc_v.is_collectable() {
2216 state.gc_table_barrier_back(&tbl, &rc_v);
2217 }
2218 match rb_v {
2219 LuaValue::Int(n) => tbl.raw_set_int(state, n, rc_v)?,
2220 LuaValue::Str(s) if s.is_short() => {
2221 tbl.raw_set_short_str(state, s, rc_v)?
2222 }
2223 _ => tbl.raw_set(state, rb_v, rc_v)?,
2224 }
2225 } else {
2226 let fast = if let LuaValue::Int(n) = &rb_v {
2227 state.fast_get_int(&ra_v, *n)?
2228 } else {
2229 state.fast_get(&ra_v, &rb_v)?
2230 };
2231 if fast.is_some() {
2232 state.gc_value_barrier_back(&ra_v, &rc_v);
2233 match rb_v {
2234 LuaValue::Int(n) => tbl.raw_set_int(state, n, rc_v)?,
2235 LuaValue::Str(s) if s.is_short() => {
2236 tbl.raw_set_short_str(state, s, rc_v)?
2237 }
2238 _ => tbl.raw_set(state, rb_v, rc_v)?,
2239 }
2240 } else {
2241 state.set_ci_savedpc(ci, pc);
2242 state.set_top(state.ci_top(ci));
2243 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2244 trap = state.ci_trap(ci);
2245 }
2246 }
2247 } else {
2248 state.set_ci_savedpc(ci, pc);
2249 state.set_top(state.ci_top(ci));
2250 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2251 trap = state.ci_trap(ci);
2252 }
2253 }
2254 OpCode::SetI => {
2256 let ra_idx = base + i.arg_a();
2257 let ra_v = state.get_at(ra_idx);
2258 let c = i.arg_b() as i64;
2259 let rc_v = if i.test_k() {
2260 constants[i.arg_c() as usize]
2261 } else {
2262 state.get_at(base + i.arg_c())
2263 };
2264 if let LuaValue::Table(tbl) = ra_v {
2265 if !tbl.has_metatable() {
2266 if rc_v.is_collectable() {
2267 state.gc_table_barrier_back(&tbl, &rc_v);
2268 }
2269 tbl.raw_set_int(state, c, rc_v)?;
2270 } else {
2271 let fast = state.fast_get_int(&ra_v, c)?;
2272 if fast.is_some() {
2273 state.gc_value_barrier_back(&ra_v, &rc_v);
2274 tbl.raw_set_int(state, c, rc_v)?;
2275 } else {
2276 state.set_ci_savedpc(ci, pc);
2277 state.set_top(state.ci_top(ci));
2278 finish_set(
2279 state,
2280 ra_v,
2281 LuaValue::Int(c),
2282 rc_v,
2283 false,
2284 Some(ra_idx),
2285 None,
2286 )?;
2287 trap = state.ci_trap(ci);
2288 }
2289 }
2290 } else {
2291 state.set_ci_savedpc(ci, pc);
2292 state.set_top(state.ci_top(ci));
2293 finish_set(
2294 state,
2295 ra_v,
2296 LuaValue::Int(c),
2297 rc_v,
2298 false,
2299 Some(ra_idx),
2300 None,
2301 )?;
2302 trap = state.ci_trap(ci);
2303 }
2304 }
2305 OpCode::SetField => {
2307 let ra_idx = base + i.arg_a();
2308 let ra_v = state.get_at(ra_idx);
2309 let b_idx = i.arg_b() as usize;
2310 let key = constants[b_idx];
2311 let rc_v = if i.test_k() {
2312 constants[i.arg_c() as usize]
2313 } else {
2314 state.get_at(base + i.arg_c())
2315 };
2316 if let LuaValue::Table(tbl) = ra_v {
2317 if !tbl.has_metatable() {
2318 if rc_v.is_collectable() {
2319 state.gc_table_barrier_back(&tbl, &rc_v);
2320 }
2321 if let LuaValue::Str(s) = key {
2322 tbl.raw_set_short_str(state, s, rc_v)?;
2323 } else {
2324 tbl.raw_set(state, key, rc_v)?;
2325 }
2326 } else {
2327 match state.fast_get_short_str(&ra_v, &key)? {
2328 Some(_) => {
2329 state.gc_value_barrier_back(&ra_v, &rc_v);
2330 if let LuaValue::Str(s) = key {
2331 tbl.raw_set_short_str(state, s, rc_v)?;
2332 } else {
2333 tbl.raw_set(state, key, rc_v)?;
2334 }
2335 }
2336 None => {
2337 state.set_ci_savedpc(ci, pc);
2338 state.set_top(state.ci_top(ci));
2339 finish_set(
2340 state,
2341 ra_v,
2342 key,
2343 rc_v,
2344 false,
2345 Some(ra_idx),
2346 None,
2347 )?;
2348 trap = state.ci_trap(ci);
2349 }
2350 }
2351 }
2352 } else {
2353 state.set_ci_savedpc(ci, pc);
2354 state.set_top(state.ci_top(ci));
2355 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2356 trap = state.ci_trap(ci);
2357 }
2358 }
2359 OpCode::NewTable => {
2362 let ra = base + i.arg_a();
2363 let mut b = i.arg_b();
2364 let mut c = i.arg_c();
2365 if b > 0 {
2366 b = 1 << (b - 1);
2367 }
2368 if i.test_k() {
2369 let extra = code[pc as usize];
2370 pc += 1;
2371 const MAXARG_C: i32 = (1 << 8) - 1;
2372 c += extra.arg_ax() * (MAXARG_C + 1);
2373 } else {
2374 pc += 1; }
2376 state.set_top(ra + 1);
2377 let t = if b != 0 || c != 0 {
2378 state.new_table_with_sizes(c as u32, b as u32)?
2379 } else {
2380 state.new_table()
2381 };
2382 state.set_at(ra, LuaValue::Table(t.clone()));
2383 state.set_ci_savedpc(ci, pc);
2384 state.set_top(ra + 1);
2385 state.gc_cond_step();
2386 if state.hookmask != 0 {
2387 trap = state.ci_trap(ci);
2388 }
2389 }
2390 OpCode::Self_ => {
2392 let ra = base + i.arg_a();
2393 let rb_idx = base + i.arg_b();
2394 let rb_v = state.get_at(rb_idx);
2395 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2397 constants[k_idx]
2398 } else {
2399 state.get_at(base + i.arg_c())
2400 };
2401 state.set_at(ra + 1, rb_v.clone());
2402 match state.fast_get_short_str(&rb_v, &key)? {
2403 Some(v) => state.set_at(ra, v),
2404 None => {
2405 state.set_ci_savedpc(ci, pc);
2406 state.set_top(state.ci_top(ci));
2407 finish_get(state, rb_v, key, ra, true, Some(rb_idx), None)?;
2408 trap = state.ci_trap(ci);
2409 }
2410 }
2411 }
2412 OpCode::AddI => {
2414 let ra = base + i.arg_a();
2415 let rb = base + i.arg_b();
2416 let imm = i.arg_s_c() as i64;
2417 let rb_v = state.stack[rb.0 as usize].val;
2418 match rb_v {
2419 LuaValue::Int(iv1) => {
2420 pc += 1;
2421 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2422 }
2423 LuaValue::Float(nb) => {
2424 pc += 1;
2425 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2426 }
2427 _ => {}
2428 }
2429 }
2430 OpCode::AddK => {
2432 let ra = base + i.arg_a();
2433 let rb = base + i.arg_b();
2434 let kidx = i.arg_c() as usize;
2435 if let (Some(i1), Some(i2)) =
2436 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2437 {
2438 pc += 1;
2439 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2440 } else if let (Some(n1), Some(n2)) =
2441 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2442 {
2443 pc += 1;
2444 state.set_at(ra, LuaValue::Float(n1 + n2));
2445 }
2446 }
2447 OpCode::SubK => {
2448 let ra = base + i.arg_a();
2449 let rb = base + i.arg_b();
2450 let kidx = i.arg_c() as usize;
2451 if let (Some(i1), Some(i2)) =
2452 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2453 {
2454 pc += 1;
2455 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2456 } else if let (Some(n1), Some(n2)) =
2457 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2458 {
2459 pc += 1;
2460 state.set_at(ra, LuaValue::Float(n1 - n2));
2461 }
2462 }
2463 OpCode::MulK => {
2464 let ra = base + i.arg_a();
2465 let rb = base + i.arg_b();
2466 let kidx = i.arg_c() as usize;
2467 if let (Some(i1), Some(i2)) =
2468 (state.get_int_at(rb), state.proto_const_int(&cl, kidx))
2469 {
2470 pc += 1;
2471 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2472 } else if let (Some(n1), Some(n2)) =
2473 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2474 {
2475 pc += 1;
2476 state.set_at(ra, LuaValue::Float(n1 * n2));
2477 }
2478 }
2479 OpCode::ModK => {
2480 let ra = base + i.arg_a();
2481 let v1 = state.get_at(base + i.arg_b());
2482 let v2 = constants[i.arg_c() as usize];
2483 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
2485 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2486 }
2487 OpCode::PowK => {
2488 let ra = base + i.arg_a();
2489 let rb = base + i.arg_b();
2490 let kidx = i.arg_c() as usize;
2491 if let (Some(n1), Some(n2)) =
2492 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2493 {
2494 pc += 1;
2495 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2496 state.set_at(ra, LuaValue::Float(r));
2497 }
2498 }
2499 OpCode::DivK => {
2500 let ra = base + i.arg_a();
2501 let rb = base + i.arg_b();
2502 let kidx = i.arg_c() as usize;
2503 if let (Some(n1), Some(n2)) =
2504 (state.get_num_at(rb), state.proto_const_num(&cl, kidx))
2505 {
2506 pc += 1;
2507 state.set_at(ra, LuaValue::Float(n1 / n2));
2508 }
2509 }
2510 OpCode::IDivK => {
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 state.set_ci_savedpc(ci, pc);
2515 state.set_top(state.ci_top(ci));
2516 arith_op_checked(
2517 state,
2518 ra,
2519 &v1,
2520 &v2,
2521 &mut pc,
2522 |a, b| idiv(a, b),
2523 |a, b| (a / b).floor(),
2524 )?;
2525 }
2526 OpCode::BAndK => {
2527 let ra = base + i.arg_a();
2528 let v1 = state.get_at(base + i.arg_b());
2529 let v2 = constants[i.arg_c() as usize];
2530 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2531 }
2532 OpCode::BOrK => {
2533 let ra = base + i.arg_a();
2534 let v1 = state.get_at(base + i.arg_b());
2535 let v2 = constants[i.arg_c() as usize];
2536 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2537 }
2538 OpCode::BXOrK => {
2539 let ra = base + i.arg_a();
2540 let v1 = state.get_at(base + i.arg_b());
2541 let v2 = constants[i.arg_c() as usize];
2542 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2543 }
2544 OpCode::ShrI => {
2545 let ra = base + i.arg_a();
2546 let v = state.get_at(base + i.arg_b());
2547 let ic = i.arg_s_c() as i64;
2548 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2549 pc += 1;
2550 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2551 }
2552 }
2553 OpCode::ShlI => {
2554 let ra = base + i.arg_a();
2555 let v = state.get_at(base + i.arg_b());
2556 let ic = i.arg_s_c() as i64;
2557 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2558 pc += 1;
2559 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2560 }
2561 }
2562 OpCode::Add => {
2564 let ra = base + i.arg_a();
2565 let rb = base + i.arg_b();
2566 let rc = base + i.arg_c();
2567 let ra_u = ra.0 as usize;
2568 let rb_v = state.stack[rb.0 as usize].val;
2569 let rc_v = state.stack[rc.0 as usize].val;
2570 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2571 pc += 1;
2572 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2573 } else if let (Some(n1), Some(n2)) =
2574 (number_value(rb_v), number_value(rc_v))
2575 {
2576 pc += 1;
2577 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2578 }
2579 }
2580 OpCode::Sub => {
2581 let ra = base + i.arg_a();
2582 let rb = base + i.arg_b();
2583 let rc = base + i.arg_c();
2584 let ra_u = ra.0 as usize;
2585 let rb_v = state.stack[rb.0 as usize].val;
2586 let rc_v = state.stack[rc.0 as usize].val;
2587 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2588 pc += 1;
2589 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2590 } else if let (Some(n1), Some(n2)) =
2591 (number_value(rb_v), number_value(rc_v))
2592 {
2593 pc += 1;
2594 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2595 }
2596 }
2597 OpCode::Mul => {
2598 let ra = base + i.arg_a();
2599 let rb = base + i.arg_b();
2600 let rc = base + i.arg_c();
2601 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2602 pc += 1;
2603 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2604 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2605 pc += 1;
2606 state.set_at(ra, LuaValue::Float(n1 * n2));
2607 }
2608 }
2609 OpCode::Mod => {
2610 let ra = base + i.arg_a();
2611 let v1 = state.get_at(base + i.arg_b());
2612 let v2 = state.get_at(base + i.arg_c());
2613 state.set_ci_savedpc(ci, pc);
2614 state.set_top(state.ci_top(ci));
2615 arith_op_checked(state, ra, &v1, &v2, &mut pc, |a, b| imod(a, b), fmodf)?;
2616 }
2617 OpCode::Pow => {
2618 let ra = base + i.arg_a();
2619 let rb = base + i.arg_b();
2620 let rc = base + i.arg_c();
2621 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2622 pc += 1;
2623 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2624 state.set_at(ra, LuaValue::Float(r));
2625 }
2626 }
2627 OpCode::Div => {
2628 let ra = base + i.arg_a();
2629 let rb = base + i.arg_b();
2630 let rc = base + i.arg_c();
2631 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2632 pc += 1;
2633 state.set_at(ra, LuaValue::Float(n1 / n2));
2634 }
2635 }
2636 OpCode::IDiv => {
2637 let ra = base + i.arg_a();
2638 let v1 = state.get_at(base + i.arg_b());
2639 let v2 = state.get_at(base + i.arg_c());
2640 state.set_ci_savedpc(ci, pc);
2641 state.set_top(state.ci_top(ci));
2642 arith_op_checked(
2643 state,
2644 ra,
2645 &v1,
2646 &v2,
2647 &mut pc,
2648 |a, b| idiv(a, b),
2649 |a, b| (a / b).floor(),
2650 )?;
2651 }
2652 OpCode::BAnd => {
2655 let ra = base + i.arg_a();
2656 let v1 = state.get_at(base + i.arg_b());
2657 let v2 = state.get_at(base + i.arg_c());
2658 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2659 }
2660 OpCode::BOr => {
2661 let ra = base + i.arg_a();
2662 let v1 = state.get_at(base + i.arg_b());
2663 let v2 = state.get_at(base + i.arg_c());
2664 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2665 }
2666 OpCode::BXOr => {
2667 let ra = base + i.arg_a();
2668 let v1 = state.get_at(base + i.arg_b());
2669 let v2 = state.get_at(base + i.arg_c());
2670 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2671 }
2672 OpCode::Shr => {
2673 let ra = base + i.arg_a();
2674 let v1 = state.get_at(base + i.arg_b());
2675 let v2 = state.get_at(base + i.arg_c());
2676 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2677 }
2678 OpCode::Shl => {
2679 let ra = base + i.arg_a();
2680 let v1 = state.get_at(base + i.arg_b());
2681 let v2 = state.get_at(base + i.arg_c());
2682 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2683 }
2684 OpCode::MmBin => {
2689 let ra_idx = base + i.arg_a();
2690 let rb_idx = base + i.arg_b();
2691 let ra_v = state.get_at(ra_idx);
2692 let rb_v = state.get_at(rb_idx);
2693 let tm = tagmethod_from_index(i.arg_c() as usize);
2694 let prev_inst = code[(pc - 2) as usize];
2695 let result_idx = base + prev_inst.arg_a();
2696 state.set_ci_savedpc(ci, pc);
2697 state.set_top(state.ci_top(ci));
2698 state.try_bin_tm(
2699 &ra_v,
2700 Some(ra_idx),
2701 &rb_v,
2702 Some(rb_idx),
2703 result_idx,
2704 tm,
2705 )?;
2706 trap = state.ci_trap(ci);
2707 }
2708 OpCode::MmBinI => {
2709 let ra_idx = base + i.arg_a();
2710 let ra_v = state.get_at(ra_idx);
2711 let imm = i.arg_s_b() as i64;
2712 let tm = tagmethod_from_index(i.arg_c() as usize);
2713 let flip = i.arg_k() != 0;
2714 let prev_inst = code[(pc - 2) as usize];
2715 let result_idx = base + prev_inst.arg_a();
2716 state.set_ci_savedpc(ci, pc);
2717 state.set_top(state.ci_top(ci));
2718 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2719 trap = state.ci_trap(ci);
2720 }
2721 OpCode::MmBinK => {
2722 let ra_idx = base + i.arg_a();
2723 let ra_v = state.get_at(ra_idx);
2724 let imm = constants[i.arg_b() as usize];
2725 let tm = tagmethod_from_index(i.arg_c() as usize);
2726 let flip = i.arg_k() != 0;
2727 let prev_inst = code[(pc - 2) as usize];
2728 let result_idx = base + prev_inst.arg_a();
2729 state.set_ci_savedpc(ci, pc);
2730 state.set_top(state.ci_top(ci));
2731 state.try_bin_assoc_tm(
2732 &ra_v,
2733 Some(ra_idx),
2734 &imm,
2735 None,
2736 flip,
2737 result_idx,
2738 tm,
2739 )?;
2740 trap = state.ci_trap(ci);
2741 }
2742 OpCode::Unm => {
2746 let ra = base + i.arg_a();
2747 let rb_idx = base + i.arg_b();
2748 let rb_v = state.get_at(rb_idx);
2749 match &rb_v {
2750 LuaValue::Int(ib) => {
2751 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2752 }
2753 LuaValue::Float(nb) => {
2754 state.set_at(ra, LuaValue::Float(-nb));
2755 }
2756 _ => {
2757 state.set_ci_savedpc(ci, pc);
2758 state.set_top(state.ci_top(ci));
2759 state.try_bin_tm(
2760 &rb_v,
2761 Some(rb_idx),
2762 &rb_v,
2763 Some(rb_idx),
2764 ra,
2765 TagMethod::Unm,
2766 )?;
2767 trap = state.ci_trap(ci);
2768 }
2769 }
2770 }
2771 OpCode::BNot => {
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 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2777 state.set_at(ra, LuaValue::Int(!ib));
2778 } else {
2779 state.set_ci_savedpc(ci, pc);
2780 state.set_top(state.ci_top(ci));
2781 state.try_bin_tm(
2782 &rb_v,
2783 Some(rb_idx),
2784 &rb_v,
2785 Some(rb_idx),
2786 ra,
2787 TagMethod::Bnot,
2788 )?;
2789 trap = state.ci_trap(ci);
2790 }
2791 }
2792 OpCode::Not => {
2794 let ra = base + i.arg_a();
2795 let rb_v = state.get_at(base + i.arg_b());
2796 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2797 state.set_at(ra, LuaValue::Bool(falsy));
2798 }
2799 OpCode::Len => {
2801 let ra = base + i.arg_a();
2802 let rb_idx = base + i.arg_b();
2803 let rb_v = state.get_at(rb_idx);
2804 state.set_ci_savedpc(ci, pc);
2805 state.set_top(state.ci_top(ci));
2806 obj_len(state, ra, rb_v, rb_idx)?;
2807 trap = state.ci_trap(ci);
2808 }
2809 OpCode::Concat => {
2811 let ra = base + i.arg_a();
2812 let n = i.arg_b() as i32;
2813 state.set_top(ra + n as i32);
2814 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2816 let top = state.top_idx();
2817 state.set_ci_savedpc(ci, pc);
2818 state.set_top(top);
2819 state.gc_cond_step();
2820 trap = state.ci_trap(ci);
2821 }
2822 OpCode::Close => {
2824 let ra = base + i.arg_a();
2825 state.set_ci_savedpc(ci, pc);
2826 state.set_top(state.ci_top(ci));
2827 crate::func::close(
2828 state,
2829 ra,
2830 lua_types::status::LuaStatus::Ok as i32,
2831 true,
2832 )?;
2833 trap = state.ci_trap(ci);
2834 }
2835 OpCode::Tbc => {
2837 let ra = base + i.arg_a();
2838 state.set_ci_savedpc(ci, pc);
2839 state.set_top(state.ci_top(ci));
2840 state.new_tbc_upval(ra)?;
2841 }
2842 OpCode::Jmp => {
2844 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2845 trap = state.ci_trap(ci);
2846 }
2847 OpCode::Eq => {
2849 let ra_v = state.get_at(base + i.arg_a());
2850 let rb_v = state.get_at(base + i.arg_b());
2851 state.set_ci_savedpc(ci, pc);
2852 state.set_top(state.ci_top(ci));
2853 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2854 trap = state.ci_trap(ci);
2855 if (cond as i32) != i.arg_k() {
2856 pc += 1;
2857 } else {
2858 let next = code[pc as usize];
2859 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2860 trap = state.ci_trap(ci);
2861 }
2862 }
2863 OpCode::Lt => {
2865 let ra_v = state.get_at(base + i.arg_a());
2866 let rb_v = state.get_at(base + i.arg_b());
2867 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2868 *ia < *ib
2869 } else if matches!(
2870 (&ra_v, &rb_v),
2871 (
2872 LuaValue::Int(_) | LuaValue::Float(_),
2873 LuaValue::Int(_) | LuaValue::Float(_)
2874 )
2875 ) {
2876 lt_num(&ra_v, &rb_v)
2877 } else {
2878 state.set_ci_savedpc(ci, pc);
2879 state.set_top(state.ci_top(ci));
2880 let r = less_than_others(state, &ra_v, &rb_v)?;
2881 trap = state.ci_trap(ci);
2882 r
2883 };
2884 if (cond as i32) != i.arg_k() {
2885 pc += 1;
2886 } else {
2887 let next = code[pc as usize];
2888 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2889 trap = state.ci_trap(ci);
2890 }
2891 }
2892 OpCode::Le => {
2894 let ra_v = state.get_at(base + i.arg_a());
2895 let rb_v = state.get_at(base + i.arg_b());
2896 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2897 *ia <= *ib
2898 } else if matches!(
2899 (&ra_v, &rb_v),
2900 (
2901 LuaValue::Int(_) | LuaValue::Float(_),
2902 LuaValue::Int(_) | LuaValue::Float(_)
2903 )
2904 ) {
2905 le_num(&ra_v, &rb_v)
2906 } else {
2907 state.set_ci_savedpc(ci, pc);
2908 state.set_top(state.ci_top(ci));
2909 let r = less_equal_others(state, &ra_v, &rb_v)?;
2910 trap = state.ci_trap(ci);
2911 r
2912 };
2913 if (cond as i32) != i.arg_k() {
2914 pc += 1;
2915 } else {
2916 let next = code[pc as usize];
2917 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2918 trap = state.ci_trap(ci);
2919 }
2920 }
2921 OpCode::EqK => {
2923 let ra_v = state.get_at(base + i.arg_a());
2924 let rb_v = constants[i.arg_b() as usize];
2925 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2926 if (cond as i32) != i.arg_k() {
2927 pc += 1;
2928 } else {
2929 let next = code[pc as usize];
2930 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2931 trap = state.ci_trap(ci);
2932 }
2933 }
2934 OpCode::EqI => {
2939 let ra_v = state.get_at(base + i.arg_a());
2940 let im = i.arg_s_b() as i64;
2941 let cond: bool = match &ra_v {
2942 LuaValue::Int(iv) => *iv == im,
2943 LuaValue::Float(fv) => *fv == im as f64,
2944 _ => false,
2945 };
2946 if (cond as i32) != i.arg_k() {
2947 pc += 1;
2948 } else {
2949 let next = code[pc as usize];
2950 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2951 trap = state.ci_trap(ci);
2952 }
2953 }
2954 OpCode::LtI => {
2957 let ra = base + i.arg_a();
2958 let im = i.arg_s_b() as i64;
2959 let fast_cond = match &state.stack[ra.0 as usize].val {
2960 LuaValue::Int(ia) => Some(*ia < im),
2961 LuaValue::Float(fa) => Some(*fa < im as f64),
2962 _ => None,
2963 };
2964 let cond = match fast_cond {
2965 Some(cond) => cond,
2966 None => order_imm_slow(
2967 state,
2968 ra,
2969 pc,
2970 &mut trap,
2971 ci,
2972 i,
2973 im,
2974 false,
2975 TagMethod::Lt,
2976 )?,
2977 };
2978 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
2979 }
2980 OpCode::LeI => {
2981 let ra = base + i.arg_a();
2982 let im = i.arg_s_b() as i64;
2983 let fast_cond = match &state.stack[ra.0 as usize].val {
2984 LuaValue::Int(ia) => Some(*ia <= im),
2985 LuaValue::Float(fa) => Some(*fa <= im as f64),
2986 _ => None,
2987 };
2988 let cond = match fast_cond {
2989 Some(cond) => cond,
2990 None => order_imm_slow(
2991 state,
2992 ra,
2993 pc,
2994 &mut trap,
2995 ci,
2996 i,
2997 im,
2998 false,
2999 TagMethod::Le,
3000 )?,
3001 };
3002 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3003 }
3004 OpCode::GtI => {
3005 let ra = base + i.arg_a();
3006 let im = i.arg_s_b() as i64;
3007 let fast_cond = match &state.stack[ra.0 as usize].val {
3008 LuaValue::Int(ia) => Some(*ia > im),
3009 LuaValue::Float(fa) => Some(*fa > im as f64),
3010 _ => None,
3011 };
3012 let cond = match fast_cond {
3013 Some(cond) => cond,
3014 None => order_imm_slow(
3015 state,
3016 ra,
3017 pc,
3018 &mut trap,
3019 ci,
3020 i,
3021 im,
3022 true,
3023 TagMethod::Lt,
3024 )?,
3025 };
3026 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3027 }
3028 OpCode::GeI => {
3029 let ra = base + i.arg_a();
3030 let im = i.arg_s_b() as i64;
3031 let fast_cond = match &state.stack[ra.0 as usize].val {
3032 LuaValue::Int(ia) => Some(*ia >= im),
3033 LuaValue::Float(fa) => Some(*fa >= im as f64),
3034 _ => None,
3035 };
3036 let cond = match fast_cond {
3037 Some(cond) => cond,
3038 None => order_imm_slow(
3039 state,
3040 ra,
3041 pc,
3042 &mut trap,
3043 ci,
3044 i,
3045 im,
3046 true,
3047 TagMethod::Le,
3048 )?,
3049 };
3050 finish_order_imm_jump(state, code, &mut pc, &mut trap, ci, i, cond);
3051 }
3052 OpCode::Test => {
3054 let ra_v = state.get_at(base + i.arg_a());
3055 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
3056 if (cond as i32) != i.arg_k() {
3057 pc += 1;
3058 } else {
3059 let next = code[pc as usize];
3060 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3061 trap = state.ci_trap(ci);
3062 }
3063 }
3064 OpCode::TestSet => {
3067 let ra = base + i.arg_a();
3068 let rb_v = state.get_at(base + i.arg_b());
3069 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
3070 if (falsy as i32) == i.arg_k() {
3071 pc += 1;
3072 } else {
3073 state.set_at(ra, rb_v);
3074 let next = code[pc as usize];
3075 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3076 trap = state.ci_trap(ci);
3077 }
3078 }
3079 OpCode::Call => {
3083 let ra = base + i.arg_a();
3084 let b = i.arg_b();
3085 let nresults = i.arg_c() as i32 - 1;
3086 if b != 0 {
3087 state.set_top(ra + b);
3088 }
3089 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
3091 match state.precall(ra, nresults)? {
3092 None => {
3093 if had_hook || state.hookmask != 0 {
3097 trap = state.ci_trap(ci); }
3099 }
3100 Some(new_ci) => {
3101 ci = new_ci;
3103 continue 'startfunc;
3104 }
3105 }
3106 }
3107 OpCode::TailCall => {
3112 let ra = base + i.arg_a();
3113 let b = i.arg_b();
3114 let nparams1 = i.arg_c();
3115 let delta = if nparams1 != 0 {
3116 state.ci_nextraargs(ci) + nparams1 as i32
3117 } else {
3118 0
3119 };
3120 let top_b: i32 = if b != 0 {
3121 state.set_top(ra + b);
3122 b
3123 } else {
3124 state.top_idx() - ra
3125 };
3126 state.set_ci_savedpc(ci, pc);
3127 if i.test_k() {
3128 state.close_upvals_from_base(ci)?;
3129 }
3130 let n = state.pretailcall(ci, ra, top_b, delta)?;
3131 if n < 0 {
3132 state.note_lua_tailcall(ci);
3134 continue 'startfunc;
3135 } else {
3136 state.ci_adjust_func(ci, delta);
3138 state.poscall(ci, n as u32)?;
3139 if state.hookmask != 0 {
3140 trap = state.ci_trap(ci);
3141 }
3142 break 'dispatch; }
3144 }
3145 OpCode::Return => {
3150 let ra = base + i.arg_a();
3151 let n_raw = i.arg_b() as i32 - 1;
3152 let nparams1 = i.arg_c();
3153 let n: u32 = if n_raw < 0 {
3154 (state.top_idx() - ra) as u32
3155 } else {
3156 n_raw as u32
3157 };
3158 state.set_ci_savedpc(ci, pc);
3159 if i.test_k() {
3160 state.ci_nres_set(ci, n as i32);
3161 let ci_top = state.ci_top(ci);
3162 if state.top_idx().0 < ci_top.0 {
3163 state.set_top(ci_top);
3164 }
3165 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
3166 if state.hookmask != 0 {
3167 trap = state.ci_trap(ci);
3168 }
3169 base = state.ci_base(ci); }
3171 if nparams1 != 0 {
3172 let nextraargs = state.ci_nextraargs(ci) as u32;
3173 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
3174 }
3175 state.set_top(ra + n as i32);
3176 state.poscall(ci, n)?;
3177 if state.hookmask != 0 {
3178 trap = state.ci_trap(ci);
3179 }
3180 break 'dispatch; }
3182 OpCode::Return0 => {
3188 if state.hookmask == 0 {
3189 let ci_slot = ci.as_usize();
3190 let nres = state.call_info[ci_slot].nresults as i32;
3191 state.ci = state.call_info[ci_slot]
3192 .previous
3193 .expect("RETURN0: returning frame has no previous CallInfo");
3194 state.top = base - 1;
3195 for _ in 0..nres.max(0) {
3196 state.push(LuaValue::Nil);
3197 }
3198 } else {
3199 return0_hook(state, ci, base, i, pc, &mut trap)?;
3200 }
3201 break 'dispatch; }
3203 OpCode::Return1 => {
3207 if state.hookmask == 0 {
3208 let ci_slot = ci.as_usize();
3209 let nres = state.call_info[ci_slot].nresults as i32;
3210 state.ci = state.call_info[ci_slot]
3211 .previous
3212 .expect("RETURN1: returning frame has no previous CallInfo");
3213 if nres == 0 {
3214 state.top = base - 1;
3215 } else {
3216 let ra = base + i.arg_a();
3217 state.stack[(base - 1).0 as usize].val =
3218 state.stack[ra.0 as usize].val; state.top = base;
3220 for _ in 1..nres.max(0) {
3221 state.push(LuaValue::Nil);
3222 }
3223 }
3224 } else {
3225 return1_hook(state, ci, base, i, pc, &mut trap)?;
3226 }
3227 break 'dispatch; }
3229 OpCode::ForLoop => {
3233 let ra = base + i.arg_a();
3234 if legacy_for {
3235 if forloop_legacy(state, ra) {
3236 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3237 }
3238 if state.hookmask != 0 {
3239 trap = state.ci_trap(ci);
3240 }
3241 } else {
3242 let ra_u = ra.0 as usize;
3243 let window: &mut [crate::state::StackValue; 4] = (&mut state.stack
3244 [ra_u..ra_u + 4])
3245 .try_into()
3246 .expect("FORLOOP register window");
3247 if let LuaValue::Int(step) = window[2].val {
3248 let count = match window[1].val {
3249 LuaValue::Int(c) => c as u64,
3250 _ => 0,
3251 };
3252 if count > 0 {
3253 let idx = match window[0].val {
3254 LuaValue::Int(x) => x,
3255 _ => 0,
3256 };
3257 window[1].val = LuaValue::Int((count - 1) as i64);
3258 let new_idx = intop_add(idx, step);
3259 window[0].val = LuaValue::Int(new_idx);
3260 window[3].val = LuaValue::Int(new_idx);
3261 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3262 }
3263 } else if float_for_loop(state, ra) {
3264 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3265 }
3266 if state.hookmask != 0 {
3267 trap = state.ci_trap(ci);
3268 }
3269 }
3270 }
3271 OpCode::ForPrep => {
3273 let ra = base + i.arg_a();
3274 state.set_ci_savedpc(ci, pc);
3275 state.set_top(state.ci_top(ci));
3276 if legacy_for {
3277 forprep_legacy(state, ra)?;
3280 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3281 } else if forprep(state, ra)? {
3282 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
3283 }
3284 }
3285 OpCode::TForPrep => {
3289 let ra = base + i.arg_a();
3290 state.set_ci_savedpc(ci, pc);
3291 state.set_top(state.ci_top(ci));
3292 if tfor_55 {
3293 let closing = state.get_at(ra + 3);
3294 let control = state.get_at(ra + 2);
3295 state.set_at(ra + 2, closing);
3296 state.set_at(ra + 3, control);
3297 state.new_tbc_upval(ra + 2)?;
3298 } else {
3299 state.new_tbc_upval(ra + 3)?;
3300 }
3301 pc = (pc as i64 + i.arg_bx() as i64) as u32;
3302 let tfc_i = code[pc as usize];
3303 pc += 1;
3304 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
3305 let tfc_ra = base + tfc_i.arg_a();
3307 if tfor_55 {
3308 let src = tfc_ra.0 as usize;
3309 let func = state.stack[src].val.clone();
3310 let state_val = state.stack[src + 1].val.clone();
3311 let control = state.stack[src + 3].val.clone();
3312 state.stack[src + 3].val = func;
3313 state.stack[src + 4].val = state_val;
3314 state.stack[src + 5].val = control;
3315 state.set_top(tfc_ra + 6);
3316 state.set_ci_savedpc(ci, pc);
3317 if !state.call_known_c_at(tfc_ra + 3, tfc_i.arg_c() as i32)? {
3318 state.call_at(tfc_ra + 3, tfc_i.arg_c() as i32)?;
3319 }
3320 } else {
3321 let src = tfc_ra.0 as usize;
3322 let dst = src + 4;
3323 for k in 0..3usize {
3324 state.stack[dst + k].val = state.stack[src + k].val.clone();
3325 }
3326 state.set_top(tfc_ra + 4 + 3);
3327 state.set_ci_savedpc(ci, pc);
3328 if !state.call_known_c_at(tfc_ra + 4, tfc_i.arg_c() as i32)? {
3329 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
3330 }
3331 }
3332 trap = state.ci_trap(ci);
3333 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3335 pc += 1;
3336 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3337 let tfl_ra = base + tfl_i.arg_a();
3338 if tfor_55 {
3340 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3341 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3342 }
3343 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3344 let v = state.get_at(tfl_ra + 4);
3345 state.set_at(tfl_ra + 2, v);
3346 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3347 }
3348 }
3349 OpCode::TForCall => {
3351 let ra = base + i.arg_a();
3352 if tfor_55 {
3353 let src = ra.0 as usize;
3354 let func = state.stack[src].val.clone();
3355 let state_val = state.stack[src + 1].val.clone();
3356 let control = state.stack[src + 3].val.clone();
3357 state.stack[src + 3].val = func;
3358 state.stack[src + 4].val = state_val;
3359 state.stack[src + 5].val = control;
3360 state.set_top(ra + 6);
3361 state.set_ci_savedpc(ci, pc);
3362 if !state.call_known_c_at(ra + 3, i.arg_c() as i32)? {
3363 state.call_at(ra + 3, i.arg_c() as i32)?;
3364 }
3365 } else {
3366 let src = ra.0 as usize;
3367 let dst = src + 4;
3368 for k in 0..3usize {
3369 state.stack[dst + k].val = state.stack[src + k].val.clone();
3370 }
3371 state.set_top(ra + 4 + 3);
3372 state.set_ci_savedpc(ci, pc);
3373 if !state.call_known_c_at(ra + 4, i.arg_c() as i32)? {
3374 state.call_at(ra + 4, i.arg_c() as i32)?;
3375 }
3376 }
3377 trap = state.ci_trap(ci);
3378 base = state.ci_base(ci); let tfl_i = code[pc as usize];
3380 pc += 1;
3381 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
3382 let tfl_ra = base + tfl_i.arg_a();
3383 if tfor_55 {
3384 if !matches!(state.get_at(tfl_ra + 3), LuaValue::Nil) {
3385 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3386 }
3387 } else if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
3388 let v = state.get_at(tfl_ra + 4);
3389 state.set_at(tfl_ra + 2, v);
3390 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
3391 }
3392 }
3393 OpCode::TForLoop => {
3395 let ra = base + i.arg_a();
3396 if tfor_55 {
3397 if !matches!(state.get_at(ra + 3), LuaValue::Nil) {
3398 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3399 }
3400 } else if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
3401 let v = state.get_at(ra + 4);
3402 state.set_at(ra + 2, v);
3403 pc = (pc as i64 - i.arg_bx() as i64) as u32;
3404 }
3405 }
3406 OpCode::SetList => {
3410 let ra = base + i.arg_a();
3411 let n_raw = i.arg_b();
3412 let mut last = i.arg_c();
3413 let t_val = state.get_at(ra);
3414 let n: i32 = if n_raw == 0 {
3415 state.top_idx() - ra - 1
3416 } else {
3417 state.set_top(state.ci_top(ci));
3418 n_raw
3419 };
3420 last += n;
3421 if i.test_k() {
3422 let extra = code[pc as usize];
3423 pc += 1;
3424 const MAXARG_C: i32 = (1 << 8) - 1;
3425 last += extra.arg_ax() * (MAXARG_C + 1);
3426 }
3427 state.table_ensure_array(&t_val, last as usize)?;
3428 for k in (1..=n).rev() {
3429 let val = state.get_at(ra + k as i32);
3430 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
3431 last -= 1;
3432 state.gc_value_barrier_back(&t_val, &val);
3433 }
3434 }
3435 OpCode::Closure => {
3439 let ra = base + i.arg_a();
3440 let proto_idx = i.arg_bx() as usize;
3441 state.set_ci_savedpc(ci, pc);
3442 state.set_top(state.ci_top(ci));
3443 push_closure(state, proto_idx, ci, base, ra)?;
3444 state.set_ci_savedpc(ci, pc);
3446 state.set_top(ra + 1);
3447 state.gc_cond_step();
3448 trap = state.ci_trap(ci);
3449 }
3450 OpCode::VarArg => {
3452 let ra = base + i.arg_a();
3453 let n = i.arg_c() as i32 - 1;
3454 state.set_ci_savedpc(ci, pc);
3455 state.set_top(state.ci_top(ci));
3456 state.get_varargs(ci, ra, n)?;
3457 trap = state.ci_trap(ci);
3458 }
3459 OpCode::VarArgPrep => {
3463 let nparams = i.arg_a();
3464 state.set_ci_savedpc(ci, pc);
3465 state.adjust_varargs(ci, nparams, &cl)?;
3466 trap = state.ci_trap(ci);
3467 if trap {
3468 state.hook_call(ci)?;
3469 state.set_oldpc(1);
3470 }
3471 base = state.ci_base(ci);
3472 }
3473 OpCode::GetVArg => {
3475 let ra = base + i.arg_a();
3476 let vararg_reg = base + i.arg_b();
3477 let key = state.get_at(base + i.arg_c()).clone();
3478 let val = if let LuaValue::Table(t) = state.get_at(vararg_reg) {
3479 t.get(&key)
3480 } else {
3481 let nextra = state.ci_nextraargs(ci);
3482 match key {
3483 LuaValue::Int(n) if n >= 1 && n <= nextra as i64 => {
3484 let ci_func = state.ci_base(ci) - 1;
3485 state.get_at(ci_func - nextra + n as i32 - 1)
3486 }
3487 LuaValue::Float(f)
3488 if f.is_finite()
3489 && f.fract() == 0.0
3490 && f >= 1.0
3491 && f <= nextra as f64 =>
3492 {
3493 let ci_func = state.ci_base(ci) - 1;
3494 state.get_at(ci_func - nextra + f as i32 - 1)
3495 }
3496 LuaValue::Str(s) if s.as_bytes() == b"n" => {
3497 LuaValue::Int(nextra as i64)
3498 }
3499 _ => LuaValue::Nil,
3500 }
3501 };
3502 state.set_at(ra, val);
3503 }
3504 OpCode::ExtraArg => {
3506 debug_assert!(false, "OP_EXTRAARG executed directly");
3507 }
3508 OpCode::ErrNNil => {
3513 let ra = base + i.arg_a();
3514 if !matches!(state.get_at(ra), LuaValue::Nil) {
3515 let bx = i.arg_bx();
3516 let name: Vec<u8> = if bx == 0 {
3517 b"?".to_vec()
3518 } else {
3519 match constants[(bx - 1) as usize] {
3520 LuaValue::Str(s) => s.as_bytes().to_vec(),
3521 _ => b"?".to_vec(),
3522 }
3523 };
3524 let mut msg = Vec::with_capacity(name.len() + 24);
3525 msg.extend_from_slice(b"global '");
3526 msg.extend_from_slice(&name);
3527 msg.extend_from_slice(b"' already defined");
3528 state.set_ci_savedpc(ci, pc);
3529 return Err(crate::debug::prefixed_runtime_pub(state, msg));
3530 }
3531 }
3532 OpCode::VarArgPack => {
3540 if !cl.proto.vararg_table_needed && !i.test_k() {
3541 state.set_ci_savedpc(ci, pc);
3542 continue;
3543 }
3544 let ra = base + i.arg_a();
3545 let nextra = state.ci_nextraargs(ci);
3546 let ci_func: StackIdx = state.ci_base(ci) - 1;
3547 let t = if nextra > 0 {
3548 state.new_table_with_sizes(nextra as u32, 1)?
3549 } else {
3550 state.new_table()
3551 };
3552 for k in 0..nextra {
3553 let src: StackIdx = ci_func - nextra as i32 + k as i32;
3554 let val = state.get_at(src);
3555 t.raw_set_int(state, (k + 1) as i64, val)?;
3556 }
3557 let n_key = state.intern_str(b"n")?;
3558 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
3559 state.set_at(ra, LuaValue::Table(t));
3560 state.set_ci_savedpc(ci, pc);
3561 state.set_top(ra + 1);
3562 state.gc_cond_step();
3563 if state.hookmask != 0 {
3564 trap = state.ci_trap(ci);
3565 }
3566 }
3567 } } if state.ci_is_fresh(ci) {
3572 return Ok(());
3573 } else {
3574 ci = state
3575 .ci_previous(ci)
3576 .expect("ci_previous: not fresh frame must have previous");
3577 continue 'returning;
3578 }
3579 } } }
3582
3583#[inline(always)]
3586fn number_value(v: LuaValue) -> Option<f64> {
3587 match v {
3588 LuaValue::Float(f) => Some(f),
3589 LuaValue::Int(i) => Some(i as f64),
3590 _ => None,
3591 }
3592}
3593
3594#[allow(dead_code)]
3596#[inline]
3597fn arith_op_aux_rr(
3598 state: &mut LuaState,
3599 ra: StackIdx,
3600 v1: &LuaValue,
3601 v2: &LuaValue,
3602 pc: &mut u32,
3603 iop: fn(i64, i64) -> i64,
3604 fop: fn(f64, f64) -> f64,
3605) {
3606 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3607 *pc += 1;
3608 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3609 } else {
3610 arith_float_aux(state, ra, v1, v2, pc, fop);
3611 }
3612}
3613
3614#[allow(dead_code)]
3615#[inline]
3616fn arith_float_aux(
3617 state: &mut LuaState,
3618 ra: StackIdx,
3619 v1: &LuaValue,
3620 v2: &LuaValue,
3621 pc: &mut u32,
3622 fop: fn(f64, f64) -> f64,
3623) {
3624 let n1 = match v1 {
3625 LuaValue::Float(f) => Some(*f),
3626 LuaValue::Int(i) => Some(*i as f64),
3627 _ => None,
3628 };
3629 let n2 = match v2 {
3630 LuaValue::Float(f) => Some(*f),
3631 LuaValue::Int(i) => Some(*i as f64),
3632 _ => None,
3633 };
3634 if let (Some(n1), Some(n2)) = (n1, n2) {
3635 *pc += 1;
3636 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3637 }
3638}
3639
3640#[allow(dead_code)]
3641#[inline]
3642fn arith_op_checked(
3643 state: &mut LuaState,
3644 ra: StackIdx,
3645 v1: &LuaValue,
3646 v2: &LuaValue,
3647 pc: &mut u32,
3648 iop: fn(i64, i64) -> Result<i64, LuaError>,
3649 fop: fn(f64, f64) -> f64,
3650) -> Result<(), LuaError> {
3651 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3652 *pc += 1;
3653 let result = iop(*i1, *i2).map_err(|e| match e {
3654 LuaError::Runtime(LuaValue::Str(s)) => {
3655 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3656 }
3657 LuaError::RuntimeMsg(b) => crate::debug::prefixed_runtime_pub(state, b.into_vec()),
3658 other => other,
3659 })?;
3660 state.set_at(ra, LuaValue::Int(result));
3661 } else {
3662 arith_float_aux(state, ra, v1, v2, pc, fop);
3663 }
3664 Ok(())
3665}
3666
3667#[allow(dead_code)]
3668#[inline]
3669fn bitwise_op_k(
3670 state: &mut LuaState,
3671 ra: StackIdx,
3672 v1: &LuaValue,
3673 v2: &LuaValue, pc: &mut u32,
3675 op: fn(i64, i64) -> i64,
3676) {
3677 let i2 = match v2 {
3678 LuaValue::Int(i) => *i,
3679 _ => return,
3680 };
3681 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3682 *pc += 1;
3683 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3684 }
3685}
3686
3687#[allow(dead_code)]
3688#[inline]
3689fn bitwise_op_rr(
3690 state: &mut LuaState,
3691 ra: StackIdx,
3692 v1: &LuaValue,
3693 v2: &LuaValue,
3694 pc: &mut u32,
3695 op: fn(i64, i64) -> i64,
3696) {
3697 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3698 *pc += 1;
3699 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3700 }
3701}
3702
3703#[allow(dead_code)]
3705#[inline]
3706fn bitwise_shift_rr(
3707 state: &mut LuaState,
3708 ra: StackIdx,
3709 v1: &LuaValue,
3710 v2: &LuaValue,
3711 pc: &mut u32,
3712 right: bool,
3713) {
3714 if let (Some(i1), Some(i2)) = (to_integer_ns(v1, F2Imod::Eq), to_integer_ns(v2, F2Imod::Eq)) {
3715 let y = if right { intop_sub(0, i2) } else { i2 };
3716 *pc += 1;
3717 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3718 }
3719}
3720
3721#[cold]
3724#[inline(never)]
3725#[allow(clippy::too_many_arguments)]
3726fn order_imm_slow(
3727 state: &mut LuaState,
3728 ra: StackIdx,
3729 pc: u32,
3730 trap: &mut bool,
3731 ci: CallInfoIdx,
3732 i: Instruction,
3733 im: i64,
3734 inv: bool,
3735 tm: TagMethod,
3736) -> Result<bool, LuaError> {
3737 let ra_v = state.get_at(ra);
3738 let isf = i.arg_c() != 0;
3739 state.set_ci_savedpc(ci, pc);
3740 state.set_top(state.ci_top(ci));
3741 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3742 *trap = state.ci_trap(ci);
3743 Ok(r)
3744}
3745
3746#[inline(always)]
3747fn finish_order_imm_jump(
3748 state: &mut LuaState,
3749 code: &[Instruction],
3750 pc: &mut u32,
3751 trap: &mut bool,
3752 ci: CallInfoIdx,
3753 i: Instruction,
3754 cond: bool,
3755) {
3756 if (cond as i32) != i.arg_k() {
3757 *pc += 1;
3758 } else {
3759 let next = code[*pc as usize];
3760 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3761 if state.hookmask != 0 {
3762 *trap = state.ci_trap(ci);
3763 }
3764 }
3765}
3766
3767#[cold]
3768#[inline(never)]
3769fn return0_hook(
3770 state: &mut LuaState,
3771 ci: CallInfoIdx,
3772 base: StackIdx,
3773 i: Instruction,
3774 pc: u32,
3775 trap: &mut bool,
3776) -> Result<(), LuaError> {
3777 let ra = base + i.arg_a();
3778 state.set_top(ra);
3779 state.set_ci_savedpc(ci, pc);
3780 state.poscall(ci, 0)?;
3781 *trap = true;
3782 Ok(())
3783}
3784
3785#[cold]
3786#[inline(never)]
3787fn return1_hook(
3788 state: &mut LuaState,
3789 ci: CallInfoIdx,
3790 base: StackIdx,
3791 i: Instruction,
3792 pc: u32,
3793 trap: &mut bool,
3794) -> Result<(), LuaError> {
3795 let ra = base + i.arg_a();
3796 state.set_top(ra + 1);
3797 state.set_ci_savedpc(ci, pc);
3798 state.poscall(ci, 1)?;
3799 *trap = true;
3800 Ok(())
3801}