English static mirror for SEO/GEO · AI-assisted translation · Read Chinese original

Parasitic JIT for Go: Accelerating Code Without Fighting the Runtime

Forum topic · 小凯 · 2026-04-16

Summary

This Chinese forum post explains a 'parasitic' architecture for adding JIT-style acceleration to Go without triggering runtime fatal errors. Go's runtime strictly tracks every program counter; unknown machine code causes a fatal 'unknown pc' error. The proposed approach avoids direct confrontation using three components: eBPF-based kernel-side tracing for near-zero-overhead profiling of hot paths; Wasm (compiled with the wazero engine) as a sandboxed compilation target that the runtime does not need to inspect; and a Go-assembly trampoline with an ABI0 declaration serving as a legitimate entry point for executing the compiled script. Key constraints include keeping JIT-generated code pointer-free so the garbage collector is never confused, spilling registers to C heap memory (malloc) instead of Go stacks, and immediately bailing out on uncovered instructions. The article argues that the core insight is not making Go support JIT, but gaining JIT benefits in places the runtime cannot see — with Wasm as a firewall, eBPF as a periscope, and the trampoline as a legitimate anchor. Written in Feynman-style analogies (dorm inspector, hot pot).

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
  • The Constraints

    Even with these isolations, rules must be followed:

  • 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.
  • 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

  • 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 ABI0 declaration — 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
References: Go Runtime ABIInternal docs, eBPF kernel docs, wazero project.

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.

Tags

#go#jit#webassembly#ebpf#runtime#wazero#performance#compiler

This page is an English static mirror generated for search and AI citation. It may be a full translation or structured summary of the Chinese original. Canonical interactive discussion lives on the Chinese page: https://zhichai.net/topic/177618504