Skip to main content

luadec_rust/lua51/
opcodes.rs

1/// Lua 5.1 opcodes, matching the enum order in lopcodes.h
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3#[repr(u8)]
4pub enum OpCode {
5    Move = 0,      // A B     R(A) := R(B)
6    LoadK = 1,     // A Bx    R(A) := Kst(Bx)
7    LoadBool = 2,  // A B C   R(A) := (Bool)B; if (C) pc++
8    LoadNil = 3,   // A B     R(A) := ... := R(B) := nil
9    GetUpval = 4,  // A B     R(A) := UpValue[B]
10    GetGlobal = 5, // A Bx    R(A) := Gbl[Kst(Bx)]
11    GetTable = 6,  // A B C   R(A) := R(B)[RK(C)]
12    SetGlobal = 7, // A Bx    Gbl[Kst(Bx)] := R(A)
13    SetUpval = 8,  // A B     UpValue[B] := R(A)
14    SetTable = 9,  // A B C   R(A)[RK(B)] := RK(C)
15    NewTable = 10, // A B C   R(A) := {} (size = B,C)
16    Self_ = 11,    // A B C   R(A+1) := R(B); R(A) := R(B)[RK(C)]
17    Add = 12,      // A B C   R(A) := RK(B) + RK(C)
18    Sub = 13,      // A B C   R(A) := RK(B) - RK(C)
19    Mul = 14,      // A B C   R(A) := RK(B) * RK(C)
20    Div = 15,      // A B C   R(A) := RK(B) / RK(C)
21    Mod = 16,      // A B C   R(A) := RK(B) % RK(C)
22    Pow = 17,      // A B C   R(A) := RK(B) ^ RK(C)
23    Unm = 18,      // A B     R(A) := -R(B)
24    Not = 19,      // A B     R(A) := not R(B)
25    Len = 20,      // A B     R(A) := length of R(B)
26    Concat = 21,   // A B C   R(A) := R(B).. ... ..R(C)
27    Jmp = 22,      // sBx     pc+=sBx
28    Eq = 23,       // A B C   if ((RK(B) == RK(C)) ~= A) then pc++
29    Lt = 24,       // A B C   if ((RK(B) <  RK(C)) ~= A) then pc++
30    Le = 25,       // A B C   if ((RK(B) <= RK(C)) ~= A) then pc++
31    Test = 26,     // A C     if not (R(A) <=> C) then pc++
32    TestSet = 27,  // A B C   if (R(B) <=> C) then R(A) := R(B) else pc++
33    Call = 28,     // A B C   R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
34    TailCall = 29, // A B C   return R(A)(R(A+1), ... ,R(A+B-1))
35    Return = 30,   // A B     return R(A), ... ,R(A+B-2)
36    ForLoop = 31,  // A sBx   R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
37    ForPrep = 32,  // A sBx   R(A)-=R(A+2); pc+=sBx
38    TForLoop = 33, // A C     R(A+3), ... ,R(A+3+C) := R(A)(R(A+1), R(A+2));
39    SetList = 34,  // A B C   R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
40    Close = 35,    // A       close all variables in the stack up to (>=) R(A)
41    Closure = 36,  // A Bx    R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
42    VarArg = 37,   // A B     R(A), R(A+1), ..., R(A+B-1) = vararg
43}
44
45pub const NUM_OPCODES: usize = 38;
46
47impl OpCode {
48    pub fn from_u8(v: u8) -> Option<OpCode> {
49        if v < NUM_OPCODES as u8 {
50            // SAFETY: OpCode is repr(u8) with contiguous values 0..37
51            Some(unsafe { std::mem::transmute(v) })
52        } else {
53            None
54        }
55    }
56
57    pub fn name(self) -> &'static str {
58        OPCODE_NAMES[self as usize]
59    }
60}
61
62impl std::fmt::Display for OpCode {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.write_str(self.name())
65    }
66}
67
68/// Opcode name table, corresponding to luaP_opnames in lopcodes.c
69const OPCODE_NAMES: [&str; NUM_OPCODES] = [
70    "MOVE", "LOADK", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETGLOBAL", "GETTABLE", "SETGLOBAL",
71    "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD", "POW", "UNM",
72    "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL",
73    "RETURN", "FORLOOP", "FORPREP", "TFORLOOP", "SETLIST", "CLOSE", "CLOSURE", "VARARG",
74];
75
76/// Instruction format
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum OpMode {
79    ABC,
80    ABx,
81    AsBx,
82}
83
84/// Argument mode mask
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum OpArgMask {
87    /// Argument is not used
88    N,
89    /// Argument is used
90    U,
91    /// Argument is a register or jump offset
92    R,
93    /// Argument is a constant or register/constant
94    K,
95}
96
97/// Opcode metadata
98#[derive(Debug, Clone, Copy)]
99pub struct OpProp {
100    pub mode: OpMode,
101    pub b_mode: OpArgMask,
102    pub c_mode: OpArgMask,
103    pub sets_a: bool,
104    pub is_test: bool,
105}
106
107/// Opcode property table, matching luaP_opmodes in lopcodes.c
108pub const OP_PROPS: [OpProp; NUM_OPCODES] = {
109    use OpArgMask::*;
110    use OpMode::*;
111    const fn p(is_test: bool, sets_a: bool, b: OpArgMask, c: OpArgMask, mode: OpMode) -> OpProp {
112        OpProp {
113            mode,
114            b_mode: b,
115            c_mode: c,
116            sets_a,
117            is_test,
118        }
119    }
120    [
121        //              T      A     B  C   mode
122        p(false, true,  R, N, ABC),  // MOVE
123        p(false, true,  K, N, ABx),  // LOADK
124        p(false, true,  U, U, ABC),  // LOADBOOL
125        p(false, true,  R, N, ABC),  // LOADNIL
126        p(false, true,  U, N, ABC),  // GETUPVAL
127        p(false, true,  K, N, ABx),  // GETGLOBAL
128        p(false, true,  R, K, ABC),  // GETTABLE
129        p(false, false, K, N, ABx),  // SETGLOBAL
130        p(false, false, U, N, ABC),  // SETUPVAL
131        p(false, false, K, K, ABC),  // SETTABLE
132        p(false, true,  U, U, ABC),  // NEWTABLE
133        p(false, true,  R, K, ABC),  // SELF
134        p(false, true,  K, K, ABC),  // ADD
135        p(false, true,  K, K, ABC),  // SUB
136        p(false, true,  K, K, ABC),  // MUL
137        p(false, true,  K, K, ABC),  // DIV
138        p(false, true,  K, K, ABC),  // MOD
139        p(false, true,  K, K, ABC),  // POW
140        p(false, true,  R, N, ABC),  // UNM
141        p(false, true,  R, N, ABC),  // NOT
142        p(false, true,  R, N, ABC),  // LEN
143        p(false, true,  R, R, ABC),  // CONCAT
144        p(false, false, R, N, AsBx), // JMP
145        p(true,  false, K, K, ABC),  // EQ
146        p(true,  false, K, K, ABC),  // LT
147        p(true,  false, K, K, ABC),  // LE
148        p(true,  true,  R, U, ABC),  // TEST
149        p(true,  true,  R, U, ABC),  // TESTSET
150        p(false, true,  U, U, ABC),  // CALL
151        p(false, true,  U, U, ABC),  // TAILCALL
152        p(false, false, U, N, ABC),  // RETURN
153        p(false, true,  R, N, AsBx), // FORLOOP
154        p(false, true,  R, N, AsBx), // FORPREP
155        p(true,  false, N, U, ABC),  // TFORLOOP
156        p(false, false, U, U, ABC),  // SETLIST
157        p(false, false, N, N, ABC),  // CLOSE
158        p(false, true,  U, N, ABx),  // CLOSURE
159        p(false, true,  U, N, ABC),  // VARARG
160    ]
161};
162
163impl OpCode {
164    pub fn props(self) -> &'static OpProp {
165        &OP_PROPS[self as usize]
166    }
167}