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}