Gaming

The Browser Loophole That Could Sneak Emulators Onto iPhone

Apple blocks the one thing fast emulators need. A student found a side door that is already on every iPhone. Here is how it works.

DA

Founder & Lead Technician

June 30, 2026 at 4:15 AM IST 5 min
The Browser Loophole That Could Sneak Emulators Onto iPhone

Quick answer

A student project called WATaBoy compiles Game Boy instructions to WebAssembly at runtime, letting the browser turn them into native code. In a proof-of-concept benchmark it beat a native interpreter, hinting at a path for fast emulators on iOS, where Apple bans normal JIT compilation.

Apple bans the one trick fast emulators need. A student found a way around it.

The block has a name: JIT compilation. It is why Dolphin, the popular GameCube and Wii emulator, has never shipped on the App Store. As developer OatmealDome laid out in his post on why Dolphin is not coming to iOS, Apple does not let normal apps generate machine code on the fly and then run it. Without that, a heavy emulator crawls.

So the obvious question has been: do we just wait years for iPhone chips to get fast enough to brute-force it with a slow interpreter?

Maybe not. Because Apple left one door open, and it is sitting on every iPhone already.

The exception hiding in plain sight

That door is the web browser. Apple forbids apps from doing just-in-time compilation, but it carves out an exception for WebKit, the engine behind Safari. WebKit ships with JavaScriptCore, and JavaScriptCore absolutely does JIT compilation in its higher-performance tiers.

Here is the mechanism. Call a JavaScript function enough times and the engine stops interpreting it line by line. It optimises it and compiles it down to native machine code so it runs fast. The same thing happens with WebAssembly, the low-level binary format browsers run.

Now connect the dots. If the browser is allowed to turn WebAssembly into native code, you do not have to generate native code yourself at all. You generate Wasm. The browser does the forbidden part for you, legally.

That is the whole idea behind a project called WATaBoy.

What WATaBoy actually did

WATaBoy is a Game Boy emulator built as an undergraduate final-year project. The author built it twice on purpose: once as a plain interpreter, and once using this JIT-to-Wasm approach, then benchmarked the two against each other.

The naming is deliberate. The author calls it a JIT-to-Wasm rather than a Wasm JIT, to keep it separate from the thing the browser engine does afterward when it recompiles that Wasm into machine code. So there are two layers of compilation stacked: the emulator emits Wasm at runtime, then the browser JITs that Wasm to native code.

The idea did not come from nowhere. The author credits Andy Wingo's writing on just-in-time code generation within WebAssembly as the spark that made it seem possible. A few existing projects already lean on the same trick, including the Jiterpreter and v86.

But here is the part that makes this notable. According to the author, no game console emulator had used this technique before, and nobody had measured it head-to-head against an interpreter running natively to see which is actually faster.

Why a Game Boy emulator even needs a JIT

If you know emulation, you just winced. A Game Boy is ancient hardware. How could it possibly need just-in-time compilation?

It is a fair objection, and the honest answer is that it does not need it the way a modern console would. The author is upfront that a Game Boy benefits far less from JIT than a sixth-generation console would. The reason a Game Boy was chosen is scope: it was fast enough to build inside a final-year project, while still being a real, working test case.

The trickier problem is staying cycle-accurate, meaning the emulator has to match the original hardware's exact timing, not just produce the right end result. WATaBoy leans on techniques from GameRoy, another emulator whose write-up explains how JIT compilation can coexist with cycle accuracy. GameRoy's own JIT targets x86 directly, but the author notes that nearly all of its optimisation tricks carry over to a Wasm target too.

The headline result: in this benchmark, the JIT-to-Wasm build beat the native interpreter. On paper, generating Wasm and letting the browser recompile it outran interpreting instructions directly in native code.

How it is wired together under the hood

The build is done in Rust, and the author deliberately skips the usual comfort tools. Normally a Rust-to-web project reaches for wasm-bindgen and wasm-pack to auto-generate the glue between Rust and JavaScript. WATaBoy avoids them because they get awkward when you are working with Wasm at this low a level.

Instead the data crosses the Rust-to-JavaScript boundary through the C ABI, passing raw pointers and buffer lengths rather than rich JavaScript objects. The actual Wasm bytecode is built at runtime using the wasm-encoder crate, which lets you emit Wasm instructions with a builder-style API instead of hand-writing raw bytes. One catch worth flagging if you try to reproduce it: the project needs Nightly Rust, because it uses a small amount of inline Wasm.

What this means for you, and what happens next

Be clear-eyed here. This is a proof of concept and a benchmark, not Dolphin on your iPhone. A Game Boy is a featherweight compared to a GameCube, and the author says so plainly. Nobody has shown this scales to a demanding sixth-gen console yet.

But the direction is the interesting part. The thing blocking serious emulators on iOS was never raw chip speed, it was Apple's JIT ban. This work demonstrates a legitimate path that routes around the ban entirely by using the one JIT Apple already permits, the browser's.

So what should you watch for over the next stretch?

  • Bigger targets. The real test is whether someone applies JIT-to-Wasm to a heavier console and still beats an interpreter. That is the experiment this project invites.
  • Browser-based emulator frontends. If this scales, expect more emulators that run inside a web view on iOS rather than fighting the App Store's native-code rules.
  • The same trick beyond games. Any CPU-bound workload that wants speed on a JIT-restricted platform could borrow this pattern. Emulation is just the obvious first stop.

For now, treat WATaBoy as a signal. A student answered a question the big emulator projects had mostly shrugged at, and the answer was yes, the side door works. The next person to walk through it might be carrying something a lot heavier than a Game Boy.

Source: Hacker News

Frequently asked questions

Why can Apple ban JIT but emulators still run in a browser on iPhone?

Apple blocks apps from generating and running native machine code at runtime, which is how fast emulators normally work. The one exception is web browsers: WebKit and its JavaScriptCore engine are allowed to JIT-compile hot JavaScript and WebAssembly into native code. A JIT-to-Wasm emulator piggybacks on that allowed path instead of generating native code itself.

What is the difference between a JIT-to-Wasm and a normal Wasm emulator?

A normal Wasm emulator is compiled once, ahead of time, into a fixed WebAssembly module. A JIT-to-Wasm emulator like WATaBoy generates new WebAssembly bytecode while it runs, based on the game code it sees, and hands that to the browser to compile into native machine code. It is dynamic recompilation, just using Wasm as the target instead of x86 or ARM.

Does this mean Dolphin or GameCube emulators are coming to iPhone?

Not yet. WATaBoy is a Game Boy proof of concept built as a final-year university project, and the Game Boy is a far lighter workload than a sixth-generation console. The result shows the technique can be fast, but porting something as demanding as Dolphin would be a much larger effort. Treat this as a promising direction, not a shipping product.

#JITtoWasm#GameBoyemulator#iOSemulation#WebAssembly
Share
DA

Founder & Lead Technician

Daniel founded Ask Technicians to cut through bad tech advice. He writes hands-on troubleshooting guides drawn from years of real-world repair and support work.

Related guides