An undergrad's Game Boy emulator beats a native interpreter by JIT-ing to WebAssembly
WATaBoy compiles Game Boy CPU instructions into WebAssembly at runtime, then lets the browser JIT that Wasm down to machine code. Running Pokemon Blue, the double-translated path edges out a native C interpreter by about 1.2x.
The trick is the second layer. WATaBoy emits WebAssembly bytecode for hot game code, and Safari's engine compiles that Wasm to native machine code on its own — so the emulator rides the browser's JIT instead of fighting it.
A systems engineer in the thread deflated the surprise with arithmetic: Wasm overhead runs near 20 percent, an interpreter's loop overhead near 1000. Beating the interpreter was never the hard part. The novelty is a Game Boy JIT runtime existing at all.
A two-layer JIT that turns the browser into the compiler

WATaBoy is a final-year undergraduate project with a deliberately odd design: instead of interpreting Game Boy instructions one by one, it translates them into WebAssembly bytecode at runtime. It doesn't generate native machine code itself. The browser's JS/Wasm engine does that, taking the freshly emitted Wasm and JIT-compiling it the same way it would a hot JavaScript function.
The payoff shows up in the benchmarks. On Pokemon Blue, the JIT-to-Wasm path ran roughly 1.2x faster than a native interpreter and about 1.5x faster than a Wasm interpreter. Safari posted the strongest numbers across browsers with no browser-specific tuning. The author's framing of why a layer of indirection wins: "we benefit from JIT, despite being an extra layer of indirection away from the native machine code."
The real motivation is platform politics. Emulators like Dolphin can't ship on iOS because Apple bans runtime JIT compilation, except inside web browsers, where JavaScriptCore is allowed to compile hot code to native. Route your emulator's generated code through Wasm in a browser tab, and you inherit a JIT Apple otherwise forbids.
The thread: "of course it beats an interpreter, that's not the cool part"
The headline reads like a paradox; an engineer in the thread reframed it as plain arithmetic.
"Of course it beats a native interpreter. WASM overhead is about 20%, interpreter overhead is about 1000%. What's cool here is to have a GameBoy JIT runtime at all." — an engineer who put numbers to the overhead
The genuinely interesting find, for several readers, was the iOS escape hatch itself.
"Apple has one exception to its JIT restrictions: web browsers… if a JS function is called enough times, eventually it'll be optimised and compiled into native machine code. The same is true for WebAssembly… Such a beautiful way to get around restrictions." — bawolff, a MediaWiki contributor
The approach has lineage. A Waterloo mechatronics grad pointed back to Andrew Kelley's 2013 attempt to statically recompile NES code, which stalled on hand-written assembler that wouldn't map cleanly to LLVM IR. Its conclusion argued a JIT, recompiling hot paths once you have runtime data, was the way to go.
"In the conclusion he specifically calls out a JIT-type methodology as probably being the way to go, where you live-recompile the hot paths when you have the runtime data required to actually understand them… Very cool to see something like that in action." — an engineer who'd followed Kelley's static-recompilation work
Not everyone bought the premise. One commenter pointed to StikDebug, a tool that enables JIT on iOS without the browser detour, arguing the project's stated motivation skips an existing solution. And the perennial reminder that browser-fast is not hardware-fast: a retro-emulation user noted a natively coded emulator still runs faster on a 166 MHz Pentium than this does on a Core Ultra i9 — the Wasm tax is real, even when it wins the matchup it was measured against.
Get breakdowns like this every day
The top Hacker News stories, unpacked — by email, Telegram, or RSS.
NixOS 26.05 ships from 2,842 contributors — and LLMs are quietly driving its adoption
NixOS 26.05 "Yarara" landed with 59,703 commits since the last release and 17,532 packages deleted on purpose. In the thread, convert after convert credits the same unexpected onboarding tool: an LLM that can finally read and write their config.