HN
Today

WATaBoy: JIT-Ing Game Boy Instructions to WASM Beats a Native Interpreter

This article details the creation of WATaBoy, a Game Boy emulator that ingeniously uses JIT compilation to WebAssembly, showcasing a novel approach to bypass iOS's JIT restrictions. It demonstrates how this method not only works but also outperforms native interpreters, offering a clever solution for high-performance emulation in web environments. The technical depth, creative problem-solving, and practical results make it a compelling read for those interested in WebAssembly, emulation, and platform limitations.

10
Score
0
Comments
#2
Highest Rank
7h
on Front Page
First Seen
Jun 29, 3:00 PM
Last Seen
Jun 29, 9:00 PM
Rank Over Time
8244566

The Lowdown

The author, in their final undergraduate project, explored a workaround for iOS's JIT compilation restrictions, which notoriously prevent high-performance emulators like Dolphin from running on the platform. Recognizing that web browsers are exempt from these restrictions and can JIT-compile WebAssembly, the project, WATaBoy, aimed to prove that JIT-ing Game Boy instructions to WebAssembly could lead to performance superior to a native interpreter. This ambitious endeavor tackled the challenge of indirect code generation and execution, pushing the boundaries of what's possible with WebAssembly for complex applications like emulators.

  • The Problem: iOS restricts JIT compilation, hindering CPU-bound emulators. WebKit's JS engine, however, can JIT-compile WebAssembly.
  • The Solution: Generate WebAssembly bytecode at runtime from Game Boy instructions, allowing the browser's engine to compile it into native machine code.
  • Proof of Concept (WATaBoy): A Game Boy emulator was built with two modes: a native interpreter and a JIT-to-Wasm compiler, to benchmark their performance.
  • Implementation Details (Rust): The article dives into the Rust implementation using wasm-encoder for Wasm bytecode generation and inline WebAssembly for dispatching functions via an indirect function table. It highlights the need for Nightly Rust and specific linker flags for WebAssembly table growth and export.
  • JavaScript Embedder: The necessary JavaScript code is provided to load the main Wasm module, compile and instantiate dynamically generated Wasm bytecode, and link it into the main module's function table.
  • Performance Benchmarks: Tests on a MacBook Air M2 across different browsers (Safari, Chrome, Firefox) showed the JIT-to-Wasm approach to be approximately 1.2x faster than a native interpreter and 1.5x faster than a Wasm interpreter for Game Boy emulation.
  • Browser Performance: Safari surprisingly outperformed Chrome and Firefox in these specific benchmarks, despite no explicit tuning for WebKit.
  • Future Work: Plans include adding audio and GBC support, optimizing PPU emulation, and exploring more advanced JIT and interpreter optimizations. The author also notes the current lack of ergonomic tooling for Wasm codegen as a barrier to wider adoption. While acknowledging limitations such as the lack of hardware fastmem optimizations and the specific nature of the benchmark, the project successfully demonstrated the viability and performance benefits of JIT-to-Wasm for emulation. This technique holds promise for cross-platform console emulation, especially on iOS, and underscores the potential for WebAssembly as a powerful target for performance-critical applications.