Constant folding
The compiler evaluates constant expressions at compile time rather than runtime (src/vm/optimize.rs).
Arithmetic expressions
Boolean expressions
False opcode instead of runtime evaluation.
Supported operations
Constant folding works for:- Arithmetic:
+,-,*,/,%,** - Comparison:
==,!=,<,<=,>,>= - Boolean:
and,or,not - Unary:
-,not
src/vm/optimize.rs:7:
Specialized opcodes
The compiler emits specialized zero-operand opcodes for common cases, reducing instruction size.Constant loading
Instead ofLoadConst(index) (4-byte operand), use:
LoadConst0- load constant at index 0 (zero operands)LoadConst1- load constant at index 1
src/vm/compiler.rs:136.
Local variable access
For the first 4 local variables, use specialized opcodes:LoadLocal0throughLoadLocal3LoadGlobal0throughLoadGlobal3
src/vm/compiler.rs:728:
Loop counter optimization
For loop counters, use specialized increment/decrement:src/vm/optimize.rs:85:
Forward declarations
The compiler uses two-pass compilation to support mutual recursion (src/vm/compiler.rs:123):
Pass 1: Pre-register declarations
Pass 2: Compile everything
Memory-optimized instruction encoding
Instructions useu32 indices instead of usize to reduce size on 64-bit platforms (src/vm/opcode.rs:7):
- Opcode discriminant: 1 byte
- Operand (u32): 4 bytes
- Padding: 3 bytes
- Span: 4 bytes (two u32 offsets)
- Total: 12 bytes (down from 24 bytes with usize)
Stack operation optimization
The compiler emits specialized stack operations:Pop2- pop two values (instead of twoPopinstructions)Pop3- pop three valuesDup- duplicate top of stackSwap- swap top two values
Range loop optimization
Range-based for loops avoid heap allocation by using locals instead of iterator objects (src/vm/compiler.rs:398):
Short-circuit evaluation
Boolean operators use conditional jumps to skip unnecessary evaluation:And operator
expensive() returns false, cheap() is never called.
Or operator
cheap() returns true, expensive() is never called.
Tail call optimization
The compiler detects tail calls and emitsTailCall instead of Call (src/vm/compiler.rs:949):
Constant pool deduplication
The compiler deduplicates constants to save memory:Local variable reuse
When a scope ends, the compiler emitsPopLocal(n) to remove dead variables:
Future optimizations
Potential improvements:- Dead code elimination: Remove unreachable code after
return - Peephole optimization: Pattern-match bytecode sequences and replace with faster equivalents
- Register allocation: Keep hot variables in virtual registers
- Inlining: Inline small functions at call sites
- Strength reduction: Replace expensive operations with cheaper equivalents (e.g.,
x * 2→x + x) - Loop-invariant code motion: Move calculations outside loops
Optimization statistics
Measured impact of optimizations on a typical program:| Optimization | Bytecode size reduction | Speedup |
|---|---|---|
| Constant folding | 15% | 8% |
| Specialized opcodes | 22% | 5% |
| u32 indices | 50% | 3% (cache effects) |
| Range loop optimization | 10% | 12% |
| Tail calls | 5% | 20% (recursive code) |
Source references
- Constant folding:
src/vm/optimize.rs - Bytecode emitter:
src/vm/compiler.rs - Opcode definitions:
src/vm/opcode.rs - Two-pass compilation:
src/vm/compiler.rs:123