luau-bytecode 0.732.0

Luau bytecode model, builder, serializer, and dumper
Documentation
use super::{
    BytecodeBlock, BytecodeBlockId, BytecodeEdge, BytecodeEdgeKind, BytecodeImmediate,
    BytecodeImmediateId, BytecodeInstruction, BytecodeInstructionId, BytecodeInstructionStream,
    BytecodeOperand, BytecodePhi, BytecodePhiId, BytecodeProjection, BytecodeProjectionId,
    InstructionPc,
};
use crate::error::BytecodeReadError;
use crate::model::Register;
use crate::model::{Instruction, InstructionAux};
use crate::opcodes::Opcode;
use std::collections::{HashMap, HashSet};

fn constant_index(value: u32) -> i32 {
    i32::try_from(value).expect("constant index must fit int32")
}

pub(super) struct FunctionGraphBuilder {
    pub(super) immediates: Vec<BytecodeImmediate>,
    pub(super) phis: Vec<BytecodePhi>,
    pub(super) projections: Vec<BytecodeProjection>,
    pub(super) registers: HashMap<BytecodeOperand, Register>,
    pub(super) block_phis: Vec<Vec<BytecodePhiId>>,
    producers: Producers,
    current_block: BytecodeBlockId,
}

impl Default for FunctionGraphBuilder {
    fn default() -> Self {
        Self {
            immediates: Vec::new(),
            phis: Vec::new(),
            projections: Vec::new(),
            registers: HashMap::new(),
            block_phis: Vec::new(),
            producers: Producers::default(),
            current_block: BytecodeBlockId::new(0),
        }
    }
}

#[derive(Clone)]
struct BlockProducers {
    own: HashMap<Register, BytecodeOperand>,
    cached: HashMap<Register, BytecodeOperand>,
    multi_return: Option<BytecodeOperand>,
    multi_return_start: Register,
    invalid_after: i32,
    sealed: bool,
    unsealed_predecessors: usize,
    incomplete_phis: HashMap<Register, BytecodeOperand>,
}

impl Default for BlockProducers {
    fn default() -> Self {
        Self {
            own: HashMap::new(),
            cached: HashMap::new(),
            multi_return: None,
            multi_return_start: 0xff,
            invalid_after: 255,
            sealed: false,
            unsealed_predecessors: 0,
            incomplete_phis: HashMap::new(),
        }
    }
}

#[derive(Default)]
struct Producers {
    blocks: Vec<BlockProducers>,
}

impl FunctionGraphBuilder {
    pub(super) fn new(
        blocks: &[BytecodeBlock],
        parameter_count: u8,
        entry: BytecodeBlockId,
    ) -> Self {
        let mut builder = Self {
            producers: Producers {
                blocks: vec![BlockProducers::default(); blocks.len()],
            },
            block_phis: vec![Vec::new(); blocks.len()],
            ..Self::default()
        };

        for (index, block) in blocks.iter().enumerate() {
            builder.producers.blocks[index].unsealed_predecessors = block.predecessors().len();
            builder.producers.blocks[index].sealed = block.predecessors().is_empty();
        }

        for register in 0..parameter_count {
            builder.add_producer_to(entry, register, BytecodeOperand::VmRegister(register));
        }

        builder
    }

    pub(super) fn begin_block(
        &mut self,
        block: BytecodeBlockId,
        _entry: BytecodeBlockId,
        _predecessors: &[BytecodeEdge],
    ) {
        self.current_block = block;
    }
}

mod operands;
mod producers;