The Problem
You want Go to run faster, so the natural idea is a JIT: compile hot code to machine code and execute it directly. This works in Java and C++, but breaks in Go.
Why? Because Go's runtime is a "control freak." It must know what your program is doing at every moment — what pointers are on the stack, when to grow the stack, when to GC. If you sneak in your own generated machine code, the runtime looks at it and says: "I've never seen this PC address" — and kills the process with fatal error: unknown pc.
Since you can't win head-on, go parasitic.
The Three-Step Approach
Step 1: Watch (Tracing via eBPF)
Don't instrument Go code — it's slow and detectable. Use eBPF to observe from the kernel side, like watching through a window while the dorm inspector checks rooms. Profiling of hot behavior happens at near-zero overhead, completely invisible to the runtime.
Step 2: Write the Script (Compilation to Wasm)
You can't generate raw machine code — the runtime would notice. Instead, compile the hot paths into a "script" written in WebAssembly. Wasm is a sandbox: the runtime doesn't need to understand what's inside, because the Wasm engine (wazero) has already handled all safety concerns. The runtime just sees "a legitimate student reading a book."
Step 3: Swap the Actor (Execution via Trampoline)
To execute the script, use a "legitimate student" — a trampoline written in Go assembly, carrying an ABI0 declaration as its "student ID." It raises its hand in class, gets called on, quietly reads the script, and reports back. The runtime only ever sees a legitimate Go function.
The Core Insight
The insight isn't "how to make Go support JIT" — it's "how to get JIT benefits while Go doesn't support JIT."
Don't make the Go runtime support JIT; do JIT where the runtime can't see. The analogy to DFlash: don't compete with autoregressive models on quality — be an excellent guesser.
- Wasm is the firewall isolating the runtime from the JIT
- eBPF is the periscope for undetected observation
- The trampoline is the springboard for legitimate entry into the isolated zone
- JIT code must be pointer-free. The runtime can't see what you're doing; if your JIT code holds a pointer to a Go object, the GC doesn't know about it and may collect it — leaving you with a dangling pointer and a crash.
- Spill to the C heap, not the Go stack. When registers run out, data goes to malloc'd C memory — the GC scans Go stacks, so spilling there is forbidden.
- Bail out immediately on uncovered instructions. Don't push through — you don't know whether an instruction might trigger a runtime checkpoint.
- eBPF tracing: kernel-side, non-intrusive profiling, near-zero overhead
- Wasm sandbox: wazero engine handles cross-platform/safety/performance; the drafter is only on the order of 2B parameters
- Trampoline: written in Go assembly with an
ABI0declaration — the legitimate anchor - Isolation strategy: JIT code must be pointer-free; register spills go to the C heap (malloc)
- Safe anchor: all JIT calls wrapped in standard Go assembly functions
The Constraints
Even with these isolations, rules must be followed:
Feynman Check
Imagine a dorm with a strict inspector, and you want to secretly cook hot pot. Installing a hot plate openly means getting caught. So:
1. Install a camera outside the window (eBPF) to see when roommates are hungriest; 2. Write the cooking steps as a script (Wasm) in a language the inspector can't read; 3. Find a legitimate roommate (trampoline) with a valid student ID who cooks per the script when the inspector isn't looking.
The inspector only ever sees a normal roommate. If this explanation makes sense to you, the understanding holds.
Technical Details
This is the parasitic architecture: not "turning Go into Java," but finding the optimal solution within Go's constraints. Sidestep the blade rather than clash with it.