Bytecode Virtual Machine Backend
The AdeshLang Bytecode Virtual Machine is a portable, compact, and high-performance stack-based virtual machine. It compiles AdeshLang source code to a platform-independent bytecode format (.adbc) that runs anywhere without requiring external C toolchains or LLVM installations.
┌──────────────────────────────────────────────────────────┐
│ Bytecode Compilation Flow │
├──────────────────────────────────────────────────────────┤
│ Source (.adesh) ──► Semantic IR ──► Bytecode (.adbc) │
│ │ │
│ ▼ │
│ Stack-based VM Loop │
│ [Fetch-Decode-Exec] │
└──────────────────────────────────────────────────────────┘
1. VM Architecture Overview
The Bytecode VM operates with:
- Stack-based Execution: Operands are pushed onto and popped from an evaluation value stack.
- Value Representation: Compact 64-bit tagged unions / NaN-boxing for zero-allocation scalar values (integers, floats, booleans, pointers).
- Constant Pool: Stores deduplicated strings, large floating-point numbers, and symbol identifiers.
- Call Frame Stack: Manages function return addresses, base pointer offsets, and local variable slots.
- Zero-GC Integration: Interacts directly with
adesh_allocreference counts without a garbage collection stop-the-world loop.
2. Opcode Reference Table
AdeshLang Bytecode instructions use an 8-bit opcode followed by 0, 1, or 2 operands:
| Opcode | Mnemonic | Operands | Description |
|---|---|---|---|
0x01 | Noop | None | No operation. |
0x02 | PushConst | idx: u32 | Pushes constant at constant pool idx onto the stack. |
0x03 | PushI64 | val: i64 | Pushes inline 64-bit integer onto the stack. |
0x04 | Pop | None | Discards top item from the stack. |
0x05 | Dup | None | Duplicates top item on the stack. |
0x06 | LoadLocal | slot: u16 | Pushes value from local stack frame slot onto the stack. |
0x07 | StoreLocal | slot: u16 | Pops value from stack and writes to local slot. |
0x08 | LoadGlobal | idx: u32 | Loads value from global table. |
0x09 | StoreGlobal | idx: u32 | Stores value to global table. |
0x0A | Add | None | Pops $b, a$, pushes $a + b$. |
0x0B | Sub | None | Pops $b, a$, pushes $a - b$. |
0x0C | Mul | None | Pops $b, a$, pushes $a \times b$. |
0x0D | Div | None | Pops $b, a$, pushes $a / b$. |
0x0E | Mod | None | Pops $b, a$, pushes $a \pmod b$. |
0x0F | CallDecorated | fn: u32, pipe: u32 | Dispatches decorated function pipeline. |
0x10 | Jump | offset: i32 | Unconditional jump to relative bytecode offset. |
0x11 | JumpIfFalse | offset: i32 | Pops boolean condition; jumps if false. |
0x12 | Call | argc: u8 | Calls function with argc arguments. |
0x13 | Return | None | Returns from active call frame. |
0x14 | AllocArc | size: u32 | Allocates zero-GC ARC managed heap object. |
0x15 | DropArc | None | Decrements ARC count and frees memory if count reaches zero. |
3. Bytecode Compilation & Execution
# Run source code using the Bytecode VM backend
adesh run --backend=vm program.adesh
# Pre-compile source into standalone portable bytecode archive (.adbc)
adesh compile --target=bytecode -o program.adbc program.adesh
# Execute compiled bytecode file directly
adesh run program.adbc
4. Disassembling Bytecode
Inspect generated bytecode and stack instructions with adesh disasm:
adesh disasm program.adesh
Sample Disassembly Output:
=== Bytecode Disassembly: fn calculate(a: i64, b: i64): i64 ===
Constants: [ 10 ]
Locals: [ a, b, temp ]
0000: LoadLocal 0 ; push 'a'
0002: LoadLocal 1 ; push 'b'
0004: Add ; a + b
0005: PushConst 0 ; push 10
0007: Mul ; (a + b) * 10
0008: StoreLocal 2 ; temp = (a + b) * 10
0010: LoadLocal 2 ; push temp
0012: Return ; return result
5. Portability & Sandboxing
Because the Bytecode VM is implemented in pure Rust without native platform dependencies:
- Bytecode binaries (
.adbc) are 100% portable across Linux, macOS, Windows, BSD, and WebAssembly. - The VM can be embedded inside other applications as a deterministic, memory-safe scripting runtime.