Repository navigation
Commit 5e5e6c8
committed
Introduce NightMonkey: an ahead-of-time JS-to-Wasm compiler.
**NightMonkey** is an ahead-of-time JS-to-Wasm compilation tier built
inside SpiderMonkey. NIGHT expands to *Nonlocal Inference with Guiding
Heuristics for Types*: an optimistic whole-program type analysis guides
code generation, with dynamic guards for correctness. (The night monkey,
genus *Aotus*, is the only truly nocturnal monkey: it does its work in
the night, before the program runs during the day.)
Each JS function's bytecode is compiled to a WebAssembly function that
runs alongside the runtime compiled to Wasm. There are two modes of use:
- **Snapshot** (the shipping flow): the `nightmonkey` host binary drives
Wizer in-process to snapshot the runtime plus loaded user program (or
processes an existing Wizer snapshot), reads out JS bytecode and heap
objects (such as prototype objects), and rewrites that snapshot with
compiled bodies.
- **In-process** (the testing flow): the JS shell compiled to Wasm runs
under `wasm-jit-runner`, walks its own live heap, compiles the script
tree, and injects the bodies into its running instance via runner
hostcalls (`--night-inprocess`). A drop-in shell for jit-tests.
NightMonkey has a two-part structure: an *optimistic static type
analysis* and a *guard-based codegen backend*. The idea is that we:
1. "Predict" types statically, using a model of JavaScript semantics
that is intentionally optimistic (elides corner-cases). We call this
the "likelier-types analysis" (in a nod to the initial version of the
analysis, the "likely-types analysis"; this one is a little better).
2. Generate an optimistic Wasm body for a given JS function bytecode
body, using those predicted types.
3. Insert dynamic guards checking those assumptions, with fallbacks to a
fully generic (but still compiled!) Wasm body.
The *key constraint* that NightMonkey adheres to, and attempts to solve:
we cannot derive type information, or any other profiling information,
by observing a running program. In other words, unlike the standard JIT
approach based on the "JIT hypothesis" (that a warmed-up program will
reach a steady state with stable types, which we can then specialize
for), we must decide any specialization we will do ahead-of-time, based
on whatever analysis or heuristics we can come up with. The thing we
permit ourselves in return is much more analysis time: unlike a JIT
engine, we do not need to compile in milliseconds.
NightMonkey performs its analysis using a whole-program, call-sensitive,
points-to (heap abstraction) + callgraph analysis, over a lattice that
is a hybrid of a Steensgaard (union-find-based) and capped Andersen
(points-to-set/membership-based) design.
The codegen using the types that come out of this analysis is then a
"two-track" approach: there is one optimistic track that adheres to
"type contexts" that are maximally optimal, and one fully generic track.
(Earlier experiments tried to do more multiversioning, a la Static Basic
Block Versioning, but that did not converge well.)
As of 2026-09-04, comparing to native IonMonkey and baseline tiers, and
against Wasm-hosted interpreter and weval+PBL execution:
```plain
bench native-ion nat-baseline wasm-interp weval aot aot/wasm-int aot/weval weval/wasm-int ion/weval ion/aot baseline/aot
richards 29205 6489 377 936 11893 31.55 12.71 2.48 31.20 2.46 0.55
deltablue 28179 6870 395 978 6678 16.91 6.83 2.48 28.81 4.22 1.03
crypto 42755 5654 714 949 15696 21.98 16.54 1.33 45.05 2.72 0.36
raytrace 58549 11458 1045 1815 11964 11.45 6.59 1.74 32.26 4.89 0.96
earley-boyer 83262 21153 1510 3982 15088 9.99 3.79 2.64 20.91 5.52 1.40
navier-stokes 43926 8269 1223 2090 24980 20.43 11.95 1.71 21.02 1.76 0.33
splay 29291 23303 5248 6853 10693 2.04 1.56 1.31 4.27 2.74 2.18
regexp 18601 7223 596 766 2484 4.17 3.24 1.29 24.28 7.49 2.91
pdfjs 95804 40738 4116 6185 24743 6.01 4.00 1.50 15.49 3.87 1.65
mandreel 73940 11619 865 1269 19545 22.60 15.40 1.47 58.27 3.78 0.59
code-load 70224 69259 37108 37005 37271 1.00 1.01 1.00 1.90 1.88 1.86
box2d 99321 22370 1896 4135 25999 13.71 6.29 2.18 24.02 3.82 0.86
react-bench 0.631 1.415 15.026 10.421 2.862 5.25 3.64 1.44 16.52 4.54 2.02
geomean 49233 14111 1527 2569 14247 8.93 5.37 1.66 18.94 3.53 1.05
(octane = Score higher-better; react-bench = ms/render lower-better; best-of-3, taskset -c 1)
(ratio cols = speedup of A over B, direction-corrected for react-bench;
geomean row: lane cols over octane scores only, ratio cols over all benches)
```
We can conclude that NightMonkey is ~9x faster than the Wasm interpreter on
average, or ~5x faster than weval+PBL. It is nearly on par with the native
baseline compiler, and within ~3.5x of the IonMonkey optimized native-code
ceiling (while running within a Wasm engine). On benchmarks where type-based
specialization works especially well, NightMonkey comes within ~2.5x (e.g.
Richards) of native Ion.
This work has been done over the past ~6 months with the use of
LLM-assisted code generation (mainly Claude Opus and Fable) but with
careful line-by-line review and obsessive review of analysis results and
generated code. I've read through the whole implementation, checked it
to the best of my ability and will continue to do so. It is "a lot" but
it does pass jit-tests cleanly. This commit message and the README are
fully human-authored.1 parent b8f4a57 commit 5e5e6c8
201 files changed
Lines changed: 98053 additions & 1 deletion
File tree
- .github/workflows
- compiler
- src
- likelier
- source
- wasm
- bbv
- configs
- docs
- guest
- src
- nightmonkey
- src
- runtime
- scripts
- shell
- snapshot
- src
- spidermonkey
- tests
- jit-test/night
- third_party/wizer
- tools
- codesize
- wasm-jit-runner
- guest
- example
- src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
0 commit comments