1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[repr(u8)]
20pub enum OpMode {
21 Abc = 0,
22 ABx = 1,
23 AsBx = 2,
24 Ax = 3,
25 SJ = 4,
26}
27
28pub const SIZE_C: u32 = 8;
32pub const SIZE_B: u32 = 8;
33pub const SIZE_BX: u32 = SIZE_C + SIZE_B + 1;
34pub const SIZE_A: u32 = 8;
35pub const SIZE_AX: u32 = SIZE_BX + SIZE_A;
36pub const SIZE_S_J: u32 = SIZE_BX + SIZE_A;
37pub const SIZE_OP: u32 = 7;
38
39pub const POS_OP: u32 = 0;
43pub const POS_A: u32 = POS_OP + SIZE_OP;
44pub const POS_K: u32 = POS_A + SIZE_A;
45pub const POS_B: u32 = POS_K + 1;
46pub const POS_C: u32 = POS_B + SIZE_B;
47pub const POS_BX: u32 = POS_K;
48pub const POS_AX: u32 = POS_A;
49pub const POS_S_J: u32 = POS_A;
50
51pub const MAXARG_BX: u32 = (1u32 << SIZE_BX) - 1;
55pub const OFFSET_S_BX: i32 = (MAXARG_BX >> 1) as i32;
56pub const MAXARG_AX: u32 = (1u32 << SIZE_AX) - 1;
57pub const MAXARG_S_J: u32 = (1u32 << SIZE_S_J) - 1;
58pub const OFFSET_S_J: i32 = (MAXARG_S_J >> 1) as i32;
59pub const MAXARG_A: u32 = (1u32 << SIZE_A) - 1;
60pub const MAXARG_B: u32 = (1u32 << SIZE_B) - 1;
61pub const MAXARG_C: u32 = (1u32 << SIZE_C) - 1;
62pub const OFFSET_S_C: i32 = (MAXARG_C >> 1) as i32;
63
64pub const NO_REG: u32 = MAXARG_A;
67
68pub const MAXINDEXRK: u32 = MAXARG_B;
71
72pub const LFIELDS_PER_FLUSH: u32 = 50;
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
86#[repr(u8)]
87pub enum OpCode {
88 Move = 0,
89 LoadI,
90 LoadF,
91 LoadK,
92 LoadKX,
93 LoadFalse,
94 LFalseSkip,
95 LoadTrue,
96 LoadNil,
97 GetUpVal,
98 SetUpVal,
99
100 GetTabUp,
101 GetTable,
102 GetI,
103 GetField,
104
105 SetTabUp,
106 SetTable,
107 SetI,
108 SetField,
109
110 NewTable,
111
112 Self_,
114
115 AddI,
116
117 AddK,
118 SubK,
119 MulK,
120 ModK,
121 PowK,
122 DivK,
123 IDivK,
124
125 BAndK,
126 BOrK,
127 BXorK,
128
129 ShrI,
130 ShlI,
131
132 Add,
133 Sub,
134 Mul,
135 Mod,
136 Pow,
137 Div,
138 IDiv,
139
140 BAnd,
141 BOr,
142 BXor,
143 Shl,
144 Shr,
145
146 MmBin,
147 MmBinI,
148 MmBinK,
149
150 Unm,
151 BNot,
152 Not,
153 Len,
154
155 Concat,
156
157 Close,
158 Tbc,
159 Jmp,
160
161 Eq,
162 Lt,
163 Le,
164
165 EqK,
166 EqI,
167 LtI,
168 LeI,
169 GtI,
170 GeI,
171
172 Test,
173 TestSet,
174
175 Call,
176 TailCall,
177
178 Return,
179 Return0,
180 Return1,
181
182 ForLoop,
183 ForPrep,
184
185 TForPrep,
186 TForCall,
187 TForLoop,
188
189 SetList,
190
191 Closure,
192
193 VarArg,
194
195 VarArgPrep,
196
197 ExtraArg,
198}
199
200pub const NUM_OPCODES: usize = OpCode::ExtraArg as usize + 1;
203
204impl OpCode {
205 pub fn from_u32(v: u32) -> Option<Self> {
214 match v {
215 0 => Some(Self::Move),
216 1 => Some(Self::LoadI),
217 2 => Some(Self::LoadF),
218 3 => Some(Self::LoadK),
219 4 => Some(Self::LoadKX),
220 5 => Some(Self::LoadFalse),
221 6 => Some(Self::LFalseSkip),
222 7 => Some(Self::LoadTrue),
223 8 => Some(Self::LoadNil),
224 9 => Some(Self::GetUpVal),
225 10 => Some(Self::SetUpVal),
226 11 => Some(Self::GetTabUp),
227 12 => Some(Self::GetTable),
228 13 => Some(Self::GetI),
229 14 => Some(Self::GetField),
230 15 => Some(Self::SetTabUp),
231 16 => Some(Self::SetTable),
232 17 => Some(Self::SetI),
233 18 => Some(Self::SetField),
234 19 => Some(Self::NewTable),
235 20 => Some(Self::Self_),
236 21 => Some(Self::AddI),
237 22 => Some(Self::AddK),
238 23 => Some(Self::SubK),
239 24 => Some(Self::MulK),
240 25 => Some(Self::ModK),
241 26 => Some(Self::PowK),
242 27 => Some(Self::DivK),
243 28 => Some(Self::IDivK),
244 29 => Some(Self::BAndK),
245 30 => Some(Self::BOrK),
246 31 => Some(Self::BXorK),
247 32 => Some(Self::ShrI),
248 33 => Some(Self::ShlI),
249 34 => Some(Self::Add),
250 35 => Some(Self::Sub),
251 36 => Some(Self::Mul),
252 37 => Some(Self::Mod),
253 38 => Some(Self::Pow),
254 39 => Some(Self::Div),
255 40 => Some(Self::IDiv),
256 41 => Some(Self::BAnd),
257 42 => Some(Self::BOr),
258 43 => Some(Self::BXor),
259 44 => Some(Self::Shl),
260 45 => Some(Self::Shr),
261 46 => Some(Self::MmBin),
262 47 => Some(Self::MmBinI),
263 48 => Some(Self::MmBinK),
264 49 => Some(Self::Unm),
265 50 => Some(Self::BNot),
266 51 => Some(Self::Not),
267 52 => Some(Self::Len),
268 53 => Some(Self::Concat),
269 54 => Some(Self::Close),
270 55 => Some(Self::Tbc),
271 56 => Some(Self::Jmp),
272 57 => Some(Self::Eq),
273 58 => Some(Self::Lt),
274 59 => Some(Self::Le),
275 60 => Some(Self::EqK),
276 61 => Some(Self::EqI),
277 62 => Some(Self::LtI),
278 63 => Some(Self::LeI),
279 64 => Some(Self::GtI),
280 65 => Some(Self::GeI),
281 66 => Some(Self::Test),
282 67 => Some(Self::TestSet),
283 68 => Some(Self::Call),
284 69 => Some(Self::TailCall),
285 70 => Some(Self::Return),
286 71 => Some(Self::Return0),
287 72 => Some(Self::Return1),
288 73 => Some(Self::ForLoop),
289 74 => Some(Self::ForPrep),
290 75 => Some(Self::TForPrep),
291 76 => Some(Self::TForCall),
292 77 => Some(Self::TForLoop),
293 78 => Some(Self::SetList),
294 79 => Some(Self::Closure),
295 80 => Some(Self::VarArg),
296 81 => Some(Self::VarArgPrep),
297 82 => Some(Self::ExtraArg),
298 _ => None,
299 }
300 }
301}
302
303const fn opmode_byte(mm: u8, ot: u8, it: u8, t: u8, a: u8, m: u8) -> u8 {
316 (mm << 7) | (ot << 6) | (it << 5) | (t << 4) | (a << 3) | m
317}
318
319const M_ABC: u8 = OpMode::Abc as u8;
321const M_ABX: u8 = OpMode::ABx as u8;
322const M_ASBX: u8 = OpMode::AsBx as u8;
323const M_AX: u8 = OpMode::Ax as u8;
324const M_SJ: u8 = OpMode::SJ as u8;
325
326pub(crate) const OP_MODES: [u8; NUM_OPCODES] = [
338 opmode_byte(0, 0, 0, 0, 1, M_ABC),
339 opmode_byte(0, 0, 0, 0, 1, M_ASBX),
340 opmode_byte(0, 0, 0, 0, 1, M_ASBX),
341 opmode_byte(0, 0, 0, 0, 1, M_ABX),
342 opmode_byte(0, 0, 0, 0, 1, M_ABX),
343 opmode_byte(0, 0, 0, 0, 1, M_ABC),
344 opmode_byte(0, 0, 0, 0, 1, M_ABC),
345 opmode_byte(0, 0, 0, 0, 1, M_ABC),
346 opmode_byte(0, 0, 0, 0, 1, M_ABC),
347 opmode_byte(0, 0, 0, 0, 1, M_ABC),
348 opmode_byte(0, 0, 0, 0, 0, M_ABC),
349 opmode_byte(0, 0, 0, 0, 1, M_ABC),
350 opmode_byte(0, 0, 0, 0, 1, M_ABC),
351 opmode_byte(0, 0, 0, 0, 1, M_ABC),
352 opmode_byte(0, 0, 0, 0, 1, M_ABC),
353 opmode_byte(0, 0, 0, 0, 0, M_ABC),
354 opmode_byte(0, 0, 0, 0, 0, M_ABC),
355 opmode_byte(0, 0, 0, 0, 0, M_ABC),
356 opmode_byte(0, 0, 0, 0, 0, M_ABC),
357 opmode_byte(0, 0, 0, 0, 1, M_ABC),
358 opmode_byte(0, 0, 0, 0, 1, M_ABC),
359 opmode_byte(0, 0, 0, 0, 1, M_ABC),
360 opmode_byte(0, 0, 0, 0, 1, M_ABC),
361 opmode_byte(0, 0, 0, 0, 1, M_ABC),
362 opmode_byte(0, 0, 0, 0, 1, M_ABC),
363 opmode_byte(0, 0, 0, 0, 1, M_ABC),
364 opmode_byte(0, 0, 0, 0, 1, M_ABC),
365 opmode_byte(0, 0, 0, 0, 1, M_ABC),
366 opmode_byte(0, 0, 0, 0, 1, M_ABC),
367 opmode_byte(0, 0, 0, 0, 1, M_ABC),
368 opmode_byte(0, 0, 0, 0, 1, M_ABC),
369 opmode_byte(0, 0, 0, 0, 1, M_ABC),
370 opmode_byte(0, 0, 0, 0, 1, M_ABC),
371 opmode_byte(0, 0, 0, 0, 1, M_ABC),
372 opmode_byte(0, 0, 0, 0, 1, M_ABC),
373 opmode_byte(0, 0, 0, 0, 1, M_ABC),
374 opmode_byte(0, 0, 0, 0, 1, M_ABC),
375 opmode_byte(0, 0, 0, 0, 1, M_ABC),
376 opmode_byte(0, 0, 0, 0, 1, M_ABC),
377 opmode_byte(0, 0, 0, 0, 1, M_ABC),
378 opmode_byte(0, 0, 0, 0, 1, M_ABC),
379 opmode_byte(0, 0, 0, 0, 1, M_ABC),
380 opmode_byte(0, 0, 0, 0, 1, M_ABC),
381 opmode_byte(0, 0, 0, 0, 1, M_ABC),
382 opmode_byte(0, 0, 0, 0, 1, M_ABC),
383 opmode_byte(0, 0, 0, 0, 1, M_ABC),
384 opmode_byte(1, 0, 0, 0, 0, M_ABC),
385 opmode_byte(1, 0, 0, 0, 0, M_ABC),
386 opmode_byte(1, 0, 0, 0, 0, M_ABC),
387 opmode_byte(0, 0, 0, 0, 1, M_ABC),
388 opmode_byte(0, 0, 0, 0, 1, M_ABC),
389 opmode_byte(0, 0, 0, 0, 1, M_ABC),
390 opmode_byte(0, 0, 0, 0, 1, M_ABC),
391 opmode_byte(0, 0, 0, 0, 1, M_ABC),
392 opmode_byte(0, 0, 0, 0, 0, M_ABC),
393 opmode_byte(0, 0, 0, 0, 0, M_ABC),
394 opmode_byte(0, 0, 0, 0, 0, M_SJ),
395 opmode_byte(0, 0, 0, 1, 0, M_ABC),
396 opmode_byte(0, 0, 0, 1, 0, M_ABC),
397 opmode_byte(0, 0, 0, 1, 0, M_ABC),
398 opmode_byte(0, 0, 0, 1, 0, M_ABC),
399 opmode_byte(0, 0, 0, 1, 0, M_ABC),
400 opmode_byte(0, 0, 0, 1, 0, M_ABC),
401 opmode_byte(0, 0, 0, 1, 0, M_ABC),
402 opmode_byte(0, 0, 0, 1, 0, M_ABC),
403 opmode_byte(0, 0, 0, 1, 0, M_ABC),
404 opmode_byte(0, 0, 0, 1, 0, M_ABC),
405 opmode_byte(0, 0, 0, 1, 1, M_ABC),
406 opmode_byte(0, 1, 1, 0, 1, M_ABC),
407 opmode_byte(0, 1, 1, 0, 1, M_ABC),
408 opmode_byte(0, 0, 1, 0, 0, M_ABC),
409 opmode_byte(0, 0, 0, 0, 0, M_ABC),
410 opmode_byte(0, 0, 0, 0, 0, M_ABC),
411 opmode_byte(0, 0, 0, 0, 1, M_ABX),
412 opmode_byte(0, 0, 0, 0, 1, M_ABX),
413 opmode_byte(0, 0, 0, 0, 0, M_ABX),
414 opmode_byte(0, 0, 0, 0, 0, M_ABC),
415 opmode_byte(0, 0, 0, 0, 1, M_ABX),
416 opmode_byte(0, 0, 1, 0, 0, M_ABC),
417 opmode_byte(0, 0, 0, 0, 1, M_ABX),
418 opmode_byte(0, 1, 0, 0, 1, M_ABC),
419 opmode_byte(0, 0, 1, 0, 1, M_ABC),
420 opmode_byte(0, 0, 0, 0, 0, M_AX),
421];
422
423pub fn get_op_mode(op: OpCode) -> OpMode {
429 match OP_MODES[op as usize] & 7 {
430 0 => OpMode::Abc,
431 1 => OpMode::ABx,
432 2 => OpMode::AsBx,
433 3 => OpMode::Ax,
434 4 => OpMode::SJ,
435 _ => OpMode::Abc,
437 }
438}
439
440#[inline]
443pub fn test_a_mode(op: OpCode) -> bool {
444 (OP_MODES[op as usize] & (1 << 3)) != 0
445}
446
447#[inline]
450pub fn test_t_mode(op: OpCode) -> bool {
451 (OP_MODES[op as usize] & (1 << 4)) != 0
452}
453
454#[inline]
457pub fn test_it_mode(op: OpCode) -> bool {
458 (OP_MODES[op as usize] & (1 << 5)) != 0
459}
460
461#[inline]
464pub fn test_ot_mode(op: OpCode) -> bool {
465 (OP_MODES[op as usize] & (1 << 6)) != 0
466}
467
468#[inline]
471pub fn test_mm_mode(op: OpCode) -> bool {
472 (OP_MODES[op as usize] & (1 << 7)) != 0
473}
474
475#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
483#[repr(transparent)]
484pub struct Instruction(pub u32);
485
486impl Instruction {
487 #[inline]
492 pub const fn get_arg(self, pos: u32, size: u32) -> u32 {
493 (self.0 >> pos) & ((1u32 << size) - 1)
494 }
495
496 #[inline]
499 pub fn set_arg(&mut self, v: u32, pos: u32, size: u32) {
500 let mask = ((1u32 << size) - 1) << pos;
501 self.0 = (self.0 & !mask) | ((v << pos) & mask);
502 }
503
504 #[inline]
509 pub fn opcode(self) -> Option<OpCode> {
510 OpCode::from_u32(self.get_arg(POS_OP, SIZE_OP))
511 }
512
513 #[inline]
516 pub fn set_opcode(&mut self, op: OpCode) {
517 self.set_arg(op as u32, POS_OP, SIZE_OP);
518 }
519
520 #[inline]
523 pub const fn arg_a(self) -> u32 {
524 self.get_arg(POS_A, SIZE_A)
525 }
526
527 #[inline]
528 pub fn set_arg_a(&mut self, v: u32) {
529 self.set_arg(v, POS_A, SIZE_A);
530 }
531
532 #[inline]
535 pub const fn arg_k(self) -> u32 {
536 self.get_arg(POS_K, 1)
537 }
538
539 #[inline]
540 pub const fn test_k(self) -> bool {
541 self.arg_k() != 0
542 }
543
544 #[inline]
545 pub fn set_arg_k(&mut self, v: u32) {
546 self.set_arg(v, POS_K, 1);
547 }
548
549 #[inline]
552 pub const fn arg_b(self) -> u32 {
553 self.get_arg(POS_B, SIZE_B)
554 }
555
556 #[inline]
557 pub const fn arg_s_b(self) -> i32 {
558 self.arg_b() as i32 - OFFSET_S_C
559 }
560
561 #[inline]
562 pub fn set_arg_b(&mut self, v: u32) {
563 self.set_arg(v, POS_B, SIZE_B);
564 }
565
566 #[inline]
569 pub const fn arg_c(self) -> u32 {
570 self.get_arg(POS_C, SIZE_C)
571 }
572
573 #[inline]
574 pub const fn arg_s_c(self) -> i32 {
575 self.arg_c() as i32 - OFFSET_S_C
576 }
577
578 #[inline]
579 pub fn set_arg_c(&mut self, v: u32) {
580 self.set_arg(v, POS_C, SIZE_C);
581 }
582
583 #[inline]
586 pub const fn arg_bx(self) -> u32 {
587 self.get_arg(POS_BX, SIZE_BX)
588 }
589
590 #[inline]
591 pub fn set_arg_bx(&mut self, v: u32) {
592 self.set_arg(v, POS_BX, SIZE_BX);
593 }
594
595 #[inline]
596 pub const fn arg_s_bx(self) -> i32 {
597 self.arg_bx() as i32 - OFFSET_S_BX
598 }
599
600 #[inline]
601 pub fn set_arg_s_bx(&mut self, b: i32) {
602 self.set_arg_bx((b + OFFSET_S_BX) as u32);
603 }
604
605 #[inline]
608 pub const fn arg_ax(self) -> u32 {
609 self.get_arg(POS_AX, SIZE_AX)
610 }
611
612 #[inline]
613 pub fn set_arg_ax(&mut self, v: u32) {
614 self.set_arg(v, POS_AX, SIZE_AX);
615 }
616
617 #[inline]
620 pub const fn arg_s_j(self) -> i32 {
621 self.get_arg(POS_S_J, SIZE_S_J) as i32 - OFFSET_S_J
622 }
623
624 #[inline]
625 pub fn set_arg_s_j(&mut self, j: i32) {
626 self.set_arg((j + OFFSET_S_J) as u32, POS_S_J, SIZE_S_J);
627 }
628
629 #[inline]
634 pub fn abck(op: OpCode, a: u32, b: u32, c: u32, k: u32) -> Self {
635 Self(
636 ((op as u32) << POS_OP)
637 | (a << POS_A)
638 | (b << POS_B)
639 | (c << POS_C)
640 | (k << POS_K),
641 )
642 }
643
644 #[inline]
647 pub fn abx(op: OpCode, a: u32, bc: u32) -> Self {
648 Self(((op as u32) << POS_OP) | (a << POS_A) | (bc << POS_BX))
649 }
650
651 #[inline]
654 pub fn ax(op: OpCode, a: u32) -> Self {
655 Self(((op as u32) << POS_OP) | (a << POS_AX))
656 }
657
658 #[inline]
661 pub fn sj(op: OpCode, j: u32, k: u32) -> Self {
662 Self(((op as u32) << POS_OP) | (j << POS_S_J) | (k << POS_K))
663 }
664
665 pub fn is_out_top(self) -> bool {
671 match self.opcode() {
672 Some(op) => (test_ot_mode(op) && self.arg_c() == 0) || op == OpCode::TailCall,
673 None => false,
674 }
675 }
676
677 pub fn is_in_top(self) -> bool {
680 match self.opcode() {
681 Some(op) => test_it_mode(op) && self.arg_b() == 0,
682 None => false,
683 }
684 }
685
686 pub fn op_mode(self) -> Option<OpMode> {
689 self.opcode().map(get_op_mode)
690 }
691}
692
693#[inline]
702pub const fn int_to_s_c(i: i32) -> u32 {
703 (i + OFFSET_S_C) as u32
704}
705
706#[inline]
709pub const fn s_c_to_int(i: u32) -> i32 {
710 i as i32 - OFFSET_S_C
711}
712
713#[cfg(test)]
716mod tests {
717 use super::*;
718
719 #[test]
720 fn num_opcodes_matches_enum() {
721 assert_eq!(NUM_OPCODES, 83);
722 assert_eq!(OpCode::ExtraArg as usize, 82);
723 }
724
725 #[test]
726 fn op_modes_table_length() {
727 assert_eq!(OP_MODES.len(), NUM_OPCODES);
728 }
729
730 #[test]
731 fn opmode_byte_values() {
732 assert_eq!(OP_MODES[OpCode::Move as usize], 0b00001000); assert_eq!(OP_MODES[OpCode::LoadI as usize], 0b00001010); assert_eq!(OP_MODES[OpCode::Jmp as usize], 0b00000100); assert_eq!(OP_MODES[OpCode::MmBin as usize], 0b10000000); assert_eq!(OP_MODES[OpCode::Call as usize], 0b01101000); assert_eq!(OP_MODES[OpCode::ExtraArg as usize], 0b00000011); }
739
740 #[test]
741 fn from_u32_round_trip() {
742 for i in 0..NUM_OPCODES {
743 let op = OpCode::from_u32(i as u32).expect("valid opcode");
744 assert_eq!(op as usize, i);
745 }
746 assert!(OpCode::from_u32(83).is_none());
747 }
748
749 #[test]
750 fn instruction_arg_a() {
751 let i = Instruction::abck(OpCode::Move, 5, 3, 0, 0);
752 assert_eq!(i.arg_a(), 5);
753 assert_eq!(i.arg_b(), 3);
754 }
755
756 #[test]
757 fn instruction_s_bx_round_trip() {
758 let mut i = Instruction::abx(OpCode::LoadK, 0, 0);
759 i.set_arg_s_bx(-10);
760 assert_eq!(i.arg_s_bx(), -10);
761 i.set_arg_s_bx(0);
762 assert_eq!(i.arg_s_bx(), 0);
763 i.set_arg_s_bx(100);
764 assert_eq!(i.arg_s_bx(), 100);
765 }
766
767 #[test]
768 fn instruction_s_j_round_trip() {
769 let mut i = Instruction::sj(OpCode::Jmp, (OFFSET_S_J) as u32, 0);
770 assert_eq!(i.arg_s_j(), 0);
771 i.set_arg_s_j(42);
772 assert_eq!(i.arg_s_j(), 42);
773 i.set_arg_s_j(-1);
774 assert_eq!(i.arg_s_j(), -1);
775 }
776
777 #[test]
778 fn get_op_mode_smoke() {
779 assert_eq!(get_op_mode(OpCode::Move), OpMode::Abc);
780 assert_eq!(get_op_mode(OpCode::LoadI), OpMode::AsBx);
781 assert_eq!(get_op_mode(OpCode::LoadK), OpMode::ABx);
782 assert_eq!(get_op_mode(OpCode::Jmp), OpMode::SJ);
783 assert_eq!(get_op_mode(OpCode::ExtraArg), OpMode::Ax);
784 }
785
786 #[test]
787 fn int_to_s_c_round_trip() {
788 assert_eq!(s_c_to_int(int_to_s_c(0)), 0);
789 assert_eq!(s_c_to_int(int_to_s_c(100)), 100);
790 assert_eq!(s_c_to_int(int_to_s_c(-50)), -50);
791 }
792}
793
794