Summary
Many Visit / VisitMut implementors only inspect runtime code, yet every impl monomorphizes the TypeScript type-grammar walk_* functions it can reach. Measurement shows this is ~23% of all visitor machinery bytes in oxlint. Proposal: an opt-out associated const on the traits (VISIT_TS_TYPES) that gates the default visit_* methods of pure type-space nodes. A working prototype cut 203 KiB off the oxlint binary with zero behavior change (all 1168 linter tests pass).
Measured baseline
Methodology: release profile exactly as shipped (fat LTO, codegen-units=1, panic=abort) with strip=none and -Csymbol-mangling-version=v0 so each monomorphization is attributable to its instantiating type; cargo-bloat --message-format json for bins, nm address-deltas + rustfilt for the napi cdylibs. arm64 macOS, rustc 1.96.1.
Visitor/traverse machinery as share of .text:
| artifact |
file / .text |
Visit |
VisitMut |
Traverse |
total |
oxlint |
17.5 / 11.8 MiB |
1.05 MiB (52 impls) |
130 KiB |
— (not linked) |
~10% |
oxc_transform_napi |
4.3 / 3.0 MiB |
269 KiB (14 impls) |
248 KiB (12 impls) |
393 KiB |
~30% |
oxc_minify_napi |
3.0 / 2.0 MiB |
135 KiB (5 impls) |
0 |
164 KiB |
~15% |
oxfmt |
8.3 / 5.6 MiB |
0 |
0 |
0 |
0% (dep present, no live impls — fully dead-stripped) |
Key facts:
- Marginal cost of one
Visit/VisitMut impl is ~10–27 KiB (LTO prunes unreachable walks; only walks reachable from the entry visit_* calls are instantiated). A full-surface visitor (SemanticBuilder) is ~68–80 KiB.
oxc_linter has 44 helper visitors ≈ 819 KiB — the largest visitor cost in oxlint.
- TS-grammar walks (
walk_ts_*) are 282 KiB = 23% of oxlint's visitor machinery, remarkably uniform: ~20–24% of every small helper visitor, 18% of SemanticBuilder.
- A
Traverse walk-tree instantiation is ~31–38 KiB; only 5 exist workspace-wide (TransformerImpl, ModuleRunnerTransform, InjectGlobalVariables, and the minifier fork's PeepholeOptimizations, Normalize) — the plugin-dispatch architecture is already good for binary size.
oxc_traverse's generated ancestor.rs (18.6k lines) is ~free in the binary (<1 KiB survives dead-stripping) — its cost is compile time, not size.
- In
oxc-transform, oxc_traverse and oxc_minifier's private traverse fork coexist; the duplicated ctx layer costs ~70–100 KiB.
Summary
Many
Visit/VisitMutimplementors only inspect runtime code, yet every impl monomorphizes the TypeScript type-grammarwalk_*functions it can reach. Measurement shows this is ~23% of all visitor machinery bytes inoxlint. Proposal: an opt-out associated const on the traits (VISIT_TS_TYPES) that gates the defaultvisit_*methods of pure type-space nodes. A working prototype cut 203 KiB off theoxlintbinary with zero behavior change (all 1168 linter tests pass).Measured baseline
Methodology: release profile exactly as shipped (fat LTO,
codegen-units=1,panic=abort) withstrip=noneand-Csymbol-mangling-version=v0so each monomorphization is attributable to its instantiating type;cargo-bloat --message-format jsonfor bins,nmaddress-deltas +rustfiltfor the napi cdylibs. arm64 macOS, rustc 1.96.1.Visitor/traverse machinery as share of
.text:oxlintoxc_transform_napioxc_minify_napioxfmtKey facts:
Visit/VisitMutimpl is ~10–27 KiB (LTO prunes unreachable walks; only walks reachable from the entryvisit_*calls are instantiated). A full-surface visitor (SemanticBuilder) is ~68–80 KiB.oxc_linterhas 44 helper visitors ≈ 819 KiB — the largest visitor cost in oxlint.walk_ts_*) are 282 KiB = 23% of oxlint's visitor machinery, remarkably uniform: ~20–24% of every small helper visitor, 18% ofSemanticBuilder.Traversewalk-tree instantiation is ~31–38 KiB; only 5 exist workspace-wide (TransformerImpl,ModuleRunnerTransform,InjectGlobalVariables, and the minifier fork'sPeepholeOptimizations,Normalize) — the plugin-dispatch architecture is already good for binary size.oxc_traverse's generatedancestor.rs(18.6k lines) is ~free in the binary (<1 KiB survives dead-stripping) — its cost is compile time, not size.oxc-transform,oxc_traverseandoxc_minifier's private traverse fork coexist; the duplicated ctx layer costs ~70–100 KiB.