Skip to main content

luaur_bytecode/methods/
bytecode_builder_patch_jump_d.rs

1use crate::records::bytecode_builder::BytecodeBuilder;
2use crate::records::jump::Jump;
3use luaur_common::enums::luau_opcode::LuauOpcode;
4use luaur_common::functions::is_jump_d::isJumpD;
5use luaur_common::macros::luau_assert::LUAU_ASSERT;
6use luaur_common::macros::luau_insn_d::LUAU_INSN_D;
7use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
8
9impl BytecodeBuilder {
10    pub fn patch_jump_d(&mut self, jump_label: usize, target_label: usize) -> bool {
11        LUAU_ASSERT!(jump_label < self.insns.len());
12
13        let jump_insn = self.insns[jump_label];
14        #[allow(path_statements)]
15        {
16            let _ = jump_insn;
17        }
18
19        LUAU_ASSERT!(isJumpD(unsafe {
20            core::mem::transmute(LUAU_INSN_OP(jump_insn) as u8)
21        }));
22        LUAU_ASSERT!(LUAU_INSN_D(jump_insn) == 0);
23
24        LUAU_ASSERT!(target_label <= self.insns.len());
25
26        let offset = target_label as i32 - jump_label as i32 - 1;
27
28        if (offset as i16) as i32 == offset {
29            self.insns[jump_label] |= ((offset as u16) as u32) << 16;
30        } else if offset.abs() < (1 << 23) {
31            // our jump doesn't fit into 16 bits; we will need to repatch the bytecode sequence with jump trampolines, see expandJumps
32            // C++ `kMaxJumpDistance = 1 << 23` (not 32767): jumps up to ~8M instructions are
33            // handled via JUMPX trampolines in expandJumps; only beyond that is it an error.
34            self.has_long_jumps = true;
35        } else {
36            return false;
37        }
38
39        self.jumps.push(Jump {
40            source: jump_label as u32,
41            target: target_label as u32,
42        });
43
44        true
45    }
46}