English · 한국어
Run dynamic logic inside Go with explicit resource limits, typed host calls, and a threaded semantic baseline.
- Bounded execution — stack, heap, frame depth, fuel, hooks, context.
- Direct host calls — typed, reflection-free
HostFunctionpath. - Native tier — ARM64 execution, on by default, with threaded fallback.
go get github.com/siyul-park/minivmRequires Go 1.26.2+. The VM core uses only the Go standard library.
Build and run a bytecode program that calculates 6 × 7:
prog := program.New([]instr.Instruction{
instr.New(instr.I32_CONST, 6),
instr.New(instr.I32_CONST, 7),
instr.New(instr.I32_MUL),
})
vm := interp.New(prog)
defer vm.Close()
if err := vm.Run(context.Background()); err != nil {
log.Fatal(err)
}
result, _ := vm.Pop() // types.I32(42)minivm keeps the execution model explicit: bytecode in, controlled runtime, typed value out.
| Capability | What it gives you |
|---|---|
| Embeddable runtime | First-class functions, locals, globals, closures, refs, strings, arrays, structs, maps, coroutines, and structured errors |
| Host integration | Typed HostFunction calls plus Marshal and Unmarshal for ordinary Go values |
| Resource control | Stack, heap, frame, fuel, context, hook, and debugger controls |
| Fast baseline | Closure-threaded dispatch with low steady-state allocation |
| Semantic baseline | Threaded interpreter with explicit resource controls |
| Safe admission | Static bytecode verification before execution |
- Scripting engines that execute user-defined behavior under host policy
- Rule engines that change runtime decisions without redeployment
- DSL runtimes that need a compact execution layer
- Plugin systems that isolate extension logic from the host application
Expose Go behavior through a typed host function:
lookup := interp.NewHostFunction(
&types.FunctionType{
Params: []types.Type{types.TypeI32},
Returns: []types.Type{types.TypeI32},
},
func(vm *interp.Interpreter, params []types.Boxed) ([]types.Boxed, error) {
price := db.GetPrice(int(params[0].I32()))
return []types.Boxed{types.BoxI32(price)}, nil
},
)Parameters and results stay in typed []types.Boxed values. The direct path does not require reflection or interface{} boxing.
See Host Integration for marshaling, host objects, and lifetime rules.
Threaded execution is the semantic baseline. ARM64 native execution is on by default and tuned or disabled with interp.WithThreshold; measurements and reproduction live in Benchmarks.
if err := program.Verify(prog); err != nil {
log.Fatal(err)
}The verifier rejects malformed control flow, invalid stack behavior, and type mismatches before execution. The run CLI verifies loaded programs by default.
prog, err := optimize.New(optimize.O2).Optimize(prog)Optimization levels range from local constant folding and deduplication to dead-code elimination and cross-block global value numbering.
vm := interp.New(prog,
interp.WithStack(4096),
interp.WithHeap(512),
interp.WithFrame(256),
interp.WithFuel(10_000),
interp.WithTick(128),
)Use hooks for policy checks and debug.NewDebugger with WithHook(dbg.Hook) and WithTick(1) for instruction-accurate breakpoints and stepping (Debugging).
Program → Verify → optimize? → threaded ⇄ native (ARM64)
The threaded interpreter is the semantic baseline and complete execution engine. On ARM64 the JIT adds native execution for hot functions once a program has run long enough to repay a compile (WithThreshold); unsupported paths return to threaded execution.
The instruction set is WebAssembly-inspired but intentionally custom. It uses one-byte opcodes with fixed-width or length-prefixed operands.
| Feature | Status |
|---|---|
| Threaded interpreter | ✅ Available |
| Static bytecode verifier | ✅ Available |
AOT optimizer (O1-O3) |
✅ Available |
ARM64 native tier (on by default, interp.WithThreshold) |
✅ Available |
| Debugger and profiler | ✅ Available |
| x86-64 native backend | 🔲 Not implemented |
The x86-64 assembler backend is not present. See the Roadmap for current priorities.
| Guide | Use it for |
|---|---|
| Documentation Index | Browse all project documentation |
| Compatibility | Check Go, platform, CGO, and build-tag support |
| Host Integration | Connect bytecode with Go values and functions |
| Verification | Understand static admission checks and limits |
| Debugging | Use breakpoints, stepping, and inspection |
| Testing | Understand executable specifications and gates |
| Benchmarks | Reproduce performance and allocation measurements |