Bytecode VM
Overview
The bytecode VM is a stack-based virtual machine. Instructions operate on an implicit operand stack, pushing and popping values. This is the original execution backend for ƿit.
Compilation Pipeline
Source → Tokenize → Parse (AST) → Bytecode → Link → Execute
The compiler emits JSFunctionBytecode objects containing opcode sequences, constant pools, and debug information.
Instruction Categories
Value Loading
| Opcode | Description |
|---|
push_i32 | Push a 32-bit immediate integer |
push_const | Push a value from the constant pool |
null | Push null |
push_false | Push false |
push_true | Push true |
Stack Manipulation
| Opcode | Description |
|---|
drop | Remove top of stack |
dup | Duplicate top of stack |
dup1 / dup2 / dup3 | Duplicate item at depth |
swap | Swap top two items |
rot3l / rot3r | Rotate top three items |
insert2 / insert3 | Insert top item deeper |
nip | Remove second item |
Variable Access
| Opcode | Description |
|---|
get_var | Load variable by name (pre-link) |
put_var | Store variable by name (pre-link) |
get_loc / put_loc | Access local variable by index |
get_arg / put_arg | Access function argument by index |
get_env_slot / set_env_slot | Access closure variable (post-link) |
get_global_slot / set_global_slot | Access global variable (post-link) |
Variable access opcodes are patched during linking. get_var instructions are rewritten to get_loc, get_env_slot, or get_global_slot depending on where the variable is resolved.
Arithmetic
| Opcode | Description |
|---|
add / sub / mul / div | Basic arithmetic |
mod / pow | Modulo and power |
neg / inc / dec | Unary operations |
add_loc / inc_loc / dec_loc | Optimized local variable update |
Comparison and Logic
| Opcode | Description |
|---|
strict_eq / strict_neq | Equality (ƿit uses strict only) |
lt / lte / gt / gte | Ordered comparison |
not / lnot | Logical / bitwise not |
and / or / xor | Bitwise operations |
Control Flow
| Opcode | Description |
|---|
goto | Unconditional jump |
if_true / if_false | Conditional jump |
goto8 / goto16 | Short jumps (size-optimized) |
if_true8 / if_false8 | Short conditional jumps |
catch | Set exception handler |
Function Calls
| Opcode | Description |
|---|
call | Call function with N arguments |
tail_call | Tail-call optimization |
call_method | Call method on object |
return | Return value from function |
return_undef | Return null from function |
throw | Throw exception (disrupt) |
Property Access
| Opcode | Description |
|---|
get_field | Get named property |
put_field | Set named property |
get_array_el | Get computed property |
put_array_el | Set computed property |
define_field | Define property during object literal |
Object Creation
| Opcode | Description |
|---|
object | Create new empty object |
array_from | Create array from stack values |
Bytecode Patching
During the link/integrate phase, symbolic variable references are resolved to concrete access instructions. This is a critical optimization — the interpreter does not perform name lookups at runtime.
A get_var "x" instruction becomes:
get_loc 3 — if x is local variable at index 3get_env_slot 1, 5 — if x is captured from outer scope (depth 1, slot 5)get_global_slot 7 — if x is a global