OpenJDK 21 on WebAssembly

HotSpot Zero + JIT

A real JVM, running in your browser tab

This is OpenJDK 21's HotSpot interpreter (Zero) compiled to WebAssembly, with a bytecode-to-wasm JIT. It compiles and runs Java entirely client-side β€” no server, no round-trips. Everything below is a static site served from GitHub Pages.

🎨

Swing / Java2D demo

A Swing application rendering through Java2D onto an HTML canvas β€” real AWT peers, painted frame-by-frame from inside the wasm JVM. Boots in ~2s.

⌨️

Live javac REPL

Edit Java, compile it with the in-VM javac, and run it β€” console output streams straight back. The VM stays warm, so re-runs take ~1s.

🧊

3D / WebGL demo

A Java program issuing OpenGL calls through JNI, translated to WebGL and rendered to a canvas β€” a spinning shaded triangle, same path as the Minecraft port.

πŸ—‚οΈ

Filesystem inspector

Browse the JVM's in-memory filesystem β€” the JDK modules under /jdk, the app classpath /app, and the /work scratch area.

🌐

Networking demo

Java opens a real TCP socket and fetches a URL over HTTP, tunneled through a local relay. Run the relay, then fetch live sites from inside the VM.

🌱

Spring Boot in the tab

A real Spring Boot app on embedded Tomcat, running inside the JVM. The page calls its REST endpoint over an emulated TCP loopback β€” no network, no relay.

πŸͺ£

TinyS3 object storage

A real S3-compatible server (TinyS3, Java/Netty) running inside the tab. Upload and browse objects through the AWS SDK over an emulated TCP loopback β€” the server, storage, and client all in one browser page.

βš™οΈ

How the JIT works

Inside the bytecode β†’ WebAssembly JIT: the compile pipeline, the dispatch-loop control flow, the MacroAssembler-style emitter layer, and what it compiles.

πŸ“˜

Integration guide

How to embed this JVM in your own web app β€” load a bundle, boot it, compile source, wire a canvas for graphics/input, and add networking via the relay.

How it works. The page loads an ~8 MB wasm build of libjvm plus the JDK runtime data (~25 MB gzipped, decompressed in the browser). A service worker adds the cross-origin isolation headers that SharedArrayBuffer (wasm threads) needs, since GitHub Pages can't set them itself. First load fetches the runtime once, then it's cached.