1#[allow(unused_imports)] use crate::prelude::*;
24use lua_types::{
25 CallInfoIdx, GcRef, LuaError, LuaString, LuaValue, StackIdx,
26};
27use lua_types::tagmethod::TagMethod;
28use lua_types::opcode::Instruction;
29use crate::state::LuaState;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
57#[allow(non_camel_case_types)]
58#[repr(u8)]
59pub enum OpCode {
60 Move = 0,
61 LoadI = 1,
62 LoadF = 2,
63 LoadK = 3,
64 LoadKX = 4,
65 LoadFalse = 5,
66 LFalseSkip = 6,
67 LoadTrue = 7,
68 LoadNil = 8,
69 GetUpVal = 9,
70 SetUpVal = 10,
71 GetTabUp = 11,
72 GetTable = 12,
73 GetI = 13,
74 GetField = 14,
75 SetTabUp = 15,
76 SetTable = 16,
77 SetI = 17,
78 SetField = 18,
79 NewTable = 19,
80 Self_ = 20,
81 AddI = 21,
82 AddK = 22,
83 SubK = 23,
84 MulK = 24,
85 ModK = 25,
86 PowK = 26,
87 DivK = 27,
88 IDivK = 28,
89 BAndK = 29,
90 BOrK = 30,
91 BXOrK = 31,
92 ShrI = 32,
93 ShlI = 33,
94 Add = 34,
95 Sub = 35,
96 Mul = 36,
97 Mod = 37,
98 Pow = 38,
99 Div = 39,
100 IDiv = 40,
101 BAnd = 41,
102 BOr = 42,
103 BXOr = 43,
104 Shl = 44,
105 Shr = 45,
106 MmBin = 46,
107 MmBinI = 47,
108 MmBinK = 48,
109 Unm = 49,
110 BNot = 50,
111 Not = 51,
112 Len = 52,
113 Concat = 53,
114 Close = 54,
115 Tbc = 55,
116 Jmp = 56,
117 Eq = 57,
118 Lt = 58,
119 Le = 59,
120 EqK = 60,
121 EqI = 61,
122 LtI = 62,
123 LeI = 63,
124 GtI = 64,
125 GeI = 65,
126 Test = 66,
127 TestSet = 67,
128 Call = 68,
129 TailCall = 69,
130 Return = 70,
131 Return0 = 71,
132 Return1 = 72,
133 ForLoop = 73,
134 ForPrep = 74,
135 TForPrep = 75,
136 TForCall = 76,
137 TForLoop = 77,
138 SetList = 78,
139 Closure = 79,
140 VarArg = 80,
141 VarArgPrep = 81,
142 ExtraArg = 82,
143 ErrNNil = 83,
150 VarArgPack = 84,
158}
159
160#[allow(dead_code)]
164const NUM_OPCODES: u8 = 85;
165
166impl OpCode {
167 #[allow(non_upper_case_globals)]
174 pub const LoadKx: OpCode = OpCode::LoadKX;
175
176 #[allow(non_upper_case_globals)]
178 pub const GetUpval: OpCode = OpCode::GetUpVal;
179
180 pub fn from_u32(v: u32) -> Option<Self> {
184 match v {
185 0 => Some(Self::Move),
186 1 => Some(Self::LoadI),
187 2 => Some(Self::LoadF),
188 3 => Some(Self::LoadK),
189 4 => Some(Self::LoadKX),
190 5 => Some(Self::LoadFalse),
191 6 => Some(Self::LFalseSkip),
192 7 => Some(Self::LoadTrue),
193 8 => Some(Self::LoadNil),
194 9 => Some(Self::GetUpVal),
195 10 => Some(Self::SetUpVal),
196 11 => Some(Self::GetTabUp),
197 12 => Some(Self::GetTable),
198 13 => Some(Self::GetI),
199 14 => Some(Self::GetField),
200 15 => Some(Self::SetTabUp),
201 16 => Some(Self::SetTable),
202 17 => Some(Self::SetI),
203 18 => Some(Self::SetField),
204 19 => Some(Self::NewTable),
205 20 => Some(Self::Self_),
206 21 => Some(Self::AddI),
207 22 => Some(Self::AddK),
208 23 => Some(Self::SubK),
209 24 => Some(Self::MulK),
210 25 => Some(Self::ModK),
211 26 => Some(Self::PowK),
212 27 => Some(Self::DivK),
213 28 => Some(Self::IDivK),
214 29 => Some(Self::BAndK),
215 30 => Some(Self::BOrK),
216 31 => Some(Self::BXOrK),
217 32 => Some(Self::ShrI),
218 33 => Some(Self::ShlI),
219 34 => Some(Self::Add),
220 35 => Some(Self::Sub),
221 36 => Some(Self::Mul),
222 37 => Some(Self::Mod),
223 38 => Some(Self::Pow),
224 39 => Some(Self::Div),
225 40 => Some(Self::IDiv),
226 41 => Some(Self::BAnd),
227 42 => Some(Self::BOr),
228 43 => Some(Self::BXOr),
229 44 => Some(Self::Shl),
230 45 => Some(Self::Shr),
231 46 => Some(Self::MmBin),
232 47 => Some(Self::MmBinI),
233 48 => Some(Self::MmBinK),
234 49 => Some(Self::Unm),
235 50 => Some(Self::BNot),
236 51 => Some(Self::Not),
237 52 => Some(Self::Len),
238 53 => Some(Self::Concat),
239 54 => Some(Self::Close),
240 55 => Some(Self::Tbc),
241 56 => Some(Self::Jmp),
242 57 => Some(Self::Eq),
243 58 => Some(Self::Lt),
244 59 => Some(Self::Le),
245 60 => Some(Self::EqK),
246 61 => Some(Self::EqI),
247 62 => Some(Self::LtI),
248 63 => Some(Self::LeI),
249 64 => Some(Self::GtI),
250 65 => Some(Self::GeI),
251 66 => Some(Self::Test),
252 67 => Some(Self::TestSet),
253 68 => Some(Self::Call),
254 69 => Some(Self::TailCall),
255 70 => Some(Self::Return),
256 71 => Some(Self::Return0),
257 72 => Some(Self::Return1),
258 73 => Some(Self::ForLoop),
259 74 => Some(Self::ForPrep),
260 75 => Some(Self::TForPrep),
261 76 => Some(Self::TForCall),
262 77 => Some(Self::TForLoop),
263 78 => Some(Self::SetList),
264 79 => Some(Self::Closure),
265 80 => Some(Self::VarArg),
266 81 => Some(Self::VarArgPrep),
267 82 => Some(Self::ExtraArg),
268 83 => Some(Self::ErrNNil),
269 84 => Some(Self::VarArgPack),
270 _ => None,
271 }
272 }
273}
274
275pub trait InstructionExt {
279 fn opcode(&self) -> OpCode;
280 fn arg_a(&self) -> i32;
281 fn arg_b(&self) -> i32;
282 fn arg_c(&self) -> i32;
283 fn arg_k(&self) -> i32;
284 fn arg_ax(&self) -> i32;
285 fn arg_bx(&self) -> i32;
286 fn arg_s_b(&self) -> i32;
287 fn arg_s_c(&self) -> i32;
288 fn arg_s_j(&self) -> i32;
289 fn arg_s_bx(&self) -> i32;
290 fn test_k(&self) -> bool;
291 fn test_a_mode(&self) -> bool;
292 fn is_mm_mode(&self) -> bool;
293 fn is_vararg_prep(&self) -> bool;
294 fn is_in_top(&self) -> bool;
295}
296
297impl InstructionExt for Instruction {
298 #[inline(always)]
306 fn opcode(&self) -> OpCode {
307 match (self.raw() & 0x7F) as u8 {
308 0 => OpCode::Move,
309 1 => OpCode::LoadI,
310 2 => OpCode::LoadF,
311 3 => OpCode::LoadK,
312 4 => OpCode::LoadKX,
313 5 => OpCode::LoadFalse,
314 6 => OpCode::LFalseSkip,
315 7 => OpCode::LoadTrue,
316 8 => OpCode::LoadNil,
317 9 => OpCode::GetUpVal,
318 10 => OpCode::SetUpVal,
319 11 => OpCode::GetTabUp,
320 12 => OpCode::GetTable,
321 13 => OpCode::GetI,
322 14 => OpCode::GetField,
323 15 => OpCode::SetTabUp,
324 16 => OpCode::SetTable,
325 17 => OpCode::SetI,
326 18 => OpCode::SetField,
327 19 => OpCode::NewTable,
328 20 => OpCode::Self_,
329 21 => OpCode::AddI,
330 22 => OpCode::AddK,
331 23 => OpCode::SubK,
332 24 => OpCode::MulK,
333 25 => OpCode::ModK,
334 26 => OpCode::PowK,
335 27 => OpCode::DivK,
336 28 => OpCode::IDivK,
337 29 => OpCode::BAndK,
338 30 => OpCode::BOrK,
339 31 => OpCode::BXOrK,
340 32 => OpCode::ShrI,
341 33 => OpCode::ShlI,
342 34 => OpCode::Add,
343 35 => OpCode::Sub,
344 36 => OpCode::Mul,
345 37 => OpCode::Mod,
346 38 => OpCode::Pow,
347 39 => OpCode::Div,
348 40 => OpCode::IDiv,
349 41 => OpCode::BAnd,
350 42 => OpCode::BOr,
351 43 => OpCode::BXOr,
352 44 => OpCode::Shl,
353 45 => OpCode::Shr,
354 46 => OpCode::MmBin,
355 47 => OpCode::MmBinI,
356 48 => OpCode::MmBinK,
357 49 => OpCode::Unm,
358 50 => OpCode::BNot,
359 51 => OpCode::Not,
360 52 => OpCode::Len,
361 53 => OpCode::Concat,
362 54 => OpCode::Close,
363 55 => OpCode::Tbc,
364 56 => OpCode::Jmp,
365 57 => OpCode::Eq,
366 58 => OpCode::Lt,
367 59 => OpCode::Le,
368 60 => OpCode::EqK,
369 61 => OpCode::EqI,
370 62 => OpCode::LtI,
371 63 => OpCode::LeI,
372 64 => OpCode::GtI,
373 65 => OpCode::GeI,
374 66 => OpCode::Test,
375 67 => OpCode::TestSet,
376 68 => OpCode::Call,
377 69 => OpCode::TailCall,
378 70 => OpCode::Return,
379 71 => OpCode::Return0,
380 72 => OpCode::Return1,
381 73 => OpCode::ForLoop,
382 74 => OpCode::ForPrep,
383 75 => OpCode::TForPrep,
384 76 => OpCode::TForCall,
385 77 => OpCode::TForLoop,
386 78 => OpCode::SetList,
387 79 => OpCode::Closure,
388 80 => OpCode::VarArg,
389 81 => OpCode::VarArgPrep,
390 82 => OpCode::ExtraArg,
391 83 => OpCode::ErrNNil,
392 84 => OpCode::VarArgPack,
393 _ => OpCode::ExtraArg,
394 }
395 }
396 #[inline] fn arg_a(&self) -> i32 { ((self.raw() >> 7) & 0xFF) as i32 }
397 #[inline] fn arg_b(&self) -> i32 { ((self.raw() >> 16) & 0xFF) as i32 }
398 #[inline] fn arg_c(&self) -> i32 { ((self.raw() >> 24) & 0xFF) as i32 }
399 #[inline] fn arg_k(&self) -> i32 { ((self.raw() >> 15) & 0x1) as i32 }
400 #[inline] fn arg_ax(&self) -> i32 { (self.raw() >> 7) as i32 }
401 #[inline] fn arg_bx(&self) -> i32 { (self.raw() >> 15) as i32 }
402 #[inline] fn arg_s_b(&self) -> i32 { self.arg_b() - 0x7F }
403 #[inline] fn arg_s_c(&self) -> i32 { self.arg_c() - 0x7F }
404 #[inline] fn arg_s_j(&self) -> i32 { self.arg_ax() - 0xFFFFFF }
405 #[inline] fn arg_s_bx(&self) -> i32 { self.arg_bx() - 0xFFFF }
406 #[inline] fn test_k(&self) -> bool { (self.raw() & (1 << 15)) != 0 }
407 #[inline]
408 fn test_a_mode(&self) -> bool {
409 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
410 }
411 #[inline]
412 fn is_mm_mode(&self) -> bool {
413 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
414 }
415 #[inline]
416 fn is_vararg_prep(&self) -> bool {
417 matches!(self.opcode(), OpCode::VarArgPrep)
418 }
419 #[inline]
420 fn is_in_top(&self) -> bool {
421 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
422 }
423}
424
425const OP_MODE_BYTES: [u8; NUM_OPCODES as usize] = [
438 0x08, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80, 0x80, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x04, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x68, 0x68, 0x20, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, 0x09, 0x20, 0x09, 0x48, 0x28, 0x03, 0x01, 0x08, ];
524
525#[inline(always)]
526fn op_mode_byte(op: OpCode) -> u8 {
527 OP_MODE_BYTES[op as usize]
528}
529
530const MAX_TAG_LOOP: i32 = 2000;
534
535const NBITS: u32 = 64;
536
537#[derive(Debug, Clone, Copy, PartialEq, Eq)]
541pub(crate) enum F2Imod {
542 Eq,
544 Floor,
546 Ceil,
548}
549
550#[inline]
553fn intop_add(a: i64, b: i64) -> i64 {
554 (a as u64).wrapping_add(b as u64) as i64
555}
556
557#[inline]
558fn intop_sub(a: i64, b: i64) -> i64 {
559 (a as u64).wrapping_sub(b as u64) as i64
560}
561
562#[inline]
563fn intop_mul(a: i64, b: i64) -> i64 {
564 (a as u64).wrapping_mul(b as u64) as i64
565}
566
567#[inline]
569fn intop_shr(x: i64, n: u32) -> i64 {
570 (x as u64 >> n) as i64
572}
573
574#[inline]
575fn intop_shl(x: i64, n: u32) -> i64 {
576 (x as u64).wrapping_shl(n) as i64
577}
578
579#[inline]
580fn intop_band(a: i64, b: i64) -> i64 { ((a as u64) & (b as u64)) as i64 }
581#[inline]
582fn intop_bor(a: i64, b: i64) -> i64 { ((a as u64) | (b as u64)) as i64 }
583#[inline]
584fn intop_bxor(a: i64, b: i64) -> i64 { ((a as u64) ^ (b as u64)) as i64 }
585
586#[inline]
591fn int_fits_float(i: i64) -> bool {
592 const MAXINTFITSF: u64 = 1u64 << f64::MANTISSA_DIGITS;
593 (MAXINTFITSF.wrapping_add(i as u64)) <= 2 * MAXINTFITSF
594}
595
596fn str_to_number(obj: &LuaValue) -> Option<LuaValue> {
602 let s = match obj {
604 LuaValue::Str(ts) => ts.as_bytes().to_vec(),
605 _ => return None,
606 };
607 let trimmed = trim_whitespace(&s);
609 if trimmed.is_empty() {
610 return None;
611 }
612 let mut result = LuaValue::Nil;
613 if crate::object::str2num(trimmed, &mut result) != 0 {
614 return Some(result);
615 }
616 None
617}
618
619fn trim_whitespace(s: &[u8]) -> &[u8] {
620 let start = s.iter().position(|&b| !b.is_ascii_whitespace()).unwrap_or(s.len());
621 let end = s.iter().rposition(|&b| !b.is_ascii_whitespace()).map(|i| i + 1).unwrap_or(0);
622 if start <= end { &s[start..end] } else { &s[0..0] }
623}
624
625pub(crate) fn tonumber_(obj: &LuaValue) -> Option<f64> {
631 if let LuaValue::Int(i) = obj {
632 return Some(*i as f64);
633 }
634 if let Some(v) = str_to_number(obj) {
635 return match v {
636 LuaValue::Float(f) => Some(f),
637 LuaValue::Int(i) => Some(i as f64),
638 _ => None,
639 };
640 }
641 None
642}
643
644fn tonumber(obj: &LuaValue) -> Option<f64> {
646 if let LuaValue::Float(f) = obj {
647 return Some(*f);
648 }
649 tonumber_(obj)
650}
651
652pub(crate) fn flt_to_integer(n: f64, mode: F2Imod) -> Option<i64> {
655 let f = n.floor();
656 if n != f {
657 match mode {
658 F2Imod::Eq => return None,
659 F2Imod::Ceil => {
660 let f = f + 1.0;
662 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
664 return Some(f as i64);
665 }
666 return None;
667 }
668 F2Imod::Floor => { }
669 }
670 }
671 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
672 Some(f as i64)
673 } else {
674 None
675 }
676}
677
678pub(crate) fn to_integer_ns(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
680 if let LuaValue::Float(f) = obj {
681 return flt_to_integer(*f, mode);
682 }
683 if let LuaValue::Int(i) = obj {
684 return Some(*i);
685 }
686 None
687}
688
689pub(crate) fn to_integer(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
691 let coerced;
692 let obj = if let Some(v) = str_to_number(obj) {
693 coerced = v;
694 &coerced
695 } else {
696 obj
697 };
698 to_integer_ns(obj, mode)
699}
700
701fn forlimit(
708 state: &mut LuaState,
709 init: i64,
710 lim: &LuaValue,
711 step: i64,
712) -> Result<(bool, i64), LuaError> {
713 let round = if step < 0 { F2Imod::Ceil } else { F2Imod::Floor };
714 if let Some(p) = to_integer(lim, round) {
715 let skip = if step > 0 { init > p } else { init < p };
716 return Ok((skip, p));
717 }
718 let flim = match tonumber(lim) {
719 Some(f) => f,
720 None => return Err(crate::debug::for_error(state, lim, b"limit")),
721 };
722 if 0.0_f64 < flim {
723 if step < 0 {
725 return Ok((true, 0));
726 }
727 Ok((false, i64::MAX))
728 } else {
729 if step > 0 {
731 return Ok((true, 0));
732 }
733 Ok((false, i64::MIN))
734 }
735}
736
737pub(crate) fn forprep(state: &mut LuaState, ra: StackIdx) -> Result<bool, LuaError> {
742 let pinit = state.get_at(ra);
743 let plimit = state.get_at(ra + 1);
744 let pstep = state.get_at(ra + 2);
745
746 if let (LuaValue::Int(init), LuaValue::Int(step)) = (&pinit, &pstep) {
747 let init = *init;
748 let step = *step;
749 if step == 0 {
750 return Err(LuaError::runtime(format_args!("'for' step is zero")));
751 }
752 state.set_at(ra + 3, LuaValue::Int(init));
753
754 let (skip, limit) = forlimit(state, init, &plimit, step)?;
755 if skip {
756 return Ok(true);
757 }
758 let count: u64 = if step > 0 {
759 let c = (limit as u64).wrapping_sub(init as u64);
760 if step != 1 { c / (step as u64) } else { c }
761 } else {
762 let c = (init as u64).wrapping_sub(limit as u64);
763 c / (((-(step + 1)) as u64).wrapping_add(1))
764 };
765 state.set_at(ra + 1, LuaValue::Int(count as i64));
766 Ok(false)
767 } else {
768 let limit_f = match tonumber(&plimit) {
769 Some(f) => f,
770 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
771 };
772 let step_f = match tonumber(&pstep) {
773 Some(f) => f,
774 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
775 };
776 let init_f = match tonumber(&pinit) {
777 Some(f) => f,
778 None => return Err(crate::debug::for_error(state, &pinit, b"initial value")),
779 };
780 if step_f == 0.0 {
781 return Err(LuaError::runtime(format_args!("'for' step is zero")));
782 }
783 let skip = if step_f > 0.0 { limit_f < init_f } else { init_f < limit_f };
784 if skip {
785 return Ok(true);
786 }
787 state.set_at(ra + 1, LuaValue::Float(limit_f));
789 state.set_at(ra + 2, LuaValue::Float(step_f));
790 state.set_at(ra, LuaValue::Float(init_f));
791 state.set_at(ra + 3, LuaValue::Float(init_f));
792 Ok(false)
793 }
794}
795
796fn forlimit_legacy(obj: &LuaValue, step: i64) -> Option<(i64, bool)> {
802 let round = if step < 0 { F2Imod::Ceil } else { F2Imod::Floor };
803 if let Some(p) = to_integer(obj, round) {
804 return Some((p, false));
805 }
806 let n = tonumber(obj)?;
807 if 0.0 < n {
808 Some((i64::MAX, step < 0))
809 } else {
810 Some((i64::MIN, step >= 0))
811 }
812}
813
814pub(crate) fn forprep_legacy(state: &mut LuaState, ra: StackIdx) -> Result<(), LuaError> {
822 let init = state.get_at(ra);
823 let plimit = state.get_at(ra + 1);
824 let pstep = state.get_at(ra + 2);
825
826 if let (LuaValue::Int(initv), LuaValue::Int(stepv)) = (&init, &pstep) {
827 let (initv, stepv) = (*initv, *stepv);
828 if let Some((ilimit, stopnow)) = forlimit_legacy(&plimit, stepv) {
829 let base = if stopnow { 0 } else { initv };
830 state.set_at(ra + 1, LuaValue::Int(ilimit));
831 state.set_at(ra, LuaValue::Int(intop_sub(base, stepv)));
832 return Ok(());
833 }
834 }
837
838 let nlimit = match tonumber(&plimit) {
839 Some(f) => f,
840 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
841 };
842 let nstep = match tonumber(&pstep) {
843 Some(f) => f,
844 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
845 };
846 let ninit = match tonumber(&init) {
847 Some(f) => f,
848 None => return Err(crate::debug::for_error(state, &init, b"initial value")),
849 };
850 state.set_at(ra + 1, LuaValue::Float(nlimit));
851 state.set_at(ra + 2, LuaValue::Float(nstep));
852 state.set_at(ra, LuaValue::Float(ninit - nstep));
853 Ok(())
854}
855
856fn forloop_legacy(state: &mut LuaState, ra: StackIdx) -> bool {
861 if let LuaValue::Int(step) = state.get_at(ra + 2) {
862 let idx = intop_add(
863 match state.get_at(ra) {
864 LuaValue::Int(x) => x,
865 _ => 0,
866 },
867 step,
868 );
869 let limit = match state.get_at(ra + 1) {
870 LuaValue::Int(l) => l,
871 _ => 0,
872 };
873 let cont = if step > 0 { idx <= limit } else { limit <= idx };
874 if cont {
875 state.set_at(ra, LuaValue::Int(idx));
876 state.set_at(ra + 3, LuaValue::Int(idx));
877 }
878 cont
879 } else {
880 let step = match state.get_at(ra + 2) {
881 LuaValue::Float(f) => f,
882 _ => return false,
883 };
884 let idx = match state.get_at(ra) {
885 LuaValue::Float(f) => f,
886 _ => return false,
887 } + step;
888 let limit = match state.get_at(ra + 1) {
889 LuaValue::Float(f) => f,
890 _ => return false,
891 };
892 let cont = if step > 0.0 { idx <= limit } else { limit <= idx };
893 if cont {
894 state.set_at(ra, LuaValue::Float(idx));
895 state.set_at(ra + 3, LuaValue::Float(idx));
896 }
897 cont
898 }
899}
900
901fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
903 let step = match state.get_at(ra + 2) {
905 LuaValue::Float(f) => f,
906 _ => return false,
907 };
908 let limit = match state.get_at(ra + 1) {
909 LuaValue::Float(f) => f,
910 _ => return false,
911 };
912 let idx = match state.get_at(ra) {
913 LuaValue::Float(f) => f,
914 _ => return false,
915 };
916 let idx = idx + step;
917 if if step > 0.0 { idx <= limit } else { limit <= idx } {
918 state.set_at(ra, LuaValue::Float(idx));
919 state.set_at(ra + 3, LuaValue::Float(idx));
920 true
921 } else {
922 false
923 }
924}
925
926pub(crate) fn finish_get(
932 state: &mut LuaState,
933 t_val: LuaValue,
934 key: LuaValue,
935 result_idx: StackIdx,
936 slot_empty: bool,
937 t_idx: Option<StackIdx>,
938) -> Result<(), LuaError> {
939 let mut t = t_val;
940 let mut t_idx = t_idx;
941 for _loop in 0..MAX_TAG_LOOP {
942 let tm: LuaValue;
943 if slot_empty && !matches!(t, LuaValue::Table(_)) {
944 tm = state.get_tm_by_obj(&t, TagMethod::Index);
945 if matches!(tm, LuaValue::Nil) {
946 return Err(match t_idx {
947 Some(idx) => crate::debug::type_error(state, &t, idx, b"index"),
948 None => LuaError::type_error(&t, "index"),
949 });
950 }
951 } else {
952 let mt = state.table_metatable(&t);
953 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
954 if matches!(tm, LuaValue::Nil) {
955 state.set_at(result_idx, LuaValue::Nil);
956 return Ok(());
957 }
958 }
959 if matches!(tm, LuaValue::Function(_)) {
960 state.call_tm_res(tm, &t, &key, result_idx)?;
961 return Ok(());
962 }
963 t = tm.clone();
964 t_idx = None;
965 if let Some(v) = state.fast_get(&t, &key)? {
966 state.set_at(result_idx, v);
967 return Ok(());
968 }
969 }
971 Err(LuaError::runtime(format_args!("'__index' chain too long; possible loop")))
972}
973
974pub(crate) fn finish_set(
983 state: &mut LuaState,
984 t_val: LuaValue,
985 key: LuaValue,
986 val: LuaValue,
987 _slot_present: bool,
988 t_idx: Option<StackIdx>,
989 var_hint: Option<(&[u8], &[u8])>,
990) -> Result<(), LuaError> {
991 let mut t = t_val;
992 let mut t_idx = t_idx;
993 for _loop in 0..MAX_TAG_LOOP {
994 let tm: LuaValue;
995 if matches!(t, LuaValue::Table(_)) {
996 let mt = state.table_metatable(&t);
997 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
998 if matches!(tm, LuaValue::Nil) {
999 state.table_raw_set(&t, key, val.clone())?;
1000 state.gc_value_barrier_back(&t, &val);
1001 return Ok(());
1002 }
1003 } else {
1004 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
1005 if matches!(tm, LuaValue::Nil) {
1006 return Err(match (t_idx, var_hint) {
1007 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
1008 (None, Some((kind, name))) => {
1009 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
1010 }
1011 (None, None) => LuaError::type_error(&t, "index"),
1012 });
1013 }
1014 }
1015 if matches!(tm, LuaValue::Function(_)) {
1016 state.call_tm(tm, &t, &key, &val)?;
1017 return Ok(());
1018 }
1019 t = tm.clone();
1020 t_idx = None;
1021 if state.fast_get(&t, &key)?.is_some() {
1022 state.table_raw_set(&t, key.clone(), val.clone())?;
1023 state.gc_value_barrier_back(&t, &val);
1024 return Ok(());
1025 }
1026 }
1027 Err(LuaError::runtime(format_args!("'__newindex' chain too long; possible loop")))
1028}
1029
1030fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
1041 let mut s1 = s1;
1044 let mut s2 = s2;
1045 loop {
1046 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
1048 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
1049 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
1051 if seg_cmp != std::cmp::Ordering::Equal {
1052 return seg_cmp;
1053 }
1054 if z2 == s2.len() {
1056 if z1 == s1.len() {
1058 return std::cmp::Ordering::Equal;
1059 }
1060 return std::cmp::Ordering::Greater; }
1062 if z1 == s1.len() {
1063 return std::cmp::Ordering::Less; }
1065 s1 = &s1[z1 + 1..];
1067 s2 = &s2[z2 + 1..];
1068 }
1069}
1070
1071#[inline]
1074fn lt_int_float(i: i64, f: f64) -> bool {
1075 if int_fits_float(i) {
1076 (i as f64) < f
1077 } else {
1078 match flt_to_integer(f, F2Imod::Ceil) {
1079 Some(fi) => i < fi,
1080 None => f > 0.0, }
1082 }
1083}
1084
1085#[inline]
1086fn le_int_float(i: i64, f: f64) -> bool {
1087 if int_fits_float(i) {
1088 (i as f64) <= f
1089 } else {
1090 match flt_to_integer(f, F2Imod::Floor) {
1091 Some(fi) => i <= fi,
1092 None => f > 0.0,
1093 }
1094 }
1095}
1096
1097#[inline]
1098fn lt_float_int(f: f64, i: i64) -> bool {
1099 if int_fits_float(i) {
1100 f < (i as f64)
1101 } else {
1102 match flt_to_integer(f, F2Imod::Floor) {
1103 Some(fi) => fi < i,
1104 None => f < 0.0,
1105 }
1106 }
1107}
1108
1109#[inline]
1110fn le_float_int(f: f64, i: i64) -> bool {
1111 if int_fits_float(i) {
1112 f <= (i as f64)
1113 } else {
1114 match flt_to_integer(f, F2Imod::Ceil) {
1115 Some(fi) => fi <= i,
1116 None => f < 0.0,
1117 }
1118 }
1119}
1120
1121#[inline]
1122fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
1123 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1124 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1125 match (l, r) {
1126 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1127 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1128 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1129 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1130 _ => false,
1131 }
1132}
1133
1134#[inline]
1135fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1136 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1137 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1138 match (l, r) {
1139 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1140 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1141 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1142 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1143 _ => false,
1144 }
1145}
1146
1147fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1149 debug_assert!(!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1150 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))));
1151 match (l, r) {
1152 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1153 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1154 }
1155 _ => state.call_order_tm(l, r, TagMethod::Lt),
1156 }
1157}
1158
1159pub(crate) fn less_than(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1160 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1161 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1162 {
1163 Ok(lt_num(l, r))
1164 } else {
1165 less_than_others(state, l, r)
1166 }
1167}
1168
1169fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1170 match (l, r) {
1171 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1172 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1173 }
1174 _ => state.call_order_tm(l, r, TagMethod::Le),
1175 }
1176}
1177
1178pub(crate) fn less_equal(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1179 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1180 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1181 {
1182 Ok(le_num(l, r))
1183 } else {
1184 less_equal_others(state, l, r)
1185 }
1186}
1187
1188pub(crate) fn equal_obj(
1192 state: Option<&mut LuaState>,
1193 t1: &LuaValue,
1194 t2: &LuaValue,
1195) -> Result<bool, LuaError> {
1196 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1199 if !same_variant {
1200 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1201 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1202 if !(t1_is_num && t2_is_num) {
1203 return Ok(false);
1204 }
1205 let i1 = to_integer_ns(t1, F2Imod::Eq);
1207 let i2 = to_integer_ns(t2, F2Imod::Eq);
1208 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1209 }
1210
1211 match (t1, t2) {
1212 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1213 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1214 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1215 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1216 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1217 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1218 use lua_types::closure::LuaClosure;
1219 let same = match (f1, f2) {
1220 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1221 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1222 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1223 _ => false,
1224 };
1225 Ok(same)
1226 }
1227 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1228 Ok(s1 == s2)
1231 }
1232 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1233 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1236 return Ok(true);
1237 }
1238 let Some(state) = state else { return Ok(false); };
1239 let tm1 = state.fast_tm_ud(u1, TagMethod::Eq);
1240 let tm = if matches!(tm1, LuaValue::Nil) {
1241 state.fast_tm_ud(u2, TagMethod::Eq)
1242 } else {
1243 tm1
1244 };
1245 if matches!(tm, LuaValue::Nil) {
1246 return Ok(false);
1247 }
1248 let result = state.call_tm_res_bool(tm, t1, t2)?;
1249 Ok(result)
1250 }
1251 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1252 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1253 return Ok(true);
1254 }
1255 let Some(state) = state else { return Ok(false); };
1256 let mt1 = h1.metatable();
1258 let mt2 = h2.metatable();
1259 let tm1 = state.fast_tm_table(mt1.as_ref(), TagMethod::Eq);
1260 let tm = if matches!(tm1, LuaValue::Nil) {
1261 state.fast_tm_table(mt2.as_ref(), TagMethod::Eq)
1262 } else {
1263 tm1
1264 };
1265 if matches!(tm, LuaValue::Nil) {
1266 return Ok(false);
1267 }
1268 let result = state.call_tm_res_bool(tm, t1, t2)?;
1269 Ok(result)
1270 }
1271 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1272 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1273 }
1274}
1275
1276fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1280 buf.clear();
1281 let mut remaining = n;
1282 loop {
1283 let idx = top - remaining as i32;
1284 let v = state.get_at(idx);
1285 if let LuaValue::Str(ts) = v {
1286 buf.extend_from_slice(ts.as_bytes());
1287 }
1288 if remaining <= 1 {
1289 break;
1290 }
1291 remaining -= 1;
1292 }
1293}
1294
1295pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1297 if total == 1 {
1298 return Ok(());
1299 }
1300 if total == 2 {
1301 let top = state.top_idx();
1302 let v_tm1 = state.get_at(top - 1);
1303 let v_tm2 = state.get_at(top - 2);
1304 if concat_pair_fast(state, top, v_tm2, v_tm1)? {
1305 return Ok(());
1306 }
1307 }
1308 let mut total = total;
1309 loop {
1310 let top = state.top_idx();
1311 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1316 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1317 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1319 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1320 if !top2_coercible || !top1_stringlike {
1321 state.try_concat_tm(&v_tm1, &v_tm2)?;
1322 total -= 1;
1327 let top = state.top_idx();
1328 state.set_top(top - 1);
1329 if total <= 1 {
1330 break;
1331 }
1332 continue;
1333 }
1334
1335 let is_empty = |v: &LuaValue| -> bool {
1336 matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty())
1337 };
1338
1339 let n: u32;
1340 if is_empty(&v_tm1) {
1341 state.coerce_to_string(top - 2)?;
1342 n = 2;
1343 } else if is_empty(&v_tm2) {
1344 state.coerce_to_string(top - 1)?;
1347 let v = state.get_at(top - 1);
1348 state.set_at(top - 2, v);
1349 n = 2;
1350 } else {
1351 state.coerce_to_string(top - 1)?;
1353 let s1 = match state.get_at(top - 1) {
1354 LuaValue::Str(ts) => ts.as_bytes().len(),
1355 _ => 0,
1356 };
1357 let mut total_len = s1;
1358 let mut count: u32 = 1;
1359 let top = state.top_idx();
1360 loop {
1361 if count as i32 >= total {
1362 break;
1363 }
1364 let idx = top - (count as i32 + 1);
1365 let v = state.get_at(idx);
1366 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1367 break;
1368 }
1369 state.coerce_to_string(idx)?;
1370 let l = match state.get_at(idx) {
1371 LuaValue::Str(ts) => ts.as_bytes().len(),
1372 _ => 0,
1373 };
1374 if l >= usize::MAX - total_len {
1375 state.set_top(top - total as i32);
1377 return Err(LuaError::runtime(format_args!("string length overflow")));
1378 }
1379 total_len += l;
1380 count += 1;
1381 }
1382 n = count;
1383
1384 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1386 let top = state.top_idx();
1387 copy_to_buf(state, top, n, &mut buf);
1388 let ts = state.intern_or_create_str(&buf)?;
1389 state.set_at(top - n as i32, LuaValue::Str(ts));
1390 }
1391 total -= n as i32 - 1;
1392 let top = state.top_idx();
1393 state.set_top(top - ((n - 1) as i32));
1394
1395 if total <= 1 {
1396 break;
1397 }
1398 }
1399 Ok(())
1400}
1401
1402enum ConcatPiece {
1403 Str(GcRef<LuaString>),
1404 Num(Vec<u8>),
1405}
1406
1407impl ConcatPiece {
1408 #[inline]
1409 fn len(&self) -> usize {
1410 match self {
1411 ConcatPiece::Str(s) => s.as_bytes().len(),
1412 ConcatPiece::Num(bytes) => bytes.len(),
1413 }
1414 }
1415
1416 #[inline]
1417 fn append_to(&self, out: &mut Vec<u8>) {
1418 match self {
1419 ConcatPiece::Str(s) => out.extend_from_slice(s.as_bytes()),
1420 ConcatPiece::Num(bytes) => out.extend_from_slice(bytes),
1421 }
1422 }
1423}
1424
1425#[inline]
1426fn concat_piece(v: LuaValue, version: lua_types::LuaVersion) -> Option<ConcatPiece> {
1427 match v {
1428 LuaValue::Str(s) => Some(ConcatPiece::Str(s)),
1429 LuaValue::Int(_) | LuaValue::Float(_) => {
1430 Some(ConcatPiece::Num(crate::object::number_to_str_buf(&v, version)))
1431 }
1432 _ => None,
1433 }
1434}
1435
1436#[inline]
1437fn concat_pair_fast(
1438 state: &mut LuaState,
1439 top: StackIdx,
1440 left: LuaValue,
1441 right: LuaValue,
1442) -> Result<bool, LuaError> {
1443 let version = state.global().lua_version;
1444 let Some(left) = concat_piece(left, version) else {
1445 return Ok(false);
1446 };
1447 let Some(right) = concat_piece(right, version) else {
1448 return Ok(false);
1449 };
1450 let total_len = left
1451 .len()
1452 .checked_add(right.len())
1453 .ok_or_else(|| LuaError::runtime(format_args!("string length overflow")))?;
1454 let mut buf = Vec::with_capacity(total_len);
1455 left.append_to(&mut buf);
1456 right.append_to(&mut buf);
1457 let ts = state.intern_or_create_str(&buf)?;
1458 state.set_at(top - 2, LuaValue::Str(ts));
1459 state.set_top(top - 1);
1460 Ok(true)
1461}
1462
1463pub(crate) fn obj_len(state: &mut LuaState, ra: StackIdx, rb: LuaValue, rb_idx: StackIdx) -> Result<(), LuaError> {
1467 match &rb {
1468 LuaValue::Table(_) => {
1469 let consult_len_tm = !matches!(
1474 state.global().lua_version,
1475 lua_types::LuaVersion::V51
1476 );
1477 let tm = if consult_len_tm {
1478 let mt = state.table_metatable(&rb);
1479 state.fast_tm_table(mt.as_ref(), TagMethod::Len)
1480 } else {
1481 LuaValue::Nil
1482 };
1483 if matches!(tm, LuaValue::Nil) {
1484 let n = state.table_length(&rb)?;
1485 state.set_at(ra, LuaValue::Int(n as i64));
1486 return Ok(());
1487 }
1488 state.call_tm_res(tm, &rb, &rb, ra)?;
1490 }
1491 LuaValue::Str(ts) => {
1492 let n = ts.len();
1495 state.set_at(ra, LuaValue::Int(n as i64));
1496 }
1497 other => {
1498 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1500 if matches!(tm, LuaValue::Nil) {
1501 return Err(crate::debug::type_error(state, other, rb_idx, b"get length of"));
1502 }
1503 state.call_tm_res(tm, &rb, &rb, ra)?;
1504 }
1505 }
1506 Ok(())
1507}
1508
1509pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1513 if (n as u64).wrapping_add(1) <= 1 {
1514 if n == 0 {
1515 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1516 }
1517 return Ok(intop_sub(0, m));
1518 }
1519 let q = m / n;
1520 if (m ^ n) < 0 && m % n != 0 {
1522 Ok(q - 1)
1523 } else {
1524 Ok(q)
1525 }
1526}
1527
1528pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1530 if (n as u64).wrapping_add(1) <= 1 {
1531 if n == 0 {
1532 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1533 }
1534 return Ok(0);
1535 }
1536 let r = m % n;
1537 if r != 0 && (r ^ n) < 0 {
1538 Ok(r + n)
1539 } else {
1540 Ok(r)
1541 }
1542}
1543
1544pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1546 let r = m % n;
1547 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1548 if opposite_signs {
1549 r + n
1550 } else {
1551 r
1552 }
1553}
1554
1555pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1558 use TagMethod::*;
1559 match i {
1560 0 => Index, 1 => NewIndex, 2 => Gc, 3 => Mode, 4 => Len, 5 => Eq,
1561 6 => Add, 7 => Sub, 8 => Mul, 9 => Mod, 10 => Pow, 11 => Div,
1562 12 => Idiv, 13 => Band, 14 => Bor, 15 => Bxor, 16 => Shl, 17 => Shr,
1563 18 => Unm, 19 => Bnot, 20 => Lt, 21 => Le, 22 => Concat, 23 => Call,
1564 24 => Close,
1565 _ => Index,
1566 }
1567}
1568
1569pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1572 imod(a, b)
1573}
1574
1575pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1578 idiv(a, b)
1579}
1580
1581pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1584 Ok(fmodf(a, b))
1585}
1586
1587pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1589 if y < 0 {
1590 if y <= -(NBITS as i64) {
1591 0
1592 } else {
1593 intop_shr(x, (-y) as u32)
1594 }
1595 } else {
1596 if y >= NBITS as i64 {
1597 0
1598 } else {
1599 intop_shl(x, y as u32)
1600 }
1601 }
1602}
1603
1604fn push_closure(
1610 state: &mut LuaState,
1611 proto_idx: usize, ci: CallInfoIdx,
1613 base: StackIdx,
1614 ra: StackIdx,
1615) -> Result<(), LuaError> {
1616 state.push_closure(proto_idx, ci, base, ra)
1620}
1621
1622pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1627 let ci = state.current_ci_idx();
1631 let base = state.ci_base(ci);
1632 let inst = state.ci_prev_instruction(ci);
1633 let op = inst.opcode();
1634
1635 match op {
1636 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1638 let prev_inst = state.ci_prev2_instruction(ci);
1639 let a = prev_inst.arg_a();
1640 state.dec_top();
1641 let top = state.top_idx();
1642 let v = state.get_at(top);
1643 state.set_at(base + a, v);
1644 }
1645 OpCode::Unm | OpCode::BNot | OpCode::Len
1647 | OpCode::GetTabUp | OpCode::GetTable | OpCode::GetI
1648 | OpCode::GetField | OpCode::Self_ => {
1649 let a = inst.arg_a();
1650 state.dec_top();
1651 let top = state.top_idx();
1652 let v = state.get_at(top);
1653 state.set_at(base + a, v);
1654 }
1655 OpCode::Lt | OpCode::Le | OpCode::LtI | OpCode::LeI
1659 | OpCode::GtI | OpCode::GeI | OpCode::Eq => {
1660 let top_minus1 = state.top_idx() - 1;
1661 let v = state.get_at(top_minus1);
1662 let mut res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1663 state.dec_top();
1664 if (state.get_ci(ci).callstatus & crate::state::CIST_LEQ) != 0 {
1669 state.get_ci_mut(ci).callstatus &= !crate::state::CIST_LEQ;
1670 res = !res;
1671 }
1672 if (res as i32) != inst.arg_k() {
1673 state.ci_skip_next_instruction(ci);
1674 }
1675 }
1676 OpCode::Concat => {
1682 let top = state.top_idx() - 1; let a = inst.arg_a();
1684 let total_concat = (top - 1 - (base + a)) as i32;
1685 let v = state.get_at(top);
1686 state.set_at(top - 2, v);
1687 state.set_top(top - 1);
1688 concat(state, total_concat)?;
1689 }
1690 OpCode::Close => {
1691 state.ci_step_pc_back(ci);
1692 }
1693 OpCode::Return => {
1697 let a = inst.arg_a();
1698 let ra = base + a;
1699 let nres = state.ci_nres(ci);
1700 state.set_top(ra + nres);
1701 state.ci_step_pc_back(ci);
1702 }
1703 other => {
1704 debug_assert!(
1705 matches!(
1706 other,
1707 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1708 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1709 ),
1710 "unexpected opcode in finish_op: {:?}",
1711 other
1712 );
1713 }
1714 }
1715 Ok(())
1716}
1717
1718pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1730 let mut trap: bool;
1731 let legacy_for = matches!(
1738 state.global().lua_version,
1739 lua_types::LuaVersion::V51 | lua_types::LuaVersion::V52 | lua_types::LuaVersion::V53
1740 );
1741
1742 'startfunc: loop {
1744 trap = state.hook_mask() != 0;
1745
1746 'returning: loop {
1749 let ci_slot = ci.as_usize();
1750 let func_idx = state.call_info[ci_slot].func;
1751 let cl = match state.stack.get(func_idx.0 as usize).map(|slot| slot.val) {
1752 Some(LuaValue::Function(lua_types::closure::LuaClosure::Lua(c))) => c,
1753 _ => {
1754 return Err(LuaError::runtime(format_args!(
1755 "internal: execute called on non-Lua frame"
1756 )));
1757 }
1758 };
1759 let code = &cl.proto.code;
1760 let constants = &cl.proto.k;
1761 let mut pc: u32 = state.call_info[ci_slot].saved_pc();
1763
1764 if trap {
1765 trap = state.trace_call(ci)?;
1766 }
1767 let mut base: StackIdx = state.call_info[ci.as_usize()].func + 1;
1768
1769 'dispatch: loop {
1771 if trap {
1772 trap = state.trace_exec(ci, pc)?;
1773 base = state.ci_base(ci); }
1775 let i: Instruction = code[pc as usize];
1776 pc += 1;
1777 let op = i.opcode();
1778 #[cfg(feature = "opcode-profile")]
1779 crate::opcode_profile::record(op);
1780
1781 debug_assert!(base == state.ci_base(ci));
1782
1783 #[cfg(debug_assertions)]
1787 {
1788 let op_mode = op_mode_byte(op);
1789 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1790 state.set_top(base);
1791 }
1792 }
1793
1794 match op {
1795 OpCode::Move => {
1797 let ra = base + i.arg_a();
1798 let rb = base + i.arg_b();
1799 let v = state.stack[rb.0 as usize].val;
1800 state.stack[ra.0 as usize].val = v;
1801 }
1802 OpCode::LoadI => {
1804 let ra = base + i.arg_a();
1805 let b = i.arg_s_bx() as i64;
1806 state.stack[ra.0 as usize].val = LuaValue::Int(b);
1807 }
1808 OpCode::LoadF => {
1810 let ra = base + i.arg_a();
1811 let b = i.arg_s_bx() as f64;
1812 state.stack[ra.0 as usize].val = LuaValue::Float(b);
1813 }
1814 OpCode::LoadK => {
1816 let ra = base + i.arg_a();
1817 let k_idx = i.arg_bx() as usize;
1818 state.stack[ra.0 as usize].val = constants[k_idx];
1819 }
1820 OpCode::LoadKX => {
1822 let ra = base + i.arg_a();
1823 let extra = code[pc as usize];
1824 pc += 1;
1825 let k_idx = extra.arg_ax() as usize;
1826 state.stack[ra.0 as usize].val = constants[k_idx];
1827 }
1828 OpCode::LoadFalse => {
1830 let ra = base + i.arg_a();
1831 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
1832 }
1833 OpCode::LFalseSkip => {
1835 let ra = base + i.arg_a();
1836 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
1837 pc += 1;
1838 }
1839 OpCode::LoadTrue => {
1841 let ra = base + i.arg_a();
1842 state.stack[ra.0 as usize].val = LuaValue::Bool(true);
1843 }
1844 OpCode::LoadNil => {
1846 let ra = base + i.arg_a();
1847 let b = i.arg_b();
1848 for k in 0..=b {
1849 state.stack[(ra + k).0 as usize].val = LuaValue::Nil;
1850 }
1851 }
1852 OpCode::GetUpVal => {
1854 let ra = base + i.arg_a();
1855 let b = i.arg_b() as usize;
1856 let uv = cl.upval(b);
1857 let v = match uv.try_open_payload() {
1858 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1859 state.stack[idx.0 as usize].val
1860 }
1861 Some(_) => state.upvalue_get(&cl, b),
1862 None => uv.closed_value(),
1863 };
1864 state.stack[ra.0 as usize].val = v;
1865 }
1866 OpCode::SetUpVal => {
1869 let ra = base + i.arg_a();
1870 let b = i.arg_b() as usize;
1871 let v = state.stack[ra.0 as usize].val;
1872 let uv = cl.upval(b);
1873 match uv.try_open_payload() {
1874 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1875 state.stack[idx.0 as usize].val = v;
1876 if v.is_collectable() {
1877 state.gc_barrier_upval(&uv, &v);
1878 }
1879 }
1880 None => {
1881 uv.set_closed_value(v);
1882 if v.is_collectable() {
1883 state.gc_barrier_upval(&uv, &v);
1884 }
1885 }
1886 _ => {
1887 state.upvalue_set(&cl, b, v)?;
1888 }
1889 }
1890 }
1891 OpCode::GetTabUp => {
1895 let ra = base + i.arg_a();
1896 let b = i.arg_b() as usize;
1897 let k_idx = i.arg_c() as usize;
1898 let upval = state.upvalue_get(&cl, b);
1899 let key = constants[k_idx];
1900 match state.fast_get_short_str(&upval, &key)? {
1901 Some(v) => state.set_at(ra, v),
1902 None => {
1903 state.set_ci_savedpc(ci, pc);
1904 state.set_top(state.ci_top(ci));
1905 finish_get(state, upval, key, ra, true, None)?;
1906 trap = state.ci_trap(ci);
1907 }
1908 }
1909 }
1910 OpCode::GetTable => {
1913 let ra = base + i.arg_a();
1914 let rb_idx = base + i.arg_b();
1915 let rb_v = state.get_at(rb_idx);
1916 let rc_v = state.get_at(base + i.arg_c());
1917 let fast_result = if let LuaValue::Int(n) = &rc_v {
1918 state.fast_get_int(&rb_v, *n)?
1919 } else {
1920 state.fast_get(&rb_v, &rc_v)?
1921 };
1922 match fast_result {
1923 Some(v) => state.set_at(ra, v),
1924 None => {
1925 state.set_ci_savedpc(ci, pc);
1926 state.set_top(state.ci_top(ci));
1927 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1928 trap = state.ci_trap(ci);
1929 }
1930 }
1931 }
1932 OpCode::GetI => {
1936 let ra = base + i.arg_a();
1937 let rb_idx = base + i.arg_b();
1938 let rb_v = state.get_at(rb_idx);
1939 let c = i.arg_c() as i64;
1940 match state.fast_get_int(&rb_v, c)? {
1941 Some(v) => state.set_at(ra, v),
1942 None => {
1943 let key = LuaValue::Int(c);
1944 state.set_ci_savedpc(ci, pc);
1945 state.set_top(state.ci_top(ci));
1946 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1947 trap = state.ci_trap(ci);
1948 }
1949 }
1950 }
1951 OpCode::GetField => {
1953 let ra = base + i.arg_a();
1954 let rb_idx = base + i.arg_b();
1955 let rb_v = state.get_at(rb_idx);
1956 let k_idx = i.arg_c() as usize;
1957 let key = constants[k_idx];
1958 match state.fast_get_short_str(&rb_v, &key)? {
1959 Some(v) => state.set_at(ra, v),
1960 None => {
1961 state.set_ci_savedpc(ci, pc);
1962 state.set_top(state.ci_top(ci));
1963 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1964 trap = state.ci_trap(ci);
1965 }
1966 }
1967 }
1968 OpCode::SetTabUp => {
1970 let a = i.arg_a() as usize;
1971 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1973 constants[i.arg_c() as usize]
1974 } else {
1975 state.get_at(base + i.arg_c())
1976 };
1977 let upval = state.upvalue_get(&cl, a);
1978 let key = constants[b_idx];
1979 match state.fast_get_short_str(&upval, &key)? {
1980 Some(_slot) => {
1981 state.table_raw_set(&upval, key, rc_v.clone())?;
1982 state.gc_value_barrier_back(&upval, &rc_v);
1983 }
1984 None => {
1985 state.set_ci_savedpc(ci, pc);
1986 state.set_top(state.ci_top(ci));
1987 let upval_name: Vec<u8> = cl
1988 .proto
1989 .upvalues
1990 .get(a)
1991 .and_then(|uv| uv.name.as_ref())
1992 .map(|s| s.as_bytes().to_vec())
1993 .unwrap_or_else(|| b"?".to_vec());
1994 let hint: Option<(&[u8], &[u8])> =
1995 Some((b"upvalue", &upval_name));
1996 finish_set(state, upval, key, rc_v, false, None, hint)?;
1997 trap = state.ci_trap(ci);
1998 }
1999 }
2000 }
2001 OpCode::SetTable => {
2003 let ra_idx = base + i.arg_a();
2004 let ra_v = state.get_at(ra_idx);
2005 let rb_v = state.get_at(base + i.arg_b());
2006 let rc_v = if i.test_k() {
2007 constants[i.arg_c() as usize]
2008 } else {
2009 state.get_at(base + i.arg_c())
2010 };
2011 if let LuaValue::Table(tbl) = ra_v {
2012 if tbl.metatable().is_none() {
2013 state.gc_table_barrier_back(&tbl, &rc_v);
2014 tbl.raw_set(state, rb_v, rc_v)?;
2015 } else {
2016 let fast = if let LuaValue::Int(n) = &rb_v {
2017 state.fast_get_int(&ra_v, *n)?
2018 } else {
2019 state.fast_get(&ra_v, &rb_v)?
2020 };
2021 if fast.is_some() {
2022 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
2023 state.gc_value_barrier_back(&ra_v, &rc_v);
2024 } else {
2025 state.set_ci_savedpc(ci, pc);
2026 state.set_top(state.ci_top(ci));
2027 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2028 trap = state.ci_trap(ci);
2029 }
2030 }
2031 } else {
2032 state.set_ci_savedpc(ci, pc);
2033 state.set_top(state.ci_top(ci));
2034 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
2035 trap = state.ci_trap(ci);
2036 }
2037 }
2038 OpCode::SetI => {
2040 let ra_idx = base + i.arg_a();
2041 let ra_v = state.get_at(ra_idx);
2042 let c = i.arg_b() as i64;
2043 let rc_v = if i.test_k() {
2044 constants[i.arg_c() as usize]
2045 } else {
2046 state.get_at(base + i.arg_c())
2047 };
2048 if let LuaValue::Table(tbl) = ra_v {
2049 if tbl.metatable().is_none() {
2050 state.gc_table_barrier_back(&tbl, &rc_v);
2051 tbl.raw_set_int(state, c, rc_v)?;
2052 } else {
2053 let fast = state.fast_get_int(&ra_v, c)?;
2054 if fast.is_some() {
2055 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
2056 state.gc_value_barrier_back(&ra_v, &rc_v);
2057 } else {
2058 state.set_ci_savedpc(ci, pc);
2059 state.set_top(state.ci_top(ci));
2060 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
2061 trap = state.ci_trap(ci);
2062 }
2063 }
2064 } else {
2065 state.set_ci_savedpc(ci, pc);
2066 state.set_top(state.ci_top(ci));
2067 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
2068 trap = state.ci_trap(ci);
2069 }
2070 }
2071 OpCode::SetField => {
2073 let ra_idx = base + i.arg_a();
2074 let ra_v = state.get_at(ra_idx);
2075 let b_idx = i.arg_b() as usize;
2076 let key = constants[b_idx];
2077 let rc_v = if i.test_k() {
2078 constants[i.arg_c() as usize]
2079 } else {
2080 state.get_at(base + i.arg_c())
2081 };
2082 if let LuaValue::Table(tbl) = ra_v {
2083 if tbl.metatable().is_none() {
2084 state.gc_table_barrier_back(&tbl, &rc_v);
2085 tbl.raw_set(state, key, rc_v)?;
2086 } else {
2087 match state.fast_get_short_str(&ra_v, &key)? {
2088 Some(_) => {
2089 state.table_raw_set(&ra_v, key, rc_v.clone())?;
2090 state.gc_value_barrier_back(&ra_v, &rc_v);
2091 }
2092 None => {
2093 state.set_ci_savedpc(ci, pc);
2094 state.set_top(state.ci_top(ci));
2095 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2096 trap = state.ci_trap(ci);
2097 }
2098 }
2099 }
2100 } else {
2101 state.set_ci_savedpc(ci, pc);
2102 state.set_top(state.ci_top(ci));
2103 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2104 trap = state.ci_trap(ci);
2105 }
2106 }
2107 OpCode::NewTable => {
2110 let ra = base + i.arg_a();
2111 let mut b = i.arg_b();
2112 let mut c = i.arg_c();
2113 if b > 0 {
2114 b = 1 << (b - 1);
2115 }
2116 if i.test_k() {
2117 let extra = code[pc as usize];
2118 pc += 1;
2119 const MAXARG_C: i32 = (1 << 8) - 1;
2120 c += extra.arg_ax() * (MAXARG_C + 1);
2121 } else {
2122 pc += 1; }
2124 state.set_top(ra + 1);
2125 let t = if b != 0 || c != 0 {
2126 state.new_table_with_sizes(c as u32, b as u32)?
2127 } else {
2128 state.new_table()
2129 };
2130 state.set_at(ra, LuaValue::Table(t.clone()));
2131 state.set_ci_savedpc(ci, pc);
2132 state.set_top(ra + 1);
2133 state.gc_cond_step();
2134 if state.hookmask != 0 {
2135 trap = state.ci_trap(ci);
2136 }
2137 }
2138 OpCode::Self_ => {
2140 let ra = base + i.arg_a();
2141 let rb_idx = base + i.arg_b();
2142 let rb_v = state.get_at(rb_idx);
2143 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2145 constants[k_idx]
2146 } else {
2147 state.get_at(base + i.arg_c())
2148 };
2149 state.set_at(ra + 1, rb_v.clone());
2150 match state.fast_get_short_str(&rb_v, &key)? {
2151 Some(v) => state.set_at(ra, v),
2152 None => {
2153 state.set_ci_savedpc(ci, pc);
2154 state.set_top(state.ci_top(ci));
2155 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
2156 trap = state.ci_trap(ci);
2157 }
2158 }
2159 }
2160 OpCode::AddI => {
2162 let ra = base + i.arg_a();
2163 let rb = base + i.arg_b();
2164 let imm = i.arg_s_c() as i64;
2165 let rb_v = state.stack[rb.0 as usize].val;
2166 match rb_v {
2167 LuaValue::Int(iv1) => {
2168 pc += 1;
2169 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2170 }
2171 LuaValue::Float(nb) => {
2172 pc += 1;
2173 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2174 }
2175 _ => {}
2176 }
2177 }
2178 OpCode::AddK => {
2180 let ra = base + i.arg_a();
2181 let rb = base + i.arg_b();
2182 let kidx = i.arg_c() as usize;
2183 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2184 pc += 1;
2185 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2186 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2187 pc += 1;
2188 state.set_at(ra, LuaValue::Float(n1 + n2));
2189 }
2190 }
2191 OpCode::SubK => {
2192 let ra = base + i.arg_a();
2193 let rb = base + i.arg_b();
2194 let kidx = i.arg_c() as usize;
2195 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2196 pc += 1;
2197 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2198 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2199 pc += 1;
2200 state.set_at(ra, LuaValue::Float(n1 - n2));
2201 }
2202 }
2203 OpCode::MulK => {
2204 let ra = base + i.arg_a();
2205 let rb = base + i.arg_b();
2206 let kidx = i.arg_c() as usize;
2207 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2208 pc += 1;
2209 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2210 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2211 pc += 1;
2212 state.set_at(ra, LuaValue::Float(n1 * n2));
2213 }
2214 }
2215 OpCode::ModK => {
2216 let ra = base + i.arg_a();
2217 let v1 = state.get_at(base + i.arg_b());
2218 let v2 = constants[i.arg_c() as usize];
2219 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
2221 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2222 |a, b| imod(a, b), fmodf)?;
2223 }
2224 OpCode::PowK => {
2225 let ra = base + i.arg_a();
2226 let rb = base + i.arg_b();
2227 let kidx = i.arg_c() as usize;
2228 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2229 pc += 1;
2230 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2231 state.set_at(ra, LuaValue::Float(r));
2232 }
2233 }
2234 OpCode::DivK => {
2235 let ra = base + i.arg_a();
2236 let rb = base + i.arg_b();
2237 let kidx = i.arg_c() as usize;
2238 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2239 pc += 1;
2240 state.set_at(ra, LuaValue::Float(n1 / n2));
2241 }
2242 }
2243 OpCode::IDivK => {
2244 let ra = base + i.arg_a();
2245 let v1 = state.get_at(base + i.arg_b());
2246 let v2 = constants[i.arg_c() as usize];
2247 state.set_ci_savedpc(ci, pc);
2248 state.set_top(state.ci_top(ci));
2249 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2250 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2251 }
2252 OpCode::BAndK => {
2253 let ra = base + i.arg_a();
2254 let v1 = state.get_at(base + i.arg_b());
2255 let v2 = constants[i.arg_c() as usize];
2256 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2257 }
2258 OpCode::BOrK => {
2259 let ra = base + i.arg_a();
2260 let v1 = state.get_at(base + i.arg_b());
2261 let v2 = constants[i.arg_c() as usize];
2262 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2263 }
2264 OpCode::BXOrK => {
2265 let ra = base + i.arg_a();
2266 let v1 = state.get_at(base + i.arg_b());
2267 let v2 = constants[i.arg_c() as usize];
2268 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2269 }
2270 OpCode::ShrI => {
2271 let ra = base + i.arg_a();
2272 let v = state.get_at(base + i.arg_b());
2273 let ic = i.arg_s_c() as i64;
2274 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2275 pc += 1;
2276 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2277 }
2278 }
2279 OpCode::ShlI => {
2280 let ra = base + i.arg_a();
2281 let v = state.get_at(base + i.arg_b());
2282 let ic = i.arg_s_c() as i64;
2283 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2284 pc += 1;
2285 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2286 }
2287 }
2288 OpCode::Add => {
2290 let ra = base + i.arg_a();
2291 let rb = base + i.arg_b();
2292 let rc = base + i.arg_c();
2293 let ra_u = ra.0 as usize;
2294 let rb_v = state.stack[rb.0 as usize].val;
2295 let rc_v = state.stack[rc.0 as usize].val;
2296 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2297 pc += 1;
2298 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2299 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2300 pc += 1;
2301 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2302 }
2303 }
2304 OpCode::Sub => {
2305 let ra = base + i.arg_a();
2306 let rb = base + i.arg_b();
2307 let rc = base + i.arg_c();
2308 let ra_u = ra.0 as usize;
2309 let rb_v = state.stack[rb.0 as usize].val;
2310 let rc_v = state.stack[rc.0 as usize].val;
2311 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2312 pc += 1;
2313 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2314 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2315 pc += 1;
2316 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2317 }
2318 }
2319 OpCode::Mul => {
2320 let ra = base + i.arg_a();
2321 let rb = base + i.arg_b();
2322 let rc = base + i.arg_c();
2323 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2324 pc += 1;
2325 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2326 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2327 pc += 1;
2328 state.set_at(ra, LuaValue::Float(n1 * n2));
2329 }
2330 }
2331 OpCode::Mod => {
2332 let ra = base + i.arg_a();
2333 let v1 = state.get_at(base + i.arg_b());
2334 let v2 = state.get_at(base + i.arg_c());
2335 state.set_ci_savedpc(ci, pc);
2336 state.set_top(state.ci_top(ci));
2337 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2338 |a, b| imod(a, b), fmodf)?;
2339 }
2340 OpCode::Pow => {
2341 let ra = base + i.arg_a();
2342 let rb = base + i.arg_b();
2343 let rc = base + i.arg_c();
2344 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2345 pc += 1;
2346 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2347 state.set_at(ra, LuaValue::Float(r));
2348 }
2349 }
2350 OpCode::Div => {
2351 let ra = base + i.arg_a();
2352 let rb = base + i.arg_b();
2353 let rc = base + i.arg_c();
2354 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2355 pc += 1;
2356 state.set_at(ra, LuaValue::Float(n1 / n2));
2357 }
2358 }
2359 OpCode::IDiv => {
2360 let ra = base + i.arg_a();
2361 let v1 = state.get_at(base + i.arg_b());
2362 let v2 = state.get_at(base + i.arg_c());
2363 state.set_ci_savedpc(ci, pc);
2364 state.set_top(state.ci_top(ci));
2365 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2366 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2367 }
2368 OpCode::BAnd => {
2371 let ra = base + i.arg_a();
2372 let v1 = state.get_at(base + i.arg_b());
2373 let v2 = state.get_at(base + i.arg_c());
2374 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2375 }
2376 OpCode::BOr => {
2377 let ra = base + i.arg_a();
2378 let v1 = state.get_at(base + i.arg_b());
2379 let v2 = state.get_at(base + i.arg_c());
2380 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2381 }
2382 OpCode::BXOr => {
2383 let ra = base + i.arg_a();
2384 let v1 = state.get_at(base + i.arg_b());
2385 let v2 = state.get_at(base + i.arg_c());
2386 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2387 }
2388 OpCode::Shr => {
2389 let ra = base + i.arg_a();
2390 let v1 = state.get_at(base + i.arg_b());
2391 let v2 = state.get_at(base + i.arg_c());
2392 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2393 }
2394 OpCode::Shl => {
2395 let ra = base + i.arg_a();
2396 let v1 = state.get_at(base + i.arg_b());
2397 let v2 = state.get_at(base + i.arg_c());
2398 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2399 }
2400 OpCode::MmBin => {
2405 let ra_idx = base + i.arg_a();
2406 let rb_idx = base + i.arg_b();
2407 let ra_v = state.get_at(ra_idx);
2408 let rb_v = state.get_at(rb_idx);
2409 let tm = tagmethod_from_index(i.arg_c() as usize);
2410 let prev_inst = code[(pc - 2) as usize];
2411 let result_idx = base + prev_inst.arg_a();
2412 state.set_ci_savedpc(ci, pc);
2413 state.set_top(state.ci_top(ci));
2414 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2415 trap = state.ci_trap(ci);
2416 }
2417 OpCode::MmBinI => {
2418 let ra_idx = base + i.arg_a();
2419 let ra_v = state.get_at(ra_idx);
2420 let imm = i.arg_s_b() as i64;
2421 let tm = tagmethod_from_index(i.arg_c() as usize);
2422 let flip = i.arg_k() != 0;
2423 let prev_inst = code[(pc - 2) as usize];
2424 let result_idx = base + prev_inst.arg_a();
2425 state.set_ci_savedpc(ci, pc);
2426 state.set_top(state.ci_top(ci));
2427 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2428 trap = state.ci_trap(ci);
2429 }
2430 OpCode::MmBinK => {
2431 let ra_idx = base + i.arg_a();
2432 let ra_v = state.get_at(ra_idx);
2433 let imm = constants[i.arg_b() as usize];
2434 let tm = tagmethod_from_index(i.arg_c() as usize);
2435 let flip = i.arg_k() != 0;
2436 let prev_inst = code[(pc - 2) as usize];
2437 let result_idx = base + prev_inst.arg_a();
2438 state.set_ci_savedpc(ci, pc);
2439 state.set_top(state.ci_top(ci));
2440 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2441 trap = state.ci_trap(ci);
2442 }
2443 OpCode::Unm => {
2447 let ra = base + i.arg_a();
2448 let rb_idx = base + i.arg_b();
2449 let rb_v = state.get_at(rb_idx);
2450 match &rb_v {
2451 LuaValue::Int(ib) => {
2452 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2453 }
2454 LuaValue::Float(nb) => {
2455 state.set_at(ra, LuaValue::Float(-nb));
2456 }
2457 _ => {
2458 state.set_ci_savedpc(ci, pc);
2459 state.set_top(state.ci_top(ci));
2460 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2461 trap = state.ci_trap(ci);
2462 }
2463 }
2464 }
2465 OpCode::BNot => {
2467 let ra = base + i.arg_a();
2468 let rb_idx = base + i.arg_b();
2469 let rb_v = state.get_at(rb_idx);
2470 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2471 state.set_at(ra, LuaValue::Int(!ib));
2472 } else {
2473 state.set_ci_savedpc(ci, pc);
2474 state.set_top(state.ci_top(ci));
2475 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2476 trap = state.ci_trap(ci);
2477 }
2478 }
2479 OpCode::Not => {
2481 let ra = base + i.arg_a();
2482 let rb_v = state.get_at(base + i.arg_b());
2483 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2484 state.set_at(ra, LuaValue::Bool(falsy));
2485 }
2486 OpCode::Len => {
2488 let ra = base + i.arg_a();
2489 let rb_idx = base + i.arg_b();
2490 let rb_v = state.get_at(rb_idx);
2491 state.set_ci_savedpc(ci, pc);
2492 state.set_top(state.ci_top(ci));
2493 obj_len(state, ra, rb_v, rb_idx)?;
2494 trap = state.ci_trap(ci);
2495 }
2496 OpCode::Concat => {
2498 let ra = base + i.arg_a();
2499 let n = i.arg_b() as i32;
2500 state.set_top(ra + n as i32);
2501 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2503 let top = state.top_idx();
2504 state.set_ci_savedpc(ci, pc);
2505 state.set_top(top);
2506 state.gc_cond_step();
2507 trap = state.ci_trap(ci);
2508 }
2509 OpCode::Close => {
2511 let ra = base + i.arg_a();
2512 state.set_ci_savedpc(ci, pc);
2513 state.set_top(state.ci_top(ci));
2514 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2515 trap = state.ci_trap(ci);
2516 }
2517 OpCode::Tbc => {
2519 let ra = base + i.arg_a();
2520 state.set_ci_savedpc(ci, pc);
2521 state.set_top(state.ci_top(ci));
2522 state.new_tbc_upval(ra)?;
2523 }
2524 OpCode::Jmp => {
2526 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2527 trap = state.ci_trap(ci);
2528 }
2529 OpCode::Eq => {
2531 let ra_v = state.get_at(base + i.arg_a());
2532 let rb_v = state.get_at(base + i.arg_b());
2533 state.set_ci_savedpc(ci, pc);
2534 state.set_top(state.ci_top(ci));
2535 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2536 trap = state.ci_trap(ci);
2537 if (cond as i32) != i.arg_k() {
2538 pc += 1;
2539 } else {
2540 let next = code[pc as usize];
2541 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2542 trap = state.ci_trap(ci);
2543 }
2544 }
2545 OpCode::Lt => {
2547 let ra_v = state.get_at(base + i.arg_a());
2548 let rb_v = state.get_at(base + i.arg_b());
2549 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2550 *ia < *ib
2551 } else if matches!((&ra_v, &rb_v),
2552 (LuaValue::Int(_) | LuaValue::Float(_),
2553 LuaValue::Int(_) | LuaValue::Float(_))) {
2554 lt_num(&ra_v, &rb_v)
2555 } else {
2556 state.set_ci_savedpc(ci, pc);
2557 state.set_top(state.ci_top(ci));
2558 let r = less_than_others(state, &ra_v, &rb_v)?;
2559 trap = state.ci_trap(ci);
2560 r
2561 };
2562 if (cond as i32) != i.arg_k() {
2563 pc += 1;
2564 } else {
2565 let next = code[pc as usize];
2566 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2567 trap = state.ci_trap(ci);
2568 }
2569 }
2570 OpCode::Le => {
2572 let ra_v = state.get_at(base + i.arg_a());
2573 let rb_v = state.get_at(base + i.arg_b());
2574 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2575 *ia <= *ib
2576 } else if matches!((&ra_v, &rb_v),
2577 (LuaValue::Int(_) | LuaValue::Float(_),
2578 LuaValue::Int(_) | LuaValue::Float(_))) {
2579 le_num(&ra_v, &rb_v)
2580 } else {
2581 state.set_ci_savedpc(ci, pc);
2582 state.set_top(state.ci_top(ci));
2583 let r = less_equal_others(state, &ra_v, &rb_v)?;
2584 trap = state.ci_trap(ci);
2585 r
2586 };
2587 if (cond as i32) != i.arg_k() {
2588 pc += 1;
2589 } else {
2590 let next = code[pc as usize];
2591 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2592 trap = state.ci_trap(ci);
2593 }
2594 }
2595 OpCode::EqK => {
2597 let ra_v = state.get_at(base + i.arg_a());
2598 let rb_v = constants[i.arg_b() as usize];
2599 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2600 if (cond as i32) != i.arg_k() {
2601 pc += 1;
2602 } else {
2603 let next = code[pc as usize];
2604 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2605 trap = state.ci_trap(ci);
2606 }
2607 }
2608 OpCode::EqI => {
2613 let ra_v = state.get_at(base + i.arg_a());
2614 let im = i.arg_s_b() as i64;
2615 let cond: bool = match &ra_v {
2616 LuaValue::Int(iv) => *iv == im,
2617 LuaValue::Float(fv) => *fv == im as f64,
2618 _ => false,
2619 };
2620 if (cond as i32) != i.arg_k() {
2621 pc += 1;
2622 } else {
2623 let next = code[pc as usize];
2624 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2625 trap = state.ci_trap(ci);
2626 }
2627 }
2628 OpCode::LtI => {
2631 let ra = base + i.arg_a();
2632 let im = i.arg_s_b() as i64;
2633 let fast_cond = match &state.stack[ra.0 as usize].val {
2634 LuaValue::Int(ia) => Some(*ia < im),
2635 LuaValue::Float(fa) => Some(*fa < im as f64),
2636 _ => None,
2637 };
2638 let cond = match fast_cond {
2639 Some(cond) => cond,
2640 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2641 };
2642 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2643 }
2644 OpCode::LeI => {
2645 let ra = base + i.arg_a();
2646 let im = i.arg_s_b() as i64;
2647 let fast_cond = match &state.stack[ra.0 as usize].val {
2648 LuaValue::Int(ia) => Some(*ia <= im),
2649 LuaValue::Float(fa) => Some(*fa <= im as f64),
2650 _ => None,
2651 };
2652 let cond = match fast_cond {
2653 Some(cond) => cond,
2654 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2655 };
2656 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2657 }
2658 OpCode::GtI => {
2659 let ra = base + i.arg_a();
2660 let im = i.arg_s_b() as i64;
2661 let fast_cond = match &state.stack[ra.0 as usize].val {
2662 LuaValue::Int(ia) => Some(*ia > im),
2663 LuaValue::Float(fa) => Some(*fa > im as f64),
2664 _ => None,
2665 };
2666 let cond = match fast_cond {
2667 Some(cond) => cond,
2668 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2669 };
2670 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2671 }
2672 OpCode::GeI => {
2673 let ra = base + i.arg_a();
2674 let im = i.arg_s_b() as i64;
2675 let fast_cond = match &state.stack[ra.0 as usize].val {
2676 LuaValue::Int(ia) => Some(*ia >= im),
2677 LuaValue::Float(fa) => Some(*fa >= im as f64),
2678 _ => None,
2679 };
2680 let cond = match fast_cond {
2681 Some(cond) => cond,
2682 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2683 };
2684 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2685 }
2686 OpCode::Test => {
2688 let ra_v = state.get_at(base + i.arg_a());
2689 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2690 if (cond as i32) != i.arg_k() {
2691 pc += 1;
2692 } else {
2693 let next = code[pc as usize];
2694 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2695 trap = state.ci_trap(ci);
2696 }
2697 }
2698 OpCode::TestSet => {
2701 let ra = base + i.arg_a();
2702 let rb_v = state.get_at(base + i.arg_b());
2703 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2704 if (falsy as i32) == i.arg_k() {
2705 pc += 1;
2706 } else {
2707 state.set_at(ra, rb_v);
2708 let next = code[pc as usize];
2709 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2710 trap = state.ci_trap(ci);
2711 }
2712 }
2713 OpCode::Call => {
2717 let ra = base + i.arg_a();
2718 let b = i.arg_b();
2719 let nresults = i.arg_c() as i32 - 1;
2720 if b != 0 {
2721 state.set_top(ra + b);
2722 }
2723 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2725 match state.precall(ra, nresults)? {
2726 None => {
2727 if had_hook || state.hookmask != 0 {
2731 trap = state.ci_trap(ci); }
2733 }
2734 Some(new_ci) => {
2735 ci = new_ci;
2737 continue 'startfunc;
2738 }
2739 }
2740 }
2741 OpCode::TailCall => {
2746 let ra = base + i.arg_a();
2747 let b = i.arg_b();
2748 let nparams1 = i.arg_c();
2749 let delta = if nparams1 != 0 {
2750 state.ci_nextraargs(ci) + nparams1 as i32
2751 } else {
2752 0
2753 };
2754 let top_b: i32 = if b != 0 {
2755 state.set_top(ra + b);
2756 b
2757 } else {
2758 state.top_idx() - ra
2759 };
2760 state.set_ci_savedpc(ci, pc);
2761 if i.test_k() {
2762 state.close_upvals_from_base(ci)?;
2763 }
2764 let n = state.pretailcall(ci, ra, top_b, delta)?;
2765 if n < 0 {
2766 continue 'startfunc;
2768 } else {
2769 state.ci_adjust_func(ci, delta);
2771 state.poscall(ci, n as u32)?;
2772 if state.hookmask != 0 {
2773 trap = state.ci_trap(ci);
2774 }
2775 break 'dispatch; }
2777 }
2778 OpCode::Return => {
2783 let ra = base + i.arg_a();
2784 let n_raw = i.arg_b() as i32 - 1;
2785 let nparams1 = i.arg_c();
2786 let n: u32 = if n_raw < 0 {
2787 (state.top_idx() - ra) as u32
2788 } else {
2789 n_raw as u32
2790 };
2791 state.set_ci_savedpc(ci, pc);
2792 if i.test_k() {
2793 state.ci_nres_set(ci, n as i32);
2794 let ci_top = state.ci_top(ci);
2795 if state.top_idx().0 < ci_top.0 {
2796 state.set_top(ci_top);
2797 }
2798 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2799 if state.hookmask != 0 {
2800 trap = state.ci_trap(ci);
2801 }
2802 base = state.ci_base(ci); }
2804 if nparams1 != 0 {
2805 let nextraargs = state.ci_nextraargs(ci) as u32;
2806 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2807 }
2808 state.set_top(ra + n as i32);
2809 state.poscall(ci, n)?;
2810 if state.hookmask != 0 {
2811 trap = state.ci_trap(ci);
2812 }
2813 break 'dispatch; }
2815 OpCode::Return0 => {
2821 if state.hookmask == 0 {
2822 let ci_slot = ci.as_usize();
2823 let nres = state.call_info[ci_slot].nresults as i32;
2824 state.ci = state.call_info[ci_slot]
2825 .previous
2826 .expect("RETURN0: returning frame has no previous CallInfo");
2827 state.top = base - 1;
2828 for _ in 0..nres.max(0) {
2829 state.push(LuaValue::Nil);
2830 }
2831 } else {
2832 return0_hook(state, ci, base, i, pc, &mut trap)?;
2833 }
2834 break 'dispatch; }
2836 OpCode::Return1 => {
2840 if state.hookmask == 0 {
2841 let ci_slot = ci.as_usize();
2842 let nres = state.call_info[ci_slot].nresults as i32;
2843 state.ci = state.call_info[ci_slot]
2844 .previous
2845 .expect("RETURN1: returning frame has no previous CallInfo");
2846 if nres == 0 {
2847 state.top = base - 1;
2848 } else {
2849 let ra = base + i.arg_a();
2850 state.stack[(base - 1).0 as usize].val =
2851 state.stack[ra.0 as usize].val; state.top = base;
2853 for _ in 1..nres.max(0) {
2854 state.push(LuaValue::Nil);
2855 }
2856 }
2857 } else {
2858 return1_hook(state, ci, base, i, pc, &mut trap)?;
2859 }
2860 break 'dispatch; }
2862 OpCode::ForLoop => {
2866 let ra = base + i.arg_a();
2867 if legacy_for {
2868 if forloop_legacy(state, ra) {
2869 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2870 }
2871 trap = state.ci_trap(ci);
2872 } else {
2873 let ra_u = ra.0 as usize;
2874 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2875 let count = match state.stack[ra_u + 1].val {
2876 LuaValue::Int(c) => c as u64,
2877 _ => 0,
2878 };
2879 if count > 0 {
2880 let idx = match state.stack[ra_u].val {
2881 LuaValue::Int(x) => x,
2882 _ => 0,
2883 };
2884 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2885 let new_idx = intop_add(idx, step);
2886 state.stack[ra_u].val = LuaValue::Int(new_idx);
2887 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2888 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2889 }
2890 } else if float_for_loop(state, ra) {
2891 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2892 }
2893 trap = state.ci_trap(ci);
2894 }
2895 }
2896 OpCode::ForPrep => {
2898 let ra = base + i.arg_a();
2899 state.set_ci_savedpc(ci, pc);
2900 state.set_top(state.ci_top(ci));
2901 if legacy_for {
2902 forprep_legacy(state, ra)?;
2905 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2906 } else if forprep(state, ra)? {
2907 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2908 }
2909 }
2910 OpCode::TForPrep => {
2914 let ra = base + i.arg_a();
2915 state.set_ci_savedpc(ci, pc);
2916 state.set_top(state.ci_top(ci));
2917 state.new_tbc_upval(ra + 3)?;
2918 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2919 let tfc_i = code[pc as usize];
2920 pc += 1;
2921 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2922 let tfc_ra = base + tfc_i.arg_a();
2924 for k in 0..3u32 {
2925 let v = state.get_at(tfc_ra + k as i32);
2926 state.set_at(tfc_ra + 4 + k as i32, v);
2927 }
2928 state.set_top(tfc_ra + 4 + 3);
2929 state.set_ci_savedpc(ci, pc);
2930 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2931 trap = state.ci_trap(ci);
2932 base = state.ci_base(ci); let tfl_i = code[pc as usize];
2934 pc += 1;
2935 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2936 let tfl_ra = base + tfl_i.arg_a();
2937 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2939 let v = state.get_at(tfl_ra + 4);
2940 state.set_at(tfl_ra + 2, v);
2941 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2942 }
2943 }
2944 OpCode::TForCall => {
2946 let ra = base + i.arg_a();
2947 for k in 0..3u32 {
2948 let v = state.get_at(ra + k as i32);
2949 state.set_at(ra + 4 + k as i32, v);
2950 }
2951 state.set_top(ra + 4 + 3);
2952 state.set_ci_savedpc(ci, pc);
2953 state.call_at(ra + 4, i.arg_c() as i32)?;
2954 trap = state.ci_trap(ci);
2955 base = state.ci_base(ci); let tfl_i = code[pc as usize];
2957 pc += 1;
2958 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2959 let tfl_ra = base + tfl_i.arg_a();
2960 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2961 let v = state.get_at(tfl_ra + 4);
2962 state.set_at(tfl_ra + 2, v);
2963 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2964 }
2965 }
2966 OpCode::TForLoop => {
2968 let ra = base + i.arg_a();
2969 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2970 let v = state.get_at(ra + 4);
2971 state.set_at(ra + 2, v);
2972 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2973 }
2974 }
2975 OpCode::SetList => {
2979 let ra = base + i.arg_a();
2980 let n_raw = i.arg_b();
2981 let mut last = i.arg_c();
2982 let t_val = state.get_at(ra);
2983 let n: i32 = if n_raw == 0 {
2984 state.top_idx() - ra - 1
2985 } else {
2986 state.set_top(state.ci_top(ci));
2987 n_raw
2988 };
2989 last += n;
2990 if i.test_k() {
2991 let extra = code[pc as usize];
2992 pc += 1;
2993 const MAXARG_C: i32 = (1 << 8) - 1;
2994 last += extra.arg_ax() * (MAXARG_C + 1);
2995 }
2996 state.table_ensure_array(&t_val, last as usize)?;
2997 for k in (1..=n).rev() {
2998 let val = state.get_at(ra + k as i32);
2999 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
3000 last -= 1;
3001 state.gc_value_barrier_back(&t_val, &val);
3002 }
3003 }
3004 OpCode::Closure => {
3008 let ra = base + i.arg_a();
3009 let proto_idx = i.arg_bx() as usize;
3010 state.set_ci_savedpc(ci, pc);
3011 state.set_top(state.ci_top(ci));
3012 push_closure(state, proto_idx, ci, base, ra)?;
3013 state.set_ci_savedpc(ci, pc);
3015 state.set_top(ra + 1);
3016 state.gc_cond_step();
3017 trap = state.ci_trap(ci);
3018 }
3019 OpCode::VarArg => {
3021 let ra = base + i.arg_a();
3022 let n = i.arg_c() as i32 - 1;
3023 state.set_ci_savedpc(ci, pc);
3024 state.set_top(state.ci_top(ci));
3025 state.get_varargs(ci, ra, n)?;
3026 trap = state.ci_trap(ci);
3027 }
3028 OpCode::VarArgPrep => {
3032 let nparams = i.arg_a();
3033 state.set_ci_savedpc(ci, pc);
3034 state.adjust_varargs(ci, nparams, &cl)?;
3035 trap = state.ci_trap(ci);
3036 if trap {
3037 state.hook_call(ci)?;
3038 state.set_oldpc(1);
3039 }
3040 base = state.ci_base(ci);
3041 }
3042 OpCode::ExtraArg => {
3044 debug_assert!(false, "OP_EXTRAARG executed directly");
3045 }
3046 OpCode::ErrNNil => {
3051 let ra = base + i.arg_a();
3052 if !matches!(state.get_at(ra), LuaValue::Nil) {
3053 let bx = i.arg_bx();
3054 let name: Vec<u8> = if bx == 0 {
3055 b"?".to_vec()
3056 } else {
3057 match constants[(bx - 1) as usize] {
3058 LuaValue::Str(s) => s.as_bytes().to_vec(),
3059 _ => b"?".to_vec(),
3060 }
3061 };
3062 let mut msg = Vec::with_capacity(name.len() + 24);
3063 msg.extend_from_slice(b"global '");
3064 msg.extend_from_slice(&name);
3065 msg.extend_from_slice(b"' already defined");
3066 state.set_ci_savedpc(ci, pc);
3067 return Err(crate::debug::prefixed_runtime_pub(state, msg));
3068 }
3069 }
3070 OpCode::VarArgPack => {
3078 let ra = base + i.arg_a();
3079 let nextra = state.ci_nextraargs(ci);
3080 let ci_func: StackIdx = state.ci_base(ci) - 1;
3081 let t = if nextra > 0 {
3082 state.new_table_with_sizes(nextra as u32, 1)?
3083 } else {
3084 state.new_table()
3085 };
3086 for k in 0..nextra {
3087 let src: StackIdx = ci_func - nextra as i32 + k as i32;
3088 let val = state.get_at(src);
3089 t.raw_set_int(state, (k + 1) as i64, val)?;
3090 }
3091 let n_key = state.intern_str(b"n")?;
3092 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
3093 state.set_at(ra, LuaValue::Table(t));
3094 state.set_ci_savedpc(ci, pc);
3095 state.gc_cond_step();
3096 if state.hookmask != 0 {
3097 trap = state.ci_trap(ci);
3098 }
3099 }
3100 } } if state.ci_is_fresh(ci) {
3105 return Ok(());
3106 } else {
3107 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
3108 continue 'returning;
3109 }
3110 } } }
3113
3114#[inline(always)]
3117fn number_value(v: LuaValue) -> Option<f64> {
3118 match v {
3119 LuaValue::Float(f) => Some(f),
3120 LuaValue::Int(i) => Some(i as f64),
3121 _ => None,
3122 }
3123}
3124
3125#[allow(dead_code)]
3127#[inline]
3128fn arith_op_aux_rr(
3129 state: &mut LuaState,
3130 ra: StackIdx,
3131 v1: &LuaValue,
3132 v2: &LuaValue,
3133 pc: &mut u32,
3134 iop: fn(i64, i64) -> i64,
3135 fop: fn(f64, f64) -> f64,
3136) {
3137 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3138 *pc += 1;
3139 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3140 } else {
3141 arith_float_aux(state, ra, v1, v2, pc, fop);
3142 }
3143}
3144
3145#[allow(dead_code)]
3146#[inline]
3147fn arith_float_aux(
3148 state: &mut LuaState,
3149 ra: StackIdx,
3150 v1: &LuaValue,
3151 v2: &LuaValue,
3152 pc: &mut u32,
3153 fop: fn(f64, f64) -> f64,
3154) {
3155 let n1 = match v1 {
3156 LuaValue::Float(f) => Some(*f),
3157 LuaValue::Int(i) => Some(*i as f64),
3158 _ => None,
3159 };
3160 let n2 = match v2 {
3161 LuaValue::Float(f) => Some(*f),
3162 LuaValue::Int(i) => Some(*i as f64),
3163 _ => None,
3164 };
3165 if let (Some(n1), Some(n2)) = (n1, n2) {
3166 *pc += 1;
3167 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3168 }
3169}
3170
3171#[allow(dead_code)]
3172#[inline]
3173fn arith_op_checked(
3174 state: &mut LuaState,
3175 ra: StackIdx,
3176 v1: &LuaValue,
3177 v2: &LuaValue,
3178 pc: &mut u32,
3179 iop: fn(i64, i64) -> Result<i64, LuaError>,
3180 fop: fn(f64, f64) -> f64,
3181) -> Result<(), LuaError> {
3182 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3183 *pc += 1;
3184 let result = iop(*i1, *i2).map_err(|e| match e {
3185 LuaError::Runtime(LuaValue::Str(s)) => {
3186 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3187 }
3188 other => other,
3189 })?;
3190 state.set_at(ra, LuaValue::Int(result));
3191 } else {
3192 arith_float_aux(state, ra, v1, v2, pc, fop);
3193 }
3194 Ok(())
3195}
3196
3197#[allow(dead_code)]
3198#[inline]
3199fn bitwise_op_k(
3200 state: &mut LuaState,
3201 ra: StackIdx,
3202 v1: &LuaValue,
3203 v2: &LuaValue, pc: &mut u32,
3205 op: fn(i64, i64) -> i64,
3206) {
3207 let i2 = match v2 {
3208 LuaValue::Int(i) => *i,
3209 _ => return,
3210 };
3211 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3212 *pc += 1;
3213 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3214 }
3215}
3216
3217#[allow(dead_code)]
3218#[inline]
3219fn bitwise_op_rr(
3220 state: &mut LuaState,
3221 ra: StackIdx,
3222 v1: &LuaValue,
3223 v2: &LuaValue,
3224 pc: &mut u32,
3225 op: fn(i64, i64) -> i64,
3226) {
3227 if let (Some(i1), Some(i2)) = (
3228 to_integer_ns(v1, F2Imod::Eq),
3229 to_integer_ns(v2, F2Imod::Eq),
3230 ) {
3231 *pc += 1;
3232 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3233 }
3234}
3235
3236#[allow(dead_code)]
3238#[inline]
3239fn bitwise_shift_rr(
3240 state: &mut LuaState,
3241 ra: StackIdx,
3242 v1: &LuaValue,
3243 v2: &LuaValue,
3244 pc: &mut u32,
3245 right: bool,
3246) {
3247 if let (Some(i1), Some(i2)) = (
3248 to_integer_ns(v1, F2Imod::Eq),
3249 to_integer_ns(v2, F2Imod::Eq),
3250 ) {
3251 let y = if right { intop_sub(0, i2) } else { i2 };
3252 *pc += 1;
3253 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3254 }
3255}
3256
3257#[cold]
3260#[inline(never)]
3261#[allow(clippy::too_many_arguments)]
3262fn order_imm_slow(
3263 state: &mut LuaState,
3264 ra: StackIdx,
3265 pc: u32,
3266 trap: &mut bool,
3267 ci: CallInfoIdx,
3268 i: Instruction,
3269 im: i64,
3270 inv: bool,
3271 tm: TagMethod,
3272) -> Result<bool, LuaError> {
3273 let ra_v = state.get_at(ra);
3274 let isf = i.arg_c() != 0;
3275 state.set_ci_savedpc(ci, pc);
3276 state.set_top(state.ci_top(ci));
3277 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3278 *trap = state.ci_trap(ci);
3279 Ok(r)
3280}
3281
3282#[inline(always)]
3283fn finish_order_imm_jump(
3284 state: &mut LuaState,
3285 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
3286 pc: &mut u32,
3287 trap: &mut bool,
3288 ci: CallInfoIdx,
3289 i: Instruction,
3290 cond: bool,
3291) {
3292 if (cond as i32) != i.arg_k() {
3293 *pc += 1;
3294 } else {
3295 let next = state.proto_code(&cl, *pc);
3296 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3297 *trap = state.ci_trap(ci);
3298 }
3299}
3300
3301#[cold]
3302#[inline(never)]
3303fn return0_hook(
3304 state: &mut LuaState,
3305 ci: CallInfoIdx,
3306 base: StackIdx,
3307 i: Instruction,
3308 pc: u32,
3309 trap: &mut bool,
3310) -> Result<(), LuaError> {
3311 let ra = base + i.arg_a();
3312 state.set_top(ra);
3313 state.set_ci_savedpc(ci, pc);
3314 state.poscall(ci, 0)?;
3315 *trap = true;
3316 Ok(())
3317}
3318
3319#[cold]
3320#[inline(never)]
3321fn return1_hook(
3322 state: &mut LuaState,
3323 ci: CallInfoIdx,
3324 base: StackIdx,
3325 i: Instruction,
3326 pc: u32,
3327 trap: &mut bool,
3328) -> Result<(), LuaError> {
3329 let ra = base + i.arg_a();
3330 state.set_top(ra + 1);
3331 state.set_ci_savedpc(ci, pc);
3332 state.poscall(ci, 1)?;
3333 *trap = true;
3334 Ok(())
3335}
3336
3337