Step 1 — Inline Caches and the Megamorphic Cliff
Goal
Measure the IC penalty, and discover that its shape (a cliff, then flat) matters more than its size.
Predict first
One access site, objs[i % n].v, reading from n objects with n distinct hidden classes.
Predict the slowdown versus n = 1 for n = 2, 4, 8, 16.
Most people predict a smooth curve. Commit to four numbers.
Run
cd src && npm install && npm run ic
Expected output:
distinct shapes | IC state | median ms | ns/read | vs monomorphic
1 | monomorphic | 5.30 | 1.767 | 1.00x
2 | polymorphic | 5.30 | 1.767 | 1.00x
4 | polymorphic | 6.50 | 2.167 | 1.23x
8 | megamorphic | 10.40 | 3.467 | 1.96x
16 | megamorphic | 10.30 | 3.433 | 1.94x
What just happened
An inline cache records, per access site, which shapes have been seen and where the property lives.
- 1 shape — direct offset load.
- 2–4 shapes — a short linear check. Measured: free at 2, 1.23× at 4.
- 5+ shapes — the site gives up and falls back to the global stub cache: a hash lookup.
Two consequences that change what you would do:
- 1 → 4 shapes is nearly free. Refactoring to make a site strictly monomorphic is usually not worth it. A lot of advice implicitly assumes the curve is linear from 1.
- 8 → 16 costs nothing further. Once megamorphic, reducing shape variety buys nothing unless you get back under the threshold — which heterogeneous data rarely allows. "We reduced our shapes from 40 to 12" is a change with no effect.
So the only actionable form is: avoid crossing the cliff in genuinely hot code. Everywhere else, note the absolute number — 1.7 ns — and go to Step 4.
Checkpoint
docs/verification.md Checkpoint 1.