Skip to main content

byteflow/bytecode/
chunk.rs

1use super::instruction::Instruction;
2use super::value::Value;
3
4/// On-disk magic for the `.bf` module format (see design notes §32).
5/// Chosen so a corrupted/truncated file is rejected in the first 4 bytes
6/// rather than partway through decoding.
7pub const MAGIC: [u8; 4] = *b"BFV0";
8
9/// Current ABI version. Bump on any breaking change to instruction
10/// encoding, constant representation, or function-table layout.
11///
12/// v2: [`Value::Message`] wire tag `5`.
13/// v3: `Message.reply_cap`; [`Value::Cap`] wire tag `6` (FlowCap).
14/// v4: [`Value::Str`] tag `7`, [`Value::Bytes`] tag `8`.
15/// v5: CapId is 128-bit; `Message.payload` is a nested [`Value`].
16pub const ABI_VERSION: u32 = 5;
17
18/// A callable entry point inside a [`Chunk`]: either bytecode-defined or a
19/// slot reserved for a native (Rust) function registered with the runtime
20/// via the FFI table (design notes §30-31).
21#[derive(Clone, Debug, PartialEq)]
22pub struct FunctionDef {
23    pub name: String,
24    /// Index into `Chunk::code` where execution starts.
25    pub entry: u32,
26    /// Number of parameters, passed in registers `r0..r{arity}`.
27    pub arity: u8,
28    /// Upper bound on registers this function uses; the VM allocates
29    /// exactly this many per call frame instead of a fixed worst-case size.
30    pub num_registers: u8,
31}
32
33/// A compiled unit of Byteflow bytecode: code, constants and the function
34/// table. One `Chunk` can back many concurrently-running processes — it is
35/// immutable after construction, so it is shared behind an `Arc` rather than
36/// copied per Flow (see `byteflow-vm::Vm::chunk`).
37#[derive(Clone, Debug, Default)]
38pub struct Chunk {
39    pub name: String,
40    pub constants: Vec<Value>,
41    pub code: Vec<Instruction>,
42    pub functions: Vec<FunctionDef>,
43}
44
45impl Chunk {
46    pub fn function(&self, index: u32) -> Option<&FunctionDef> {
47        self.functions.get(index as usize)
48    }
49
50    pub fn constant(&self, index: u32) -> Option<&Value> {
51        self.constants.get(index as usize)
52    }
53
54    /// Number of instructions, used by the verifier to bound-check jump
55    /// targets ahead of time instead of on every branch at runtime.
56    pub fn len(&self) -> usize {
57        self.code.len()
58    }
59
60    pub fn is_empty(&self) -> bool {
61        self.code.is_empty()
62    }
63}