Module Internals
Internally, the Blaze interpreter uses an instance of a Blaze Virual Machine (VM). The VM is a stack machine, meaning that instructions assume that operands will be on the stack, and results placed onto the stack.
Take the following Blaze program:
func main() {
var x = 2 + 3;
}
We can compile it by using blzc -s .\app.txt -d, where -d indicates to also store debug information (line numbers).
To dump the module information, use the the -d (as in dump) flag on the interpreter: blzi -m app.blzm -d, which produces the following output:
== INFORMATION ==
Version 1.0
Name '.\app.txt'
Debug? True
== CONSTANTS ==
0: String(main)
1: Number(2)
2: Number(5)
== VARIABLES ==
0: main (PRIVATE)
== FUNCTIONS ==
<anonymous> (# args: 0, # locals: 0, Varargs: False, # instructions: 4)
1 LDFUNC 1
STVAR 0
0 LDNULL 0
RET 0
main (# args: 0, # locals: 1, Varargs: False, # instructions: 6)
2 LDCONST 1
LDCONST 2
ADD 0
STLOCAL 0
0 LDNULL 0
RET 0
== CLASSES ==
Instruction Format
Each instruction consists of:
- An opcode (1 byte): determines the instruction type.
- Optional operands (1–4 bytes): depending on the instruction.
Operands include:
- Constant indices: reference values in the constants table.
- Variable indices: used to access locals or globals.
- Offsets: for jumps and conditional branches.
If an operand doesn't fit in one byte, EXTENDED_ARG instructions are used to increase its size.
Constants Table
The constants table stores all literals used in the program: numbers and strings. Each constant has an index used by the instructions.
Constants can be loaded onto the stack by using the LDCONST instruction whose argument is an index into the constant table.
Variables Table
Each variable declared at module level is stored with its name and visibility and can be accessed using STVAR and LDVAR instructions.
Note
The parameter for STVAR and LDVAR is not a direct variable index. Instead, it refers to the index of a string constant that contains the name of the variable.
Functions Table
Each function is compiled to bytecode and stored with:
- Name (optional)
- Argument count
- Whether it accepts varargs
- Local count
- Instruction count
- Its bytecode instructions
Example Walkthrough
Take the main function from the bytecode dump from earlier:
main (# args: 0, # locals: 1, Varargs: False, # instructions: 6)
2 LDCONST 1
LDCONST 2
ADD 0
STLOCAL 0
0 LDNULL 0
RET 0
Here's what happens:
| Instruction | Stack | Description |
|---|---|---|
LDCONST 1 |
2 | Push the constant 2 (index 1) onto the stack |
LDCONST 2 |
2, 3 | Push the constant 3 (index 2) onto the stack |
ADD |
5 | Pop and add both values and push the result 5 |
STLOCAL 0 |
∅ | Pops and stores the result in the first local variable x |
LDNULL |
null | Pushes null to be returned from function |
RET |
null | Returns from the function |
Note: ∅ denotes empty stack