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}