lua_kit/bytecode.rs
1//! Tools for bytecode generation.
2
3const BITRK: u32 = 1 << 8;
4
5/// A slot which is either a register (`R`) or constant (`K`).
6#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
7pub enum RK {
8 /// A register index.
9 R(u8),
10 /// A constant table index.
11 K(u8),
12}
13
14impl RK {
15 /// Convert a number to an `RK`.
16 pub fn decode(value: u32) -> RK {
17 if value & BITRK != 0 {
18 RK::K((value & !BITRK) as u8)
19 } else {
20 RK::R(value as u8)
21 }
22 }
23 /// Convert this `RK` to a number.
24 pub fn encode(&self) -> u32 {
25 match self {
26 &RK::R(r) => r as u32,
27 &RK::K(k) => (k as u32) | BITRK,
28 }
29 }
30}
31
32/// Encode an instruction with `A`, `B`, and `C` parameters.
33pub fn encode(op: Opcode, a: u8, b: u32, c: u32) -> u32 {
34 (op as u32) | ((a as u32) << 6) | ((c & 0x1ff) << 14) | ((b & 0x1ff) << 23)
35}
36
37/// Encode an instruction with `A` and `Bx` parameters.
38pub fn encode_bx(op: Opcode, a: u8, bx: u32) -> u32 {
39 (op as u32) | ((a as u32) << 6) | ((bx & 0x3ffff) << 14)
40}
41
42/// Encode an instruction with `A` and `sBx` parameters.
43pub fn encode_sbx(op: Opcode, a: u8, sbx: i32) -> u32 {
44 (op as u32) | ((a as u32) << 6) | ((((sbx + 0x20000) as u32) & 0x3ffff) << 14)
45}
46
47/// Encode an instruction with an `Ax` parameter.
48pub fn encode_ax(op: Opcode, ax: u32) -> u32 {
49 (op as u32) | ((ax & 0x3ffffff) << 6)
50}
51
52// LSB 6 8 9 9 MSB
53// |------|--------|---------|---------|
54// |opcode| A | C | B |
55// |opcode| A | Bx or sBx |
56// |opcode| Ax |
57// All 'skips' (pc++) assume that next instruction is a jump.
58
59/// A Lua opcode.
60#[repr(u8)]
61#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
62pub enum Opcode { // Args Action
63 Move, // A B R(A) := R(B)
64 LoadK, // A Bx R(A) := Kst(Bx)
65 LoadKX, // A R(A) := Kst(extra arg)
66 // ^- the next 'instruction' is always EXTRAARG.
67 LoadBool, // A B C R(A) := (Bool)B; if (C) pc++
68 LoadNil, // A B R(A), R(A+1), ..., R(A+B) := nil
69
70 GetUpval, // A B R(A) := UpValue[B]
71 GetTabUp, // A B C R(A) := UpValue[B][RK(C)]
72 GetTable, // A B C R(A) := R(B)[RK(C)]
73
74 SetTabUp, // A B C UpValue[A][RK(B)] := RK(C)
75 SetUpval, // A B UpValue[B] := R(A)
76 SetTable, // A B C R(A)[RK(B)] := RK(C)
77
78 NewTable, // A B C R(A) := {} (size = B,C)
79
80 Self_, // A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
81
82 Add, // A B C R(A) := RK(B) + RK(C)
83 Sub, // A B C R(A) := RK(B) - RK(C)
84 Mul, // A B C R(A) := RK(B) * RK(C)
85 Mod, // A B C R(A) := RK(B) % RK(C)
86 Pow, // A B C R(A) := RK(B) ^ RK(C)
87 Div, // A B C R(A) := RK(B) / RK(C)
88 IntDiv, // A B C R(A) := RK(B) // RK(C)
89 BinAnd, // A B C R(A) := RK(B) & RK(C)
90 BinOr, // A B C R(A) := RK(B) | RK(C)
91 BinXor, // A B C R(A) := RK(B) ~ RK(C)
92 ShLeft, // A B C R(A) := RK(B) << RK(C)
93 ShRight, // A B C R(A) := RK(B) >> RK(C)
94 UnMinus, // A B R(A) := -R(B)
95 BinNot, // A B R(A) := ~R(B)
96 Not, // A B R(A) := not R(B)
97 Len, // A B R(A) := length of R(B)
98
99 Concat, // A B C R(A) := R(B).. ... ..R(C)
100
101 Jump, // A sBx pc += sBx; if(A) close all upvalues >= R(A - 1)
102 Eq, // A B C if ((RK(B) == RK(C)) ~= A) then pc++
103 Less, // A B C if ((RK(B) < RK(C)) ~= A) then pc++
104 LessEq, // A B C if ((RK(B) <= RK(C)) ~= A) then pc++
105 // ^- A specifies what condition the test should accept (true or false).
106 Test, // A C if not (R(A) <=> C) then pc++
107 TestSet, // A B C if (R(B) <=> C) then R(A) := R(B) else pc++
108
109 Call, // A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
110 // ^- if (B == 0) then B = top. If (C == 0), then 'top' is
111 // set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
112 // OP_SETLIST) may use 'top'.
113 TailCall, // A B C return R(A)(R(A+1), ... ,R(A+B-1))
114 Return, // A B return R(A), ... ,R(A+B-2)
115 // ^- if (B == 0) then return up to 'top'
116
117 ForLoop, // A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
118 ForPrep, // A sBx R(A)-=R(A+2); pc+=sBx
119 TForCall, // A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
120 TForLoop, // A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }
121 SetList, // A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
122 // ^- if (B == 0) then B = 'top'; if (C == 0) then next
123 // 'instruction' is EXTRAARG(real C).
124 Closure, // A Bx R(A) := closure(KPROTO[Bx])
125 VarArg, // A B R(A), R(A+1), ..., R(A+B-2) = vararg
126 // ^- if (B == 0) then use actual number of varargs and
127 // set top (like in OP_CALL with C == 0).
128 ExtraArg, // Ax extra (larger) argument for previous opcode
129}