1#[cfg(feature = "lua51")]
2const LUA_OP_SIZE: u32 = 6;
3#[cfg(feature = "lua51")]
4const LUA_A_SIZE: u32 = 8;
5#[cfg(feature = "lua51")]
6const LUA_B_SIZE: u32 = 9;
7#[cfg(feature = "lua51")]
8const LUA_C_SIZE: u32 = 9;
9#[cfg(feature = "lua51")]
10const LUA_BX_SIZE: u32 = LUA_B_SIZE + LUA_C_SIZE;
11
12#[cfg(feature = "lua51")]
13const LUA_OP_POSITION: u32 = 0;
14#[cfg(feature = "lua51")]
15const LUA_A_POSITION: u32 = LUA_OP_SIZE;
16#[cfg(feature = "lua51")]
17const LUA_C_POSITION: u32 = LUA_A_POSITION + LUA_A_SIZE;
18#[cfg(feature = "lua51")]
19const LUA_B_POSITION: u32 = LUA_C_POSITION + LUA_C_SIZE;
20#[cfg(feature = "lua51")]
21const LUA_BX_POSITION: u32 = LUA_C_POSITION;
22
23#[cfg(feature = "lua51")]
24pub const MAX_ARG_BX: u32 = (1 << LUA_BX_SIZE) - 1;
25#[cfg(feature = "lua51")]
26pub const MAX_ARG_SBX: i32 = (MAX_ARG_BX as i32) >> 1;
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq)]
29pub enum LuaOpMode {
30 IA,
31 IAB,
32 IAC,
33 IABC,
34
35 IAx,
36 IABx,
37 IAsBx,
38}
39
40#[cfg(feature = "lua51")]
41#[repr(u8)]
42#[derive(Copy, Clone, Debug, PartialEq, Eq)]
43pub enum LuaOpcode {
44 Move,
45 LoadK,
46 LoadBool,
47 LoadNil,
48 GetUpval,
49
50 GetGlobal,
51 GetTable,
52
53 SetGlobal,
54 SetUpval,
55 SetTable,
56
57 NewTable,
58
59 Self_,
60
61 Add,
62 Sub,
63 Mul,
64 Div,
65 Mod,
66 Pow,
67 Unm,
68 Not,
69 Len,
70
71 Concat,
72
73 Jmp,
74
75 Eq,
76 Lt,
77 Le,
78
79 Test,
80 TestSet,
81
82 Call,
83 TailCall,
84 Return,
85
86 ForLoop,
87 ForPrep,
88
89 TForLoop,
90 SetList,
91
92 Close,
93 Closure,
94
95 Vararg,
96}
97
98#[cfg(feature = "luau")]
99#[repr(u8)]
100#[derive(Copy, Clone, Debug, PartialEq, Eq)]
101pub enum LuauOpcode {
102 Nop,
103 Break,
104 LoadNil,
105 LoadB,
106 LoadN,
107 LoadK,
108 Move,
109 GetGlobal,
110 SetGlobal,
111 GetUpval,
112 SetUpval,
113 CloseUpvals,
114 GetImport,
115 GetTable,
116 SetTable,
117 GetTableKs,
118 SetTableKs,
119 GetTableN,
120 SetTableN,
121 NewClosure,
122 NameCall,
123 Call,
124 Return,
125 Jump,
126 JumpBack,
127 JumpIf,
128 JumpIfNot,
129 JumpIfEq,
130 JumpIfLe,
131 JumpIfLt,
132 JumpIfNotEq,
133 JumpIfNotLe,
134 JumpIfNotLt,
135 Add,
136 Sub,
137 Mul,
138 Div,
139 Mod,
140 Pow,
141 AddK,
142 SubK,
143 MulK,
144 DivK,
145 ModK,
146 PowK,
147 And,
148 Or,
149 AndK,
150 OrK,
151 Concat,
152 Not,
153 Minus,
154 Length,
155 NewTable,
156 DupTable,
157 SetList,
158 ForNPrep,
159 ForNLoop,
160 ForGLoop,
161 ForGPrepInext,
162 FastCall3,
163 ForGPrepNext,
164 NativeCall,
165 GetVarargs,
166 DupClosure,
167 PrepVarargs,
168 LoadKx,
169 JumpX,
170 FastCall,
171 Coverage,
172 Capture,
173 SubRk,
174 DivRk,
175 FastCall1,
176 FastCall2,
177 FastCall2K,
178 ForGPrep,
179 JumpXeqkNil,
180 JumpXeqkB,
181 JumpXeqkN,
182 JumpXeqkS,
183 IDiv,
184 IDivK,
185}
186
187#[cfg(feature = "lua51")]
188impl LuaOpcode {
189 pub fn index(op: u8) -> LuaOpcode {
190 unsafe { std::mem::transmute(op) }
191 }
192
193 pub fn mode(&self) -> LuaOpMode {
194 match self {
195 LuaOpcode::Move => LuaOpMode::IABC,
196 LuaOpcode::LoadK => LuaOpMode::IABx,
197 LuaOpcode::LoadBool => LuaOpMode::IABC,
198 LuaOpcode::LoadNil => LuaOpMode::IAB,
199
200 LuaOpcode::GetUpval | LuaOpcode::SetUpval => LuaOpMode::IAB,
201 LuaOpcode::GetGlobal | LuaOpcode::SetGlobal => LuaOpMode::IABx,
202 LuaOpcode::GetTable | LuaOpcode::SetTable | LuaOpcode::NewTable => LuaOpMode::IABC,
203 LuaOpcode::Self_ => LuaOpMode::IABC,
204
205 LuaOpcode::Add
206 | LuaOpcode::Sub
207 | LuaOpcode::Mul
208 | LuaOpcode::Div
209 | LuaOpcode::Mod
210 | LuaOpcode::Pow => LuaOpMode::IABC,
211
212 LuaOpcode::Unm | LuaOpcode::Not | LuaOpcode::Len => LuaOpMode::IAB,
213
214 LuaOpcode::Concat => LuaOpMode::IABC,
215 LuaOpcode::Jmp => LuaOpMode::IAsBx, LuaOpcode::Eq | LuaOpcode::Lt | LuaOpcode::Le => LuaOpMode::IABC,
218
219 LuaOpcode::Test => LuaOpMode::IAC,
220 LuaOpcode::TestSet => LuaOpMode::IABC,
221
222 LuaOpcode::Call | LuaOpcode::TailCall => LuaOpMode::IABC,
223 LuaOpcode::Return => LuaOpMode::IAB,
224
225 LuaOpcode::ForLoop => LuaOpMode::IAsBx,
226 LuaOpcode::ForPrep => LuaOpMode::IAsBx,
227 LuaOpcode::TForLoop => LuaOpMode::IAC,
228 LuaOpcode::SetList => LuaOpMode::IABC,
229
230 LuaOpcode::Close => LuaOpMode::IA,
231 LuaOpcode::Closure => LuaOpMode::IABx,
232
233 LuaOpcode::Vararg => LuaOpMode::IAB,
234 }
235 }
236}
237
238#[cfg(feature = "luau")]
239impl LuauOpcode {
240 pub fn index(op: u8) -> LuauOpcode {
241 unsafe { std::mem::transmute(op) }
242 }
243
244 pub fn length(&self) -> u8 {
245 match self {
246 LuauOpcode::GetGlobal
247 | LuauOpcode::SetGlobal
248 | LuauOpcode::GetImport
249 | LuauOpcode::GetTableKs
250 | LuauOpcode::SetTableKs
251 | LuauOpcode::NameCall
252 | LuauOpcode::JumpIfEq
253 | LuauOpcode::JumpIfLt
254 | LuauOpcode::JumpIfLe
255 | LuauOpcode::JumpIfNotEq
256 | LuauOpcode::JumpIfNotLt
257 | LuauOpcode::JumpIfNotLe
258 | LuauOpcode::NewTable
259 | LuauOpcode::SetList
260 | LuauOpcode::ForGLoop
261 | LuauOpcode::FastCall3
262 | LuauOpcode::LoadKx
263 | LuauOpcode::FastCall2
264 | LuauOpcode::FastCall2K
265 | LuauOpcode::JumpXeqkB
266 | LuauOpcode::JumpXeqkN
267 | LuauOpcode::JumpXeqkS => 2,
268 _ => 1,
269 }
270 }
271}
272
273#[derive(Copy, Clone, Debug, PartialEq, Eq)]
274pub enum Opcode {
275 #[cfg(feature = "lua51")]
276 LuaOpcode(LuaOpcode),
277 #[cfg(feature = "luau")]
278 LuauOpcode(LuauOpcode),
279}
280
281#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
282pub struct Instruction(pub u32);
283
284#[cfg(feature = "lua51")]
285pub trait LuaInstruction {
286 fn opcode(&self) -> Opcode;
287 fn from_abc(op: Opcode, a: u32, b: u32, c: u32) -> Self;
288 fn from_abx(opcode: Opcode, a: u32, bx: u32) -> Self;
289
290 fn get(&self, size: u32, position: u32) -> u32;
291 fn a(&self) -> u32;
292 fn b(&self) -> u32;
293 fn c(&self) -> u32;
294 fn bx(&self) -> u32;
295 fn sbx(&self) -> i32;
296
297 fn set(&mut self, value: u32, position: u32, size: u32) -> &mut Self;
298 fn set_a(&mut self, a: u32) -> &mut Self;
299 fn set_b(&mut self, b: u32) -> &mut Self;
300 fn set_c(&mut self, c: u32) -> &mut Self;
301 fn set_bx(&mut self, bx: u32) -> &mut Self;
302 fn set_sbx(&mut self, sbx: i32) -> &mut Self;
303
304 fn mask_0(&self, n: u32, p: u32) -> u32;
306 fn mask_1(&self, n: u32, p: u32) -> u32;
308}
309
310#[cfg(feature = "luau")]
311pub trait LuauInstruction {
312 fn opcode(&self) -> Opcode;
313
314 fn from_abc(op: Opcode, a: u32, b: u32, c: u32) -> Self;
315 fn from_ad(opcode: Opcode, a: u32, d: u32) -> Self;
316 fn from_e(opcode: Opcode, e: u32) -> Self;
317
318 fn a(&self) -> u32;
319 fn b(&self) -> u32;
320 fn c(&self) -> u32;
321 fn d(&self) -> u32;
322 fn e(&self) -> u32;
323}
324
325#[cfg(feature = "lua51")]
326impl LuaInstruction for Instruction {
327 fn opcode(&self) -> Opcode {
328 let op = ((self.0 >> LUA_OP_POSITION) as u8) & self.mask_1(LUA_OP_SIZE, 0) as u8;
329 Opcode::LuaOpcode(LuaOpcode::index(op))
330 }
331
332 fn from_abc(opcode: Opcode, a: u32, b: u32, c: u32) -> Self {
333 let mut instruction = match opcode {
334 Opcode::LuaOpcode(op) => Instruction(op as u32),
335 _ => unreachable!(),
336 };
337
338 Instruction(instruction.set_a(a).set_b(b).set_c(c).0)
339 }
340
341 fn from_abx(opcode: Opcode, a: u32, bx: u32) -> Self {
342 let mut instruction = match opcode {
343 Opcode::LuaOpcode(op) => Instruction(op as u32),
344 _ => unreachable!(),
345 };
346
347 Instruction(instruction.set_a(a).set_bx(bx).0)
348 }
349
350 fn a(&self) -> u32 {
351 self.get(LUA_A_SIZE, LUA_A_POSITION)
352 }
353
354 fn b(&self) -> u32 {
355 self.get(LUA_B_SIZE, LUA_B_POSITION)
356 }
357
358 fn c(&self) -> u32 {
359 self.get(LUA_C_SIZE, LUA_C_POSITION)
360 }
361
362 fn bx(&self) -> u32 {
363 self.get(LUA_BX_SIZE, LUA_BX_POSITION)
364 }
365
366 fn sbx(&self) -> i32 {
367 (self.bx() as i32) - MAX_ARG_SBX
368 }
369
370 fn set_a(&mut self, a: u32) -> &mut Self {
371 self.set(a, LUA_A_SIZE, LUA_A_POSITION)
372 }
373
374 fn set_b(&mut self, b: u32) -> &mut Self {
375 self.set(b, LUA_B_SIZE, LUA_B_POSITION)
376 }
377
378 fn set_c(&mut self, c: u32) -> &mut Self {
379 self.set(c, LUA_C_SIZE, LUA_C_POSITION)
380 }
381
382 fn set_bx(&mut self, bx: u32) -> &mut Self {
383 self.set(bx, LUA_BX_SIZE, LUA_BX_POSITION)
384 }
385
386 fn set_sbx(&mut self, bx: i32) -> &mut Self {
387 self.set_bx((bx + MAX_ARG_SBX) as u32)
388 }
389
390 fn get(&self, size: u32, position: u32) -> u32 {
391 (self.0 >> position) & self.mask_1(size, 0)
392 }
393
394 fn set(&mut self, value: u32, size: u32, position: u32) -> &mut Self {
395 self.0 = (self.mask_1(size, position) & (value << position))
396 | (self.0 & self.mask_0(size, position));
397
398 self
399 }
400
401 fn mask_1(&self, n: u32, p: u32) -> u32 {
402 ((1u32 << n) - 1) << p
403 }
404
405 fn mask_0(&self, n: u32, p: u32) -> u32 {
406 !self.mask_1(n, p)
407 }
408}
409
410#[cfg(feature = "luau")]
411impl LuauInstruction for Instruction {
412 fn opcode(&self) -> Opcode {
413 let op = (self.0 & 0xff) as u8;
414 Opcode::LuauOpcode(LuauOpcode::index(op))
415 }
416
417 fn from_abc(opcode: Opcode, a: u32, b: u32, c: u32) -> Self {
418 let op = match opcode {
419 Opcode::LuauOpcode(op) => op as u32,
420 _ => unreachable!(),
421 };
422
423 Instruction((op) | (a << 8) | (b << 16) | (c << 24))
424 }
425
426 fn from_ad(opcode: Opcode, a: u32, d: u32) -> Self {
427 let op = match opcode {
428 Opcode::LuauOpcode(op) => op as u32,
429 _ => unreachable!(),
430 };
431
432 Instruction((op) | (a << 8) | (d << 16))
433 }
434
435 fn from_e(opcode: Opcode, e: u32) -> Self {
436 let op = match opcode {
437 Opcode::LuauOpcode(op) => op as u32,
438 _ => unreachable!(),
439 };
440
441 Instruction(op | e << 8)
442 }
443
444 fn a(&self) -> u32 {
445 (self.0 >> 8) & 0xff
446 }
447
448 fn b(&self) -> u32 {
449 (self.0 >> 16) & 0xff
450 }
451
452 fn c(&self) -> u32 {
453 (self.0 >> 24) & 0xff
454 }
455
456 fn d(&self) -> u32 {
457 LuauInstruction::b(self) | LuauInstruction::c(self)
458 }
459
460 fn e(&self) -> u32 {
461 LuauInstruction::a(self) | LuauInstruction::d(self)
462 }
463}
464
465impl Instruction {
466 pub fn from_bytes(bytes: &[u8]) -> Self {
467 Instruction(u32::from_le_bytes(bytes.try_into().unwrap()))
468 }
469}