1#[allow(unused_imports)] use crate::prelude::*;
24use lua_types::{
25 CallInfoIdx, GcRef, LuaError, 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_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_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 let mut total = total;
1301 loop {
1302 let top = state.top_idx();
1303 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1308 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1309 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1311 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1312 if !top2_coercible || !top1_stringlike {
1313 state.try_concat_tm(&v_tm1, &v_tm2)?;
1314 total -= 1;
1319 let top = state.top_idx();
1320 state.set_top(top - 1);
1321 if total <= 1 {
1322 break;
1323 }
1324 continue;
1325 }
1326
1327 let is_empty = |v: &LuaValue| -> bool {
1328 matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty())
1329 };
1330
1331 let n: u32;
1332 if is_empty(&v_tm1) {
1333 state.coerce_to_string(top - 2)?;
1334 n = 2;
1335 } else if is_empty(&v_tm2) {
1336 state.coerce_to_string(top - 1)?;
1339 let v = state.get_at(top - 1);
1340 state.set_at(top - 2, v);
1341 n = 2;
1342 } else {
1343 state.coerce_to_string(top - 1)?;
1345 let s1 = match state.get_at(top - 1) {
1346 LuaValue::Str(ts) => ts.as_bytes().len(),
1347 _ => 0,
1348 };
1349 let mut total_len = s1;
1350 let mut count: u32 = 1;
1351 let top = state.top_idx();
1352 loop {
1353 if count as i32 >= total {
1354 break;
1355 }
1356 let idx = top - (count as i32 + 1);
1357 let v = state.get_at(idx);
1358 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1359 break;
1360 }
1361 state.coerce_to_string(idx)?;
1362 let l = match state.get_at(idx) {
1363 LuaValue::Str(ts) => ts.as_bytes().len(),
1364 _ => 0,
1365 };
1366 if l >= usize::MAX - total_len {
1367 state.set_top(top - total as i32);
1369 return Err(LuaError::runtime(format_args!("string length overflow")));
1370 }
1371 total_len += l;
1372 count += 1;
1373 }
1374 n = count;
1375
1376 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1378 let top = state.top_idx();
1379 copy_to_buf(state, top, n, &mut buf);
1380 let ts = state.intern_or_create_str(&buf)?;
1381 state.set_at(top - n as i32, LuaValue::Str(ts));
1382 }
1383 total -= n as i32 - 1;
1384 let top = state.top_idx();
1385 state.set_top(top - ((n - 1) as i32));
1386
1387 if total <= 1 {
1388 break;
1389 }
1390 }
1391 Ok(())
1392}
1393
1394pub(crate) fn obj_len(state: &mut LuaState, ra: StackIdx, rb: LuaValue, rb_idx: StackIdx) -> Result<(), LuaError> {
1398 match &rb {
1399 LuaValue::Table(_) => {
1400 let consult_len_tm = !matches!(
1405 state.global().lua_version,
1406 lua_types::LuaVersion::V51
1407 );
1408 let tm = if consult_len_tm {
1409 let mt = state.table_metatable(&rb);
1410 state.fast_tm_table(mt.as_ref(), TagMethod::Len)
1411 } else {
1412 LuaValue::Nil
1413 };
1414 if matches!(tm, LuaValue::Nil) {
1415 let n = state.table_length(&rb)?;
1416 state.set_at(ra, LuaValue::Int(n as i64));
1417 return Ok(());
1418 }
1419 state.call_tm_res(tm, &rb, &rb, ra)?;
1421 }
1422 LuaValue::Str(ts) => {
1423 let n = ts.len();
1426 state.set_at(ra, LuaValue::Int(n as i64));
1427 }
1428 other => {
1429 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1431 if matches!(tm, LuaValue::Nil) {
1432 return Err(crate::debug::type_error(state, other, rb_idx, b"get length of"));
1433 }
1434 state.call_tm_res(tm, &rb, &rb, ra)?;
1435 }
1436 }
1437 Ok(())
1438}
1439
1440pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1444 if (n as u64).wrapping_add(1) <= 1 {
1445 if n == 0 {
1446 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1447 }
1448 return Ok(intop_sub(0, m));
1449 }
1450 let q = m / n;
1451 if (m ^ n) < 0 && m % n != 0 {
1453 Ok(q - 1)
1454 } else {
1455 Ok(q)
1456 }
1457}
1458
1459pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1461 if (n as u64).wrapping_add(1) <= 1 {
1462 if n == 0 {
1463 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1464 }
1465 return Ok(0);
1466 }
1467 let r = m % n;
1468 if r != 0 && (r ^ n) < 0 {
1469 Ok(r + n)
1470 } else {
1471 Ok(r)
1472 }
1473}
1474
1475pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1477 let r = m % n;
1478 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1479 if opposite_signs {
1480 r + n
1481 } else {
1482 r
1483 }
1484}
1485
1486pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1489 use TagMethod::*;
1490 match i {
1491 0 => Index, 1 => NewIndex, 2 => Gc, 3 => Mode, 4 => Len, 5 => Eq,
1492 6 => Add, 7 => Sub, 8 => Mul, 9 => Mod, 10 => Pow, 11 => Div,
1493 12 => Idiv, 13 => Band, 14 => Bor, 15 => Bxor, 16 => Shl, 17 => Shr,
1494 18 => Unm, 19 => Bnot, 20 => Lt, 21 => Le, 22 => Concat, 23 => Call,
1495 24 => Close,
1496 _ => Index,
1497 }
1498}
1499
1500pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1503 imod(a, b)
1504}
1505
1506pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1509 idiv(a, b)
1510}
1511
1512pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1515 Ok(fmodf(a, b))
1516}
1517
1518pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1520 if y < 0 {
1521 if y <= -(NBITS as i64) {
1522 0
1523 } else {
1524 intop_shr(x, (-y) as u32)
1525 }
1526 } else {
1527 if y >= NBITS as i64 {
1528 0
1529 } else {
1530 intop_shl(x, y as u32)
1531 }
1532 }
1533}
1534
1535fn push_closure(
1541 state: &mut LuaState,
1542 proto_idx: usize, ci: CallInfoIdx,
1544 base: StackIdx,
1545 ra: StackIdx,
1546) -> Result<(), LuaError> {
1547 state.push_closure(proto_idx, ci, base, ra)
1551}
1552
1553pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1558 let ci = state.current_ci_idx();
1562 let base = state.ci_base(ci);
1563 let inst = state.ci_prev_instruction(ci);
1564 let op = inst.opcode();
1565
1566 match op {
1567 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1569 let prev_inst = state.ci_prev2_instruction(ci);
1570 let a = prev_inst.arg_a();
1571 state.dec_top();
1572 let top = state.top_idx();
1573 let v = state.get_at(top);
1574 state.set_at(base + a, v);
1575 }
1576 OpCode::Unm | OpCode::BNot | OpCode::Len
1578 | OpCode::GetTabUp | OpCode::GetTable | OpCode::GetI
1579 | OpCode::GetField | OpCode::Self_ => {
1580 let a = inst.arg_a();
1581 state.dec_top();
1582 let top = state.top_idx();
1583 let v = state.get_at(top);
1584 state.set_at(base + a, v);
1585 }
1586 OpCode::Lt | OpCode::Le | OpCode::LtI | OpCode::LeI
1590 | OpCode::GtI | OpCode::GeI | OpCode::Eq => {
1591 let top_minus1 = state.top_idx() - 1;
1592 let v = state.get_at(top_minus1);
1593 let mut res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1594 state.dec_top();
1595 if (state.get_ci(ci).callstatus & crate::state::CIST_LEQ) != 0 {
1600 state.get_ci_mut(ci).callstatus &= !crate::state::CIST_LEQ;
1601 res = !res;
1602 }
1603 if (res as i32) != inst.arg_k() {
1604 state.ci_skip_next_instruction(ci);
1605 }
1606 }
1607 OpCode::Concat => {
1613 let top = state.top_idx() - 1; let a = inst.arg_a();
1615 let total_concat = (top - 1 - (base + a)) as i32;
1616 let v = state.get_at(top);
1617 state.set_at(top - 2, v);
1618 state.set_top(top - 1);
1619 concat(state, total_concat)?;
1620 }
1621 OpCode::Close => {
1622 state.ci_step_pc_back(ci);
1623 }
1624 OpCode::Return => {
1628 let a = inst.arg_a();
1629 let ra = base + a;
1630 let nres = state.ci_nres(ci);
1631 state.set_top(ra + nres);
1632 state.ci_step_pc_back(ci);
1633 }
1634 other => {
1635 debug_assert!(
1636 matches!(
1637 other,
1638 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1639 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1640 ),
1641 "unexpected opcode in finish_op: {:?}",
1642 other
1643 );
1644 }
1645 }
1646 Ok(())
1647}
1648
1649pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1661 let mut trap: bool;
1662 let legacy_for = matches!(
1669 state.global().lua_version,
1670 lua_types::LuaVersion::V51 | lua_types::LuaVersion::V52 | lua_types::LuaVersion::V53
1671 );
1672
1673 'startfunc: loop {
1675 trap = state.hook_mask() != 0;
1676
1677 'returning: loop {
1680 let cl = match state.ci_lua_closure(ci) {
1681 Some(c) => c,
1682 None => {
1683 return Err(LuaError::runtime(format_args!(
1684 "internal: execute called on non-Lua frame"
1685 )));
1686 }
1687 };
1688 let mut pc: u32 = state.ci_savedpc(ci);
1690
1691 if trap {
1692 trap = state.trace_call(ci)?;
1693 }
1694 let mut base: StackIdx = state.ci_base(ci);
1695
1696 'dispatch: loop {
1698 if trap {
1699 trap = state.trace_exec(ci, pc)?;
1700 base = state.ci_base(ci); }
1702 let i: Instruction = state.proto_code(&cl, pc);
1703 pc += 1;
1704 let op = i.opcode();
1705
1706 debug_assert!(base == state.ci_base(ci));
1707
1708 #[cfg(debug_assertions)]
1712 {
1713 let op_mode = op_mode_byte(op);
1714 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1715 state.set_top(base);
1716 }
1717 }
1718
1719 match op {
1720 OpCode::Move => {
1722 let ra = base + i.arg_a();
1723 let rb = base + i.arg_b();
1724 let v = state.stack[rb.0 as usize].val;
1725 state.stack[ra.0 as usize].val = v;
1726 }
1727 OpCode::LoadI => {
1729 let ra = base + i.arg_a();
1730 let b = i.arg_s_bx() as i64;
1731 state.set_at(ra, LuaValue::Int(b));
1732 }
1733 OpCode::LoadF => {
1735 let ra = base + i.arg_a();
1736 let b = i.arg_s_bx() as f64;
1737 state.set_at(ra, LuaValue::Float(b));
1738 }
1739 OpCode::LoadK => {
1741 let ra = base + i.arg_a();
1742 let k_idx = i.arg_bx() as usize;
1743 let v = state.proto_const(&cl, k_idx).clone();
1744 state.set_at(ra, v);
1745 }
1746 OpCode::LoadKX => {
1748 let ra = base + i.arg_a();
1749 let extra = state.proto_code(&cl, pc);
1750 pc += 1;
1751 let k_idx = extra.arg_ax() as usize;
1752 let v = state.proto_const(&cl, k_idx).clone();
1753 state.set_at(ra, v);
1754 }
1755 OpCode::LoadFalse => {
1757 let ra = base + i.arg_a();
1758 state.set_at(ra, LuaValue::Bool(false));
1759 }
1760 OpCode::LFalseSkip => {
1762 let ra = base + i.arg_a();
1763 state.set_at(ra, LuaValue::Bool(false));
1764 pc += 1;
1765 }
1766 OpCode::LoadTrue => {
1768 let ra = base + i.arg_a();
1769 state.set_at(ra, LuaValue::Bool(true));
1770 }
1771 OpCode::LoadNil => {
1773 let ra = base + i.arg_a();
1774 let b = i.arg_b();
1775 for k in 0..=b {
1776 state.set_at(ra + k, LuaValue::Nil);
1777 }
1778 }
1779 OpCode::GetUpVal => {
1781 let ra = base + i.arg_a();
1782 let b = i.arg_b() as usize;
1783 let v = state.upvalue_get(&cl, b);
1784 state.set_at(ra, v);
1785 }
1786 OpCode::SetUpVal => {
1789 let ra = base + i.arg_a();
1790 let b = i.arg_b() as usize;
1791 let v = state.stack[ra.0 as usize].val;
1792 let uv = cl.upval(b);
1793 match uv.try_open_payload() {
1794 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1795 state.stack[idx.0 as usize].val = v;
1796 state.gc_barrier_upval(&uv, &v);
1797 }
1798 _ => {
1799 state.upvalue_set(&cl, b, v)?;
1800 }
1801 }
1802 }
1803 OpCode::GetTabUp => {
1807 let ra = base + i.arg_a();
1808 let b = i.arg_b() as usize;
1809 let k_idx = i.arg_c() as usize;
1810 let upval = state.upvalue_get(&cl, b);
1811 let key = state.proto_const(&cl, k_idx).clone();
1812 match state.fast_get_short_str(&upval, &key)? {
1813 Some(v) => state.set_at(ra, v),
1814 None => {
1815 state.set_ci_savedpc(ci, pc);
1816 state.set_top(state.ci_top(ci));
1817 finish_get(state, upval, key, ra, true, None)?;
1818 trap = state.ci_trap(ci);
1819 }
1820 }
1821 }
1822 OpCode::GetTable => {
1825 let ra = base + i.arg_a();
1826 let rb_idx = base + i.arg_b();
1827 let rb_v = state.get_at(rb_idx);
1828 let rc_v = state.get_at(base + i.arg_c());
1829 let fast_result = if let LuaValue::Int(n) = &rc_v {
1830 state.fast_get_int(&rb_v, *n)?
1831 } else {
1832 state.fast_get(&rb_v, &rc_v)?
1833 };
1834 match fast_result {
1835 Some(v) => state.set_at(ra, v),
1836 None => {
1837 state.set_ci_savedpc(ci, pc);
1838 state.set_top(state.ci_top(ci));
1839 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1840 trap = state.ci_trap(ci);
1841 }
1842 }
1843 }
1844 OpCode::GetI => {
1848 let ra = base + i.arg_a();
1849 let rb_idx = base + i.arg_b();
1850 let rb_v = state.get_at(rb_idx);
1851 let c = i.arg_c() as i64;
1852 match state.fast_get_int(&rb_v, c)? {
1853 Some(v) => state.set_at(ra, v),
1854 None => {
1855 let key = LuaValue::Int(c);
1856 state.set_ci_savedpc(ci, pc);
1857 state.set_top(state.ci_top(ci));
1858 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1859 trap = state.ci_trap(ci);
1860 }
1861 }
1862 }
1863 OpCode::GetField => {
1865 let ra = base + i.arg_a();
1866 let rb_idx = base + i.arg_b();
1867 let rb_v = state.get_at(rb_idx);
1868 let k_idx = i.arg_c() as usize;
1869 let key = state.proto_const(&cl, k_idx).clone();
1870 match state.fast_get_short_str(&rb_v, &key)? {
1871 Some(v) => state.set_at(ra, v),
1872 None => {
1873 state.set_ci_savedpc(ci, pc);
1874 state.set_top(state.ci_top(ci));
1875 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1876 trap = state.ci_trap(ci);
1877 }
1878 }
1879 }
1880 OpCode::SetTabUp => {
1882 let a = i.arg_a() as usize;
1883 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1885 state.proto_const(&cl, i.arg_c() as usize).clone()
1886 } else {
1887 state.get_at(base + i.arg_c())
1888 };
1889 let upval = state.upvalue_get(&cl, a);
1890 let key = state.proto_const(&cl, b_idx).clone();
1891 match state.fast_get_short_str(&upval, &key)? {
1892 Some(_slot) => {
1893 state.table_raw_set(&upval, key, rc_v.clone())?;
1894 state.gc_barrier_back(&upval, &rc_v);
1895 }
1896 None => {
1897 state.set_ci_savedpc(ci, pc);
1898 state.set_top(state.ci_top(ci));
1899 let upval_name: Vec<u8> = cl
1900 .proto
1901 .upvalues
1902 .get(a)
1903 .and_then(|uv| uv.name.as_ref())
1904 .map(|s| s.as_bytes().to_vec())
1905 .unwrap_or_else(|| b"?".to_vec());
1906 let hint: Option<(&[u8], &[u8])> =
1907 Some((b"upvalue", &upval_name));
1908 finish_set(state, upval, key, rc_v, false, None, hint)?;
1909 trap = state.ci_trap(ci);
1910 }
1911 }
1912 }
1913 OpCode::SetTable => {
1915 let ra_idx = base + i.arg_a();
1916 let ra_v = state.get_at(ra_idx);
1917 let rb_v = state.get_at(base + i.arg_b());
1918 let rc_v = if i.test_k() {
1919 state.proto_const(&cl, i.arg_c() as usize).clone()
1920 } else {
1921 state.get_at(base + i.arg_c())
1922 };
1923 let fast = if let LuaValue::Int(n) = &rb_v {
1924 state.fast_get_int(&ra_v, *n)?
1925 } else {
1926 state.fast_get(&ra_v, &rb_v)?
1927 };
1928 if fast.is_some() {
1929 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1930 state.gc_barrier_back(&ra_v, &rc_v);
1931 } else {
1932 state.set_ci_savedpc(ci, pc);
1933 state.set_top(state.ci_top(ci));
1934 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1935 trap = state.ci_trap(ci);
1936 }
1937 }
1938 OpCode::SetI => {
1940 let ra_idx = base + i.arg_a();
1941 let ra_v = state.get_at(ra_idx);
1942 let c = i.arg_b() as i64;
1943 let rc_v = if i.test_k() {
1944 state.proto_const(&cl, i.arg_c() as usize).clone()
1945 } else {
1946 state.get_at(base + i.arg_c())
1947 };
1948 let fast = state.fast_get_int(&ra_v, c)?;
1949 if fast.is_some() {
1950 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1951 state.gc_barrier_back(&ra_v, &rc_v);
1952 } else {
1953 state.set_ci_savedpc(ci, pc);
1954 state.set_top(state.ci_top(ci));
1955 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1956 trap = state.ci_trap(ci);
1957 }
1958 }
1959 OpCode::SetField => {
1961 let ra_idx = base + i.arg_a();
1962 let ra_v = state.get_at(ra_idx);
1963 let b_idx = i.arg_b() as usize;
1964 let key = state.proto_const(&cl, b_idx).clone();
1965 let rc_v = if i.test_k() {
1966 state.proto_const(&cl, i.arg_c() as usize).clone()
1967 } else {
1968 state.get_at(base + i.arg_c())
1969 };
1970 match state.fast_get_short_str(&ra_v, &key)? {
1971 Some(_) => {
1972 state.table_raw_set(&ra_v, key, rc_v.clone())?;
1973 state.gc_barrier_back(&ra_v, &rc_v);
1974 }
1975 None => {
1976 state.set_ci_savedpc(ci, pc);
1977 state.set_top(state.ci_top(ci));
1978 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
1979 trap = state.ci_trap(ci);
1980 }
1981 }
1982 }
1983 OpCode::NewTable => {
1986 let ra = base + i.arg_a();
1987 let mut b = i.arg_b();
1988 let mut c = i.arg_c();
1989 if b > 0 {
1990 b = 1 << (b - 1);
1991 }
1992 if i.test_k() {
1993 let extra = state.proto_code(&cl, pc);
1994 pc += 1;
1995 const MAXARG_C: i32 = (1 << 8) - 1;
1996 c += extra.arg_ax() * (MAXARG_C + 1);
1997 } else {
1998 pc += 1; }
2000 state.set_top(ra + 1);
2001 let t = if b != 0 || c != 0 {
2002 state.new_table_with_sizes(c as u32, b as u32)?
2003 } else {
2004 state.new_table()
2005 };
2006 state.set_at(ra, LuaValue::Table(t.clone()));
2007 state.set_ci_savedpc(ci, pc);
2008 state.set_top(ra + 1);
2009 state.gc_cond_step();
2010 if state.hookmask != 0 {
2011 trap = state.ci_trap(ci);
2012 }
2013 }
2014 OpCode::Self_ => {
2016 let ra = base + i.arg_a();
2017 let rb_idx = base + i.arg_b();
2018 let rb_v = state.get_at(rb_idx);
2019 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2021 state.proto_const(&cl, k_idx).clone()
2022 } else {
2023 state.get_at(base + i.arg_c())
2024 };
2025 state.set_at(ra + 1, rb_v.clone());
2026 match state.fast_get_short_str(&rb_v, &key)? {
2027 Some(v) => state.set_at(ra, v),
2028 None => {
2029 state.set_ci_savedpc(ci, pc);
2030 state.set_top(state.ci_top(ci));
2031 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
2032 trap = state.ci_trap(ci);
2033 }
2034 }
2035 }
2036 OpCode::AddI => {
2038 let ra = base + i.arg_a();
2039 let rb = base + i.arg_b();
2040 let imm = i.arg_s_c() as i64;
2041 let rb_v = state.stack[rb.0 as usize].val;
2042 match rb_v {
2043 LuaValue::Int(iv1) => {
2044 pc += 1;
2045 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2046 }
2047 LuaValue::Float(nb) => {
2048 pc += 1;
2049 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2050 }
2051 _ => {}
2052 }
2053 }
2054 OpCode::AddK => {
2056 let ra = base + i.arg_a();
2057 let rb = base + i.arg_b();
2058 let kidx = i.arg_c() as usize;
2059 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2060 pc += 1;
2061 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2062 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2063 pc += 1;
2064 state.set_at(ra, LuaValue::Float(n1 + n2));
2065 }
2066 }
2067 OpCode::SubK => {
2068 let ra = base + i.arg_a();
2069 let rb = base + i.arg_b();
2070 let kidx = i.arg_c() as usize;
2071 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2072 pc += 1;
2073 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2074 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2075 pc += 1;
2076 state.set_at(ra, LuaValue::Float(n1 - n2));
2077 }
2078 }
2079 OpCode::MulK => {
2080 let ra = base + i.arg_a();
2081 let rb = base + i.arg_b();
2082 let kidx = i.arg_c() as usize;
2083 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2084 pc += 1;
2085 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2086 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2087 pc += 1;
2088 state.set_at(ra, LuaValue::Float(n1 * n2));
2089 }
2090 }
2091 OpCode::ModK => {
2092 let ra = base + i.arg_a();
2093 let v1 = state.get_at(base + i.arg_b());
2094 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2095 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
2097 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2098 |a, b| imod(a, b), fmodf)?;
2099 }
2100 OpCode::PowK => {
2101 let ra = base + i.arg_a();
2102 let rb = base + i.arg_b();
2103 let kidx = i.arg_c() as usize;
2104 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2105 pc += 1;
2106 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2107 state.set_at(ra, LuaValue::Float(r));
2108 }
2109 }
2110 OpCode::DivK => {
2111 let ra = base + i.arg_a();
2112 let rb = base + i.arg_b();
2113 let kidx = i.arg_c() as usize;
2114 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2115 pc += 1;
2116 state.set_at(ra, LuaValue::Float(n1 / n2));
2117 }
2118 }
2119 OpCode::IDivK => {
2120 let ra = base + i.arg_a();
2121 let v1 = state.get_at(base + i.arg_b());
2122 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2123 state.set_ci_savedpc(ci, pc);
2124 state.set_top(state.ci_top(ci));
2125 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2126 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2127 }
2128 OpCode::BAndK => {
2129 let ra = base + i.arg_a();
2130 let v1 = state.get_at(base + i.arg_b());
2131 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2132 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2133 }
2134 OpCode::BOrK => {
2135 let ra = base + i.arg_a();
2136 let v1 = state.get_at(base + i.arg_b());
2137 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2138 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2139 }
2140 OpCode::BXOrK => {
2141 let ra = base + i.arg_a();
2142 let v1 = state.get_at(base + i.arg_b());
2143 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
2144 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2145 }
2146 OpCode::ShrI => {
2147 let ra = base + i.arg_a();
2148 let v = state.get_at(base + i.arg_b());
2149 let ic = i.arg_s_c() as i64;
2150 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2151 pc += 1;
2152 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2153 }
2154 }
2155 OpCode::ShlI => {
2156 let ra = base + i.arg_a();
2157 let v = state.get_at(base + i.arg_b());
2158 let ic = i.arg_s_c() as i64;
2159 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2160 pc += 1;
2161 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2162 }
2163 }
2164 OpCode::Add => {
2166 let ra = base + i.arg_a();
2167 let rb = base + i.arg_b();
2168 let rc = base + i.arg_c();
2169 let ra_u = ra.0 as usize;
2170 let rb_v = state.stack[rb.0 as usize].val;
2171 let rc_v = state.stack[rc.0 as usize].val;
2172 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2173 pc += 1;
2174 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2175 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2176 pc += 1;
2177 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2178 }
2179 }
2180 OpCode::Sub => {
2181 let ra = base + i.arg_a();
2182 let rb = base + i.arg_b();
2183 let rc = base + i.arg_c();
2184 let ra_u = ra.0 as usize;
2185 let rb_v = state.stack[rb.0 as usize].val;
2186 let rc_v = state.stack[rc.0 as usize].val;
2187 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2188 pc += 1;
2189 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2190 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2191 pc += 1;
2192 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2193 }
2194 }
2195 OpCode::Mul => {
2196 let ra = base + i.arg_a();
2197 let rb = base + i.arg_b();
2198 let rc = base + i.arg_c();
2199 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2200 pc += 1;
2201 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2202 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2203 pc += 1;
2204 state.set_at(ra, LuaValue::Float(n1 * n2));
2205 }
2206 }
2207 OpCode::Mod => {
2208 let ra = base + i.arg_a();
2209 let v1 = state.get_at(base + i.arg_b());
2210 let v2 = state.get_at(base + i.arg_c());
2211 state.set_ci_savedpc(ci, pc);
2212 state.set_top(state.ci_top(ci));
2213 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2214 |a, b| imod(a, b), fmodf)?;
2215 }
2216 OpCode::Pow => {
2217 let ra = base + i.arg_a();
2218 let rb = base + i.arg_b();
2219 let rc = base + i.arg_c();
2220 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2221 pc += 1;
2222 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2223 state.set_at(ra, LuaValue::Float(r));
2224 }
2225 }
2226 OpCode::Div => {
2227 let ra = base + i.arg_a();
2228 let rb = base + i.arg_b();
2229 let rc = base + i.arg_c();
2230 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2231 pc += 1;
2232 state.set_at(ra, LuaValue::Float(n1 / n2));
2233 }
2234 }
2235 OpCode::IDiv => {
2236 let ra = base + i.arg_a();
2237 let v1 = state.get_at(base + i.arg_b());
2238 let v2 = state.get_at(base + i.arg_c());
2239 state.set_ci_savedpc(ci, pc);
2240 state.set_top(state.ci_top(ci));
2241 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2242 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2243 }
2244 OpCode::BAnd => {
2247 let ra = base + i.arg_a();
2248 let v1 = state.get_at(base + i.arg_b());
2249 let v2 = state.get_at(base + i.arg_c());
2250 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2251 }
2252 OpCode::BOr => {
2253 let ra = base + i.arg_a();
2254 let v1 = state.get_at(base + i.arg_b());
2255 let v2 = state.get_at(base + i.arg_c());
2256 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2257 }
2258 OpCode::BXOr => {
2259 let ra = base + i.arg_a();
2260 let v1 = state.get_at(base + i.arg_b());
2261 let v2 = state.get_at(base + i.arg_c());
2262 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2263 }
2264 OpCode::Shr => {
2265 let ra = base + i.arg_a();
2266 let v1 = state.get_at(base + i.arg_b());
2267 let v2 = state.get_at(base + i.arg_c());
2268 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2269 }
2270 OpCode::Shl => {
2271 let ra = base + i.arg_a();
2272 let v1 = state.get_at(base + i.arg_b());
2273 let v2 = state.get_at(base + i.arg_c());
2274 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2275 }
2276 OpCode::MmBin => {
2281 let ra_idx = base + i.arg_a();
2282 let rb_idx = base + i.arg_b();
2283 let ra_v = state.get_at(ra_idx);
2284 let rb_v = state.get_at(rb_idx);
2285 let tm = tagmethod_from_index(i.arg_c() as usize);
2286 let prev_inst = state.proto_code(&cl, pc - 2);
2287 let result_idx = base + prev_inst.arg_a();
2288 state.set_ci_savedpc(ci, pc);
2289 state.set_top(state.ci_top(ci));
2290 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2291 trap = state.ci_trap(ci);
2292 }
2293 OpCode::MmBinI => {
2294 let ra_idx = base + i.arg_a();
2295 let ra_v = state.get_at(ra_idx);
2296 let imm = i.arg_s_b() as i64;
2297 let tm = tagmethod_from_index(i.arg_c() as usize);
2298 let flip = i.arg_k() != 0;
2299 let prev_inst = state.proto_code(&cl, pc - 2);
2300 let result_idx = base + prev_inst.arg_a();
2301 state.set_ci_savedpc(ci, pc);
2302 state.set_top(state.ci_top(ci));
2303 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2304 trap = state.ci_trap(ci);
2305 }
2306 OpCode::MmBinK => {
2307 let ra_idx = base + i.arg_a();
2308 let ra_v = state.get_at(ra_idx);
2309 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2310 let tm = tagmethod_from_index(i.arg_c() as usize);
2311 let flip = i.arg_k() != 0;
2312 let prev_inst = state.proto_code(&cl, pc - 2);
2313 let result_idx = base + prev_inst.arg_a();
2314 state.set_ci_savedpc(ci, pc);
2315 state.set_top(state.ci_top(ci));
2316 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2317 trap = state.ci_trap(ci);
2318 }
2319 OpCode::Unm => {
2323 let ra = base + i.arg_a();
2324 let rb_idx = base + i.arg_b();
2325 let rb_v = state.get_at(rb_idx);
2326 match &rb_v {
2327 LuaValue::Int(ib) => {
2328 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2329 }
2330 LuaValue::Float(nb) => {
2331 state.set_at(ra, LuaValue::Float(-nb));
2332 }
2333 _ => {
2334 state.set_ci_savedpc(ci, pc);
2335 state.set_top(state.ci_top(ci));
2336 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2337 trap = state.ci_trap(ci);
2338 }
2339 }
2340 }
2341 OpCode::BNot => {
2343 let ra = base + i.arg_a();
2344 let rb_idx = base + i.arg_b();
2345 let rb_v = state.get_at(rb_idx);
2346 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2347 state.set_at(ra, LuaValue::Int(!ib));
2348 } else {
2349 state.set_ci_savedpc(ci, pc);
2350 state.set_top(state.ci_top(ci));
2351 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2352 trap = state.ci_trap(ci);
2353 }
2354 }
2355 OpCode::Not => {
2357 let ra = base + i.arg_a();
2358 let rb_v = state.get_at(base + i.arg_b());
2359 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2360 state.set_at(ra, LuaValue::Bool(falsy));
2361 }
2362 OpCode::Len => {
2364 let ra = base + i.arg_a();
2365 let rb_idx = base + i.arg_b();
2366 let rb_v = state.get_at(rb_idx);
2367 state.set_ci_savedpc(ci, pc);
2368 state.set_top(state.ci_top(ci));
2369 obj_len(state, ra, rb_v, rb_idx)?;
2370 trap = state.ci_trap(ci);
2371 }
2372 OpCode::Concat => {
2374 let ra = base + i.arg_a();
2375 let n = i.arg_b() as i32;
2376 state.set_top(ra + n as i32);
2377 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2379 let top = state.top_idx();
2380 state.set_ci_savedpc(ci, pc);
2381 state.set_top(top);
2382 state.gc_cond_step();
2383 trap = state.ci_trap(ci);
2384 }
2385 OpCode::Close => {
2387 let ra = base + i.arg_a();
2388 state.set_ci_savedpc(ci, pc);
2389 state.set_top(state.ci_top(ci));
2390 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2391 trap = state.ci_trap(ci);
2392 }
2393 OpCode::Tbc => {
2395 let ra = base + i.arg_a();
2396 state.set_ci_savedpc(ci, pc);
2397 state.set_top(state.ci_top(ci));
2398 state.new_tbc_upval(ra)?;
2399 }
2400 OpCode::Jmp => {
2402 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2403 trap = state.ci_trap(ci);
2404 }
2405 OpCode::Eq => {
2407 let ra_v = state.get_at(base + i.arg_a());
2408 let rb_v = state.get_at(base + i.arg_b());
2409 state.set_ci_savedpc(ci, pc);
2410 state.set_top(state.ci_top(ci));
2411 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2412 trap = state.ci_trap(ci);
2413 if (cond as i32) != i.arg_k() {
2414 pc += 1;
2415 } else {
2416 let next = state.proto_code(&cl, pc);
2417 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2418 trap = state.ci_trap(ci);
2419 }
2420 }
2421 OpCode::Lt => {
2423 let ra_v = state.get_at(base + i.arg_a());
2424 let rb_v = state.get_at(base + i.arg_b());
2425 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2426 *ia < *ib
2427 } else if matches!((&ra_v, &rb_v),
2428 (LuaValue::Int(_) | LuaValue::Float(_),
2429 LuaValue::Int(_) | LuaValue::Float(_))) {
2430 lt_num(&ra_v, &rb_v)
2431 } else {
2432 state.set_ci_savedpc(ci, pc);
2433 state.set_top(state.ci_top(ci));
2434 let r = less_than_others(state, &ra_v, &rb_v)?;
2435 trap = state.ci_trap(ci);
2436 r
2437 };
2438 if (cond as i32) != i.arg_k() {
2439 pc += 1;
2440 } else {
2441 let next = state.proto_code(&cl, pc);
2442 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2443 trap = state.ci_trap(ci);
2444 }
2445 }
2446 OpCode::Le => {
2448 let ra_v = state.get_at(base + i.arg_a());
2449 let rb_v = state.get_at(base + i.arg_b());
2450 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2451 *ia <= *ib
2452 } else if matches!((&ra_v, &rb_v),
2453 (LuaValue::Int(_) | LuaValue::Float(_),
2454 LuaValue::Int(_) | LuaValue::Float(_))) {
2455 le_num(&ra_v, &rb_v)
2456 } else {
2457 state.set_ci_savedpc(ci, pc);
2458 state.set_top(state.ci_top(ci));
2459 let r = less_equal_others(state, &ra_v, &rb_v)?;
2460 trap = state.ci_trap(ci);
2461 r
2462 };
2463 if (cond as i32) != i.arg_k() {
2464 pc += 1;
2465 } else {
2466 let next = state.proto_code(&cl, pc);
2467 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2468 trap = state.ci_trap(ci);
2469 }
2470 }
2471 OpCode::EqK => {
2473 let ra_v = state.get_at(base + i.arg_a());
2474 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2475 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2476 if (cond as i32) != i.arg_k() {
2477 pc += 1;
2478 } else {
2479 let next = state.proto_code(&cl, pc);
2480 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2481 trap = state.ci_trap(ci);
2482 }
2483 }
2484 OpCode::EqI => {
2489 let ra_v = state.get_at(base + i.arg_a());
2490 let im = i.arg_s_b() as i64;
2491 let cond: bool = match &ra_v {
2492 LuaValue::Int(iv) => *iv == im,
2493 LuaValue::Float(fv) => *fv == im as f64,
2494 _ => false,
2495 };
2496 if (cond as i32) != i.arg_k() {
2497 pc += 1;
2498 } else {
2499 let next = state.proto_code(&cl, pc);
2500 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2501 trap = state.ci_trap(ci);
2502 }
2503 }
2504 OpCode::LtI => {
2507 let ra = base + i.arg_a();
2508 let im = i.arg_s_b() as i64;
2509 let fast_cond = match &state.stack[ra.0 as usize].val {
2510 LuaValue::Int(ia) => Some(*ia < im),
2511 LuaValue::Float(fa) => Some(*fa < im as f64),
2512 _ => None,
2513 };
2514 let cond = match fast_cond {
2515 Some(cond) => cond,
2516 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2517 };
2518 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2519 }
2520 OpCode::LeI => {
2521 let ra = base + i.arg_a();
2522 let im = i.arg_s_b() as i64;
2523 let fast_cond = match &state.stack[ra.0 as usize].val {
2524 LuaValue::Int(ia) => Some(*ia <= im),
2525 LuaValue::Float(fa) => Some(*fa <= im as f64),
2526 _ => None,
2527 };
2528 let cond = match fast_cond {
2529 Some(cond) => cond,
2530 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2531 };
2532 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2533 }
2534 OpCode::GtI => {
2535 let ra = base + i.arg_a();
2536 let im = i.arg_s_b() as i64;
2537 let fast_cond = match &state.stack[ra.0 as usize].val {
2538 LuaValue::Int(ia) => Some(*ia > im),
2539 LuaValue::Float(fa) => Some(*fa > im as f64),
2540 _ => None,
2541 };
2542 let cond = match fast_cond {
2543 Some(cond) => cond,
2544 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2545 };
2546 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2547 }
2548 OpCode::GeI => {
2549 let ra = base + i.arg_a();
2550 let im = i.arg_s_b() as i64;
2551 let fast_cond = match &state.stack[ra.0 as usize].val {
2552 LuaValue::Int(ia) => Some(*ia >= im),
2553 LuaValue::Float(fa) => Some(*fa >= im as f64),
2554 _ => None,
2555 };
2556 let cond = match fast_cond {
2557 Some(cond) => cond,
2558 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2559 };
2560 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2561 }
2562 OpCode::Test => {
2564 let ra_v = state.get_at(base + i.arg_a());
2565 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2566 if (cond as i32) != i.arg_k() {
2567 pc += 1;
2568 } else {
2569 let next = state.proto_code(&cl, pc);
2570 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2571 trap = state.ci_trap(ci);
2572 }
2573 }
2574 OpCode::TestSet => {
2577 let ra = base + i.arg_a();
2578 let rb_v = state.get_at(base + i.arg_b());
2579 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2580 if (falsy as i32) == i.arg_k() {
2581 pc += 1;
2582 } else {
2583 state.set_at(ra, rb_v);
2584 let next = state.proto_code(&cl, pc);
2585 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2586 trap = state.ci_trap(ci);
2587 }
2588 }
2589 OpCode::Call => {
2593 let ra = base + i.arg_a();
2594 let b = i.arg_b();
2595 let nresults = i.arg_c() as i32 - 1;
2596 if b != 0 {
2597 state.set_top(ra + b);
2598 }
2599 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2601 match state.precall(ra, nresults)? {
2602 None => {
2603 if had_hook || state.hookmask != 0 {
2607 trap = state.ci_trap(ci); }
2609 }
2610 Some(new_ci) => {
2611 ci = new_ci;
2613 continue 'startfunc;
2614 }
2615 }
2616 }
2617 OpCode::TailCall => {
2622 let ra = base + i.arg_a();
2623 let b = i.arg_b();
2624 let nparams1 = i.arg_c();
2625 let delta = if nparams1 != 0 {
2626 state.ci_nextraargs(ci) + nparams1 as i32
2627 } else {
2628 0
2629 };
2630 let top_b: i32 = if b != 0 {
2631 state.set_top(ra + b);
2632 b
2633 } else {
2634 state.top_idx() - ra
2635 };
2636 state.set_ci_savedpc(ci, pc);
2637 if i.test_k() {
2638 state.close_upvals_from_base(ci)?;
2639 }
2640 let n = state.pretailcall(ci, ra, top_b, delta)?;
2641 if n < 0 {
2642 continue 'startfunc;
2644 } else {
2645 state.ci_adjust_func(ci, delta);
2647 state.poscall(ci, n as u32)?;
2648 if state.hookmask != 0 {
2649 trap = state.ci_trap(ci);
2650 }
2651 break 'dispatch; }
2653 }
2654 OpCode::Return => {
2659 let ra = base + i.arg_a();
2660 let n_raw = i.arg_b() as i32 - 1;
2661 let nparams1 = i.arg_c();
2662 let n: u32 = if n_raw < 0 {
2663 (state.top_idx() - ra) as u32
2664 } else {
2665 n_raw as u32
2666 };
2667 state.set_ci_savedpc(ci, pc);
2668 if i.test_k() {
2669 state.ci_nres_set(ci, n as i32);
2670 let ci_top = state.ci_top(ci);
2671 if state.top_idx().0 < ci_top.0 {
2672 state.set_top(ci_top);
2673 }
2674 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2675 if state.hookmask != 0 {
2676 trap = state.ci_trap(ci);
2677 }
2678 base = state.ci_base(ci); }
2680 if nparams1 != 0 {
2681 let nextraargs = state.ci_nextraargs(ci) as u32;
2682 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2683 }
2684 state.set_top(ra + n as i32);
2685 state.poscall(ci, n)?;
2686 if state.hookmask != 0 {
2687 trap = state.ci_trap(ci);
2688 }
2689 break 'dispatch; }
2691 OpCode::Return0 => {
2697 if state.hookmask == 0 {
2698 let ci_slot = ci.as_usize();
2699 let nres = state.call_info[ci_slot].nresults as i32;
2700 state.ci = state.call_info[ci_slot]
2701 .previous
2702 .expect("RETURN0: returning frame has no previous CallInfo");
2703 state.top = base - 1;
2704 for _ in 0..nres.max(0) {
2705 state.push(LuaValue::Nil);
2706 }
2707 } else {
2708 return0_hook(state, ci, base, i, pc, &mut trap)?;
2709 }
2710 break 'dispatch; }
2712 OpCode::Return1 => {
2716 if state.hookmask == 0 {
2717 let ci_slot = ci.as_usize();
2718 let nres = state.call_info[ci_slot].nresults as i32;
2719 state.ci = state.call_info[ci_slot]
2720 .previous
2721 .expect("RETURN1: returning frame has no previous CallInfo");
2722 if nres == 0 {
2723 state.top = base - 1;
2724 } else {
2725 let ra = base + i.arg_a();
2726 state.stack[(base - 1).0 as usize].val =
2727 state.stack[ra.0 as usize].val; state.top = base;
2729 for _ in 1..nres.max(0) {
2730 state.push(LuaValue::Nil);
2731 }
2732 }
2733 } else {
2734 return1_hook(state, ci, base, i, pc, &mut trap)?;
2735 }
2736 break 'dispatch; }
2738 OpCode::ForLoop => {
2742 let ra = base + i.arg_a();
2743 if legacy_for {
2744 if forloop_legacy(state, ra) {
2745 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2746 }
2747 trap = state.ci_trap(ci);
2748 } else {
2749 let ra_u = ra.0 as usize;
2750 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2751 let count = match state.stack[ra_u + 1].val {
2752 LuaValue::Int(c) => c as u64,
2753 _ => 0,
2754 };
2755 if count > 0 {
2756 let idx = match state.stack[ra_u].val {
2757 LuaValue::Int(x) => x,
2758 _ => 0,
2759 };
2760 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2761 let new_idx = intop_add(idx, step);
2762 state.stack[ra_u].val = LuaValue::Int(new_idx);
2763 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2764 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2765 }
2766 } else if float_for_loop(state, ra) {
2767 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2768 }
2769 trap = state.ci_trap(ci);
2770 }
2771 }
2772 OpCode::ForPrep => {
2774 let ra = base + i.arg_a();
2775 state.set_ci_savedpc(ci, pc);
2776 state.set_top(state.ci_top(ci));
2777 if legacy_for {
2778 forprep_legacy(state, ra)?;
2781 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2782 } else if forprep(state, ra)? {
2783 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2784 }
2785 }
2786 OpCode::TForPrep => {
2790 let ra = base + i.arg_a();
2791 state.set_ci_savedpc(ci, pc);
2792 state.set_top(state.ci_top(ci));
2793 state.new_tbc_upval(ra + 3)?;
2794 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2795 let tfc_i = state.proto_code(&cl, pc);
2796 pc += 1;
2797 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2798 let tfc_ra = base + tfc_i.arg_a();
2800 for k in 0..3u32 {
2801 let v = state.get_at(tfc_ra + k as i32);
2802 state.set_at(tfc_ra + 4 + k as i32, v);
2803 }
2804 state.set_top(tfc_ra + 4 + 3);
2805 state.set_ci_savedpc(ci, pc);
2806 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2807 trap = state.ci_trap(ci);
2808 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2810 pc += 1;
2811 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2812 let tfl_ra = base + tfl_i.arg_a();
2813 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2815 let v = state.get_at(tfl_ra + 4);
2816 state.set_at(tfl_ra + 2, v);
2817 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2818 }
2819 }
2820 OpCode::TForCall => {
2822 let ra = base + i.arg_a();
2823 for k in 0..3u32 {
2824 let v = state.get_at(ra + k as i32);
2825 state.set_at(ra + 4 + k as i32, v);
2826 }
2827 state.set_top(ra + 4 + 3);
2828 state.set_ci_savedpc(ci, pc);
2829 state.call_at(ra + 4, i.arg_c() as i32)?;
2830 trap = state.ci_trap(ci);
2831 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2833 pc += 1;
2834 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2835 let tfl_ra = base + tfl_i.arg_a();
2836 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2837 let v = state.get_at(tfl_ra + 4);
2838 state.set_at(tfl_ra + 2, v);
2839 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2840 }
2841 }
2842 OpCode::TForLoop => {
2844 let ra = base + i.arg_a();
2845 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2846 let v = state.get_at(ra + 4);
2847 state.set_at(ra + 2, v);
2848 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2849 }
2850 }
2851 OpCode::SetList => {
2855 let ra = base + i.arg_a();
2856 let n_raw = i.arg_b();
2857 let mut last = i.arg_c();
2858 let t_val = state.get_at(ra);
2859 let n: i32 = if n_raw == 0 {
2860 state.top_idx() - ra - 1
2861 } else {
2862 state.set_top(state.ci_top(ci));
2863 n_raw
2864 };
2865 last += n;
2866 if i.test_k() {
2867 let extra = state.proto_code(&cl, pc);
2868 pc += 1;
2869 const MAXARG_C: i32 = (1 << 8) - 1;
2870 last += extra.arg_ax() * (MAXARG_C + 1);
2871 }
2872 state.table_ensure_array(&t_val, last as usize)?;
2873 for k in (1..=n).rev() {
2874 let val = state.get_at(ra + k as i32);
2875 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2876 last -= 1;
2877 state.gc_barrier_back(&t_val, &val);
2878 }
2879 }
2880 OpCode::Closure => {
2884 let ra = base + i.arg_a();
2885 let proto_idx = i.arg_bx() as usize;
2886 state.set_ci_savedpc(ci, pc);
2887 state.set_top(state.ci_top(ci));
2888 push_closure(state, proto_idx, ci, base, ra)?;
2889 state.set_ci_savedpc(ci, pc);
2891 state.set_top(ra + 1);
2892 state.gc_cond_step();
2893 trap = state.ci_trap(ci);
2894 }
2895 OpCode::VarArg => {
2897 let ra = base + i.arg_a();
2898 let n = i.arg_c() as i32 - 1;
2899 state.set_ci_savedpc(ci, pc);
2900 state.set_top(state.ci_top(ci));
2901 state.get_varargs(ci, ra, n)?;
2902 trap = state.ci_trap(ci);
2903 }
2904 OpCode::VarArgPrep => {
2908 let nparams = i.arg_a();
2909 state.set_ci_savedpc(ci, pc);
2910 state.adjust_varargs(ci, nparams, &cl)?;
2911 trap = state.ci_trap(ci);
2912 if trap {
2913 state.hook_call(ci)?;
2914 state.set_oldpc(1);
2915 }
2916 base = state.ci_base(ci);
2917 }
2918 OpCode::ExtraArg => {
2920 debug_assert!(false, "OP_EXTRAARG executed directly");
2921 }
2922 OpCode::ErrNNil => {
2927 let ra = base + i.arg_a();
2928 if !matches!(state.get_at(ra), LuaValue::Nil) {
2929 let bx = i.arg_bx();
2930 let name: Vec<u8> = if bx == 0 {
2931 b"?".to_vec()
2932 } else {
2933 match state.proto_const(&cl, (bx - 1) as usize) {
2934 LuaValue::Str(s) => s.as_bytes().to_vec(),
2935 _ => b"?".to_vec(),
2936 }
2937 };
2938 let mut msg = Vec::with_capacity(name.len() + 24);
2939 msg.extend_from_slice(b"global '");
2940 msg.extend_from_slice(&name);
2941 msg.extend_from_slice(b"' already defined");
2942 state.set_ci_savedpc(ci, pc);
2943 return Err(crate::debug::prefixed_runtime_pub(state, msg));
2944 }
2945 }
2946 OpCode::VarArgPack => {
2954 let ra = base + i.arg_a();
2955 let nextra = state.ci_nextraargs(ci);
2956 let ci_func: StackIdx = state.ci_base(ci) - 1;
2957 let t = if nextra > 0 {
2958 state.new_table_with_sizes(nextra as u32, 1)?
2959 } else {
2960 state.new_table()
2961 };
2962 for k in 0..nextra {
2963 let src: StackIdx = ci_func - nextra as i32 + k as i32;
2964 let val = state.get_at(src);
2965 t.raw_set_int(state, (k + 1) as i64, val)?;
2966 }
2967 let n_key = state.intern_str(b"n")?;
2968 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
2969 state.set_at(ra, LuaValue::Table(t));
2970 state.set_ci_savedpc(ci, pc);
2971 state.gc_cond_step();
2972 if state.hookmask != 0 {
2973 trap = state.ci_trap(ci);
2974 }
2975 }
2976 } } if state.ci_is_fresh(ci) {
2981 return Ok(());
2982 } else {
2983 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2984 continue 'returning;
2985 }
2986 } } }
2989
2990#[inline(always)]
2993fn number_value(v: LuaValue) -> Option<f64> {
2994 match v {
2995 LuaValue::Float(f) => Some(f),
2996 LuaValue::Int(i) => Some(i as f64),
2997 _ => None,
2998 }
2999}
3000
3001#[allow(dead_code)]
3003#[inline]
3004fn arith_op_aux_rr(
3005 state: &mut LuaState,
3006 ra: StackIdx,
3007 v1: &LuaValue,
3008 v2: &LuaValue,
3009 pc: &mut u32,
3010 iop: fn(i64, i64) -> i64,
3011 fop: fn(f64, f64) -> f64,
3012) {
3013 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3014 *pc += 1;
3015 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3016 } else {
3017 arith_float_aux(state, ra, v1, v2, pc, fop);
3018 }
3019}
3020
3021#[allow(dead_code)]
3022#[inline]
3023fn arith_float_aux(
3024 state: &mut LuaState,
3025 ra: StackIdx,
3026 v1: &LuaValue,
3027 v2: &LuaValue,
3028 pc: &mut u32,
3029 fop: fn(f64, f64) -> f64,
3030) {
3031 let n1 = match v1 {
3032 LuaValue::Float(f) => Some(*f),
3033 LuaValue::Int(i) => Some(*i as f64),
3034 _ => None,
3035 };
3036 let n2 = match v2 {
3037 LuaValue::Float(f) => Some(*f),
3038 LuaValue::Int(i) => Some(*i as f64),
3039 _ => None,
3040 };
3041 if let (Some(n1), Some(n2)) = (n1, n2) {
3042 *pc += 1;
3043 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3044 }
3045}
3046
3047#[allow(dead_code)]
3048#[inline]
3049fn arith_op_checked(
3050 state: &mut LuaState,
3051 ra: StackIdx,
3052 v1: &LuaValue,
3053 v2: &LuaValue,
3054 pc: &mut u32,
3055 iop: fn(i64, i64) -> Result<i64, LuaError>,
3056 fop: fn(f64, f64) -> f64,
3057) -> Result<(), LuaError> {
3058 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3059 *pc += 1;
3060 let result = iop(*i1, *i2).map_err(|e| match e {
3061 LuaError::Runtime(LuaValue::Str(s)) => {
3062 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3063 }
3064 other => other,
3065 })?;
3066 state.set_at(ra, LuaValue::Int(result));
3067 } else {
3068 arith_float_aux(state, ra, v1, v2, pc, fop);
3069 }
3070 Ok(())
3071}
3072
3073#[allow(dead_code)]
3074#[inline]
3075fn bitwise_op_k(
3076 state: &mut LuaState,
3077 ra: StackIdx,
3078 v1: &LuaValue,
3079 v2: &LuaValue, pc: &mut u32,
3081 op: fn(i64, i64) -> i64,
3082) {
3083 let i2 = match v2 {
3084 LuaValue::Int(i) => *i,
3085 _ => return,
3086 };
3087 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3088 *pc += 1;
3089 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3090 }
3091}
3092
3093#[allow(dead_code)]
3094#[inline]
3095fn bitwise_op_rr(
3096 state: &mut LuaState,
3097 ra: StackIdx,
3098 v1: &LuaValue,
3099 v2: &LuaValue,
3100 pc: &mut u32,
3101 op: fn(i64, i64) -> i64,
3102) {
3103 if let (Some(i1), Some(i2)) = (
3104 to_integer_ns(v1, F2Imod::Eq),
3105 to_integer_ns(v2, F2Imod::Eq),
3106 ) {
3107 *pc += 1;
3108 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3109 }
3110}
3111
3112#[allow(dead_code)]
3114#[inline]
3115fn bitwise_shift_rr(
3116 state: &mut LuaState,
3117 ra: StackIdx,
3118 v1: &LuaValue,
3119 v2: &LuaValue,
3120 pc: &mut u32,
3121 right: bool,
3122) {
3123 if let (Some(i1), Some(i2)) = (
3124 to_integer_ns(v1, F2Imod::Eq),
3125 to_integer_ns(v2, F2Imod::Eq),
3126 ) {
3127 let y = if right { intop_sub(0, i2) } else { i2 };
3128 *pc += 1;
3129 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3130 }
3131}
3132
3133#[cold]
3136#[inline(never)]
3137#[allow(clippy::too_many_arguments)]
3138fn order_imm_slow(
3139 state: &mut LuaState,
3140 ra: StackIdx,
3141 pc: u32,
3142 trap: &mut bool,
3143 ci: CallInfoIdx,
3144 i: Instruction,
3145 im: i64,
3146 inv: bool,
3147 tm: TagMethod,
3148) -> Result<bool, LuaError> {
3149 let ra_v = state.get_at(ra);
3150 let isf = i.arg_c() != 0;
3151 state.set_ci_savedpc(ci, pc);
3152 state.set_top(state.ci_top(ci));
3153 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3154 *trap = state.ci_trap(ci);
3155 Ok(r)
3156}
3157
3158#[inline(always)]
3159fn finish_order_imm_jump(
3160 state: &mut LuaState,
3161 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
3162 pc: &mut u32,
3163 trap: &mut bool,
3164 ci: CallInfoIdx,
3165 i: Instruction,
3166 cond: bool,
3167) {
3168 if (cond as i32) != i.arg_k() {
3169 *pc += 1;
3170 } else {
3171 let next = state.proto_code(&cl, *pc);
3172 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3173 *trap = state.ci_trap(ci);
3174 }
3175}
3176
3177#[cold]
3178#[inline(never)]
3179fn return0_hook(
3180 state: &mut LuaState,
3181 ci: CallInfoIdx,
3182 base: StackIdx,
3183 i: Instruction,
3184 pc: u32,
3185 trap: &mut bool,
3186) -> Result<(), LuaError> {
3187 let ra = base + i.arg_a();
3188 state.set_top(ra);
3189 state.set_ci_savedpc(ci, pc);
3190 state.poscall(ci, 0)?;
3191 *trap = true;
3192 Ok(())
3193}
3194
3195#[cold]
3196#[inline(never)]
3197fn return1_hook(
3198 state: &mut LuaState,
3199 ci: CallInfoIdx,
3200 base: StackIdx,
3201 i: Instruction,
3202 pc: u32,
3203 trap: &mut bool,
3204) -> Result<(), LuaError> {
3205 let ra = base + i.arg_a();
3206 state.set_top(ra + 1);
3207 state.set_ci_savedpc(ci, pc);
3208 state.poscall(ci, 1)?;
3209 *trap = true;
3210 Ok(())
3211}
3212
3213