Zero-cost memory primitives, Static Single Assignment (SSA) lifetime analysis, and transparent compiler integration for Go.
RustyGo brings determinism and massive memory footprint reductions to Go by abstracting away the Garbage Collector. It proves allocation lifetimes statically using Static Single Assignment (SSA) dataflow verification, automatically routing safe allocations to thread-local arenas while preserving standard heap fallbacks for unsafe memory.
flowchart TD
subgraph BuildSystem["Build System Interception"]
Cmd["go build / rustygoc"] --> ToolExec["-toolexec Compiler Interceptor"]
end
subgraph AnalysisEngine["Static Analysis Core (golang.org/x/tools/go/analysis)"]
ToolExec --> SSA["SSA Program Extractor"]
SSA --> Discovery["Allocation Discovery Pass"]
Discovery --> Summaries["Inter-Procedural Function Summaries"]
Summaries --> Lifetime["Graph-Based Lifetime & Alias Checker"]
Lifetime --> Escape["Escape Classifier (SAFE / UNSAFE / UNKNOWN)"]
end
subgraph TransformationEngine["Code Transformation & Execution"]
Escape -->|SAFE -> Arena| Rewriter["AST Arena Rewriter"]
Escape -->|UNSAFE -> Heap| Fallback["Standard Go Heap Fallback"]
Rewriter --> Runtime["Thread-Local Bump Arena (rg.Arena)"]
Fallback --> GoGC["Go Runtime Garbage Collector"]
end
subgraph StandaloneVet["CI/CD Driver"]
VetCmd["rustygo-vet ./..."] --> AnalysisEngine
end
-toolexecInterceptor (compilerplugin): Interceptsgo tool compileinvocations transparently during standardgo build.- Allocation Discovery (
internal/analysis/allocation): Discovers candidate allocations (new,make, composite literals) and tags them with stable IDs. - Function Summaries (
internal/analysis/summary): Computes inter-procedural parameter escape and return flow summaries across package boundaries. - Lifetime Checker (
internal/analysis/lifetime): Builds path-compressed flow graphs tracking aliases, field stores, channels, and lexical regions (Function -> Block -> Loop -> Scope). - Escape Classifier (
internal/analysis/escape): Maps findings into optimization directives (SAFE -> Arena,UNSAFE -> Heap,UNKNOWN -> Heap). - AST Arena Rewriter (
internal/analysis/rewrite): Source-to-source AST rewriter that transparently injectsrustygoarena setups and allocation calls. - Standalone Vet Driver (
cmd/rustygo-vet): Packageablego/analysisvet driver for CI/CD pipelines and linters (golangci-lint).
- π PROPOSAL.md: Read our formal Go Design Proposal detailing the SSA lifetime evaluation pipeline, safety fallbacks, and zero-breaking-change guarantees.
- ποΈ ARCHITECTURE.md: Details the single source of truth static analysis pipeline and component flow.
- β‘ BENCHMARKS.md: View comprehensive benchmark measurements, system specs, and reproduction instructions.
| Strategy | Latency (ns/op) |
Memory (B/op) |
Heap Allocs (allocs/op) |
Speedup vs Heap |
|---|---|---|---|---|
rustygo.LocalArena (Unsync Pointer Bump) |
3.20 ns | 0 B | 0 allocs | ~15.8x faster |
RustyGo Thread-Local Arena (Arena.TryAlloc) |
5.40 ns | 0 B | 0 allocs | ~9.4x faster |
RustyGo Zero-Copy JSON Scanner (codec.JSONScanner) |
239.8 ns | 100 B | 2 allocs | ~4.0x faster |
Standard Go Heap Allocation (make([]byte, 256)) |
50.80 ns | 256 B | 1 allocs | Baseline |
Standard Go JSON (encoding/json.Unmarshal) |
955.1 ns | 280 B | 7 allocs | Baseline |
Note: Microbenchmarks measure isolated allocation latency and deallocation overhead under synthetic loop conditions, not full end-to-end application throughput.
For dedicated goroutines or thread-pinned workers, LocalArena skips all mutex and atomic CAS instructions, achieving sub-4ns pointer bump latency:
la := rustygo.NewLocalArena(64 * 1024)
defer la.Close()
buf := la.Alloc(128)
alignedBuf := la.AllocCacheAligned(256) // 64-byte L1 cacheline aligned
la.Reset() // Instant zero-cost reuseDecode incoming JSON streams directly into arena storage using zero-copy unsafe.String slices without triggering Go GC allocations:
scanner := codec.NewJSONScanner(payload)
for {
tokType, val, err := scanner.Next(scope)
if err == io.EOF { break }
if tokType == codec.JSONTokenKey {
_, val, _ := scanner.Next(scope)
// val is stored directly in arena memory
}
}Bind arenas directly to context.Context and HTTP request lifecycles:
// HTTP Server with automatic request-scope arena cleanup:
http.Handle("/api", rustygo.HTTPMiddleware(arena)(myHandler))
func myHandler(w http.ResponseWriter, r *http.Request) {
scope, _ := rustygo.ScopeFromContext(r.Context())
buf := scope.Alloc(1024) // Auto-recycled when HTTP request returns!
}- Hardware Guard Pages (
WithGuardPages(true)): Maps trailing memory pages withPAGE_NOACCESS(Windows) /PROT_NONE(Unix). Buffer overruns immediately trigger hardwareSIGSEGVinstead of silent heap corruption. - ASan Scope Poisoning (
WithPoisonOnScopeExit(0xDE)): Fills freed memory on scope exit with0xDEto trap use-after-scope reads and writes in test environments.
Enforce Rust-like lifetime guarantees in pure Go. When annotated with //rustygo:arena, rustygo-vet halts the build if an allocation escapes its lexical scope:
//rustygo:arena
ptr := new(MyStruct) // Verified by linter! Build fails if ptr escapes.codec.JSONScanner uses SIMD-Within-A-Register (SWAR) 64-bit vector arithmetic to process string tokens 8 bytes per clock cycle, bypassing byte-by-byte loops and delivering up to 4x faster throughput on long payload fields.
Full binary deserialization with direct *rustygo.Scope storage binding for strings and byte slices without heap escapes:
dec := codec.NewMsgPackDecoder(data)
mapLen, _ := dec.DecodeMapHeader()
key, _ := dec.DecodeString(scope) // Zero-alloc string stored directly in scope
val, _ := dec.DecodeBytes(scope) // Zero-alloc raw payloadEliminates cross-CPU mutex contention for high-concurrency server workloads by partitioning pre-warmed slabs into shards scaled to runtime.GOMAXPROCS:
pool := rustygo.NewShardedArenaPool(64*1024, 32)
defer pool.Close()
_ = pool.WithScope(func(s *rustygo.Scope) error {
slice := rustygo.AllocSlice[byte](s, 4096)
return process(slice)
})Eliminates chunk re-allocation overhead by tracking call-site peak usage via exponential moving averages, auto-sizing subsequent arena allocations:
_ = rustygo.WithAutoTunedScope("handle_request", func(s *rustygo.Scope) error {
buf := rustygo.AllocSlice[byte](s, dynamicSize)
return handle(buf)
})Run builds with the -rustygo-explain flag to inspect SSA analysis decisions directly in your terminal:
# Install rustygoc wrapper
go install ./compilerplugin/cmd/rustygoc
# Run build with interactive analysis logging
rustygoc build -rustygo-explain ./...Output Example:
[SAFE] main.go:42: Allocation of 'Buffer' -> Bound to Thread-Local Arena
[UNSAFE] main.go:88: Allocation of 'Data' Escapes -> Reason: Channel send across goroutine boundary
[UNKNOWN] main.go:104: Allocation of 'Config' -> Lifetime unproven
Packageable analyzer using golang.org/x/tools/go/analysis for GitHub Actions or golangci-lint:
# Install rustygo-vet
go install ./cmd/rustygo-vet
# Run static vet analysis on any module
rustygo-vet ./...You can invoke the pipeline programmatically in your own Go tools:
package main
import (
"golang.org/x/tools/go/ssa"
"rustygo/internal/analysis/pipeline"
)
func AnalyzeProgram(prog *ssa.Program) {
res, err := pipeline.Run(prog)
if err != nil {
panic(err)
}
for _, dec := range res.Decisions {
println("Allocation ID:", dec.Allocation.ID)
println("Decision:", dec.Decision)
println("Reason:", dec.Reason)
}
}"RustyGo never optimizes unless safety can be proven."
An allocation status of
UNKNOWNis treated exactly likeUNSAFE(fallback to standard Go heap allocation).
[x] Dynamic slab growth & geometric doubling
[x] LocalArena unsynchronized bump allocator
[x] Zero-copy JSON streaming tokenizer
[x] Request-scoped context & HTTP middleware
[x] Hardware guard pages (PROT_NONE) & memory poisoning
[x] Compile-time pragma directives (//rustygo:arena)
[x] SSA lifetime analysis & escape classifier
[x] Standalone vet driver (rustygo-vet)
[x] Interactive explain flag (-rustygo-explain)
[x] Formal Go design proposal (PROPOSAL.md)
[ ] Upstream golang.org/x/tools analyzer contribution
Repository structure:
cmd/rustygo-vet/: Standalonego/analysisvet checker CLI driver.compilerplugin/:-toolexeccompiler interceptor andrustygocCLI.codec/: Zero-copy stream and JSON parsing utilities.internal/analysis/: Modular SSA dataflow, lifetime, escape, summary, and rewrite packages.rustygo_test/: Unit, concurrency, and high-memory benchmarks.