No V8. No SpiderMonkey. No transpiler.
watjs is a JavaScript interpreter written by hand in WAT — the textual form of WebAssembly — and compiled to a single ~341 KB .wasm. It lexes, parses, and runs JavaScript entirely inside WebAssembly. The playground below is the real thing: your code is handed to the module and executed by roughly 30,000 lines of WAT.
watjs.wasm, hands it your source, and prints whatever that hand-written engine produced. Try the samples:// loading watjs.wasm…
A running .wasm module can't emit new WebAssembly at runtime — its functions are fixed at instantiation. So watjs can't JIT. Instead, "compiled" code is data in linear memory, interpreted by pre-compiled WAT handlers. Three ideas make it work:
The AST is lowered to threaded code — an array of function indices — dispatched through call_indirect. Pre-compiled WAT handlers do the work. Real JIT-to-wasm is off the table by design.
Every JS value is a single 64-bit slot. Any non-NaN f64 is a number; a quiet-NaN prefix + 3-bit tag + 48-bit payload encodes null, bool, string, object, symbol — the rest.
An earlier tree-walker was retired for a single bytecode VM. Because its stack is savable, execution can suspend and resume — which is exactly what generators and async/await need.
watjs runs the official tc39 / test262 conformance harness and passes the majority of the core-language and built-ins suites. It's a real, spec-tracking subset — not a weekend parser.
It's all there — the engine in WATX, the design notes, and a live status dashboard tracking the test262 climb.