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. 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.
  2. 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.