Language & Runtime
Bytecode VM Model
Last updated 2026-04-14
Bytecode VM Model
mustard currently uses a private stack-based bytecode.
Program Shape
- A
BytecodeProgramis a function table plus arootfunction id. - Each
FunctionPrototypestores parameter patterns, bytecode instructions, anis_asyncflag, and the guest source span that produced the function. - The root function is executed first and represents the top-level script.
Operand Model
- Each frame owns an operand stack.
- Literal loads, name loads, and closure creation push values.
- Arithmetic and comparison operations pop their operands and push one result.
StoreNameand property-set instructions push the assigned value back so assignment expressions still produce a result.JumpIfFalse,JumpIfTrue, andJumpIfNullishinspect the top-of-stack value without popping it.- The optimizer may emit private combined handlers such as
LoadSlotGetPropStatic,DupGetPropStatic, andLoadSlotDupGetPropStaticwhen the same semantics can be preserved with fewer dispatches. Awaitpops one value, coerces it to an internal guest promise, and suspends the current async continuation until a later microtask checkpoint.Returncompletes the current frame and returns the top value, defaulting toundefinedif the stack is empty.
Optimizer Boundaries
- Post-lowering bytecode optimization stays inside block-local regions.
- Within each region, the optimizer tracks abstract stack-top equivalence for
recent literal and binding loads so redundant reloads can collapse into
Dupbefore later stack-noop and superinstruction cleanup. That pass currently stays opt-in until broader portfolio data justifies enabling it by default. - Jump targets always start a fresh optimization block.
- The optimizer flushes at handler and pending-completion edges, control-flow
transfers,
await, calls, construction,return, andthrow. - There is no bytecode-level source-position marker today, so no additional source-position flush boundary is currently encoded.
Frame Layout
Each frame currently tracks:
function_id: whichFunctionPrototypeis executingip: the next instruction index to executeenv: the current lexical environmentscope_stack: the nested lexical environments introduced byPushEnvstack: the operand stack for the frameasync_promise: the backing promise for an async function frame when present
this is stored in the frame's lexical environment as a normal binding.
Validation Rules
Bytecode validation currently checks:
- the root function id exists
- closure targets and jump targets stay in range
- every function ends in
Return - stack depth stays valid across every reachable control-flow edge
- lexical scope depth stays valid across
PushEnvandPopEnv - snapshots reference existing functions, environments, cells, objects, arrays, closures, and promises
Malformed bytecode and malformed snapshots fail validation before execution or restore.