luaur_bytecode/methods/
bytecode_builder_validate_variadic.rs1use crate::records::bytecode_builder::BytecodeBuilder;
2use alloc::vec::Vec;
3use luaur_common::enums::luau_opcode::LuauOpcode;
4use luaur_common::functions::get_jump_target::getJumpTarget;
5use luaur_common::functions::get_op_length::getOpLength;
6use luaur_common::functions::is_fast_call::isFastCall;
7use luaur_common::macros::luau_assert::LUAU_ASSERT;
8use luaur_common::macros::luau_insn_b::LUAU_INSN_B;
9use luaur_common::macros::luau_insn_c::LUAU_INSN_C;
10use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
11
12impl BytecodeBuilder {
13 pub fn validate_variadic(&self) {
14 let mut variadic_seq = false;
15 let mut insn_targets = Vec::with_capacity(self.insns.len());
16 insn_targets.resize(self.insns.len(), false);
17
18 let mut i = 0;
19 while i < self.insns.len() {
20 let insn = self.insns[i];
21 let op = LuauOpcode::from(LUAU_INSN_OP(insn) as u8);
22
23 let target = getJumpTarget(insn, i as u32);
24
25 if target >= 0 && !isFastCall(op) {
26 LUAU_ASSERT!((target as usize) < self.insns.len());
27 insn_targets[target as usize] = true;
28 }
29
30 i += getOpLength(op) as usize;
31 LUAU_ASSERT!(i <= self.insns.len());
32 }
33
34 let mut i = 0;
35 while i < self.insns.len() {
36 let insn = self.insns[i];
37 let op = LuauOpcode::from(LUAU_INSN_OP(insn) as u8);
38
39 if variadic_seq {
40 LUAU_ASSERT!(!insn_targets[i]);
41 }
42
43 if op == LuauOpcode::LOP_CALL || op == LuauOpcode::LOP_CALLFB {
44 if LUAU_INSN_B(insn) == 0 {
45 LUAU_ASSERT!(variadic_seq);
46 variadic_seq = false;
47 } else {
48 LUAU_ASSERT!(!variadic_seq);
49 }
50
51 if LUAU_INSN_C(insn) == 0 {
52 LUAU_ASSERT!(!variadic_seq);
53 variadic_seq = true;
54 }
55 } else if op == LuauOpcode::LOP_GETVARARGS && LUAU_INSN_B(insn) == 0 {
56 LUAU_ASSERT!(!variadic_seq);
57 variadic_seq = true;
58 } else if (op == LuauOpcode::LOP_RETURN && LUAU_INSN_B(insn) == 0)
59 || (op == LuauOpcode::LOP_SETLIST && LUAU_INSN_C(insn) == 0)
60 {
61 LUAU_ASSERT!(variadic_seq);
62 variadic_seq = false;
63 } else if op == LuauOpcode::LOP_FASTCALL {
64 let call_target = (i as i32 + LUAU_INSN_C(insn) as i32 + 1) as usize;
65 LUAU_ASSERT!(
66 call_target < self.insns.len()
67 && LuauOpcode::from(LUAU_INSN_OP(self.insns[call_target]) as u8)
68 == LuauOpcode::LOP_CALL
69 );
70
71 if LUAU_INSN_B(self.insns[call_target]) == 0 {
72 LUAU_ASSERT!(variadic_seq);
73 } else {
74 LUAU_ASSERT!(!variadic_seq);
75 }
76 } else if op == LuauOpcode::LOP_CLOSEUPVALS
77 || op == LuauOpcode::LOP_NAMECALL
78 || op == LuauOpcode::LOP_GETIMPORT
79 || op == LuauOpcode::LOP_MOVE
80 || op == LuauOpcode::LOP_GETUPVAL
81 || op == LuauOpcode::LOP_GETGLOBAL
82 || op == LuauOpcode::LOP_GETTABLEKS
83 || op == LuauOpcode::LOP_COVERAGE
84 {
85 } else {
86 LUAU_ASSERT!(!variadic_seq);
87 }
88
89 i += getOpLength(op) as usize;
90 LUAU_ASSERT!(i <= self.insns.len());
91 }
92
93 LUAU_ASSERT!(!variadic_seq);
94 }
95}