Master the fundamental concepts of build a bytecode vm through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksA virtual machine's instruction set architecture defines what operations exist and how they encode. The first fork every VM author faces is stack-based versus register-based design. Stack VMs keep operands implicit on an evaluation stack; register VMs name explicit slots in each frame.
Stack-based designs dominate portable bytecode:
PUSH 5; PUSH 3; ADD leaves 8 on the stackRegister-based designs trade larger instructions for fewer memory touches:
ADD R1, R2, R3 names sources and destination explicitlyOpcode layout matters early. A single-byte opcode (0-255) plus optional operand bytes is the pattern CPython and your VM will follow. Getting stack effects documented now (ADD pops 2, pushes 1) is what lets the compiler, GC, and JIT plug into a stable contract.
For example, compiling print(5 + 3) might emit PUSH 5; PUSH 3; ADD; PRINT.
This exercise asks you to document a 16-opcode stack ISA before you implement the interpreter. You will implement opcode tables, stack-effect descriptions, and example sequences that every later task builds on.
Design the instruction set for a small stack VM, then build its assembler (text to bytes, resolving labels in two passes) and disassembler (bytes back to text). Every later task in this subtrack uses this ISA.
| Opcode | Mnemonic | Operand | Opcode | Mnemonic | Operand |
|---|---|---|---|---|---|
| 0x00 | HALT | 0x08 | DUP | ||
| 0x01 | PUSH | int32, little-endian | 0x09 | SWAP | |
| 0x02 | POP | 0x0a | |||
| 0x03 | ADD | 0x0b | EQ | ||
| 0x04 | SUB | 0x0c | LT | ||
| 0x05 | MUL | 0x0d | GT | ||
| 0x06 | DIV | 0x0e | JMP | uint16 address, little-endian | |
| 0x07 | NEG | 0x0f | JZ | uint16 address, little-endian |
cLoading…
0x integer in the int32 range. JMP/JZ take a label or a numeric address 0..65535.asm block, pass-1 errors first:
line N: duplicate label Xline N: unknown mnemonic Xline N: M needs an operandline N: too many operands for Mline N: undefined label Xline N: bad 32-bit immediate Xassembly failed: K error(s) are printed.N bytes: and every byte.0x%04x.??? unknown opcode and decoding continues at the next byte.(truncated operand), and decoding stops.cLoading…
Input:
cLoading…
Output:
cLoading…
jz done before done:) resolve.Hidden tests cover backward and forward labels, numeric jump targets, hex immediates, negative numbers, a label on its own line, every error message, and disassembly of every opcode.