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}
144
145#[allow(dead_code)]
149const NUM_OPCODES: u8 = 83;
150
151impl OpCode {
152 #[allow(non_upper_case_globals)]
159 pub const LoadKx: OpCode = OpCode::LoadKX;
160
161 #[allow(non_upper_case_globals)]
163 pub const GetUpval: OpCode = OpCode::GetUpVal;
164
165 pub fn from_u32(v: u32) -> Option<Self> {
169 match v {
170 0 => Some(Self::Move),
171 1 => Some(Self::LoadI),
172 2 => Some(Self::LoadF),
173 3 => Some(Self::LoadK),
174 4 => Some(Self::LoadKX),
175 5 => Some(Self::LoadFalse),
176 6 => Some(Self::LFalseSkip),
177 7 => Some(Self::LoadTrue),
178 8 => Some(Self::LoadNil),
179 9 => Some(Self::GetUpVal),
180 10 => Some(Self::SetUpVal),
181 11 => Some(Self::GetTabUp),
182 12 => Some(Self::GetTable),
183 13 => Some(Self::GetI),
184 14 => Some(Self::GetField),
185 15 => Some(Self::SetTabUp),
186 16 => Some(Self::SetTable),
187 17 => Some(Self::SetI),
188 18 => Some(Self::SetField),
189 19 => Some(Self::NewTable),
190 20 => Some(Self::Self_),
191 21 => Some(Self::AddI),
192 22 => Some(Self::AddK),
193 23 => Some(Self::SubK),
194 24 => Some(Self::MulK),
195 25 => Some(Self::ModK),
196 26 => Some(Self::PowK),
197 27 => Some(Self::DivK),
198 28 => Some(Self::IDivK),
199 29 => Some(Self::BAndK),
200 30 => Some(Self::BOrK),
201 31 => Some(Self::BXOrK),
202 32 => Some(Self::ShrI),
203 33 => Some(Self::ShlI),
204 34 => Some(Self::Add),
205 35 => Some(Self::Sub),
206 36 => Some(Self::Mul),
207 37 => Some(Self::Mod),
208 38 => Some(Self::Pow),
209 39 => Some(Self::Div),
210 40 => Some(Self::IDiv),
211 41 => Some(Self::BAnd),
212 42 => Some(Self::BOr),
213 43 => Some(Self::BXOr),
214 44 => Some(Self::Shl),
215 45 => Some(Self::Shr),
216 46 => Some(Self::MmBin),
217 47 => Some(Self::MmBinI),
218 48 => Some(Self::MmBinK),
219 49 => Some(Self::Unm),
220 50 => Some(Self::BNot),
221 51 => Some(Self::Not),
222 52 => Some(Self::Len),
223 53 => Some(Self::Concat),
224 54 => Some(Self::Close),
225 55 => Some(Self::Tbc),
226 56 => Some(Self::Jmp),
227 57 => Some(Self::Eq),
228 58 => Some(Self::Lt),
229 59 => Some(Self::Le),
230 60 => Some(Self::EqK),
231 61 => Some(Self::EqI),
232 62 => Some(Self::LtI),
233 63 => Some(Self::LeI),
234 64 => Some(Self::GtI),
235 65 => Some(Self::GeI),
236 66 => Some(Self::Test),
237 67 => Some(Self::TestSet),
238 68 => Some(Self::Call),
239 69 => Some(Self::TailCall),
240 70 => Some(Self::Return),
241 71 => Some(Self::Return0),
242 72 => Some(Self::Return1),
243 73 => Some(Self::ForLoop),
244 74 => Some(Self::ForPrep),
245 75 => Some(Self::TForPrep),
246 76 => Some(Self::TForCall),
247 77 => Some(Self::TForLoop),
248 78 => Some(Self::SetList),
249 79 => Some(Self::Closure),
250 80 => Some(Self::VarArg),
251 81 => Some(Self::VarArgPrep),
252 82 => Some(Self::ExtraArg),
253 _ => None,
254 }
255 }
256}
257
258pub trait InstructionExt {
262 fn opcode(&self) -> OpCode;
263 fn arg_a(&self) -> i32;
264 fn arg_b(&self) -> i32;
265 fn arg_c(&self) -> i32;
266 fn arg_k(&self) -> i32;
267 fn arg_ax(&self) -> i32;
268 fn arg_bx(&self) -> i32;
269 fn arg_s_b(&self) -> i32;
270 fn arg_s_c(&self) -> i32;
271 fn arg_s_j(&self) -> i32;
272 fn arg_s_bx(&self) -> i32;
273 fn test_k(&self) -> bool;
274 fn test_a_mode(&self) -> bool;
275 fn is_mm_mode(&self) -> bool;
276 fn is_vararg_prep(&self) -> bool;
277 fn is_in_top(&self) -> bool;
278}
279
280impl InstructionExt for Instruction {
281 #[inline(always)]
289 fn opcode(&self) -> OpCode {
290 match (self.raw() & 0x7F) as u8 {
291 0 => OpCode::Move,
292 1 => OpCode::LoadI,
293 2 => OpCode::LoadF,
294 3 => OpCode::LoadK,
295 4 => OpCode::LoadKX,
296 5 => OpCode::LoadFalse,
297 6 => OpCode::LFalseSkip,
298 7 => OpCode::LoadTrue,
299 8 => OpCode::LoadNil,
300 9 => OpCode::GetUpVal,
301 10 => OpCode::SetUpVal,
302 11 => OpCode::GetTabUp,
303 12 => OpCode::GetTable,
304 13 => OpCode::GetI,
305 14 => OpCode::GetField,
306 15 => OpCode::SetTabUp,
307 16 => OpCode::SetTable,
308 17 => OpCode::SetI,
309 18 => OpCode::SetField,
310 19 => OpCode::NewTable,
311 20 => OpCode::Self_,
312 21 => OpCode::AddI,
313 22 => OpCode::AddK,
314 23 => OpCode::SubK,
315 24 => OpCode::MulK,
316 25 => OpCode::ModK,
317 26 => OpCode::PowK,
318 27 => OpCode::DivK,
319 28 => OpCode::IDivK,
320 29 => OpCode::BAndK,
321 30 => OpCode::BOrK,
322 31 => OpCode::BXOrK,
323 32 => OpCode::ShrI,
324 33 => OpCode::ShlI,
325 34 => OpCode::Add,
326 35 => OpCode::Sub,
327 36 => OpCode::Mul,
328 37 => OpCode::Mod,
329 38 => OpCode::Pow,
330 39 => OpCode::Div,
331 40 => OpCode::IDiv,
332 41 => OpCode::BAnd,
333 42 => OpCode::BOr,
334 43 => OpCode::BXOr,
335 44 => OpCode::Shl,
336 45 => OpCode::Shr,
337 46 => OpCode::MmBin,
338 47 => OpCode::MmBinI,
339 48 => OpCode::MmBinK,
340 49 => OpCode::Unm,
341 50 => OpCode::BNot,
342 51 => OpCode::Not,
343 52 => OpCode::Len,
344 53 => OpCode::Concat,
345 54 => OpCode::Close,
346 55 => OpCode::Tbc,
347 56 => OpCode::Jmp,
348 57 => OpCode::Eq,
349 58 => OpCode::Lt,
350 59 => OpCode::Le,
351 60 => OpCode::EqK,
352 61 => OpCode::EqI,
353 62 => OpCode::LtI,
354 63 => OpCode::LeI,
355 64 => OpCode::GtI,
356 65 => OpCode::GeI,
357 66 => OpCode::Test,
358 67 => OpCode::TestSet,
359 68 => OpCode::Call,
360 69 => OpCode::TailCall,
361 70 => OpCode::Return,
362 71 => OpCode::Return0,
363 72 => OpCode::Return1,
364 73 => OpCode::ForLoop,
365 74 => OpCode::ForPrep,
366 75 => OpCode::TForPrep,
367 76 => OpCode::TForCall,
368 77 => OpCode::TForLoop,
369 78 => OpCode::SetList,
370 79 => OpCode::Closure,
371 80 => OpCode::VarArg,
372 81 => OpCode::VarArgPrep,
373 82 => OpCode::ExtraArg,
374 _ => OpCode::ExtraArg,
375 }
376 }
377 #[inline] fn arg_a(&self) -> i32 { ((self.raw() >> 7) & 0xFF) as i32 }
378 #[inline] fn arg_b(&self) -> i32 { ((self.raw() >> 16) & 0xFF) as i32 }
379 #[inline] fn arg_c(&self) -> i32 { ((self.raw() >> 24) & 0xFF) as i32 }
380 #[inline] fn arg_k(&self) -> i32 { ((self.raw() >> 15) & 0x1) as i32 }
381 #[inline] fn arg_ax(&self) -> i32 { (self.raw() >> 7) as i32 }
382 #[inline] fn arg_bx(&self) -> i32 { (self.raw() >> 15) as i32 }
383 #[inline] fn arg_s_b(&self) -> i32 { self.arg_b() - 0x7F }
384 #[inline] fn arg_s_c(&self) -> i32 { self.arg_c() - 0x7F }
385 #[inline] fn arg_s_j(&self) -> i32 { self.arg_ax() - 0xFFFFFF }
386 #[inline] fn arg_s_bx(&self) -> i32 { self.arg_bx() - 0xFFFF }
387 #[inline] fn test_k(&self) -> bool { (self.raw() & (1 << 15)) != 0 }
388 #[inline]
389 fn test_a_mode(&self) -> bool {
390 (op_mode_byte(self.opcode()) & (1 << 3)) != 0
391 }
392 #[inline]
393 fn is_mm_mode(&self) -> bool {
394 (op_mode_byte(self.opcode()) & (1 << 7)) != 0
395 }
396 #[inline]
397 fn is_vararg_prep(&self) -> bool {
398 matches!(self.opcode(), OpCode::VarArgPrep)
399 }
400 #[inline]
401 fn is_in_top(&self) -> bool {
402 (op_mode_byte(self.opcode()) & (1 << 5)) != 0 && self.arg_b() == 0
403 }
404}
405
406const OP_MODE_BYTES: [u8; NUM_OPCODES as usize] = [
419 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, ];
503
504#[inline(always)]
505fn op_mode_byte(op: OpCode) -> u8 {
506 OP_MODE_BYTES[op as usize]
507}
508
509const MAX_TAG_LOOP: i32 = 2000;
513
514const NBITS: u32 = 64;
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq)]
520pub(crate) enum F2Imod {
521 Eq,
523 Floor,
525 Ceil,
527}
528
529#[inline]
532fn intop_add(a: i64, b: i64) -> i64 {
533 (a as u64).wrapping_add(b as u64) as i64
534}
535
536#[inline]
537fn intop_sub(a: i64, b: i64) -> i64 {
538 (a as u64).wrapping_sub(b as u64) as i64
539}
540
541#[inline]
542fn intop_mul(a: i64, b: i64) -> i64 {
543 (a as u64).wrapping_mul(b as u64) as i64
544}
545
546#[inline]
548fn intop_shr(x: i64, n: u32) -> i64 {
549 (x as u64 >> n) as i64
551}
552
553#[inline]
554fn intop_shl(x: i64, n: u32) -> i64 {
555 (x as u64).wrapping_shl(n) as i64
556}
557
558#[inline]
559fn intop_band(a: i64, b: i64) -> i64 { ((a as u64) & (b as u64)) as i64 }
560#[inline]
561fn intop_bor(a: i64, b: i64) -> i64 { ((a as u64) | (b as u64)) as i64 }
562#[inline]
563fn intop_bxor(a: i64, b: i64) -> i64 { ((a as u64) ^ (b as u64)) as i64 }
564
565#[inline]
570fn int_fits_float(i: i64) -> bool {
571 const MAXINTFITSF: u64 = 1u64 << f64::MANTISSA_DIGITS;
572 (MAXINTFITSF.wrapping_add(i as u64)) <= 2 * MAXINTFITSF
573}
574
575fn str_to_number(obj: &LuaValue) -> Option<LuaValue> {
581 let s = match obj {
583 LuaValue::Str(ts) => ts.as_bytes().to_vec(),
584 _ => return None,
585 };
586 let trimmed = trim_whitespace(&s);
588 if trimmed.is_empty() {
589 return None;
590 }
591 let mut result = LuaValue::Nil;
592 if crate::object::str2num(trimmed, &mut result) != 0 {
593 return Some(result);
594 }
595 None
596}
597
598fn trim_whitespace(s: &[u8]) -> &[u8] {
599 let start = s.iter().position(|&b| !b.is_ascii_whitespace()).unwrap_or(s.len());
600 let end = s.iter().rposition(|&b| !b.is_ascii_whitespace()).map(|i| i + 1).unwrap_or(0);
601 if start <= end { &s[start..end] } else { &s[0..0] }
602}
603
604pub(crate) fn tonumber_(obj: &LuaValue) -> Option<f64> {
610 if let LuaValue::Int(i) = obj {
611 return Some(*i as f64);
612 }
613 if let Some(v) = str_to_number(obj) {
614 return match v {
615 LuaValue::Float(f) => Some(f),
616 LuaValue::Int(i) => Some(i as f64),
617 _ => None,
618 };
619 }
620 None
621}
622
623fn tonumber(obj: &LuaValue) -> Option<f64> {
625 if let LuaValue::Float(f) = obj {
626 return Some(*f);
627 }
628 tonumber_(obj)
629}
630
631pub(crate) fn flt_to_integer(n: f64, mode: F2Imod) -> Option<i64> {
634 let f = n.floor();
635 if n != f {
636 match mode {
637 F2Imod::Eq => return None,
638 F2Imod::Ceil => {
639 let f = f + 1.0;
641 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
643 return Some(f as i64);
644 }
645 return None;
646 }
647 F2Imod::Floor => { }
648 }
649 }
650 if f >= i64::MIN as f64 && f < (i64::MAX as f64 + 1.0) {
651 Some(f as i64)
652 } else {
653 None
654 }
655}
656
657pub(crate) fn to_integer_ns(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
659 if let LuaValue::Float(f) = obj {
660 return flt_to_integer(*f, mode);
661 }
662 if let LuaValue::Int(i) = obj {
663 return Some(*i);
664 }
665 None
666}
667
668pub(crate) fn to_integer(obj: &LuaValue, mode: F2Imod) -> Option<i64> {
670 let coerced;
671 let obj = if let Some(v) = str_to_number(obj) {
672 coerced = v;
673 &coerced
674 } else {
675 obj
676 };
677 to_integer_ns(obj, mode)
678}
679
680fn forlimit(
687 state: &mut LuaState,
688 init: i64,
689 lim: &LuaValue,
690 step: i64,
691) -> Result<(bool, i64), LuaError> {
692 let round = if step < 0 { F2Imod::Ceil } else { F2Imod::Floor };
693 if let Some(p) = to_integer(lim, round) {
694 let skip = if step > 0 { init > p } else { init < p };
695 return Ok((skip, p));
696 }
697 let flim = match tonumber(lim) {
698 Some(f) => f,
699 None => return Err(crate::debug::for_error(state, lim, b"limit")),
700 };
701 if 0.0_f64 < flim {
702 if step < 0 {
704 return Ok((true, 0));
705 }
706 Ok((false, i64::MAX))
707 } else {
708 if step > 0 {
710 return Ok((true, 0));
711 }
712 Ok((false, i64::MIN))
713 }
714}
715
716pub(crate) fn forprep(state: &mut LuaState, ra: StackIdx) -> Result<bool, LuaError> {
721 let pinit = state.get_at(ra);
722 let plimit = state.get_at(ra + 1);
723 let pstep = state.get_at(ra + 2);
724
725 if let (LuaValue::Int(init), LuaValue::Int(step)) = (&pinit, &pstep) {
726 let init = *init;
727 let step = *step;
728 if step == 0 {
729 return Err(LuaError::runtime(format_args!("'for' step is zero")));
730 }
731 state.set_at(ra + 3, LuaValue::Int(init));
732
733 let (skip, limit) = forlimit(state, init, &plimit, step)?;
734 if skip {
735 return Ok(true);
736 }
737 let count: u64 = if step > 0 {
738 let c = (limit as u64).wrapping_sub(init as u64);
739 if step != 1 { c / (step as u64) } else { c }
740 } else {
741 let c = (init as u64).wrapping_sub(limit as u64);
742 c / (((-(step + 1)) as u64).wrapping_add(1))
743 };
744 state.set_at(ra + 1, LuaValue::Int(count as i64));
745 Ok(false)
746 } else {
747 let limit_f = match tonumber(&plimit) {
748 Some(f) => f,
749 None => return Err(crate::debug::for_error(state, &plimit, b"limit")),
750 };
751 let step_f = match tonumber(&pstep) {
752 Some(f) => f,
753 None => return Err(crate::debug::for_error(state, &pstep, b"step")),
754 };
755 let init_f = match tonumber(&pinit) {
756 Some(f) => f,
757 None => return Err(crate::debug::for_error(state, &pinit, b"initial value")),
758 };
759 if step_f == 0.0 {
760 return Err(LuaError::runtime(format_args!("'for' step is zero")));
761 }
762 let skip = if step_f > 0.0 { limit_f < init_f } else { init_f < limit_f };
763 if skip {
764 return Ok(true);
765 }
766 state.set_at(ra + 1, LuaValue::Float(limit_f));
768 state.set_at(ra + 2, LuaValue::Float(step_f));
769 state.set_at(ra, LuaValue::Float(init_f));
770 state.set_at(ra + 3, LuaValue::Float(init_f));
771 Ok(false)
772 }
773}
774
775fn float_for_loop(state: &mut LuaState, ra: StackIdx) -> bool {
777 let step = match state.get_at(ra + 2) {
779 LuaValue::Float(f) => f,
780 _ => return false,
781 };
782 let limit = match state.get_at(ra + 1) {
783 LuaValue::Float(f) => f,
784 _ => return false,
785 };
786 let idx = match state.get_at(ra) {
787 LuaValue::Float(f) => f,
788 _ => return false,
789 };
790 let idx = idx + step;
791 if if step > 0.0 { idx <= limit } else { limit <= idx } {
792 state.set_at(ra, LuaValue::Float(idx));
793 state.set_at(ra + 3, LuaValue::Float(idx));
794 true
795 } else {
796 false
797 }
798}
799
800pub(crate) fn finish_get(
806 state: &mut LuaState,
807 t_val: LuaValue,
808 key: LuaValue,
809 result_idx: StackIdx,
810 slot_empty: bool,
811 t_idx: Option<StackIdx>,
812) -> Result<(), LuaError> {
813 let mut t = t_val;
814 let mut t_idx = t_idx;
815 for _loop in 0..MAX_TAG_LOOP {
816 let tm: LuaValue;
817 if slot_empty && !matches!(t, LuaValue::Table(_)) {
818 tm = state.get_tm_by_obj(&t, TagMethod::Index);
819 if matches!(tm, LuaValue::Nil) {
820 return Err(match t_idx {
821 Some(idx) => crate::debug::type_error(state, &t, idx, b"index"),
822 None => LuaError::type_error(&t, "index"),
823 });
824 }
825 } else {
826 let mt = state.table_metatable(&t);
827 tm = state.fast_tm_table(mt.as_ref(), TagMethod::Index);
828 if matches!(tm, LuaValue::Nil) {
829 state.set_at(result_idx, LuaValue::Nil);
830 return Ok(());
831 }
832 }
833 if matches!(tm, LuaValue::Function(_)) {
834 state.call_tm_res(tm, &t, &key, result_idx)?;
835 return Ok(());
836 }
837 t = tm.clone();
838 t_idx = None;
839 if let Some(v) = state.fast_get(&t, &key)? {
840 state.set_at(result_idx, v);
841 return Ok(());
842 }
843 }
845 Err(LuaError::runtime(format_args!("'__index' chain too long; possible loop")))
846}
847
848pub(crate) fn finish_set(
857 state: &mut LuaState,
858 t_val: LuaValue,
859 key: LuaValue,
860 val: LuaValue,
861 _slot_present: bool,
862 t_idx: Option<StackIdx>,
863 var_hint: Option<(&[u8], &[u8])>,
864) -> Result<(), LuaError> {
865 let mut t = t_val;
866 let mut t_idx = t_idx;
867 for _loop in 0..MAX_TAG_LOOP {
868 let tm: LuaValue;
869 if matches!(t, LuaValue::Table(_)) {
870 let mt = state.table_metatable(&t);
871 tm = state.fast_tm_table(mt.as_ref(), TagMethod::NewIndex);
872 if matches!(tm, LuaValue::Nil) {
873 state.table_raw_set(&t, key, val.clone())?;
874 state.gc_barrier_back(&t, &val);
875 return Ok(());
876 }
877 } else {
878 tm = state.get_tm_by_obj(&t, TagMethod::NewIndex);
879 if matches!(tm, LuaValue::Nil) {
880 return Err(match (t_idx, var_hint) {
881 (Some(idx), _) => crate::debug::type_error(state, &t, idx, b"index"),
882 (None, Some((kind, name))) => {
883 crate::debug::type_error_with_hint(state, &t, b"index", kind, name)
884 }
885 (None, None) => LuaError::type_error(&t, "index"),
886 });
887 }
888 }
889 if matches!(tm, LuaValue::Function(_)) {
890 state.call_tm(tm, &t, &key, &val)?;
891 return Ok(());
892 }
893 t = tm.clone();
894 t_idx = None;
895 if state.fast_get(&t, &key)?.is_some() {
896 state.table_raw_set(&t, key.clone(), val.clone())?;
897 state.gc_barrier_back(&t, &val);
898 return Ok(());
899 }
900 }
901 Err(LuaError::runtime(format_args!("'__newindex' chain too long; possible loop")))
902}
903
904fn str_cmp(s1: &[u8], s2: &[u8]) -> std::cmp::Ordering {
915 let mut s1 = s1;
918 let mut s2 = s2;
919 loop {
920 let z1 = s1.iter().position(|&b| b == 0).unwrap_or(s1.len());
922 let z2 = s2.iter().position(|&b| b == 0).unwrap_or(s2.len());
923 let seg_cmp = s1[..z1].cmp(&s2[..z2]);
925 if seg_cmp != std::cmp::Ordering::Equal {
926 return seg_cmp;
927 }
928 if z2 == s2.len() {
930 if z1 == s1.len() {
932 return std::cmp::Ordering::Equal;
933 }
934 return std::cmp::Ordering::Greater; }
936 if z1 == s1.len() {
937 return std::cmp::Ordering::Less; }
939 s1 = &s1[z1 + 1..];
941 s2 = &s2[z2 + 1..];
942 }
943}
944
945#[inline]
948fn lt_int_float(i: i64, f: f64) -> bool {
949 if int_fits_float(i) {
950 (i as f64) < f
951 } else {
952 match flt_to_integer(f, F2Imod::Ceil) {
953 Some(fi) => i < fi,
954 None => f > 0.0, }
956 }
957}
958
959#[inline]
960fn le_int_float(i: i64, f: f64) -> bool {
961 if int_fits_float(i) {
962 (i as f64) <= f
963 } else {
964 match flt_to_integer(f, F2Imod::Floor) {
965 Some(fi) => i <= fi,
966 None => f > 0.0,
967 }
968 }
969}
970
971#[inline]
972fn lt_float_int(f: f64, i: i64) -> bool {
973 if int_fits_float(i) {
974 f < (i as f64)
975 } else {
976 match flt_to_integer(f, F2Imod::Floor) {
977 Some(fi) => fi < i,
978 None => f < 0.0,
979 }
980 }
981}
982
983#[inline]
984fn le_float_int(f: f64, i: i64) -> bool {
985 if int_fits_float(i) {
986 f <= (i as f64)
987 } else {
988 match flt_to_integer(f, F2Imod::Ceil) {
989 Some(fi) => fi <= i,
990 None => f < 0.0,
991 }
992 }
993}
994
995#[inline]
996fn lt_num(l: &LuaValue, r: &LuaValue) -> bool {
997 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
998 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
999 match (l, r) {
1000 (LuaValue::Int(li), LuaValue::Int(ri)) => li < ri,
1001 (LuaValue::Int(li), LuaValue::Float(rf)) => lt_int_float(*li, *rf),
1002 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf < rf,
1003 (LuaValue::Float(lf), LuaValue::Int(ri)) => lt_float_int(*lf, *ri),
1004 _ => false,
1005 }
1006}
1007
1008#[inline]
1009fn le_num(l: &LuaValue, r: &LuaValue) -> bool {
1010 debug_assert!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_)));
1011 debug_assert!(matches!(r, LuaValue::Int(_) | LuaValue::Float(_)));
1012 match (l, r) {
1013 (LuaValue::Int(li), LuaValue::Int(ri)) => li <= ri,
1014 (LuaValue::Int(li), LuaValue::Float(rf)) => le_int_float(*li, *rf),
1015 (LuaValue::Float(lf), LuaValue::Float(rf)) => lf <= rf,
1016 (LuaValue::Float(lf), LuaValue::Int(ri)) => le_float_int(*lf, *ri),
1017 _ => false,
1018 }
1019}
1020
1021fn less_than_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1023 debug_assert!(!(matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1024 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))));
1025 match (l, r) {
1026 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1027 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) == std::cmp::Ordering::Less)
1028 }
1029 _ => state.call_order_tm(l, r, TagMethod::Lt),
1030 }
1031}
1032
1033pub(crate) fn less_than(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1034 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1035 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1036 {
1037 Ok(lt_num(l, r))
1038 } else {
1039 less_than_others(state, l, r)
1040 }
1041}
1042
1043fn less_equal_others(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1044 match (l, r) {
1045 (LuaValue::Str(ts1), LuaValue::Str(ts2)) => {
1046 Ok(str_cmp(ts1.as_bytes(), ts2.as_bytes()) != std::cmp::Ordering::Greater)
1047 }
1048 _ => state.call_order_tm(l, r, TagMethod::Le),
1049 }
1050}
1051
1052pub(crate) fn less_equal(state: &mut LuaState, l: &LuaValue, r: &LuaValue) -> Result<bool, LuaError> {
1053 if matches!(l, LuaValue::Int(_) | LuaValue::Float(_))
1054 && matches!(r, LuaValue::Int(_) | LuaValue::Float(_))
1055 {
1056 Ok(le_num(l, r))
1057 } else {
1058 less_equal_others(state, l, r)
1059 }
1060}
1061
1062pub(crate) fn equal_obj(
1066 state: Option<&mut LuaState>,
1067 t1: &LuaValue,
1068 t2: &LuaValue,
1069) -> Result<bool, LuaError> {
1070 let same_variant = std::mem::discriminant(t1) == std::mem::discriminant(t2);
1073 if !same_variant {
1074 let t1_is_num = matches!(t1, LuaValue::Int(_) | LuaValue::Float(_));
1075 let t2_is_num = matches!(t2, LuaValue::Int(_) | LuaValue::Float(_));
1076 if !(t1_is_num && t2_is_num) {
1077 return Ok(false);
1078 }
1079 let i1 = to_integer_ns(t1, F2Imod::Eq);
1081 let i2 = to_integer_ns(t2, F2Imod::Eq);
1082 return Ok(i1.is_some() && i2.is_some() && i1 == i2);
1083 }
1084
1085 match (t1, t2) {
1086 (LuaValue::Nil, LuaValue::Nil) => Ok(true),
1087 (LuaValue::Bool(b1), LuaValue::Bool(b2)) => Ok(b1 == b2),
1088 (LuaValue::Int(i1), LuaValue::Int(i2)) => Ok(i1 == i2),
1089 (LuaValue::Float(f1), LuaValue::Float(f2)) => Ok(f1 == f2),
1090 (LuaValue::LightUserData(p1), LuaValue::LightUserData(p2)) => Ok(p1 == p2),
1091 (LuaValue::Function(f1), LuaValue::Function(f2)) => {
1092 use lua_types::closure::LuaClosure;
1093 let same = match (f1, f2) {
1094 (LuaClosure::Lua(a), LuaClosure::Lua(b)) => GcRef::ptr_eq(a, b),
1095 (LuaClosure::C(a), LuaClosure::C(b)) => GcRef::ptr_eq(a, b),
1096 (LuaClosure::LightC(a), LuaClosure::LightC(b)) => a == b,
1097 _ => false,
1098 };
1099 Ok(same)
1100 }
1101 (LuaValue::Str(s1), LuaValue::Str(s2)) => {
1102 Ok(s1 == s2)
1105 }
1106 (LuaValue::UserData(u1), LuaValue::UserData(u2)) => {
1107 if std::ptr::eq(u1.as_ptr(), u2.as_ptr()) {
1110 return Ok(true);
1111 }
1112 let Some(state) = state else { return Ok(false); };
1113 let tm1 = state.fast_tm_ud(u1, TagMethod::Eq);
1114 let tm = if matches!(tm1, LuaValue::Nil) {
1115 state.fast_tm_ud(u2, TagMethod::Eq)
1116 } else {
1117 tm1
1118 };
1119 if matches!(tm, LuaValue::Nil) {
1120 return Ok(false);
1121 }
1122 let result = state.call_tm_res_bool(tm, t1, t2)?;
1123 Ok(result)
1124 }
1125 (LuaValue::Table(h1), LuaValue::Table(h2)) => {
1126 if std::ptr::eq(h1.as_ptr(), h2.as_ptr()) {
1127 return Ok(true);
1128 }
1129 let Some(state) = state else { return Ok(false); };
1130 let mt1 = h1.metatable();
1132 let mt2 = h2.metatable();
1133 let tm1 = state.fast_tm_table(mt1.as_ref(), TagMethod::Eq);
1134 let tm = if matches!(tm1, LuaValue::Nil) {
1135 state.fast_tm_table(mt2.as_ref(), TagMethod::Eq)
1136 } else {
1137 tm1
1138 };
1139 if matches!(tm, LuaValue::Nil) {
1140 return Ok(false);
1141 }
1142 let result = state.call_tm_res_bool(tm, t1, t2)?;
1143 Ok(result)
1144 }
1145 (LuaValue::Thread(a), LuaValue::Thread(b)) => Ok(GcRef::ptr_eq(a, b)),
1146 _ => Ok(std::ptr::eq(t1 as *const _, t2 as *const _)),
1147 }
1148}
1149
1150fn copy_to_buf(state: &LuaState, top: StackIdx, n: u32, buf: &mut Vec<u8>) {
1154 buf.clear();
1155 let mut remaining = n;
1156 loop {
1157 let idx = top - remaining as i32;
1158 let v = state.get_at(idx);
1159 if let LuaValue::Str(ts) = v {
1160 buf.extend_from_slice(ts.as_bytes());
1161 }
1162 if remaining <= 1 {
1163 break;
1164 }
1165 remaining -= 1;
1166 }
1167}
1168
1169pub(crate) fn concat(state: &mut LuaState, total: i32) -> Result<(), LuaError> {
1171 if total == 1 {
1172 return Ok(());
1173 }
1174 let mut total = total;
1175 loop {
1176 let top = state.top_idx();
1177 let v_tm1 = state.get_at(top - 1); let v_tm2 = state.get_at(top - 2); let top2_coercible = matches!(v_tm2, LuaValue::Str(_))
1182 || matches!(v_tm2, LuaValue::Int(_) | LuaValue::Float(_));
1183 let top1_stringlike = matches!(v_tm1, LuaValue::Str(_))
1185 || matches!(v_tm1, LuaValue::Int(_) | LuaValue::Float(_));
1186 if !top2_coercible || !top1_stringlike {
1187 state.try_concat_tm(&v_tm1, &v_tm2)?;
1188 total -= 1;
1193 let top = state.top_idx();
1194 state.set_top(top - 1);
1195 if total <= 1 {
1196 break;
1197 }
1198 continue;
1199 }
1200
1201 let is_empty = |v: &LuaValue| -> bool {
1202 matches!(v, LuaValue::Str(s) if s.as_bytes().is_empty())
1203 };
1204
1205 let n: u32;
1206 if is_empty(&v_tm1) {
1207 state.coerce_to_string(top - 2)?;
1208 n = 2;
1209 } else if is_empty(&v_tm2) {
1210 state.coerce_to_string(top - 1)?;
1213 let v = state.get_at(top - 1);
1214 state.set_at(top - 2, v);
1215 n = 2;
1216 } else {
1217 state.coerce_to_string(top - 1)?;
1219 let s1 = match state.get_at(top - 1) {
1220 LuaValue::Str(ts) => ts.as_bytes().len(),
1221 _ => 0,
1222 };
1223 let mut total_len = s1;
1224 let mut count: u32 = 1;
1225 let top = state.top_idx();
1226 loop {
1227 if count as i32 >= total {
1228 break;
1229 }
1230 let idx = top - (count as i32 + 1);
1231 let v = state.get_at(idx);
1232 if !matches!(v, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
1233 break;
1234 }
1235 state.coerce_to_string(idx)?;
1236 let l = match state.get_at(idx) {
1237 LuaValue::Str(ts) => ts.as_bytes().len(),
1238 _ => 0,
1239 };
1240 if l >= usize::MAX - total_len {
1241 state.set_top(top - total as i32);
1243 return Err(LuaError::runtime(format_args!("string length overflow")));
1244 }
1245 total_len += l;
1246 count += 1;
1247 }
1248 n = count;
1249
1250 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
1252 let top = state.top_idx();
1253 copy_to_buf(state, top, n, &mut buf);
1254 let ts = state.intern_or_create_str(&buf)?;
1255 state.set_at(top - n as i32, LuaValue::Str(ts));
1256 }
1257 total -= n as i32 - 1;
1258 let top = state.top_idx();
1259 state.set_top(top - ((n - 1) as i32));
1260
1261 if total <= 1 {
1262 break;
1263 }
1264 }
1265 Ok(())
1266}
1267
1268pub(crate) fn obj_len(state: &mut LuaState, ra: StackIdx, rb: LuaValue) -> Result<(), LuaError> {
1272 match &rb {
1273 LuaValue::Table(_) => {
1274 let mt = state.table_metatable(&rb);
1276 let tm = state.fast_tm_table(mt.as_ref(), TagMethod::Len);
1277 if matches!(tm, LuaValue::Nil) {
1278 let n = state.table_length(&rb)?;
1279 state.set_at(ra, LuaValue::Int(n as i64));
1280 return Ok(());
1281 }
1282 state.call_tm_res(tm, &rb, &rb, ra)?;
1284 }
1285 LuaValue::Str(ts) => {
1286 let n = ts.len();
1289 state.set_at(ra, LuaValue::Int(n as i64));
1290 }
1291 other => {
1292 let tm = state.get_tm_by_obj(other, TagMethod::Len);
1294 if matches!(tm, LuaValue::Nil) {
1295 return Err(LuaError::type_error(other, "get length of"));
1296 }
1297 state.call_tm_res(tm, &rb, &rb, ra)?;
1298 }
1299 }
1300 Ok(())
1301}
1302
1303pub(crate) fn idiv(m: i64, n: i64) -> Result<i64, LuaError> {
1307 if (n as u64).wrapping_add(1) <= 1 {
1308 if n == 0 {
1309 return Err(LuaError::runtime(format_args!("attempt to divide by zero")));
1310 }
1311 return Ok(intop_sub(0, m));
1312 }
1313 let q = m / n;
1314 if (m ^ n) < 0 && m % n != 0 {
1316 Ok(q - 1)
1317 } else {
1318 Ok(q)
1319 }
1320}
1321
1322pub(crate) fn imod(m: i64, n: i64) -> Result<i64, LuaError> {
1324 if (n as u64).wrapping_add(1) <= 1 {
1325 if n == 0 {
1326 return Err(LuaError::runtime(format_args!("attempt to perform 'n%0'")));
1327 }
1328 return Ok(0);
1329 }
1330 let r = m % n;
1331 if r != 0 && (r ^ n) < 0 {
1332 Ok(r + n)
1333 } else {
1334 Ok(r)
1335 }
1336}
1337
1338pub(crate) fn fmodf(m: f64, n: f64) -> f64 {
1340 let r = m % n;
1341 let opposite_signs = if r > 0.0 { n < 0.0 } else { r < 0.0 && n > 0.0 };
1342 if opposite_signs {
1343 r + n
1344 } else {
1345 r
1346 }
1347}
1348
1349pub(crate) fn tagmethod_from_index(i: usize) -> TagMethod {
1352 use TagMethod::*;
1353 match i {
1354 0 => Index, 1 => NewIndex, 2 => Gc, 3 => Mode, 4 => Len, 5 => Eq,
1355 6 => Add, 7 => Sub, 8 => Mul, 9 => Mod, 10 => Pow, 11 => Div,
1356 12 => Idiv, 13 => Band, 14 => Bor, 15 => Bxor, 16 => Shl, 17 => Shr,
1357 18 => Unm, 19 => Bnot, 20 => Lt, 21 => Le, 22 => Concat, 23 => Call,
1358 24 => Close,
1359 _ => Index,
1360 }
1361}
1362
1363pub(crate) fn int_floor_mod(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1366 imod(a, b)
1367}
1368
1369pub(crate) fn int_floor_div(_state: &mut LuaState, a: i64, b: i64) -> Result<i64, LuaError> {
1372 idiv(a, b)
1373}
1374
1375pub(crate) fn float_floor_mod(_state: &mut LuaState, a: f64, b: f64) -> Result<f64, LuaError> {
1378 Ok(fmodf(a, b))
1379}
1380
1381pub(crate) fn shiftl(x: i64, y: i64) -> i64 {
1383 if y < 0 {
1384 if y <= -(NBITS as i64) {
1385 0
1386 } else {
1387 intop_shr(x, (-y) as u32)
1388 }
1389 } else {
1390 if y >= NBITS as i64 {
1391 0
1392 } else {
1393 intop_shl(x, y as u32)
1394 }
1395 }
1396}
1397
1398fn push_closure(
1404 state: &mut LuaState,
1405 proto_idx: usize, ci: CallInfoIdx,
1407 base: StackIdx,
1408 ra: StackIdx,
1409) -> Result<(), LuaError> {
1410 state.push_closure(proto_idx, ci, base, ra)
1414}
1415
1416pub(crate) fn finish_op(state: &mut LuaState) -> Result<(), LuaError> {
1421 let ci = state.current_ci_idx();
1425 let base = state.ci_base(ci);
1426 let inst = state.ci_prev_instruction(ci);
1427 let op = inst.opcode();
1428
1429 match op {
1430 OpCode::MmBin | OpCode::MmBinI | OpCode::MmBinK => {
1432 let prev_inst = state.ci_prev2_instruction(ci);
1433 let a = prev_inst.arg_a();
1434 state.dec_top();
1435 let top = state.top_idx();
1436 let v = state.get_at(top);
1437 state.set_at(base + a, v);
1438 }
1439 OpCode::Unm | OpCode::BNot | OpCode::Len
1441 | OpCode::GetTabUp | OpCode::GetTable | OpCode::GetI
1442 | OpCode::GetField | OpCode::Self_ => {
1443 let a = inst.arg_a();
1444 state.dec_top();
1445 let top = state.top_idx();
1446 let v = state.get_at(top);
1447 state.set_at(base + a, v);
1448 }
1449 OpCode::Lt | OpCode::Le | OpCode::LtI | OpCode::LeI
1453 | OpCode::GtI | OpCode::GeI | OpCode::Eq => {
1454 let top_minus1 = state.top_idx() - 1;
1455 let v = state.get_at(top_minus1);
1456 let res = !matches!(v, LuaValue::Nil | LuaValue::Bool(false));
1457 state.dec_top();
1458 if (res as i32) != inst.arg_k() {
1459 state.ci_skip_next_instruction(ci);
1460 }
1461 }
1463 OpCode::Concat => {
1469 let top = state.top_idx() - 1; let a = inst.arg_a();
1471 let total_concat = (top - 1 - (base + a)) as i32;
1472 let v = state.get_at(top);
1473 state.set_at(top - 2, v);
1474 state.set_top(top - 1);
1475 concat(state, total_concat)?;
1476 }
1477 OpCode::Close => {
1478 state.ci_step_pc_back(ci);
1479 }
1480 OpCode::Return => {
1484 let a = inst.arg_a();
1485 let ra = base + a;
1486 let nres = state.ci_nres(ci);
1487 state.set_top(ra + nres);
1488 state.ci_step_pc_back(ci);
1489 }
1490 other => {
1491 debug_assert!(
1492 matches!(
1493 other,
1494 OpCode::TForCall | OpCode::Call | OpCode::TailCall
1495 | OpCode::SetTabUp | OpCode::SetTable | OpCode::SetI | OpCode::SetField
1496 ),
1497 "unexpected opcode in finish_op: {:?}",
1498 other
1499 );
1500 }
1501 }
1502 Ok(())
1503}
1504
1505pub(crate) fn execute(state: &mut LuaState, mut ci: CallInfoIdx) -> Result<(), LuaError> {
1517 let mut trap: bool;
1518
1519 'startfunc: loop {
1521 trap = state.hook_mask() != 0;
1522
1523 'returning: loop {
1526 let cl = match state.ci_lua_closure(ci) {
1527 Some(c) => c,
1528 None => {
1529 return Err(LuaError::runtime(format_args!(
1530 "internal: execute called on non-Lua frame"
1531 )));
1532 }
1533 };
1534 let mut pc: u32 = state.ci_savedpc(ci);
1536
1537 if trap {
1538 trap = state.trace_call(ci)?;
1539 }
1540 let mut base: StackIdx = state.ci_base(ci);
1541
1542 'dispatch: loop {
1544 if trap {
1545 trap = state.trace_exec(ci, pc)?;
1546 base = state.ci_base(ci); }
1548 let i: Instruction = state.proto_code(&cl, pc);
1549 pc += 1;
1550 let op = i.opcode();
1551
1552 debug_assert!(base == state.ci_base(ci));
1553
1554 #[cfg(debug_assertions)]
1558 {
1559 let op_mode = op_mode_byte(op);
1560 if (op_mode & (1 << 5)) == 0 || i.arg_b() != 0 {
1561 state.set_top(base);
1562 }
1563 }
1564
1565 match op {
1566 OpCode::Move => {
1568 let ra = base + i.arg_a();
1569 let rb = base + i.arg_b();
1570 let v = state.stack[rb.0 as usize].val;
1571 state.stack[ra.0 as usize].val = v;
1572 }
1573 OpCode::LoadI => {
1575 let ra = base + i.arg_a();
1576 let b = i.arg_s_bx() as i64;
1577 state.set_at(ra, LuaValue::Int(b));
1578 }
1579 OpCode::LoadF => {
1581 let ra = base + i.arg_a();
1582 let b = i.arg_s_bx() as f64;
1583 state.set_at(ra, LuaValue::Float(b));
1584 }
1585 OpCode::LoadK => {
1587 let ra = base + i.arg_a();
1588 let k_idx = i.arg_bx() as usize;
1589 let v = state.proto_const(&cl, k_idx).clone();
1590 state.set_at(ra, v);
1591 }
1592 OpCode::LoadKX => {
1594 let ra = base + i.arg_a();
1595 let extra = state.proto_code(&cl, pc);
1596 pc += 1;
1597 let k_idx = extra.arg_ax() as usize;
1598 let v = state.proto_const(&cl, k_idx).clone();
1599 state.set_at(ra, v);
1600 }
1601 OpCode::LoadFalse => {
1603 let ra = base + i.arg_a();
1604 state.set_at(ra, LuaValue::Bool(false));
1605 }
1606 OpCode::LFalseSkip => {
1608 let ra = base + i.arg_a();
1609 state.set_at(ra, LuaValue::Bool(false));
1610 pc += 1;
1611 }
1612 OpCode::LoadTrue => {
1614 let ra = base + i.arg_a();
1615 state.set_at(ra, LuaValue::Bool(true));
1616 }
1617 OpCode::LoadNil => {
1619 let ra = base + i.arg_a();
1620 let b = i.arg_b();
1621 for k in 0..=b {
1622 state.set_at(ra + k, LuaValue::Nil);
1623 }
1624 }
1625 OpCode::GetUpVal => {
1627 let ra = base + i.arg_a();
1628 let b = i.arg_b() as usize;
1629 let v = state.upvalue_get(&cl, b);
1630 state.set_at(ra, v);
1631 }
1632 OpCode::SetUpVal => {
1635 let ra = base + i.arg_a();
1636 let b = i.arg_b() as usize;
1637 let v = state.stack[ra.0 as usize].val;
1638 let uv = cl.upval(b);
1639 match uv.try_open_payload() {
1640 Some((thread_id, idx)) if thread_id as u64 == state.cached_thread_id => {
1641 state.stack[idx.0 as usize].val = v;
1642 }
1643 _ => {
1644 state.upvalue_set(&cl, b, v)?;
1645 }
1646 }
1647 }
1648 OpCode::GetTabUp => {
1652 let ra = base + i.arg_a();
1653 let b = i.arg_b() as usize;
1654 let k_idx = i.arg_c() as usize;
1655 let upval = state.upvalue_get(&cl, b);
1656 let key = state.proto_const(&cl, k_idx).clone();
1657 match state.fast_get_short_str(&upval, &key)? {
1658 Some(v) => state.set_at(ra, v),
1659 None => {
1660 state.set_ci_savedpc(ci, pc);
1661 state.set_top(state.ci_top(ci));
1662 finish_get(state, upval, key, ra, true, None)?;
1663 trap = state.ci_trap(ci);
1664 }
1665 }
1666 }
1667 OpCode::GetTable => {
1670 let ra = base + i.arg_a();
1671 let rb_idx = base + i.arg_b();
1672 let rb_v = state.get_at(rb_idx);
1673 let rc_v = state.get_at(base + i.arg_c());
1674 let fast_result = if let LuaValue::Int(n) = &rc_v {
1675 state.fast_get_int(&rb_v, *n)?
1676 } else {
1677 state.fast_get(&rb_v, &rc_v)?
1678 };
1679 match fast_result {
1680 Some(v) => state.set_at(ra, v),
1681 None => {
1682 state.set_ci_savedpc(ci, pc);
1683 state.set_top(state.ci_top(ci));
1684 finish_get(state, rb_v, rc_v, ra, true, Some(rb_idx))?;
1685 trap = state.ci_trap(ci);
1686 }
1687 }
1688 }
1689 OpCode::GetI => {
1693 let ra = base + i.arg_a();
1694 let rb_idx = base + i.arg_b();
1695 let rb_v = state.get_at(rb_idx);
1696 let c = i.arg_c() as i64;
1697 match state.fast_get_int(&rb_v, c)? {
1698 Some(v) => state.set_at(ra, v),
1699 None => {
1700 let key = LuaValue::Int(c);
1701 state.set_ci_savedpc(ci, pc);
1702 state.set_top(state.ci_top(ci));
1703 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1704 trap = state.ci_trap(ci);
1705 }
1706 }
1707 }
1708 OpCode::GetField => {
1710 let ra = base + i.arg_a();
1711 let rb_idx = base + i.arg_b();
1712 let rb_v = state.get_at(rb_idx);
1713 let k_idx = i.arg_c() as usize;
1714 let key = state.proto_const(&cl, k_idx).clone();
1715 match state.fast_get_short_str(&rb_v, &key)? {
1716 Some(v) => state.set_at(ra, v),
1717 None => {
1718 state.set_ci_savedpc(ci, pc);
1719 state.set_top(state.ci_top(ci));
1720 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1721 trap = state.ci_trap(ci);
1722 }
1723 }
1724 }
1725 OpCode::SetTabUp => {
1727 let a = i.arg_a() as usize;
1728 let b_idx = i.arg_b() as usize; let rc_v = if i.test_k() {
1730 state.proto_const(&cl, i.arg_c() as usize).clone()
1731 } else {
1732 state.get_at(base + i.arg_c())
1733 };
1734 let upval = state.upvalue_get(&cl, a);
1735 let key = state.proto_const(&cl, b_idx).clone();
1736 match state.fast_get_short_str(&upval, &key)? {
1737 Some(_slot) => {
1738 state.table_raw_set(&upval, key, rc_v.clone())?;
1739 state.gc_barrier_back(&upval, &rc_v);
1740 }
1741 None => {
1742 state.set_ci_savedpc(ci, pc);
1743 state.set_top(state.ci_top(ci));
1744 let upval_name: Vec<u8> = cl
1745 .proto
1746 .upvalues
1747 .get(a)
1748 .and_then(|uv| uv.name.as_ref())
1749 .map(|s| s.as_bytes().to_vec())
1750 .unwrap_or_else(|| b"?".to_vec());
1751 let hint: Option<(&[u8], &[u8])> =
1752 Some((b"upvalue", &upval_name));
1753 finish_set(state, upval, key, rc_v, false, None, hint)?;
1754 trap = state.ci_trap(ci);
1755 }
1756 }
1757 }
1758 OpCode::SetTable => {
1760 let ra_idx = base + i.arg_a();
1761 let ra_v = state.get_at(ra_idx);
1762 let rb_v = state.get_at(base + i.arg_b());
1763 let rc_v = if i.test_k() {
1764 state.proto_const(&cl, i.arg_c() as usize).clone()
1765 } else {
1766 state.get_at(base + i.arg_c())
1767 };
1768 let fast = if let LuaValue::Int(n) = &rb_v {
1769 state.fast_get_int(&ra_v, *n)?
1770 } else {
1771 state.fast_get(&ra_v, &rb_v)?
1772 };
1773 if fast.is_some() {
1774 state.table_raw_set(&ra_v, rb_v, rc_v.clone())?;
1775 state.gc_barrier_back(&ra_v, &rc_v);
1776 } else {
1777 state.set_ci_savedpc(ci, pc);
1778 state.set_top(state.ci_top(ci));
1779 finish_set(state, ra_v, rb_v, rc_v, false, Some(ra_idx), None)?;
1780 trap = state.ci_trap(ci);
1781 }
1782 }
1783 OpCode::SetI => {
1785 let ra_idx = base + i.arg_a();
1786 let ra_v = state.get_at(ra_idx);
1787 let c = i.arg_b() as i64;
1788 let rc_v = if i.test_k() {
1789 state.proto_const(&cl, i.arg_c() as usize).clone()
1790 } else {
1791 state.get_at(base + i.arg_c())
1792 };
1793 let fast = state.fast_get_int(&ra_v, c)?;
1794 if fast.is_some() {
1795 state.table_raw_set(&ra_v, LuaValue::Int(c), rc_v.clone())?;
1796 state.gc_barrier_back(&ra_v, &rc_v);
1797 } else {
1798 state.set_ci_savedpc(ci, pc);
1799 state.set_top(state.ci_top(ci));
1800 finish_set(state, ra_v, LuaValue::Int(c), rc_v, false, Some(ra_idx), None)?;
1801 trap = state.ci_trap(ci);
1802 }
1803 }
1804 OpCode::SetField => {
1806 let ra_idx = base + i.arg_a();
1807 let ra_v = state.get_at(ra_idx);
1808 let b_idx = i.arg_b() as usize;
1809 let key = state.proto_const(&cl, b_idx).clone();
1810 let rc_v = if i.test_k() {
1811 state.proto_const(&cl, i.arg_c() as usize).clone()
1812 } else {
1813 state.get_at(base + i.arg_c())
1814 };
1815 match state.fast_get_short_str(&ra_v, &key)? {
1816 Some(_) => {
1817 state.table_raw_set(&ra_v, key, rc_v.clone())?;
1818 state.gc_barrier_back(&ra_v, &rc_v);
1819 }
1820 None => {
1821 state.set_ci_savedpc(ci, pc);
1822 state.set_top(state.ci_top(ci));
1823 finish_set(state, ra_v, key, rc_v, false, Some(ra_idx), None)?;
1824 trap = state.ci_trap(ci);
1825 }
1826 }
1827 }
1828 OpCode::NewTable => {
1831 let ra = base + i.arg_a();
1832 let mut b = i.arg_b();
1833 let mut c = i.arg_c();
1834 if b > 0 {
1835 b = 1 << (b - 1);
1836 }
1837 if i.test_k() {
1838 let extra = state.proto_code(&cl, pc);
1839 pc += 1;
1840 const MAXARG_C: i32 = (1 << 8) - 1;
1841 c += extra.arg_ax() * (MAXARG_C + 1);
1842 } else {
1843 pc += 1; }
1845 state.set_top(ra + 1);
1846 let t = if b != 0 || c != 0 {
1847 state.new_table_with_sizes(c as u32, b as u32)?
1848 } else {
1849 state.new_table()
1850 };
1851 state.set_at(ra, LuaValue::Table(t.clone()));
1852 state.set_ci_savedpc(ci, pc);
1853 state.set_top(ra + 1);
1854 state.gc_cond_step();
1855 if state.hookmask != 0 {
1856 trap = state.ci_trap(ci);
1857 }
1858 }
1859 OpCode::Self_ => {
1861 let ra = base + i.arg_a();
1862 let rb_idx = base + i.arg_b();
1863 let rb_v = state.get_at(rb_idx);
1864 let k_idx = i.arg_c() as usize; let key = if i.test_k() {
1866 state.proto_const(&cl, k_idx).clone()
1867 } else {
1868 state.get_at(base + i.arg_c())
1869 };
1870 state.set_at(ra + 1, rb_v.clone());
1871 match state.fast_get_short_str(&rb_v, &key)? {
1872 Some(v) => state.set_at(ra, v),
1873 None => {
1874 state.set_ci_savedpc(ci, pc);
1875 state.set_top(state.ci_top(ci));
1876 finish_get(state, rb_v, key, ra, true, Some(rb_idx))?;
1877 trap = state.ci_trap(ci);
1878 }
1879 }
1880 }
1881 OpCode::AddI => {
1883 let ra = base + i.arg_a();
1884 let rb = base + i.arg_b();
1885 let imm = i.arg_s_c() as i64;
1886 let rb_v = state.stack[rb.0 as usize].val;
1887 match rb_v {
1888 LuaValue::Int(iv1) => {
1889 pc += 1;
1890 state.stack[ra.0 as usize].val = LuaValue::Int(intop_add(iv1, imm));
1891 }
1892 LuaValue::Float(nb) => {
1893 pc += 1;
1894 state.stack[ra.0 as usize].val = LuaValue::Float(nb + imm as f64);
1895 }
1896 _ => {}
1897 }
1898 }
1899 OpCode::AddK => {
1901 let ra = base + i.arg_a();
1902 let rb = base + i.arg_b();
1903 let kidx = i.arg_c() as usize;
1904 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1905 pc += 1;
1906 state.set_at(ra, LuaValue::Int(intop_add(i1, i2)));
1907 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1908 pc += 1;
1909 state.set_at(ra, LuaValue::Float(n1 + n2));
1910 }
1911 }
1912 OpCode::SubK => {
1913 let ra = base + i.arg_a();
1914 let rb = base + i.arg_b();
1915 let kidx = i.arg_c() as usize;
1916 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1917 pc += 1;
1918 state.set_at(ra, LuaValue::Int(intop_sub(i1, i2)));
1919 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1920 pc += 1;
1921 state.set_at(ra, LuaValue::Float(n1 - n2));
1922 }
1923 }
1924 OpCode::MulK => {
1925 let ra = base + i.arg_a();
1926 let rb = base + i.arg_b();
1927 let kidx = i.arg_c() as usize;
1928 if let (Some(i1), Some(i2)) = (state.get_int_at(rb), state.proto_const_int(&cl, kidx)) {
1929 pc += 1;
1930 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
1931 } else if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1932 pc += 1;
1933 state.set_at(ra, LuaValue::Float(n1 * n2));
1934 }
1935 }
1936 OpCode::ModK => {
1937 let ra = base + i.arg_a();
1938 let v1 = state.get_at(base + i.arg_b());
1939 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1940 state.set_ci_savedpc(ci, pc); state.set_top(state.ci_top(ci));
1942 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1943 |a, b| imod(a, b), fmodf)?;
1944 }
1945 OpCode::PowK => {
1946 let ra = base + i.arg_a();
1947 let rb = base + i.arg_b();
1948 let kidx = i.arg_c() as usize;
1949 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1950 pc += 1;
1951 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
1952 state.set_at(ra, LuaValue::Float(r));
1953 }
1954 }
1955 OpCode::DivK => {
1956 let ra = base + i.arg_a();
1957 let rb = base + i.arg_b();
1958 let kidx = i.arg_c() as usize;
1959 if let (Some(n1), Some(n2)) = (state.get_num_at(rb), state.proto_const_num(&cl, kidx)) {
1960 pc += 1;
1961 state.set_at(ra, LuaValue::Float(n1 / n2));
1962 }
1963 }
1964 OpCode::IDivK => {
1965 let ra = base + i.arg_a();
1966 let v1 = state.get_at(base + i.arg_b());
1967 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1968 state.set_ci_savedpc(ci, pc);
1969 state.set_top(state.ci_top(ci));
1970 arith_op_checked(state, ra, &v1, &v2, &mut pc,
1971 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
1972 }
1973 OpCode::BAndK => {
1974 let ra = base + i.arg_a();
1975 let v1 = state.get_at(base + i.arg_b());
1976 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1977 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_band);
1978 }
1979 OpCode::BOrK => {
1980 let ra = base + i.arg_a();
1981 let v1 = state.get_at(base + i.arg_b());
1982 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1983 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bor);
1984 }
1985 OpCode::BXOrK => {
1986 let ra = base + i.arg_a();
1987 let v1 = state.get_at(base + i.arg_b());
1988 let v2 = state.proto_const(&cl, i.arg_c() as usize).clone();
1989 bitwise_op_k(state, ra, &v1, &v2, &mut pc, intop_bxor);
1990 }
1991 OpCode::ShrI => {
1992 let ra = base + i.arg_a();
1993 let v = state.get_at(base + i.arg_b());
1994 let ic = i.arg_s_c() as i64;
1995 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
1996 pc += 1;
1997 state.set_at(ra, LuaValue::Int(shiftl(ib, -ic)));
1998 }
1999 }
2000 OpCode::ShlI => {
2001 let ra = base + i.arg_a();
2002 let v = state.get_at(base + i.arg_b());
2003 let ic = i.arg_s_c() as i64;
2004 if let Some(ib) = to_integer_ns(&v, F2Imod::Eq) {
2005 pc += 1;
2006 state.set_at(ra, LuaValue::Int(shiftl(ic, ib)));
2007 }
2008 }
2009 OpCode::Add => {
2011 let ra = base + i.arg_a();
2012 let rb = base + i.arg_b();
2013 let rc = base + i.arg_c();
2014 let ra_u = ra.0 as usize;
2015 let rb_v = state.stack[rb.0 as usize].val;
2016 let rc_v = state.stack[rc.0 as usize].val;
2017 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2018 pc += 1;
2019 state.stack[ra_u].val = LuaValue::Int(intop_add(i1, i2));
2020 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2021 pc += 1;
2022 state.stack[ra_u].val = LuaValue::Float(n1 + n2);
2023 }
2024 }
2025 OpCode::Sub => {
2026 let ra = base + i.arg_a();
2027 let rb = base + i.arg_b();
2028 let rc = base + i.arg_c();
2029 let ra_u = ra.0 as usize;
2030 let rb_v = state.stack[rb.0 as usize].val;
2031 let rc_v = state.stack[rc.0 as usize].val;
2032 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (rb_v, rc_v) {
2033 pc += 1;
2034 state.stack[ra_u].val = LuaValue::Int(intop_sub(i1, i2));
2035 } else if let (Some(n1), Some(n2)) = (number_value(rb_v), number_value(rc_v)) {
2036 pc += 1;
2037 state.stack[ra_u].val = LuaValue::Float(n1 - n2);
2038 }
2039 }
2040 OpCode::Mul => {
2041 let ra = base + i.arg_a();
2042 let rb = base + i.arg_b();
2043 let rc = base + i.arg_c();
2044 if let Some((i1, i2)) = state.get_int_pair_at(rb, rc) {
2045 pc += 1;
2046 state.set_at(ra, LuaValue::Int(intop_mul(i1, i2)));
2047 } else if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2048 pc += 1;
2049 state.set_at(ra, LuaValue::Float(n1 * n2));
2050 }
2051 }
2052 OpCode::Mod => {
2053 let ra = base + i.arg_a();
2054 let v1 = state.get_at(base + i.arg_b());
2055 let v2 = state.get_at(base + i.arg_c());
2056 state.set_ci_savedpc(ci, pc);
2057 state.set_top(state.ci_top(ci));
2058 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2059 |a, b| imod(a, b), fmodf)?;
2060 }
2061 OpCode::Pow => {
2062 let ra = base + i.arg_a();
2063 let rb = base + i.arg_b();
2064 let rc = base + i.arg_c();
2065 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2066 pc += 1;
2067 let r = if n2 == 2.0 { n1 * n1 } else { n1.powf(n2) };
2068 state.set_at(ra, LuaValue::Float(r));
2069 }
2070 }
2071 OpCode::Div => {
2072 let ra = base + i.arg_a();
2073 let rb = base + i.arg_b();
2074 let rc = base + i.arg_c();
2075 if let Some((n1, n2)) = state.get_num_pair_at(rb, rc) {
2076 pc += 1;
2077 state.set_at(ra, LuaValue::Float(n1 / n2));
2078 }
2079 }
2080 OpCode::IDiv => {
2081 let ra = base + i.arg_a();
2082 let v1 = state.get_at(base + i.arg_b());
2083 let v2 = state.get_at(base + i.arg_c());
2084 state.set_ci_savedpc(ci, pc);
2085 state.set_top(state.ci_top(ci));
2086 arith_op_checked(state, ra, &v1, &v2, &mut pc,
2087 |a, b| idiv(a, b), |a, b| (a / b).floor())?;
2088 }
2089 OpCode::BAnd => {
2092 let ra = base + i.arg_a();
2093 let v1 = state.get_at(base + i.arg_b());
2094 let v2 = state.get_at(base + i.arg_c());
2095 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_band);
2096 }
2097 OpCode::BOr => {
2098 let ra = base + i.arg_a();
2099 let v1 = state.get_at(base + i.arg_b());
2100 let v2 = state.get_at(base + i.arg_c());
2101 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bor);
2102 }
2103 OpCode::BXOr => {
2104 let ra = base + i.arg_a();
2105 let v1 = state.get_at(base + i.arg_b());
2106 let v2 = state.get_at(base + i.arg_c());
2107 bitwise_op_rr(state, ra, &v1, &v2, &mut pc, intop_bxor);
2108 }
2109 OpCode::Shr => {
2110 let ra = base + i.arg_a();
2111 let v1 = state.get_at(base + i.arg_b());
2112 let v2 = state.get_at(base + i.arg_c());
2113 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, true);
2114 }
2115 OpCode::Shl => {
2116 let ra = base + i.arg_a();
2117 let v1 = state.get_at(base + i.arg_b());
2118 let v2 = state.get_at(base + i.arg_c());
2119 bitwise_shift_rr(state, ra, &v1, &v2, &mut pc, false);
2120 }
2121 OpCode::MmBin => {
2126 let ra_idx = base + i.arg_a();
2127 let rb_idx = base + i.arg_b();
2128 let ra_v = state.get_at(ra_idx);
2129 let rb_v = state.get_at(rb_idx);
2130 let tm = tagmethod_from_index(i.arg_c() as usize);
2131 let prev_inst = state.proto_code(&cl, pc - 2);
2132 let result_idx = base + prev_inst.arg_a();
2133 state.set_ci_savedpc(ci, pc);
2134 state.set_top(state.ci_top(ci));
2135 state.try_bin_tm(&ra_v, Some(ra_idx), &rb_v, Some(rb_idx), result_idx, tm)?;
2136 trap = state.ci_trap(ci);
2137 }
2138 OpCode::MmBinI => {
2139 let ra_idx = base + i.arg_a();
2140 let ra_v = state.get_at(ra_idx);
2141 let imm = i.arg_s_b() as i64;
2142 let tm = tagmethod_from_index(i.arg_c() as usize);
2143 let flip = i.arg_k() != 0;
2144 let prev_inst = state.proto_code(&cl, pc - 2);
2145 let result_idx = base + prev_inst.arg_a();
2146 state.set_ci_savedpc(ci, pc);
2147 state.set_top(state.ci_top(ci));
2148 state.try_bin_i_tm(&ra_v, Some(ra_idx), imm, flip, result_idx, tm)?;
2149 trap = state.ci_trap(ci);
2150 }
2151 OpCode::MmBinK => {
2152 let ra_idx = base + i.arg_a();
2153 let ra_v = state.get_at(ra_idx);
2154 let imm = state.proto_const(&cl, i.arg_b() as usize).clone();
2155 let tm = tagmethod_from_index(i.arg_c() as usize);
2156 let flip = i.arg_k() != 0;
2157 let prev_inst = state.proto_code(&cl, pc - 2);
2158 let result_idx = base + prev_inst.arg_a();
2159 state.set_ci_savedpc(ci, pc);
2160 state.set_top(state.ci_top(ci));
2161 state.try_bin_assoc_tm(&ra_v, Some(ra_idx), &imm, None, flip, result_idx, tm)?;
2162 trap = state.ci_trap(ci);
2163 }
2164 OpCode::Unm => {
2168 let ra = base + i.arg_a();
2169 let rb_idx = base + i.arg_b();
2170 let rb_v = state.get_at(rb_idx);
2171 match &rb_v {
2172 LuaValue::Int(ib) => {
2173 state.set_at(ra, LuaValue::Int(intop_sub(0, *ib)));
2174 }
2175 LuaValue::Float(nb) => {
2176 state.set_at(ra, LuaValue::Float(-nb));
2177 }
2178 _ => {
2179 state.set_ci_savedpc(ci, pc);
2180 state.set_top(state.ci_top(ci));
2181 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Unm)?;
2182 trap = state.ci_trap(ci);
2183 }
2184 }
2185 }
2186 OpCode::BNot => {
2188 let ra = base + i.arg_a();
2189 let rb_idx = base + i.arg_b();
2190 let rb_v = state.get_at(rb_idx);
2191 if let Some(ib) = to_integer_ns(&rb_v, F2Imod::Eq) {
2192 state.set_at(ra, LuaValue::Int(!ib));
2193 } else {
2194 state.set_ci_savedpc(ci, pc);
2195 state.set_top(state.ci_top(ci));
2196 state.try_bin_tm(&rb_v, Some(rb_idx), &rb_v, Some(rb_idx), ra, TagMethod::Bnot)?;
2197 trap = state.ci_trap(ci);
2198 }
2199 }
2200 OpCode::Not => {
2202 let ra = base + i.arg_a();
2203 let rb_v = state.get_at(base + i.arg_b());
2204 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2205 state.set_at(ra, LuaValue::Bool(falsy));
2206 }
2207 OpCode::Len => {
2209 let ra = base + i.arg_a();
2210 let rb_v = state.get_at(base + i.arg_b());
2211 state.set_ci_savedpc(ci, pc);
2212 state.set_top(state.ci_top(ci));
2213 obj_len(state, ra, rb_v)?;
2214 trap = state.ci_trap(ci);
2215 }
2216 OpCode::Concat => {
2218 let ra = base + i.arg_a();
2219 let n = i.arg_b() as i32;
2220 state.set_top(ra + n as i32);
2221 state.set_ci_savedpc(ci, pc); concat(state, n)?;
2223 let top = state.top_idx();
2224 state.set_ci_savedpc(ci, pc);
2225 state.set_top(top);
2226 state.gc_cond_step();
2227 trap = state.ci_trap(ci);
2228 }
2229 OpCode::Close => {
2231 let ra = base + i.arg_a();
2232 state.set_ci_savedpc(ci, pc);
2233 state.set_top(state.ci_top(ci));
2234 crate::func::close(state, ra, lua_types::status::LuaStatus::Ok as i32, true)?;
2235 trap = state.ci_trap(ci);
2236 }
2237 OpCode::Tbc => {
2239 let ra = base + i.arg_a();
2240 state.set_ci_savedpc(ci, pc);
2241 state.set_top(state.ci_top(ci));
2242 state.new_tbc_upval(ra)?;
2243 }
2244 OpCode::Jmp => {
2246 pc = (pc as i64 + i.arg_s_j() as i64) as u32;
2247 trap = state.ci_trap(ci);
2248 }
2249 OpCode::Eq => {
2251 let ra_v = state.get_at(base + i.arg_a());
2252 let rb_v = state.get_at(base + i.arg_b());
2253 state.set_ci_savedpc(ci, pc);
2254 state.set_top(state.ci_top(ci));
2255 let cond = equal_obj(Some(state), &ra_v, &rb_v)? as u32;
2256 trap = state.ci_trap(ci);
2257 if (cond as i32) != i.arg_k() {
2258 pc += 1;
2259 } else {
2260 let next = state.proto_code(&cl, pc);
2261 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2262 trap = state.ci_trap(ci);
2263 }
2264 }
2265 OpCode::Lt => {
2267 let ra_v = state.get_at(base + i.arg_a());
2268 let rb_v = state.get_at(base + i.arg_b());
2269 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2270 *ia < *ib
2271 } else if matches!((&ra_v, &rb_v),
2272 (LuaValue::Int(_) | LuaValue::Float(_),
2273 LuaValue::Int(_) | LuaValue::Float(_))) {
2274 lt_num(&ra_v, &rb_v)
2275 } else {
2276 state.set_ci_savedpc(ci, pc);
2277 state.set_top(state.ci_top(ci));
2278 let r = less_than_others(state, &ra_v, &rb_v)?;
2279 trap = state.ci_trap(ci);
2280 r
2281 };
2282 if (cond as i32) != i.arg_k() {
2283 pc += 1;
2284 } else {
2285 let next = state.proto_code(&cl, pc);
2286 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2287 trap = state.ci_trap(ci);
2288 }
2289 }
2290 OpCode::Le => {
2292 let ra_v = state.get_at(base + i.arg_a());
2293 let rb_v = state.get_at(base + i.arg_b());
2294 let cond = if let (LuaValue::Int(ia), LuaValue::Int(ib)) = (&ra_v, &rb_v) {
2295 *ia <= *ib
2296 } else if matches!((&ra_v, &rb_v),
2297 (LuaValue::Int(_) | LuaValue::Float(_),
2298 LuaValue::Int(_) | LuaValue::Float(_))) {
2299 le_num(&ra_v, &rb_v)
2300 } else {
2301 state.set_ci_savedpc(ci, pc);
2302 state.set_top(state.ci_top(ci));
2303 let r = less_equal_others(state, &ra_v, &rb_v)?;
2304 trap = state.ci_trap(ci);
2305 r
2306 };
2307 if (cond as i32) != i.arg_k() {
2308 pc += 1;
2309 } else {
2310 let next = state.proto_code(&cl, pc);
2311 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2312 trap = state.ci_trap(ci);
2313 }
2314 }
2315 OpCode::EqK => {
2317 let ra_v = state.get_at(base + i.arg_a());
2318 let rb_v = state.proto_const(&cl, i.arg_b() as usize).clone();
2319 let cond = equal_obj(None, &ra_v, &rb_v)? as u32;
2320 if (cond as i32) != i.arg_k() {
2321 pc += 1;
2322 } else {
2323 let next = state.proto_code(&cl, pc);
2324 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2325 trap = state.ci_trap(ci);
2326 }
2327 }
2328 OpCode::EqI => {
2333 let ra_v = state.get_at(base + i.arg_a());
2334 let im = i.arg_s_b() as i64;
2335 let cond: bool = match &ra_v {
2336 LuaValue::Int(iv) => *iv == im,
2337 LuaValue::Float(fv) => *fv == im as f64,
2338 _ => false,
2339 };
2340 if (cond as i32) != i.arg_k() {
2341 pc += 1;
2342 } else {
2343 let next = state.proto_code(&cl, pc);
2344 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2345 trap = state.ci_trap(ci);
2346 }
2347 }
2348 OpCode::LtI => {
2351 let ra = base + i.arg_a();
2352 let im = i.arg_s_b() as i64;
2353 let fast_cond = match &state.stack[ra.0 as usize].val {
2354 LuaValue::Int(ia) => Some(*ia < im),
2355 LuaValue::Float(fa) => Some(*fa < im as f64),
2356 _ => None,
2357 };
2358 let cond = match fast_cond {
2359 Some(cond) => cond,
2360 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Lt)?,
2361 };
2362 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2363 }
2364 OpCode::LeI => {
2365 let ra = base + i.arg_a();
2366 let im = i.arg_s_b() as i64;
2367 let fast_cond = match &state.stack[ra.0 as usize].val {
2368 LuaValue::Int(ia) => Some(*ia <= im),
2369 LuaValue::Float(fa) => Some(*fa <= im as f64),
2370 _ => None,
2371 };
2372 let cond = match fast_cond {
2373 Some(cond) => cond,
2374 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, false, TagMethod::Le)?,
2375 };
2376 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2377 }
2378 OpCode::GtI => {
2379 let ra = base + i.arg_a();
2380 let im = i.arg_s_b() as i64;
2381 let fast_cond = match &state.stack[ra.0 as usize].val {
2382 LuaValue::Int(ia) => Some(*ia > im),
2383 LuaValue::Float(fa) => Some(*fa > im as f64),
2384 _ => None,
2385 };
2386 let cond = match fast_cond {
2387 Some(cond) => cond,
2388 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Lt)?,
2389 };
2390 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2391 }
2392 OpCode::GeI => {
2393 let ra = base + i.arg_a();
2394 let im = i.arg_s_b() as i64;
2395 let fast_cond = match &state.stack[ra.0 as usize].val {
2396 LuaValue::Int(ia) => Some(*ia >= im),
2397 LuaValue::Float(fa) => Some(*fa >= im as f64),
2398 _ => None,
2399 };
2400 let cond = match fast_cond {
2401 Some(cond) => cond,
2402 None => order_imm_slow(state, ra, pc, &mut trap, ci, i, im, true, TagMethod::Le)?,
2403 };
2404 finish_order_imm_jump(state, &cl, &mut pc, &mut trap, ci, i, cond);
2405 }
2406 OpCode::Test => {
2408 let ra_v = state.get_at(base + i.arg_a());
2409 let cond = !matches!(ra_v, LuaValue::Nil | LuaValue::Bool(false));
2410 if (cond as i32) != i.arg_k() {
2411 pc += 1;
2412 } else {
2413 let next = state.proto_code(&cl, pc);
2414 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2415 trap = state.ci_trap(ci);
2416 }
2417 }
2418 OpCode::TestSet => {
2421 let ra = base + i.arg_a();
2422 let rb_v = state.get_at(base + i.arg_b());
2423 let falsy = matches!(rb_v, LuaValue::Nil | LuaValue::Bool(false));
2424 if (falsy as i32) == i.arg_k() {
2425 pc += 1;
2426 } else {
2427 state.set_at(ra, rb_v);
2428 let next = state.proto_code(&cl, pc);
2429 pc = (pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2430 trap = state.ci_trap(ci);
2431 }
2432 }
2433 OpCode::Call => {
2437 let ra = base + i.arg_a();
2438 let b = i.arg_b();
2439 let nresults = i.arg_c() as i32 - 1;
2440 if b != 0 {
2441 state.set_top(ra + b);
2442 }
2443 state.set_ci_savedpc(ci, pc); let had_hook = state.hookmask != 0;
2445 match state.precall(ra, nresults)? {
2446 None => {
2447 if had_hook || state.hookmask != 0 {
2451 trap = state.ci_trap(ci); }
2453 }
2454 Some(new_ci) => {
2455 ci = new_ci;
2457 continue 'startfunc;
2458 }
2459 }
2460 }
2461 OpCode::TailCall => {
2466 let ra = base + i.arg_a();
2467 let b = i.arg_b();
2468 let nparams1 = i.arg_c();
2469 let delta = if nparams1 != 0 {
2470 state.ci_nextraargs(ci) + nparams1 as i32
2471 } else {
2472 0
2473 };
2474 let top_b: i32 = if b != 0 {
2475 state.set_top(ra + b);
2476 b
2477 } else {
2478 state.top_idx() - ra
2479 };
2480 state.set_ci_savedpc(ci, pc);
2481 if i.test_k() {
2482 state.close_upvals_from_base(ci)?;
2483 }
2484 let n = state.pretailcall(ci, ra, top_b, delta)?;
2485 if n < 0 {
2486 continue 'startfunc;
2488 } else {
2489 state.ci_adjust_func(ci, delta);
2491 state.poscall(ci, n as u32)?;
2492 if state.hookmask != 0 {
2493 trap = state.ci_trap(ci);
2494 }
2495 break 'dispatch; }
2497 }
2498 OpCode::Return => {
2503 let ra = base + i.arg_a();
2504 let n_raw = i.arg_b() as i32 - 1;
2505 let nparams1 = i.arg_c();
2506 let n: u32 = if n_raw < 0 {
2507 (state.top_idx() - ra) as u32
2508 } else {
2509 n_raw as u32
2510 };
2511 state.set_ci_savedpc(ci, pc);
2512 if i.test_k() {
2513 state.ci_nres_set(ci, n as i32);
2514 let ci_top = state.ci_top(ci);
2515 if state.top_idx().0 < ci_top.0 {
2516 state.set_top(ci_top);
2517 }
2518 crate::func::close(state, base, crate::func::CLOSE_K_TOP, true)?;
2519 if state.hookmask != 0 {
2520 trap = state.ci_trap(ci);
2521 }
2522 base = state.ci_base(ci); }
2524 if nparams1 != 0 {
2525 let nextraargs = state.ci_nextraargs(ci) as u32;
2526 state.ci_adjust_func(ci, nextraargs as i32 + nparams1 as i32);
2527 }
2528 state.set_top(ra + n as i32);
2529 state.poscall(ci, n)?;
2530 if state.hookmask != 0 {
2531 trap = state.ci_trap(ci);
2532 }
2533 break 'dispatch; }
2535 OpCode::Return0 => {
2541 if state.hookmask == 0 {
2542 let ci_slot = ci.as_usize();
2543 let nres = state.call_info[ci_slot].nresults as i32;
2544 state.ci = state.call_info[ci_slot]
2545 .previous
2546 .expect("RETURN0: returning frame has no previous CallInfo");
2547 state.top = base - 1;
2548 for _ in 0..nres.max(0) {
2549 state.push(LuaValue::Nil);
2550 }
2551 } else {
2552 return0_hook(state, ci, base, i, pc, &mut trap)?;
2553 }
2554 break 'dispatch; }
2556 OpCode::Return1 => {
2560 if state.hookmask == 0 {
2561 let ci_slot = ci.as_usize();
2562 let nres = state.call_info[ci_slot].nresults as i32;
2563 state.ci = state.call_info[ci_slot]
2564 .previous
2565 .expect("RETURN1: returning frame has no previous CallInfo");
2566 if nres == 0 {
2567 state.top = base - 1;
2568 } else {
2569 let ra = base + i.arg_a();
2570 state.stack[(base - 1).0 as usize].val =
2571 state.stack[ra.0 as usize].val; state.top = base;
2573 for _ in 1..nres.max(0) {
2574 state.push(LuaValue::Nil);
2575 }
2576 }
2577 } else {
2578 return1_hook(state, ci, base, i, pc, &mut trap)?;
2579 }
2580 break 'dispatch; }
2582 OpCode::ForLoop => {
2586 let ra = base + i.arg_a();
2587 let ra_u = ra.0 as usize;
2588 if let LuaValue::Int(step) = state.stack[ra_u + 2].val {
2589 let count = match state.stack[ra_u + 1].val {
2590 LuaValue::Int(c) => c as u64,
2591 _ => 0,
2592 };
2593 if count > 0 {
2594 let idx = match state.stack[ra_u].val {
2595 LuaValue::Int(x) => x,
2596 _ => 0,
2597 };
2598 state.stack[ra_u + 1].val = LuaValue::Int((count - 1) as i64);
2599 let new_idx = intop_add(idx, step);
2600 state.stack[ra_u].val = LuaValue::Int(new_idx);
2601 state.stack[ra_u + 3].val = LuaValue::Int(new_idx);
2602 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2603 }
2604 } else if float_for_loop(state, ra) {
2605 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2606 }
2607 trap = state.ci_trap(ci);
2608 }
2609 OpCode::ForPrep => {
2611 let ra = base + i.arg_a();
2612 state.set_ci_savedpc(ci, pc);
2613 state.set_top(state.ci_top(ci));
2614 if forprep(state, ra)? {
2615 pc = (pc as i64 + i.arg_bx() as i64 + 1) as u32;
2616 }
2617 }
2618 OpCode::TForPrep => {
2622 let ra = base + i.arg_a();
2623 state.set_ci_savedpc(ci, pc);
2624 state.set_top(state.ci_top(ci));
2625 state.new_tbc_upval(ra + 3)?;
2626 pc = (pc as i64 + i.arg_bx() as i64) as u32;
2627 let tfc_i = state.proto_code(&cl, pc);
2628 pc += 1;
2629 debug_assert!(tfc_i.opcode() == OpCode::TForCall);
2630 let tfc_ra = base + tfc_i.arg_a();
2632 for k in 0..3u32 {
2633 let v = state.get_at(tfc_ra + k as i32);
2634 state.set_at(tfc_ra + 4 + k as i32, v);
2635 }
2636 state.set_top(tfc_ra + 4 + 3);
2637 state.set_ci_savedpc(ci, pc);
2638 state.call_at(tfc_ra + 4, tfc_i.arg_c() as i32)?;
2639 trap = state.ci_trap(ci);
2640 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2642 pc += 1;
2643 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2644 let tfl_ra = base + tfl_i.arg_a();
2645 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2647 let v = state.get_at(tfl_ra + 4);
2648 state.set_at(tfl_ra + 2, v);
2649 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2650 }
2651 }
2652 OpCode::TForCall => {
2654 let ra = base + i.arg_a();
2655 for k in 0..3u32 {
2656 let v = state.get_at(ra + k as i32);
2657 state.set_at(ra + 4 + k as i32, v);
2658 }
2659 state.set_top(ra + 4 + 3);
2660 state.set_ci_savedpc(ci, pc);
2661 state.call_at(ra + 4, i.arg_c() as i32)?;
2662 trap = state.ci_trap(ci);
2663 base = state.ci_base(ci); let tfl_i = state.proto_code(&cl, pc);
2665 pc += 1;
2666 debug_assert!(tfl_i.opcode() == OpCode::TForLoop);
2667 let tfl_ra = base + tfl_i.arg_a();
2668 if !matches!(state.get_at(tfl_ra + 4), LuaValue::Nil) {
2669 let v = state.get_at(tfl_ra + 4);
2670 state.set_at(tfl_ra + 2, v);
2671 pc = (pc as i64 - tfl_i.arg_bx() as i64) as u32;
2672 }
2673 }
2674 OpCode::TForLoop => {
2676 let ra = base + i.arg_a();
2677 if !matches!(state.get_at(ra + 4), LuaValue::Nil) {
2678 let v = state.get_at(ra + 4);
2679 state.set_at(ra + 2, v);
2680 pc = (pc as i64 - i.arg_bx() as i64) as u32;
2681 }
2682 }
2683 OpCode::SetList => {
2687 let ra = base + i.arg_a();
2688 let n_raw = i.arg_b();
2689 let mut last = i.arg_c();
2690 let t_val = state.get_at(ra);
2691 let n: i32 = if n_raw == 0 {
2692 state.top_idx() - ra - 1
2693 } else {
2694 state.set_top(state.ci_top(ci));
2695 n_raw
2696 };
2697 last += n;
2698 if i.test_k() {
2699 let extra = state.proto_code(&cl, pc);
2700 pc += 1;
2701 const MAXARG_C: i32 = (1 << 8) - 1;
2702 last += extra.arg_ax() * (MAXARG_C + 1);
2703 }
2704 state.table_ensure_array(&t_val, last as usize)?;
2705 for k in (1..=n).rev() {
2706 let val = state.get_at(ra + k as i32);
2707 state.table_array_set(&t_val, (last - 1) as usize, val.clone())?;
2708 last -= 1;
2709 state.gc_barrier_back(&t_val, &val);
2710 }
2711 }
2712 OpCode::Closure => {
2716 let ra = base + i.arg_a();
2717 let proto_idx = i.arg_bx() as usize;
2718 state.set_ci_savedpc(ci, pc);
2719 state.set_top(state.ci_top(ci));
2720 push_closure(state, proto_idx, ci, base, ra)?;
2721 state.set_ci_savedpc(ci, pc);
2723 state.set_top(ra + 1);
2724 state.gc_cond_step();
2725 trap = state.ci_trap(ci);
2726 }
2727 OpCode::VarArg => {
2729 let ra = base + i.arg_a();
2730 let n = i.arg_c() as i32 - 1;
2731 state.set_ci_savedpc(ci, pc);
2732 state.set_top(state.ci_top(ci));
2733 state.get_varargs(ci, ra, n)?;
2734 trap = state.ci_trap(ci);
2735 }
2736 OpCode::VarArgPrep => {
2740 let nparams = i.arg_a();
2741 state.set_ci_savedpc(ci, pc);
2742 state.adjust_varargs(ci, nparams, &cl)?;
2743 trap = state.ci_trap(ci);
2744 if trap {
2745 state.hook_call(ci)?;
2746 state.set_oldpc(1);
2747 }
2748 base = state.ci_base(ci);
2749 }
2750 OpCode::ExtraArg => {
2752 debug_assert!(false, "OP_EXTRAARG executed directly");
2753 }
2754 } } if state.ci_is_fresh(ci) {
2759 return Ok(());
2760 } else {
2761 ci = state.ci_previous(ci).expect("ci_previous: not fresh frame must have previous");
2762 continue 'returning;
2763 }
2764 } } }
2767
2768#[inline(always)]
2771fn number_value(v: LuaValue) -> Option<f64> {
2772 match v {
2773 LuaValue::Float(f) => Some(f),
2774 LuaValue::Int(i) => Some(i as f64),
2775 _ => None,
2776 }
2777}
2778
2779#[allow(dead_code)]
2781#[inline]
2782fn arith_op_aux_rr(
2783 state: &mut LuaState,
2784 ra: StackIdx,
2785 v1: &LuaValue,
2786 v2: &LuaValue,
2787 pc: &mut u32,
2788 iop: fn(i64, i64) -> i64,
2789 fop: fn(f64, f64) -> f64,
2790) {
2791 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2792 *pc += 1;
2793 state.set_at(ra, LuaValue::Int(iop(*i1, *i2)));
2794 } else {
2795 arith_float_aux(state, ra, v1, v2, pc, fop);
2796 }
2797}
2798
2799#[allow(dead_code)]
2800#[inline]
2801fn arith_float_aux(
2802 state: &mut LuaState,
2803 ra: StackIdx,
2804 v1: &LuaValue,
2805 v2: &LuaValue,
2806 pc: &mut u32,
2807 fop: fn(f64, f64) -> f64,
2808) {
2809 let n1 = match v1 {
2810 LuaValue::Float(f) => Some(*f),
2811 LuaValue::Int(i) => Some(*i as f64),
2812 _ => None,
2813 };
2814 let n2 = match v2 {
2815 LuaValue::Float(f) => Some(*f),
2816 LuaValue::Int(i) => Some(*i as f64),
2817 _ => None,
2818 };
2819 if let (Some(n1), Some(n2)) = (n1, n2) {
2820 *pc += 1;
2821 state.set_at(ra, LuaValue::Float(fop(n1, n2)));
2822 }
2823}
2824
2825#[allow(dead_code)]
2826#[inline]
2827fn arith_op_checked(
2828 state: &mut LuaState,
2829 ra: StackIdx,
2830 v1: &LuaValue,
2831 v2: &LuaValue,
2832 pc: &mut u32,
2833 iop: fn(i64, i64) -> Result<i64, LuaError>,
2834 fop: fn(f64, f64) -> f64,
2835) -> Result<(), LuaError> {
2836 if let (LuaValue::Int(i1), LuaValue::Int(i2)) = (v1, v2) {
2837 *pc += 1;
2838 let result = iop(*i1, *i2).map_err(|e| match e {
2839 LuaError::Runtime(LuaValue::Str(s)) => {
2840 crate::debug::prefixed_runtime_pub(state, s.as_bytes().to_vec())
2841 }
2842 other => other,
2843 })?;
2844 state.set_at(ra, LuaValue::Int(result));
2845 } else {
2846 arith_float_aux(state, ra, v1, v2, pc, fop);
2847 }
2848 Ok(())
2849}
2850
2851#[allow(dead_code)]
2852#[inline]
2853fn bitwise_op_k(
2854 state: &mut LuaState,
2855 ra: StackIdx,
2856 v1: &LuaValue,
2857 v2: &LuaValue, pc: &mut u32,
2859 op: fn(i64, i64) -> i64,
2860) {
2861 let i2 = match v2 {
2862 LuaValue::Int(i) => *i,
2863 _ => return,
2864 };
2865 if let Some(i1) = to_integer_ns(v1, F2Imod::Eq) {
2866 *pc += 1;
2867 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2868 }
2869}
2870
2871#[allow(dead_code)]
2872#[inline]
2873fn bitwise_op_rr(
2874 state: &mut LuaState,
2875 ra: StackIdx,
2876 v1: &LuaValue,
2877 v2: &LuaValue,
2878 pc: &mut u32,
2879 op: fn(i64, i64) -> i64,
2880) {
2881 if let (Some(i1), Some(i2)) = (
2882 to_integer_ns(v1, F2Imod::Eq),
2883 to_integer_ns(v2, F2Imod::Eq),
2884 ) {
2885 *pc += 1;
2886 state.set_at(ra, LuaValue::Int(op(i1, i2)));
2887 }
2888}
2889
2890#[allow(dead_code)]
2892#[inline]
2893fn bitwise_shift_rr(
2894 state: &mut LuaState,
2895 ra: StackIdx,
2896 v1: &LuaValue,
2897 v2: &LuaValue,
2898 pc: &mut u32,
2899 right: bool,
2900) {
2901 if let (Some(i1), Some(i2)) = (
2902 to_integer_ns(v1, F2Imod::Eq),
2903 to_integer_ns(v2, F2Imod::Eq),
2904 ) {
2905 let y = if right { intop_sub(0, i2) } else { i2 };
2906 *pc += 1;
2907 state.set_at(ra, LuaValue::Int(shiftl(i1, y)));
2908 }
2909}
2910
2911#[cold]
2914#[inline(never)]
2915#[allow(clippy::too_many_arguments)]
2916fn order_imm_slow(
2917 state: &mut LuaState,
2918 ra: StackIdx,
2919 pc: u32,
2920 trap: &mut bool,
2921 ci: CallInfoIdx,
2922 i: Instruction,
2923 im: i64,
2924 inv: bool,
2925 tm: TagMethod,
2926) -> Result<bool, LuaError> {
2927 let ra_v = state.get_at(ra);
2928 let isf = i.arg_c() != 0;
2929 state.set_ci_savedpc(ci, pc);
2930 state.set_top(state.ci_top(ci));
2931 let r = state.call_order_i_tm(&ra_v, im, inv, isf, tm)?;
2932 *trap = state.ci_trap(ci);
2933 Ok(r)
2934}
2935
2936#[inline(always)]
2937fn finish_order_imm_jump(
2938 state: &mut LuaState,
2939 cl: &lua_types::GcRef<lua_types::LuaLClosure>,
2940 pc: &mut u32,
2941 trap: &mut bool,
2942 ci: CallInfoIdx,
2943 i: Instruction,
2944 cond: bool,
2945) {
2946 if (cond as i32) != i.arg_k() {
2947 *pc += 1;
2948 } else {
2949 let next = state.proto_code(&cl, *pc);
2950 *pc = (*pc as i64 + next.arg_s_j() as i64 + 1) as u32;
2951 *trap = state.ci_trap(ci);
2952 }
2953}
2954
2955#[cold]
2956#[inline(never)]
2957fn return0_hook(
2958 state: &mut LuaState,
2959 ci: CallInfoIdx,
2960 base: StackIdx,
2961 i: Instruction,
2962 pc: u32,
2963 trap: &mut bool,
2964) -> Result<(), LuaError> {
2965 let ra = base + i.arg_a();
2966 state.set_top(ra);
2967 state.set_ci_savedpc(ci, pc);
2968 state.poscall(ci, 0)?;
2969 *trap = true;
2970 Ok(())
2971}
2972
2973#[cold]
2974#[inline(never)]
2975fn return1_hook(
2976 state: &mut LuaState,
2977 ci: CallInfoIdx,
2978 base: StackIdx,
2979 i: Instruction,
2980 pc: u32,
2981 trap: &mut bool,
2982) -> Result<(), LuaError> {
2983 let ra = base + i.arg_a();
2984 state.set_top(ra + 1);
2985 state.set_ci_savedpc(ci, pc);
2986 state.poscall(ci, 1)?;
2987 *trap = true;
2988 Ok(())
2989}
2990
2991