VM Functions in Stoffel
This page explains how VM functions are defined and structured in Stoffel’s virtual machine.Rationale
VM functions form the core executable units in Stoffel. They provide a structured way to define reusable code that can be called from different parts of a program. Each function maintains its own isolated environment with local variables and registers, while still allowing controlled access to outer scopes through upvalues. This design enables modular programming within the constraints of a register-based VM architecture, supporting both MPC operations and conventional programming patterns.Comprehensive Overview
A VM function in Stoffel consists of a series of instructions that operate on registers, along with metadata describing the function’s interface and requirements. Functions are identified by name and can accept parameters, capture variables from outer scopes, and maintain their own set of registers. The VM functions use a register-based execution model where values are primarily stored and manipulated in numbered registers. This approach offers efficient instruction encoding and execution compared to stack-based alternatives, which is particularly important for the performance-sensitive operations in MPC applications.VM Function Structure
-
name: String: The unique identifier for the function.- Used for function lookup during calls
- Appears in debug output and error messages
- Must be unique within the VM’s function registry
-
parameters: Vec<String>: Names of the function’s input parameters.- Defines the expected arguments when calling the function
- Parameter values are loaded into consecutive registers starting from r0
- Also available by name through the locals map in the activation record
-
upvalues: Vec<String>: Variables to be captured from outer scopes.- Enables lexical scoping and closure functionality
- Listed separately from parameters to clearly identify captured variables
- Accessed through special upvalue operations rather than direct register access
-
parent: Option<String>: The name of the parent function, if this is a nested function.- Supports lexical scoping for nested function definitions
- Helps with upvalue resolution during closure creation
- Set to None for top-level functions
-
register_count: usize: The number of registers required by this function.- Pre-allocated when the function is called
- Determines the size of the register array in the activation record
- Should be large enough for parameters, local computations, and function calls
-
instructions: Vec<Instruction>: The sequence of instructions that comprise the function body.- Executed sequentially unless modified by control flow instructions
- Each instruction typically operates on registers
- Can include function calls, arithmetic operations, comparisons, etc.
-
labels: HashMap<String, usize>: Maps label names to instruction indices for jump targets.- Used to resolve symbolic labels in jump instructions
- Enables structured control flow (if/else, loops, etc.)
- Not included in hash calculations for performance reasons
Execution Model
When a VM function is called:- A new activation record is created with registers initialized to the Unit value
- Function parameters are copied into the first N registers and also into the locals map
- Upvalues are set up according to the function’s declaration
- The instruction pointer is set to 0
- Execution begins at the first instruction and continues until a RET instruction is encountered
- The value in the specified register is returned to the caller
Control Flow
Control flow within VM functions is managed through:- Labels: Named positions in the instruction sequence
- Jump instructions: Unconditional (JMP) and conditional (JMPEQ, JMPNEQ) transfers of control
- Function calls: Temporary transfer of control to another function
- Return instruction: Exit from the current function back to the caller
labels map, which associates string names with instruction indices. Jump instructions reference these labels by name, and the VM resolves them to the appropriate instruction index during execution.