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_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 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 ci_slot = ci.as_usize();
1681 let func_idx = state.call_info[ci_slot].func;
1682 let cl = match state.stack.get(func_idx.0 as usize).map(|slot| slot.val) {
1683 Some(LuaValue::Function(lua_types::closure::LuaClosure::Lua(c))) => c,
1684 _ => {
1685 return Err(LuaError::runtime(format_args!(
1686 "internal: execute called on non-Lua frame"
1687 )));
1688 }
1689 };
1690 let code = &cl.proto.code;
1691 let constants = &cl.proto.k;
1692 let mut pc: u32 = state.call_info[ci_slot].saved_pc();
1694
1695 if trap {
1696 trap = state.trace_call(ci)?;
1697 }
1698 let mut base: StackIdx = state.call_info[ci.as_usize()].func + 1;
1699
1700 'dispatch: loop {
1702 if trap {
1703 trap = state.trace_exec(ci, pc)?;
1704 base = state.ci_base(ci); }
1706 let i: Instruction = code[pc as usize];
1707 pc += 1;
1708 let op = i.opcode();
1709 #[cfg(feature = "opcode-profile")]
1710 crate::opcode_profile::record(op);
1711
1712 debug_assert!(base == state.ci_base(ci));
1713
1714 #[cfg(debug_assertions)]
1718 {
1719 let op_mode = op_mode_byte(op);
1720 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1721 state.set_top(base);
1722 }
1723 }
1724
1725 match op {
1726 OpCode::Move => {
1728 let ra = base + i.arg_a();
1729 let rb = base + i.arg_b();
1730 let v = state.stack[rb.0 as usize].val;
1731 state.stack[ra.0 as usize].val = v;
1732 }
1733 OpCode::LoadI => {
1735 let ra = base + i.arg_a();
1736 let b = i.arg_s_bx() as i64;
1737 state.stack[ra.0 as usize].val = LuaValue::Int(b);
1738 }
1739 OpCode::LoadF => {
1741 let ra = base + i.arg_a();
1742 let b = i.arg_s_bx() as f64;
1743 state.stack[ra.0 as usize].val = LuaValue::Float(b);
1744 }
1745 OpCode::LoadK => {
1747 let ra = base + i.arg_a();
1748 let k_idx = i.arg_bx() as usize;
1749 state.stack[ra.0 as usize].val = constants[k_idx];
1750 }
1751 OpCode::LoadKX => {
1753 let ra = base + i.arg_a();
1754 let extra = code[pc as usize];
1755 pc += 1;
1756 let k_idx = extra.arg_ax() as usize;
1757 state.stack[ra.0 as usize].val = constants[k_idx];
1758 }
1759 OpCode::LoadFalse => {
1761 let ra = base + i.arg_a();
1762 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
1763 }
1764 OpCode::LFalseSkip => {
1766 let ra = base + i.arg_a();
1767 state.stack[ra.0 as usize].val = LuaValue::Bool(false);
1768 pc += 1;
1769 }
1770 OpCode::LoadTrue => {
1772 let ra = base + i.arg_a();
1773 state.stack[ra.0 as usize].val = LuaValue::Bool(true);
1774 }
1775 OpCode::LoadNil => {
1777 let ra = base + i.arg_a();
1778 let b = i.arg_b();
1779 for k in 0..=b {
1780 state.stack[(ra + k).0 as usize].val = LuaValue::Nil;
1781 }
1782 }
1783 OpCode::GetUpVal => {
1785 let ra = base + i.arg_a();
1786 let b = i.arg_b() as usize;
1787 let uv = cl.upval(b);
1788 let v = match uv.try_open_payload() {
1789 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1790 state.stack[idx.0 as usize].val
1791 }
1792 Some(_) => state.upvalue_get(&cl, b),
1793 None => uv.closed_value(),
1794 };
1795 state.stack[ra.0 as usize].val = v;
1796 }
1797 OpCode::SetUpVal => {
1800 let ra = base + i.arg_a();
1801 let b = i.arg_b() as usize;
1802 let v = state.stack[ra.0 as usize].val;
1803 let uv = cl.upval(b);
1804 match uv.try_open_payload() {
1805 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1806 state.stack[idx.0 as usize].val = v;
1807 if v.is_collectable() {
1808 state.gc_barrier_upval(&uv, &v);
1809 }
1810 }
1811 None => {
1812 uv.set_closed_value(v);
1813 if v.is_collectable() {
1814 state.gc_barrier_upval(&uv, &v);
1815 }
1816 }
1817 _ => {
1818 state.upvalue_set(&cl, b, v)?;
1819 }
1820 }
1821 }
1822 OpCode::GetTabUp => {
1826 let ra = base + i.arg_a();
1827 let b = i.arg_b() as usize;
1828 let k_idx = i.arg_c() as usize;
1829 let upval = state.upvalue_get(&cl, b);
1830 let key = constants[k_idx];
1831 match state.fast_get_short_str(&upval, &key)? {
1832 Some(v) => state.set_at(ra, v),
1833 None => {
1834 state.set_ci_savedpc(ci, pc);
1835 state.set_top(state.ci_top(ci));
1836 finish_get(state, upval, key, ra, true, None)?;
1837 trap = state.ci_trap(ci);
1838 }
1839 }
1840 }
1841 OpCode::GetTable => {
1844 let ra = base + i.arg_a();
1845 let rb_idx = base + i.arg_b();
1846 let rb_v = state.get_at(rb_idx);
1847 let rc_v = state.get_at(base + i.arg_c());
1848 let fast_result = if let LuaValue::Int(n) = &rc_v {
1849 state.fast_get_int(&rb_v, *n)?
1850 } else {
1851 state.fast_get(&rb_v, &rc_v)?
1852 };
1853 match fast_result {
1854 Some(v) => state.set_at(ra, v),
1855 None => {
1856 state.set_ci_savedpc(ci, pc);
1857 state.set_top(state.ci_top(ci));
1858 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1859 trap = state.ci_trap(ci);
1860 }
1861 }
1862 }
1863 OpCode::GetI => {
1867 let ra = base + i.arg_a();
1868 let rb_idx = base + i.arg_b();
1869 let rb_v = state.get_at(rb_idx);
1870 let c = i.arg_c() as i64;
1871 match state.fast_get_int(&rb_v, c)? {
1872 Some(v) => state.set_at(ra, v),
1873 None => {
1874 let key = LuaValue::Int(c);
1875 state.set_ci_savedpc(ci, pc);
1876 state.set_top(state.ci_top(ci));
1877 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1878 trap = state.ci_trap(ci);
1879 }
1880 }
1881 }
1882 OpCode::GetField => {
1884 let ra = base + i.arg_a();
1885 let rb_idx = base + i.arg_b();
1886 let rb_v = state.get_at(rb_idx);
1887 let k_idx = i.arg_c() as usize;
1888 let key = constants[k_idx];
1889 match state.fast_get_short_str(&rb_v, &key)? {
1890 Some(v) => state.set_at(ra, v),
1891 None => {
1892 state.set_ci_savedpc(ci, pc);
1893 state.set_top(state.ci_top(ci));
1894 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1895 trap = state.ci_trap(ci);
1896 }
1897 }
1898 }
1899 OpCode::SetTabUp => {
1901 let a = i.arg_a() as usize;
1902 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1904 constants[i.arg_c() as usize]
1905 } else {
1906 state.get_at(base + i.arg_c())
1907 };
1908 let upval = state.upvalue_get(&cl, a);
1909 let key = constants[b_idx];
1910 match state.fast_get_short_str(&upval, &key)? {
1911 Some(_slot) => {
1912 state.table_raw_set(&upval, key, rc_v.clone())?;
1913 state.gc_value_barrier_back(&upval, &rc_v);
1914 }
1915 None => {
1916 state.set_ci_savedpc(ci, pc);
1917 state.set_top(state.ci_top(ci));
1918 let upval_name: Vec<u8> = cl
1919 .proto
1920 .upvalues
1921 .get(a)
1922 .and_then(|uv| uv.name.as_ref())
1923 .map(|s| s.as_bytes().to_vec())
1924 .unwrap_or_else(|| b"?".to_vec());
1925 let hint: Option<(&[u8], &[u8])> =
1926 Some((b"upvalue", &upval_name));
1927 finish_set(state, upval, key, rc_v, false, None, hint)?;
1928 trap = state.ci_trap(ci);
1929 }
1930 }
1931 }
1932 OpCode::SetTable => {
1934 let ra_idx = base + i.arg_a();
1935 let ra_v = state.get_at(ra_idx);
1936 let rb_v = state.get_at(base + i.arg_b());
1937 let rc_v = if i.test_k() {
1938 constants[i.arg_c() as usize]
1939 } else {
1940 state.get_at(base + i.arg_c())
1941 };
1942 if let LuaValue::Table(tbl) = ra_v {
1943 if tbl.metatable().is_none() {
1944 state.gc_table_barrier_back(&tbl, &rc_v);
1945 tbl.raw_set(state, rb_v, rc_v)?;
1946 } else {
1947 let fast = if let LuaValue::Int(n) = &rb_v {
1948 state.fast_get_int(&ra_v, *n)?
1949 } else {
1950 state.fast_get(&ra_v, &rb_v)?
1951 };
1952 if fast.is_some() {
1953 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1954 state.gc_value_barrier_back(&ra_v, &rc_v);
1955 } else {
1956 state.set_ci_savedpc(ci, pc);
1957 state.set_top(state.ci_top(ci));
1958 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1959 trap = state.ci_trap(ci);
1960 }
1961 }
1962 } else {
1963 state.set_ci_savedpc(ci, pc);
1964 state.set_top(state.ci_top(ci));
1965 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1966 trap = state.ci_trap(ci);
1967 }
1968 }
1969 OpCode::SetI => {
1971 let ra_idx = base + i.arg_a();
1972 let ra_v = state.get_at(ra_idx);
1973 let c = i.arg_b() as i64;
1974 let rc_v = if i.test_k() {
1975 constants[i.arg_c() as usize]
1976 } else {
1977 state.get_at(base + i.arg_c())
1978 };
1979 if let LuaValue::Table(tbl) = ra_v {
1980 if tbl.metatable().is_none() {
1981 state.gc_table_barrier_back(&tbl, &rc_v);
1982 tbl.raw_set_int(state, c, rc_v)?;
1983 } else {
1984 let fast = state.fast_get_int(&ra_v, c)?;
1985 if fast.is_some() {
1986 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1987 state.gc_value_barrier_back(&ra_v, &rc_v);
1988 } else {
1989 state.set_ci_savedpc(ci, pc);
1990 state.set_top(state.ci_top(ci));
1991 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1992 trap = state.ci_trap(ci);
1993 }
1994 }
1995 } else {
1996 state.set_ci_savedpc(ci, pc);
1997 state.set_top(state.ci_top(ci));
1998 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1999 trap = state.ci_trap(ci);
2000 }
2001 }
2002 OpCode::SetField => {
2004 let ra_idx = base + i.arg_a();
2005 let ra_v = state.get_at(ra_idx);
2006 let b_idx = i.arg_b() as usize;
2007 let key = constants[b_idx];
2008 let rc_v = if i.test_k() {
2009 constants[i.arg_c() as usize]
2010 } else {
2011 state.get_at(base + i.arg_c())
2012 };
2013 if let LuaValue::Table(tbl) = ra_v {
2014 if tbl.metatable().is_none() {
2015 state.gc_table_barrier_back(&tbl, &rc_v);
2016 tbl.raw_set(state, key, rc_v)?;
2017 } else {
2018 match state.fast_get_short_str(&ra_v, &key)? {
2019 Some(_) => {
2020 state.table_raw_set(&ra_v, key, rc_v.clone())?;
2021 state.gc_value_barrier_back(&ra_v, &rc_v);
2022 }
2023 None => {
2024 state.set_ci_savedpc(ci, pc);
2025 state.set_top(state.ci_top(ci));
2026 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
2027 trap = state.ci_trap(ci);
2028 }
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, key, rc_v, false, Some(ra_idx), None)?;
2035 trap = state.ci_trap(ci);
2036 }
2037 }
2038 OpCode::NewTable => {
2041 let ra = base + i.arg_a();
2042 let mut b = i.arg_b();
2043 let mut c = i.arg_c();
2044 if b > 0 {
2045 b = 1 << (b - 1);
2046 }
2047 if i.test_k() {
2048 let extra = code[pc as usize];
2049 pc += 1;
2050 const MAXARG_C: i32 = (1 << 8) - 1;
2051 c += extra.arg_ax() * (MAXARG_C + 1);
2052 } else {
2053 pc += 1; }
2055 state.set_top(ra + 1);
2056 let t = if b != 0 || c != 0 {
2057 state.new_table_with_sizes(c as u32, b as u32)?
2058 } else {
2059 state.new_table()
2060 };
2061 state.set_at(ra, LuaValue::Table(t.clone()));
2062 state.set_ci_savedpc(ci, pc);
2063 state.set_top(ra + 1);
2064 state.gc_cond_step();
2065 if state.hookmask != 0 {
2066 trap = state.ci_trap(ci);
2067 }
2068 }
2069 OpCode::Self_ => {
2071 let ra = base + i.arg_a();
2072 let rb_idx = base + i.arg_b();
2073 let rb_v = state.get_at(rb_idx);
2074 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
2076 constants[k_idx]
2077 } else {
2078 state.get_at(base + i.arg_c())
2079 };
2080 state.set_at(ra + 1, rb_v.clone());
2081 match state.fast_get_short_str(&rb_v, &key)? {
2082 Some(v) => state.set_at(ra, v),
2083 None => {
2084 state.set_ci_savedpc(ci, pc);
2085 state.set_top(state.ci_top(ci));
2086 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
2087 trap = state.ci_trap(ci);
2088 }
2089 }
2090 }
2091 OpCode::AddI => {
2093 let ra = base + i.arg_a();
2094 let rb = base + i.arg_b();
2095 let imm = i.arg_s_c() as i64;
2096 let rb_v = state.stack[rb.0 as usize].val;
2097 match rb_v {
2098 LuaValue::Int(iv1) => {
2099 pc += 1;
2100 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
2101 }
2102 LuaValue::Float(nb) => {
2103 pc += 1;
2104 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
2105 }
2106 _ => {}
2107 }
2108 }
2109 OpCode::AddK => {
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(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2115 pc += 1;
2116 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
2117 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2118 pc += 1;
2119 state.set_at(ra, LuaValue::Float(n1 + n2));
2120 }
2121 }
2122 OpCode::SubK => {
2123 let ra = base + i.arg_a();
2124 let rb = base + i.arg_b();
2125 let kidx = i.arg_c() as usize;
2126 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2127 pc += 1;
2128 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
2129 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2130 pc += 1;
2131 state.set_at(ra, LuaValue::Float(n1 - n2));
2132 }
2133 }
2134 OpCode::MulK => {
2135 let ra = base + i.arg_a();
2136 let rb = base + i.arg_b();
2137 let kidx = i.arg_c() as usize;
2138 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
2139 pc += 1;
2140 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2141 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2142 pc += 1;
2143 state.set_at(ra, LuaValue::Float(n1 * n2));
2144 }
2145 }
2146 OpCode::ModK => {
2147 let ra = base + i.arg_a();
2148 let v1 = state.get_at(base + i.arg_b());
2149 let v2 = constants[i.arg_c() as usize];
2150 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
2152 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2153 |a, b| imod(a, b), fmodf)?;
2154 }
2155 OpCode::PowK => {
2156 let ra = base + i.arg_a();
2157 let rb = base + i.arg_b();
2158 let kidx = i.arg_c() as usize;
2159 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2160 pc += 1;
2161 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2162 state.set_at(ra, LuaValue::Float(r));
2163 }
2164 }
2165 OpCode::DivK => {
2166 let ra = base + i.arg_a();
2167 let rb = base + i.arg_b();
2168 let kidx = i.arg_c() as usize;
2169 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
2170 pc += 1;
2171 state.set_at(ra, LuaValue::Float(n1 / n2));
2172 }
2173 }
2174 OpCode::IDivK => {
2175 let ra = base + i.arg_a();
2176 let v1 = state.get_at(base + i.arg_b());
2177 let v2 = constants[i.arg_c() as usize];
2178 state.set_ci_savedpc(ci, pc);
2179 state.set_top(state.ci_top(ci));
2180 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2181 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2182 }
2183 OpCode::BAndK => {
2184 let ra = base + i.arg_a();
2185 let v1 = state.get_at(base + i.arg_b());
2186 let v2 = constants[i.arg_c() as usize];
2187 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
2188 }
2189 OpCode::BOrK => {
2190 let ra = base + i.arg_a();
2191 let v1 = state.get_at(base + i.arg_b());
2192 let v2 = constants[i.arg_c() as usize];
2193 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
2194 }
2195 OpCode::BXOrK => {
2196 let ra = base + i.arg_a();
2197 let v1 = state.get_at(base + i.arg_b());
2198 let v2 = constants[i.arg_c() as usize];
2199 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
2200 }
2201 OpCode::ShrI => {
2202 let ra = base + i.arg_a();
2203 let v = state.get_at(base + i.arg_b());
2204 let ic = i.arg_s_c() as i64;
2205 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2206 pc += 1;
2207 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
2208 }
2209 }
2210 OpCode::ShlI => {
2211 let ra = base + i.arg_a();
2212 let v = state.get_at(base + i.arg_b());
2213 let ic = i.arg_s_c() as i64;
2214 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2215 pc += 1;
2216 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2217 }
2218 }
2219 OpCode::Add => {
2221 let ra = base + i.arg_a();
2222 let rb = base + i.arg_b();
2223 let rc = base + i.arg_c();
2224 let ra_u = ra.0 as usize;
2225 let rb_v = state.stack[rb.0 as usize].val;
2226 let rc_v = state.stack[rc.0 as usize].val;
2227 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2228 pc += 1;
2229 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2230 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2231 pc += 1;
2232 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2233 }
2234 }
2235 OpCode::Sub => {
2236 let ra = base + i.arg_a();
2237 let rb = base + i.arg_b();
2238 let rc = base + i.arg_c();
2239 let ra_u = ra.0 as usize;
2240 let rb_v = state.stack[rb.0 as usize].val;
2241 let rc_v = state.stack[rc.0 as usize].val;
2242 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2243 pc += 1;
2244 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2245 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2246 pc += 1;
2247 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2248 }
2249 }
2250 OpCode::Mul => {
2251 let ra = base + i.arg_a();
2252 let rb = base + i.arg_b();
2253 let rc = base + i.arg_c();
2254 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2255 pc += 1;
2256 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2257 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2258 pc += 1;
2259 state.set_at(ra, LuaValue::Float(n1 * n2));
2260 }
2261 }
2262 OpCode::Mod => {
2263 let ra = base + i.arg_a();
2264 let v1 = state.get_at(base + i.arg_b());
2265 let v2 = state.get_at(base + i.arg_c());
2266 state.set_ci_savedpc(ci, pc);
2267 state.set_top(state.ci_top(ci));
2268 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2269 |a, b| imod(a, b), fmodf)?;
2270 }
2271 OpCode::Pow => {
2272 let ra = base + i.arg_a();
2273 let rb = base + i.arg_b();
2274 let rc = base + i.arg_c();
2275 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2276 pc += 1;
2277 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2278 state.set_at(ra, LuaValue::Float(r));
2279 }
2280 }
2281 OpCode::Div => {
2282 let ra = base + i.arg_a();
2283 let rb = base + i.arg_b();
2284 let rc = base + i.arg_c();
2285 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2286 pc += 1;
2287 state.set_at(ra, LuaValue::Float(n1 / n2));
2288 }
2289 }
2290 OpCode::IDiv => {
2291 let ra = base + i.arg_a();
2292 let v1 = state.get_at(base + i.arg_b());
2293 let v2 = state.get_at(base + i.arg_c());
2294 state.set_ci_savedpc(ci, pc);
2295 state.set_top(state.ci_top(ci));
2296 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2297 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2298 }
2299 OpCode::BAnd => {
2302 let ra = base + i.arg_a();
2303 let v1 = state.get_at(base + i.arg_b());
2304 let v2 = state.get_at(base + i.arg_c());
2305 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2306 }
2307 OpCode::BOr => {
2308 let ra = base + i.arg_a();
2309 let v1 = state.get_at(base + i.arg_b());
2310 let v2 = state.get_at(base + i.arg_c());
2311 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2312 }
2313 OpCode::BXOr => {
2314 let ra = base + i.arg_a();
2315 let v1 = state.get_at(base + i.arg_b());
2316 let v2 = state.get_at(base + i.arg_c());
2317 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2318 }
2319 OpCode::Shr => {
2320 let ra = base + i.arg_a();
2321 let v1 = state.get_at(base + i.arg_b());
2322 let v2 = state.get_at(base + i.arg_c());
2323 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2324 }
2325 OpCode::Shl => {
2326 let ra = base + i.arg_a();
2327 let v1 = state.get_at(base + i.arg_b());
2328 let v2 = state.get_at(base + i.arg_c());
2329 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2330 }
2331 OpCode::MmBin => {
2336 let ra_idx = base + i.arg_a();
2337 let rb_idx = base + i.arg_b();
2338 let ra_v = state.get_at(ra_idx);
2339 let rb_v = state.get_at(rb_idx);
2340 let tm = tagmethod_from_index(i.arg_c() as usize);
2341 let prev_inst = code[(pc - 2) as usize];
2342 let result_idx = base + prev_inst.arg_a();
2343 state.set_ci_savedpc(ci, pc);
2344 state.set_top(state.ci_top(ci));
2345 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2346 trap = state.ci_trap(ci);
2347 }
2348 OpCode::MmBinI => {
2349 let ra_idx = base + i.arg_a();
2350 let ra_v = state.get_at(ra_idx);
2351 let imm = i.arg_s_b() as i64;
2352 let tm = tagmethod_from_index(i.arg_c() as usize);
2353 let flip = i.arg_k() != 0;
2354 let prev_inst = code[(pc - 2) as usize];
2355 let result_idx = base + prev_inst.arg_a();
2356 state.set_ci_savedpc(ci, pc);
2357 state.set_top(state.ci_top(ci));
2358 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2359 trap = state.ci_trap(ci);
2360 }
2361 OpCode::MmBinK => {
2362 let ra_idx = base + i.arg_a();
2363 let ra_v = state.get_at(ra_idx);
2364 let imm = constants[i.arg_b() as usize];
2365 let tm = tagmethod_from_index(i.arg_c() as usize);
2366 let flip = i.arg_k() != 0;
2367 let prev_inst = code[(pc - 2) as usize];
2368 let result_idx = base + prev_inst.arg_a();
2369 state.set_ci_savedpc(ci, pc);
2370 state.set_top(state.ci_top(ci));
2371 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2372 trap = state.ci_trap(ci);
2373 }
2374 OpCode::Unm => {
2378 let ra = base + i.arg_a();
2379 let rb_idx = base + i.arg_b();
2380 let rb_v = state.get_at(rb_idx);
2381 match &rb_v {
2382 LuaValue::Int(ib) => {
2383 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2384 }
2385 LuaValue::Float(nb) => {
2386 state.set_at(ra, LuaValue::Float(-nb));
2387 }
2388 _ => {
2389 state.set_ci_savedpc(ci, pc);
2390 state.set_top(state.ci_top(ci));
2391 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2392 trap = state.ci_trap(ci);
2393 }
2394 }
2395 }
2396 OpCode::BNot => {
2398 let ra = base + i.arg_a();
2399 let rb_idx = base + i.arg_b();
2400 let rb_v = state.get_at(rb_idx);
2401 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2402 state.set_at(ra, LuaValue::Int(!ib));
2403 } else {
2404 state.set_ci_savedpc(ci, pc);
2405 state.set_top(state.ci_top(ci));
2406 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2407 trap = state.ci_trap(ci);
2408 }
2409 }
2410 OpCode::Not => {
2412 let ra = base + i.arg_a();
2413 let rb_v = state.get_at(base + i.arg_b());
2414 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2415 state.set_at(ra, LuaValue::Bool(falsy));
2416 }
2417 OpCode::Len => {
2419 let ra = base + i.arg_a();
2420 let rb_idx = base + i.arg_b();
2421 let rb_v = state.get_at(rb_idx);
2422 state.set_ci_savedpc(ci, pc);
2423 state.set_top(state.ci_top(ci));
2424 obj_len(state, ra, rb_v, rb_idx)?;
2425 trap = state.ci_trap(ci);
2426 }
2427 OpCode::Concat => {
2429 let ra = base + i.arg_a();
2430 let n = i.arg_b() as i32;
2431 state.set_top(ra + n as i32);
2432 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2434 let top = state.top_idx();
2435 state.set_ci_savedpc(ci, pc);
2436 state.set_top(top);
2437 state.gc_cond_step();
2438 trap = state.ci_trap(ci);
2439 }
2440 OpCode::Close => {
2442 let ra = base + i.arg_a();
2443 state.set_ci_savedpc(ci, pc);
2444 state.set_top(state.ci_top(ci));
2445 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2446 trap = state.ci_trap(ci);
2447 }
2448 OpCode::Tbc => {
2450 let ra = base + i.arg_a();
2451 state.set_ci_savedpc(ci, pc);
2452 state.set_top(state.ci_top(ci));
2453 state.new_tbc_upval(ra)?;
2454 }
2455 OpCode::Jmp => {
2457 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2458 trap = state.ci_trap(ci);
2459 }
2460 OpCode::Eq => {
2462 let ra_v = state.get_at(base + i.arg_a());
2463 let rb_v = state.get_at(base + i.arg_b());
2464 state.set_ci_savedpc(ci, pc);
2465 state.set_top(state.ci_top(ci));
2466 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2467 trap = state.ci_trap(ci);
2468 if (cond as i32) != i.arg_k() {
2469 pc += 1;
2470 } else {
2471 let next = code[pc as usize];
2472 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2473 trap = state.ci_trap(ci);
2474 }
2475 }
2476 OpCode::Lt => {
2478 let ra_v = state.get_at(base + i.arg_a());
2479 let rb_v = state.get_at(base + i.arg_b());
2480 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2481 *ia < *ib
2482 } else if matches!((&ra_v, &rb_v),
2483 (LuaValue::Int(_) | LuaValue::Float(_),
2484 LuaValue::Int(_) | LuaValue::Float(_))) {
2485 lt_num(&ra_v, &rb_v)
2486 } else {
2487 state.set_ci_savedpc(ci, pc);
2488 state.set_top(state.ci_top(ci));
2489 let r = less_than_others(state, &ra_v, &rb_v)?;
2490 trap = state.ci_trap(ci);
2491 r
2492 };
2493 if (cond as i32) != i.arg_k() {
2494 pc += 1;
2495 } else {
2496 let next = code[pc as usize];
2497 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2498 trap = state.ci_trap(ci);
2499 }
2500 }
2501 OpCode::Le => {
2503 let ra_v = state.get_at(base + i.arg_a());
2504 let rb_v = state.get_at(base + i.arg_b());
2505 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2506 *ia <= *ib
2507 } else if matches!((&ra_v, &rb_v),
2508 (LuaValue::Int(_) | LuaValue::Float(_),
2509 LuaValue::Int(_) | LuaValue::Float(_))) {
2510 le_num(&ra_v, &rb_v)
2511 } else {
2512 state.set_ci_savedpc(ci, pc);
2513 state.set_top(state.ci_top(ci));
2514 let r = less_equal_others(state, &ra_v, &rb_v)?;
2515 trap = state.ci_trap(ci);
2516 r
2517 };
2518 if (cond as i32) != i.arg_k() {
2519 pc += 1;
2520 } else {
2521 let next = code[pc as usize];
2522 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2523 trap = state.ci_trap(ci);
2524 }
2525 }
2526 OpCode::EqK => {
2528 let ra_v = state.get_at(base + i.arg_a());
2529 let rb_v = constants[i.arg_b() as usize];
2530 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2531 if (cond as i32) != i.arg_k() {
2532 pc += 1;
2533 } else {
2534 let next = code[pc as usize];
2535 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2536 trap = state.ci_trap(ci);
2537 }
2538 }
2539 OpCode::EqI => {
2544 let ra_v = state.get_at(base + i.arg_a());
2545 let im = i.arg_s_b() as i64;
2546 let cond: bool = match &ra_v {
2547 LuaValue::Int(iv) => *iv == im,
2548 LuaValue::Float(fv) => *fv == im as f64,
2549 _ => false,
2550 };
2551 if (cond as i32) != i.arg_k() {
2552 pc += 1;
2553 } else {
2554 let next = code[pc as usize];
2555 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2556 trap = state.ci_trap(ci);
2557 }
2558 }
2559 OpCode::LtI => {
2562 let ra = base + i.arg_a();
2563 let im = i.arg_s_b() as i64;
2564 let fast_cond = match &state.stack[ra.0 as usize].val {
2565 LuaValue::Int(ia) => Some(*ia < im),
2566 LuaValue::Float(fa) => Some(*fa < im as f64),
2567 _ => None,
2568 };
2569 let cond = match fast_cond {
2570 Some(cond) => cond,
2571 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2572 };
2573 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2574 }
2575 OpCode::LeI => {
2576 let ra = base + i.arg_a();
2577 let im = i.arg_s_b() as i64;
2578 let fast_cond = match &state.stack[ra.0 as usize].val {
2579 LuaValue::Int(ia) => Some(*ia <= im),
2580 LuaValue::Float(fa) => Some(*fa <= im as f64),
2581 _ => None,
2582 };
2583 let cond = match fast_cond {
2584 Some(cond) => cond,
2585 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2586 };
2587 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2588 }
2589 OpCode::GtI => {
2590 let ra = base + i.arg_a();
2591 let im = i.arg_s_b() as i64;
2592 let fast_cond = match &state.stack[ra.0 as usize].val {
2593 LuaValue::Int(ia) => Some(*ia > im),
2594 LuaValue::Float(fa) => Some(*fa > im as f64),
2595 _ => None,
2596 };
2597 let cond = match fast_cond {
2598 Some(cond) => cond,
2599 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2600 };
2601 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2602 }
2603 OpCode::GeI => {
2604 let ra = base + i.arg_a();
2605 let im = i.arg_s_b() as i64;
2606 let fast_cond = match &state.stack[ra.0 as usize].val {
2607 LuaValue::Int(ia) => Some(*ia >= im),
2608 LuaValue::Float(fa) => Some(*fa >= im as f64),
2609 _ => None,
2610 };
2611 let cond = match fast_cond {
2612 Some(cond) => cond,
2613 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2614 };
2615 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2616 }
2617 OpCode::Test => {
2619 let ra_v = state.get_at(base + i.arg_a());
2620 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2621 if (cond as i32) != i.arg_k() {
2622 pc += 1;
2623 } else {
2624 let next = code[pc as usize];
2625 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2626 trap = state.ci_trap(ci);
2627 }
2628 }
2629 OpCode::TestSet => {
2632 let ra = base + i.arg_a();
2633 let rb_v = state.get_at(base + i.arg_b());
2634 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2635 if (falsy as i32) == i.arg_k() {
2636 pc += 1;
2637 } else {
2638 state.set_at(ra, rb_v);
2639 let next = code[pc as usize];
2640 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2641 trap = state.ci_trap(ci);
2642 }
2643 }
2644 OpCode::Call => {
2648 let ra = base + i.arg_a();
2649 let b = i.arg_b();
2650 let nresults = i.arg_c() as i32 - 1;
2651 if b != 0 {
2652 state.set_top(ra + b);
2653 }
2654 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2656 match state.precall(ra, nresults)? {
2657 None => {
2658 if had_hook || state.hookmask != 0 {
2662 trap = state.ci_trap(ci); }
2664 }
2665 Some(new_ci) => {
2666 ci = new_ci;
2668 continue 'startfunc;
2669 }
2670 }
2671 }
2672 OpCode::TailCall => {
2677 let ra = base + i.arg_a();
2678 let b = i.arg_b();
2679 let nparams1 = i.arg_c();
2680 let delta = if nparams1 != 0 {
2681 state.ci_nextraargs(ci) + nparams1 as i32
2682 } else {
2683 0
2684 };
2685 let top_b: i32 = if b != 0 {
2686 state.set_top(ra + b);
2687 b
2688 } else {
2689 state.top_idx() - ra
2690 };
2691 state.set_ci_savedpc(ci, pc);
2692 if i.test_k() {
2693 state.close_upvals_from_base(ci)?;
2694 }
2695 let n = state.pretailcall(ci, ra, top_b, delta)?;
2696 if n < 0 {
2697 continue 'startfunc;
2699 } else {
2700 state.ci_adjust_func(ci, delta);
2702 state.poscall(ci, n as u32)?;
2703 if state.hookmask != 0 {
2704 trap = state.ci_trap(ci);
2705 }
2706 break 'dispatch; }
2708 }
2709 OpCode::Return => {
2714 let ra = base + i.arg_a();
2715 let n_raw = i.arg_b() as i32 - 1;
2716 let nparams1 = i.arg_c();
2717 let n: u32 = if n_raw < 0 {
2718 (state.top_idx() - ra) as u32
2719 } else {
2720 n_raw as u32
2721 };
2722 state.set_ci_savedpc(ci, pc);
2723 if i.test_k() {
2724 state.ci_nres_set(ci, n as i32);
2725 let ci_top = state.ci_top(ci);
2726 if state.top_idx().0 < ci_top.0 {
2727 state.set_top(ci_top);
2728 }
2729 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2730 if state.hookmask != 0 {
2731 trap = state.ci_trap(ci);
2732 }
2733 base = state.ci_base(ci); }
2735 if nparams1 != 0 {
2736 let nextraargs = state.ci_nextraargs(ci) as u32;
2737 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2738 }
2739 state.set_top(ra + n as i32);
2740 state.poscall(ci, n)?;
2741 if state.hookmask != 0 {
2742 trap = state.ci_trap(ci);
2743 }
2744 break 'dispatch; }
2746 OpCode::Return0 => {
2752 if state.hookmask == 0 {
2753 let ci_slot = ci.as_usize();
2754 let nres = state.call_info[ci_slot].nresults as i32;
2755 state.ci = state.call_info[ci_slot]
2756 .previous
2757 .expect("RETURN0: returning frame has no previous CallInfo");
2758 state.top = base - 1;
2759 for _ in 0..nres.max(0) {
2760 state.push(LuaValue::Nil);
2761 }
2762 } else {
2763 return0_hook(state, ci, base, i, pc, &mut trap)?;
2764 }
2765 break 'dispatch; }
2767 OpCode::Return1 => {
2771 if state.hookmask == 0 {
2772 let ci_slot = ci.as_usize();
2773 let nres = state.call_info[ci_slot].nresults as i32;
2774 state.ci = state.call_info[ci_slot]
2775 .previous
2776 .expect("RETURN1: returning frame has no previous CallInfo");
2777 if nres == 0 {
2778 state.top = base - 1;
2779 } else {
2780 let ra = base + i.arg_a();
2781 state.stack[(base - 1).0 as usize].val =
2782 state.stack[ra.0 as usize].val; state.top = base;
2784 for _ in 1..nres.max(0) {
2785 state.push(LuaValue::Nil);
2786 }
2787 }
2788 } else {
2789 return1_hook(state, ci, base, i, pc, &mut trap)?;
2790 }
2791 break 'dispatch; }
2793 OpCode::ForLoop => {
2797 let ra = base + i.arg_a();
2798 if legacy_for {
2799 if forloop_legacy(state, ra) {
2800 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2801 }
2802 trap = state.ci_trap(ci);
2803 } else {
2804 let ra_u = ra.0 as usize;
2805 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2806 let count = match state.stack[ra_u + 1].val {
2807 LuaValue::Int(c) => c as u64,
2808 _ => 0,
2809 };
2810 if count > 0 {
2811 let idx = match state.stack[ra_u].val {
2812 LuaValue::Int(x) => x,
2813 _ => 0,
2814 };
2815 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2816 let new_idx = intop_add(idx, step);
2817 state.stack[ra_u].val = LuaValue::Int(new_idx);
2818 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2819 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2820 }
2821 } else if float_for_loop(state, ra) {
2822 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2823 }
2824 trap = state.ci_trap(ci);
2825 }
2826 }
2827 OpCode::ForPrep => {
2829 let ra = base + i.arg_a();
2830 state.set_ci_savedpc(ci, pc);
2831 state.set_top(state.ci_top(ci));
2832 if legacy_for {
2833 forprep_legacy(state, ra)?;
2836 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2837 } else if forprep(state, ra)? {
2838 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2839 }
2840 }
2841 OpCode::TForPrep => {
2845 let ra = base + i.arg_a();
2846 state.set_ci_savedpc(ci, pc);
2847 state.set_top(state.ci_top(ci));
2848 state.new_tbc_upval(ra + 3)?;
2849 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2850 let tfc_i = code[pc as usize];
2851 pc += 1;
2852 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2853 let tfc_ra = base + tfc_i.arg_a();
2855 for k in 0..3u32 {
2856 let v = state.get_at(tfc_ra + k as i32);
2857 state.set_at(tfc_ra + 4 + k as i32, v);
2858 }
2859 state.set_top(tfc_ra + 4 + 3);
2860 state.set_ci_savedpc(ci, pc);
2861 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2862 trap = state.ci_trap(ci);
2863 base = state.ci_base(ci); let tfl_i = code[pc as usize];
2865 pc += 1;
2866 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2867 let tfl_ra = base + tfl_i.arg_a();
2868 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2870 let v = state.get_at(tfl_ra + 4);
2871 state.set_at(tfl_ra + 2, v);
2872 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2873 }
2874 }
2875 OpCode::TForCall => {
2877 let ra = base + i.arg_a();
2878 for k in 0..3u32 {
2879 let v = state.get_at(ra + k as i32);
2880 state.set_at(ra + 4 + k as i32, v);
2881 }
2882 state.set_top(ra + 4 + 3);
2883 state.set_ci_savedpc(ci, pc);
2884 state.call_at(ra + 4, i.arg_c() as i32)?;
2885 trap = state.ci_trap(ci);
2886 base = state.ci_base(ci); let tfl_i = code[pc as usize];
2888 pc += 1;
2889 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2890 let tfl_ra = base + tfl_i.arg_a();
2891 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2892 let v = state.get_at(tfl_ra + 4);
2893 state.set_at(tfl_ra + 2, v);
2894 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2895 }
2896 }
2897 OpCode::TForLoop => {
2899 let ra = base + i.arg_a();
2900 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2901 let v = state.get_at(ra + 4);
2902 state.set_at(ra + 2, v);
2903 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2904 }
2905 }
2906 OpCode::SetList => {
2910 let ra = base + i.arg_a();
2911 let n_raw = i.arg_b();
2912 let mut last = i.arg_c();
2913 let t_val = state.get_at(ra);
2914 let n: i32 = if n_raw == 0 {
2915 state.top_idx() - ra - 1
2916 } else {
2917 state.set_top(state.ci_top(ci));
2918 n_raw
2919 };
2920 last += n;
2921 if i.test_k() {
2922 let extra = code[pc as usize];
2923 pc += 1;
2924 const MAXARG_C: i32 = (1 << 8) - 1;
2925 last += extra.arg_ax() * (MAXARG_C + 1);
2926 }
2927 state.table_ensure_array(&t_val, last as usize)?;
2928 for k in (1..=n).rev() {
2929 let val = state.get_at(ra + k as i32);
2930 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2931 last -= 1;
2932 state.gc_value_barrier_back(&t_val, &val);
2933 }
2934 }
2935 OpCode::Closure => {
2939 let ra = base + i.arg_a();
2940 let proto_idx = i.arg_bx() as usize;
2941 state.set_ci_savedpc(ci, pc);
2942 state.set_top(state.ci_top(ci));
2943 push_closure(state, proto_idx, ci, base, ra)?;
2944 state.set_ci_savedpc(ci, pc);
2946 state.set_top(ra + 1);
2947 state.gc_cond_step();
2948 trap = state.ci_trap(ci);
2949 }
2950 OpCode::VarArg => {
2952 let ra = base + i.arg_a();
2953 let n = i.arg_c() as i32 - 1;
2954 state.set_ci_savedpc(ci, pc);
2955 state.set_top(state.ci_top(ci));
2956 state.get_varargs(ci, ra, n)?;
2957 trap = state.ci_trap(ci);
2958 }
2959 OpCode::VarArgPrep => {
2963 let nparams = i.arg_a();
2964 state.set_ci_savedpc(ci, pc);
2965 state.adjust_varargs(ci, nparams, &cl)?;
2966 trap = state.ci_trap(ci);
2967 if trap {
2968 state.hook_call(ci)?;
2969 state.set_oldpc(1);
2970 }
2971 base = state.ci_base(ci);
2972 }
2973 OpCode::ExtraArg => {
2975 debug_assert!(false, "OP_EXTRAARG executed directly");
2976 }
2977 OpCode::ErrNNil => {
2982 let ra = base + i.arg_a();
2983 if !matches!(state.get_at(ra), LuaValue::Nil) {
2984 let bx = i.arg_bx();
2985 let name: Vec<u8> = if bx == 0 {
2986 b"?".to_vec()
2987 } else {
2988 match constants[(bx - 1) as usize] {
2989 LuaValue::Str(s) => s.as_bytes().to_vec(),
2990 _ => b"?".to_vec(),
2991 }
2992 };
2993 let mut msg = Vec::with_capacity(name.len() + 24);
2994 msg.extend_from_slice(b"global '");
2995 msg.extend_from_slice(&name);
2996 msg.extend_from_slice(b"' already defined");
2997 state.set_ci_savedpc(ci, pc);
2998 return Err(crate::debug::prefixed_runtime_pub(state, msg));
2999 }
3000 }
3001 OpCode::VarArgPack => {
3009 let ra = base + i.arg_a();
3010 let nextra = state.ci_nextraargs(ci);
3011 let ci_func: StackIdx = state.ci_base(ci) - 1;
3012 let t = if nextra > 0 {
3013 state.new_table_with_sizes(nextra as u32, 1)?
3014 } else {
3015 state.new_table()
3016 };
3017 for k in 0..nextra {
3018 let src: StackIdx = ci_func - nextra as i32 + k as i32;
3019 let val = state.get_at(src);
3020 t.raw_set_int(state, (k + 1) as i64, val)?;
3021 }
3022 let n_key = state.intern_str(b"n")?;
3023 t.raw_set(state, LuaValue::Str(n_key), LuaValue::Int(nextra as i64))?;
3024 state.set_at(ra, LuaValue::Table(t));
3025 state.set_ci_savedpc(ci, pc);
3026 state.gc_cond_step();
3027 if state.hookmask != 0 {
3028 trap = state.ci_trap(ci);
3029 }
3030 }
3031 } } if state.ci_is_fresh(ci) {
3036 return Ok(());
3037 } else {
3038 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
3039 continue 'returning;
3040 }
3041 } } }
3044
3045#[inline(always)]
3048fn number_value(v: LuaValue) -> Option<f64> {
3049 match v {
3050 LuaValue::Float(f) => Some(f),
3051 LuaValue::Int(i) => Some(i as f64),
3052 _ => None,
3053 }
3054}
3055
3056#[allow(dead_code)]
3058#[inline]
3059fn arith_op_aux_rr(
3060 state: &mut LuaState,
3061 ra: StackIdx,
3062 v1: &LuaValue,
3063 v2: &LuaValue,
3064 pc: &mut u32,
3065 iop: fn(i64, i64) -> i64,
3066 fop: fn(f64, f64) -> f64,
3067) {
3068 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3069 *pc += 1;
3070 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
3071 } else {
3072 arith_float_aux(state, ra, v1, v2, pc, fop);
3073 }
3074}
3075
3076#[allow(dead_code)]
3077#[inline]
3078fn arith_float_aux(
3079 state: &mut LuaState,
3080 ra: StackIdx,
3081 v1: &LuaValue,
3082 v2: &LuaValue,
3083 pc: &mut u32,
3084 fop: fn(f64, f64) -> f64,
3085) {
3086 let n1 = match v1 {
3087 LuaValue::Float(f) => Some(*f),
3088 LuaValue::Int(i) => Some(*i as f64),
3089 _ => None,
3090 };
3091 let n2 = match v2 {
3092 LuaValue::Float(f) => Some(*f),
3093 LuaValue::Int(i) => Some(*i as f64),
3094 _ => None,
3095 };
3096 if let (Some(n1), Some(n2)) = (n1, n2) {
3097 *pc += 1;
3098 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
3099 }
3100}
3101
3102#[allow(dead_code)]
3103#[inline]
3104fn arith_op_checked(
3105 state: &mut LuaState,
3106 ra: StackIdx,
3107 v1: &LuaValue,
3108 v2: &LuaValue,
3109 pc: &mut u32,
3110 iop: fn(i64, i64) -> Result<i64, LuaError>,
3111 fop: fn(f64, f64) -> f64,
3112) -> Result<(), LuaError> {
3113 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
3114 *pc += 1;
3115 let result = iop(*i1, *i2).map_err(|e| match e {
3116 LuaError::Runtime(LuaValue::Str(s)) => {
3117 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
3118 }
3119 other => other,
3120 })?;
3121 state.set_at(ra, LuaValue::Int(result));
3122 } else {
3123 arith_float_aux(state, ra, v1, v2, pc, fop);
3124 }
3125 Ok(())
3126}
3127
3128#[allow(dead_code)]
3129#[inline]
3130fn bitwise_op_k(
3131 state: &mut LuaState,
3132 ra: StackIdx,
3133 v1: &LuaValue,
3134 v2: &LuaValue, pc: &mut u32,
3136 op: fn(i64, i64) -> i64,
3137) {
3138 let i2 = match v2 {
3139 LuaValue::Int(i) => *i,
3140 _ => return,
3141 };
3142 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
3143 *pc += 1;
3144 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3145 }
3146}
3147
3148#[allow(dead_code)]
3149#[inline]
3150fn bitwise_op_rr(
3151 state: &mut LuaState,
3152 ra: StackIdx,
3153 v1: &LuaValue,
3154 v2: &LuaValue,
3155 pc: &mut u32,
3156 op: fn(i64, i64) -> i64,
3157) {
3158 if let (Some(i1), Some(i2)) = (
3159 to_integer_ns(v1, F2Imod::Eq),
3160 to_integer_ns(v2, F2Imod::Eq),
3161 ) {
3162 *pc += 1;
3163 state.set_at(ra, LuaValue::Int(op(i1, i2)));
3164 }
3165}
3166
3167#[allow(dead_code)]
3169#[inline]
3170fn bitwise_shift_rr(
3171 state: &mut LuaState,
3172 ra: StackIdx,
3173 v1: &LuaValue,
3174 v2: &LuaValue,
3175 pc: &mut u32,
3176 right: bool,
3177) {
3178 if let (Some(i1), Some(i2)) = (
3179 to_integer_ns(v1, F2Imod::Eq),
3180 to_integer_ns(v2, F2Imod::Eq),
3181 ) {
3182 let y = if right { intop_sub(0, i2) } else { i2 };
3183 *pc += 1;
3184 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
3185 }
3186}
3187
3188#[cold]
3191#[inline(never)]
3192#[allow(clippy::too_many_arguments)]
3193fn order_imm_slow(
3194 state: &mut LuaState,
3195 ra: StackIdx,
3196 pc: u32,
3197 trap: &mut bool,
3198 ci: CallInfoIdx,
3199 i: Instruction,
3200 im: i64,
3201 inv: bool,
3202 tm: TagMethod,
3203) -> Result<bool, LuaError> {
3204 let ra_v = state.get_at(ra);
3205 let isf = i.arg_c() != 0;
3206 state.set_ci_savedpc(ci, pc);
3207 state.set_top(state.ci_top(ci));
3208 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
3209 *trap = state.ci_trap(ci);
3210 Ok(r)
3211}
3212
3213#[inline(always)]
3214fn finish_order_imm_jump(
3215 state: &mut LuaState,
3216 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
3217 pc: &mut u32,
3218 trap: &mut bool,
3219 ci: CallInfoIdx,
3220 i: Instruction,
3221 cond: bool,
3222) {
3223 if (cond as i32) != i.arg_k() {
3224 *pc += 1;
3225 } else {
3226 let next = state.proto_code(&cl, *pc);
3227 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
3228 *trap = state.ci_trap(ci);
3229 }
3230}
3231
3232#[cold]
3233#[inline(never)]
3234fn return0_hook(
3235 state: &mut LuaState,
3236 ci: CallInfoIdx,
3237 base: StackIdx,
3238 i: Instruction,
3239 pc: u32,
3240 trap: &mut bool,
3241) -> Result<(), LuaError> {
3242 let ra = base + i.arg_a();
3243 state.set_top(ra);
3244 state.set_ci_savedpc(ci, pc);
3245 state.poscall(ci, 0)?;
3246 *trap = true;
3247 Ok(())
3248}
3249
3250#[cold]
3251#[inline(never)]
3252fn return1_hook(
3253 state: &mut LuaState,
3254 ci: CallInfoIdx,
3255 base: StackIdx,
3256 i: Instruction,
3257 pc: u32,
3258 trap: &mut bool,
3259) -> Result<(), LuaError> {
3260 let ra = base + i.arg_a();
3261 state.set_top(ra + 1);
3262 state.set_ci_savedpc(ci, pc);
3263 state.poscall(ci, 1)?;
3264 *trap = true;
3265 Ok(())
3266}
3267
3268