@@ -11,26 +11,38 @@ defer, with the trigger that should reopen each.
1111
1212### Protocol dispatch bundle cost
1313
14- The protocol layer (0.14.203) made the common core fns reference their protocol
15- slot to dispatch to custom types: ` assoc ` names ` IAssociative__assoc ` , ` conj `
14+ Protocol dispatch arrived in two waves, both pinning machinery into plain-data
15+ bundles.
16+
17+ Wave 1, atoms (0.14.201): ` IReset ` /` ISwap ` /` IWatchable ` /` IAtom ` /` IDeref ` were
18+ added to ` atom ` /` swap! ` /` reset! ` /` deref ` /` add-watch ` . An app using plain atoms
19+ (` swap! ` , ` add-watch ` , no custom ` IAtom ` type) pins the lot.
20+
21+ Wave 2, collections (0.14.203-205): ` assoc ` names ` IAssociative__assoc ` , ` conj `
1622names ` ICollection__conj ` , ` get ` names ` ILookup__lookup ` , ` = ` names
17- ` IEquiv__equiv ` , and so on. ADR 0006 and ` symbol-pure-dce ` shake out the slots an
18- app does not use. But a broad app uses ` assoc ` and ` conj ` and ` count ` and ` get `
19- and ` = ` together, so the union of its fns references the whole slot set, plus
20- ` INSTANCE_TYPE ` . That block is then pinned into the bundle.
23+ ` IEquiv__equiv ` , plus ` INSTANCE_TYPE ` . A broad app uses these together and pins
24+ the whole set. ADR 0006 and ` symbol-pure-dce ` shake out slots an app does not
25+ use; the union a real app references survives.
2126
22- Measured on the js-framework-benchmark reagami app (same compiled app, only the
23- runtime core.js swapped):
27+ Measured with the js-framework-benchmark reagami app, a clean official
28+ ` build-prod ` per squint version (compiled and bundled entirely on each version,
29+ gzipped):
2430
25- | runtime | raw (min) | gzip |
31+ | squint | gzip | note |
2632| ---| ---| ---|
27- | main | 25973 | 9197 |
28- | 0.14.202 (pre-protocol) | 24136 | 8659 |
29- | delta | +1837 | ** +538** |
30-
31- reagami and the demo define no ` deftype ` /` defrecord ` /` extend-type ` , so for them
32- the whole block is dead weight: it dispatches to custom impls that do not exist.
33- This is true of most plain-data apps.
33+ | 0.14.197 | 7517 | before both waves |
34+ | 0.14.200 | 7705 | before atoms |
35+ | 0.14.201 | 8644 | +939, atom protocols |
36+ | 0.14.202 | 8648 | before collections |
37+ | 0.14.205 | 9520 | collection protocols, unfixed |
38+ | 0.14.206 | 9190 | collections, after symbol-pure-dce + plain-data (-330 vs 205) |
39+
40+ Net, about 1.5 KB of the 9.0 KB shipping app (~ 17%) is protocol dispatch
41+ machinery: ~ +939 atoms plus ~ +542 collections. reagami and the demo define no
42+ ` deftype ` /` defrecord ` /` extend-type ` , so all of it is dead weight - it dispatches
43+ to custom impls that do not exist. (An earlier note swapped only the runtime
44+ core.js and reported +538; that captured the collection wave alone, undercounting
45+ the total by ~ 3x.)
3446
3547The fix is to invert the dispatch, like CLJS: base fns handle only native types
3648(Object/Array/primitive/Map/Set) and name no protocol slot; ` extend-type ` and
@@ -59,10 +71,11 @@ doc/ai/ideas.md "Emit direct fixed-arity calls" idea.
5971
6072Defer both. Ship neither fix now.
6173
62- - The protocol bundle cost is ~ 1/2 KB gzip per broad plain-data app. Recovering
63- it means reworking the protocol system that landed weeks ago, with regression
64- risk to records, transients and ` extend-type ` . The trade does not clear the bar
65- today.
74+ - The protocol bundle cost is ~ 1.5 KB gzip (~ 17% of the shipping app), in two
75+ waves. At that size the win clearly justifies the work; what defers it is
76+ risk, not payoff. Recovering it means reworking the protocol system that
77+ landed weeks ago, with regression risk to records, transients and
78+ ` extend-type ` . Do it once that code has settled, not against fresh code.
6679- The variadic runtime patch was tried in #961 and dropped: a 2-arg ` min ` /` max `
6780 arity that node cannot show a win for and that Chrome does not benefit from. The
6881 real fix is the compiler-level per-arity emission, which is larger.
@@ -72,15 +85,16 @@ Defer both. Ship neither fix now.
7285- ` bb test:size ` runs in CI (this ADR's companion change), so the protocol cost
7386 is visible per commit and a regression past the threshold fails the build.
7487- reagami sidesteps the ` min ` cost with ` js/Math.min ` and does not depend on
75- either fix. It stays current with squint and pays the ~ 1/2 KB, still the
88+ either fix. It stays current with squint and pays the ~ 1.5 KB, still the
7689 smallest app in the benchmark table.
7790- Both fixes remain open, documented with measurements, ready to execute.
7891
7992## When to revisit
8093
81- - Protocol bundle cost: when ` test:size ` shows the tax crossing a threshold that
82- matters, or a size-sensitive consumer is blocked by it - by then the protocol
83- code is battle-tested and the inversion is far less risky than doing it now
84- against fresh code.
94+ - Protocol bundle cost: the ~ 17% is already a size that matters, so the gate is
95+ not the payoff but the protocol code settling. Revisit once records,
96+ transients and ` extend-type ` have proven stable in the wild, or sooner if a
97+ size-sensitive consumer is blocked. ` test:size ` keeps the number honest
98+ meanwhile.
8599- Variadic call cost: alongside the fixed-arity codegen work in doc/ai/ideas.md,
86100 which supersedes the reverted runtime patch.
0 commit comments