This is an immersive long-form essay — best read in its dedicated layout → Open the full version
This is the seventh piece in the Field Note series, siblings to «How V8 makes JS fast» (multi-tier JIT) and «From Rust to SIMD» (WebAssembly). This one is the opposite — how a JIT-less JS engine ships full ES2023 in 70k lines of C, a 700 KB binary, and zero start-up cost. Source-level references track quickjs-ng main (compatible with Fabrice Bellard’s 2024-01-13 reference).
Five preparatory chapters + one through-line + fourteen pipeline stages + five synthesis chapters
We feed [1,2,3].map(x => x*2) to QuickJS and trace its byte stream end to end:
06 Lexer 07 Parser 08 AST→FuncDef 09 Bytecode
10 JSValue 11 Atom 12 Shape+Object 13 Closure 14 Class
15 Interp 16 Lookup 17 Promise/Gen 18 RegExp 19 GC
Every pipeline chapter carries a ”◇ In our JS line” input → output card anchoring its slice to the main line.
What this expansion adds
- Byte-level JSValue: 32-bit NaN-boxing vs 64-bit tagged, compared to V8’s Smi compression, JSC’s NaN-box, Hermes’s similar design.
- JSShape (hidden class): QuickJS has Shape but deliberately no inline caches — and that’s the core reason its hot path is 10-20× slower than V8.
- Interpreter main loop: 3000 lines of switch + computed goto with direct-threading tricks.
- Bytecode X-macros: one 250-opcode definition generating enum / dispatch table / metadata / emit helpers across 6 files.
- Closures: JSVarRef’s stack→heap transfer mechanism (borrowed from Lua’s upval).
- GC: refcount + trial-deletion cycle collection (same algorithm as Python / PHP).
- No JIT: four iron rules (single file, no JIT, refcount, no IC) make QuickJS 10-20× slower on hot paths but 30× faster startup, 20× smaller memory, 40× smaller binary.
- Embedding playbook: 30 lines of C to put JS into your project; JSRuntime vs JSContext realm model.
- Ecosystem map: QuickJS-ng / txiki.js / Just / early Cloudflare Workers / Android app scripting.
- Three-dimensional perf: across peak speed, startup, memory, QuickJS sits at the exact opposite corner from V8 / JSC / SpiderMonkey / Hermes.
Every chapter cites quickjs.c line ranges + key function names + key structs, plus the relevant ECMAScript spec § — so you can grep the source alongside this essay.
“In the world of JS engines, V8 will always be the F1 race car; QuickJS will always be the folding bicycle. The world needs both.”
Comments
0 comments