4.5 KiB
title, description
| title | description |
|---|---|
| Register VM | Register-based virtual machine (Mach) |
Overview
The Mach VM is a register-based virtual machine using 32-bit instructions. It is modeled after Lua's register VM — operands are register indices rather than stack positions, reducing instruction count and improving performance.
Instruction Formats
All instructions are 32 bits wide. Four encoding formats are used:
iABC — Three-Register
[op: 8][A: 8][B: 8][C: 8]
Used for operations on three registers: R(A) = R(B) op R(C).
iABx — Register + Constant
[op: 8][A: 8][Bx: 16]
Used for loading constants: R(A) = K(Bx).
iAsBx — Register + Signed Offset
[op: 8][A: 8][sBx: 16]
Used for conditional jumps: if R(A) then jump by sBx.
isJ — Signed Jump
[op: 8][sJ: 24]
Used for unconditional jumps with a 24-bit signed offset.
Registers
Each function frame has a fixed number of register slots, determined at compile time. Registers hold:
- R(0) —
thisbinding - R(1)..R(arity) — function arguments
- R(arity+1).. — local variables and temporaries
Instruction Set
Loading
| Opcode | Format | Description |
|---|---|---|
LOADK |
iABx | R(A) = K(Bx) — load from constant pool |
LOADI |
iAsBx | R(A) = sBx — load small integer |
LOADNULL |
iA | R(A) = null |
LOADTRUE |
iA | R(A) = true |
LOADFALSE |
iA | R(A) = false |
MOVE |
iABC | R(A) = R(B) — register copy |
Arithmetic
| Opcode | Format | Description |
|---|---|---|
ADD |
iABC | R(A) = R(B) + R(C) |
SUB |
iABC | R(A) = R(B) - R(C) |
MUL |
iABC | R(A) = R(B) * R(C) |
DIV |
iABC | R(A) = R(B) / R(C) |
MOD |
iABC | R(A) = R(B) % R(C) |
POW |
iABC | R(A) = R(B) ^ R(C) |
NEG |
iABC | R(A) = -R(B) |
INC |
iABC | R(A) = R(B) + 1 |
DEC |
iABC | R(A) = R(B) - 1 |
Comparison
| Opcode | Format | Description |
|---|---|---|
EQ |
iABC | R(A) = R(B) == R(C) |
NEQ |
iABC | R(A) = R(B) != R(C) |
LT |
iABC | R(A) = R(B) < R(C) |
LE |
iABC | R(A) = R(B) <= R(C) |
GT |
iABC | R(A) = R(B) > R(C) |
GE |
iABC | R(A) = R(B) >= R(C) |
Property Access
| Opcode | Format | Description |
|---|---|---|
GETFIELD |
iABC | R(A) = R(B)[K(C)] — named property |
SETFIELD |
iABC | R(A)[K(B)] = R(C) — set named property |
GETINDEX |
iABC | R(A) = R(B)[R(C)] — computed property |
SETINDEX |
iABC | R(A)[R(B)] = R(C) — set computed property |
Variable Resolution
| Opcode | Format | Description |
|---|---|---|
GETNAME |
iABx | Unresolved variable (compiler placeholder) |
GETINTRINSIC |
iABx | Global intrinsic / built-in |
GETENV |
iABx | Module environment variable |
GETUP |
iABC | R(A) = UpFrame(B).slots[C] — closure upvalue |
SETUP |
iABC | UpFrame(A).slots[B] = R(C) — set closure upvalue |
Control Flow
| Opcode | Format | Description |
|---|---|---|
JMP |
isJ | Unconditional jump |
JMPTRUE |
iAsBx | Jump if R(A) is true |
JMPFALSE |
iAsBx | Jump if R(A) is false |
JMPNULL |
iAsBx | Jump if R(A) is null |
Function Calls
| Opcode | Format | Description |
|---|---|---|
CALL |
iABC | Call R(A) with B args starting at R(A+1), C=keep result |
RETURN |
iA | Return R(A) |
RETNIL |
— | Return null |
CLOSURE |
iABx | Create closure from function pool entry Bx |
Object / Array
| Opcode | Format | Description |
|---|---|---|
NEWOBJECT |
iA | R(A) = {} |
NEWARRAY |
iABC | R(A) = array(B) |
PUSH |
iABC | Push R(B) to array R(A) |
JSCodeRegister
The compiled output for a function:
struct JSCodeRegister {
uint16_t arity; // argument count
uint16_t nr_slots; // total register count
uint32_t cpool_count; // constant pool size
JSValue *cpool; // constant pool
uint32_t instr_count; // instruction count
MachInstr32 *instructions; // 32-bit instruction array
uint32_t func_count; // nested function count
JSCodeRegister **functions; // nested function table
JSValue name; // function name
uint16_t disruption_pc; // exception handler offset
};
The constant pool holds all non-immediate values referenced by LOADK instructions: strings, large numbers, and other constants.