use crate::functions::get_jump_target::get_jump_target;
use crate::functions::get_op_length::get_op_length;
use crate::functions::is_fast_call::is_fast_call;
use crate::records::bytecode_block::BytecodeBlock;
use crate::records::ir_function::IrFunction;
use luaur_common::enums::luau_opcode::LuauOpcode;
use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
macro_rules! CODEGEN_ASSERT {
($expr:expr) => {
assert!($expr);
};
}
pub fn build_bytecode_blocks(function: &mut IrFunction, jump_targets: &[u8]) {
CODEGEN_ASSERT!(!function.proto.is_null());
let proto = unsafe { &*function.proto };
let bc_blocks = &mut function.bc_blocks;
bc_blocks.push(BytecodeBlock {
startpc: 0,
finishpc: -1,
});
let mut previ = 0;
let mut i = 0;
while i < proto.sizecode {
let pc_val = unsafe { *proto.code.add(i as usize) };
let op_val = LUAU_INSN_OP(pc_val) as u8;
let op: LuauOpcode = unsafe { core::mem::transmute(op_val) };
let nexti = i + get_op_length(op);
if i != 0 && jump_targets[i as usize] != 0 {
if let Some(last) = bc_blocks.last_mut() {
last.finishpc = previ;
}
bc_blocks.push(BytecodeBlock {
startpc: i,
finishpc: -1,
});
}
let target = get_jump_target(pc_val, i as u32);
if target >= 0 && !is_fast_call(op) {
if let Some(last) = bc_blocks.last_mut() {
last.finishpc = i;
}
if jump_targets[nexti as usize] == 0 {
bc_blocks.push(BytecodeBlock {
startpc: nexti,
finishpc: -1,
});
}
}
else if op == LuauOpcode::LOP_RETURN {
if let Some(last) = bc_blocks.last_mut() {
last.finishpc = i;
}
}
previ = i;
i = nexti;
CODEGEN_ASSERT!(i <= proto.sizecode);
}
}