mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-21 05:50:55 +08:00
A typed-array element read answers undefined for an index outside [0, length), so the default lowering returns a heap-boxed `number | undefined` and widens every binding, parameter and return the read reaches. In the tsc-ts scanner that boxed every character read and turned every character predicate (isLineBreak, isIdentifierPart, ...) into a function taking a boxed union. Most consumers cannot tell undefined from NaN: relational, arithmetic and bitwise operators, truthiness, Math functions, String.fromCharCode, typed-array indexing, switch over number cases, and equality with a number that is never undefined. The new analysis (nan-coded-reads.ts) follows reads through local bindings, parameters of directly called functions and methods (no overrides, no value uses), and their returns. A slot is NaN-coded when every value it receives is a NaN-coded read or slot, or any other number (converted with ToNumber on entry), and either: - it never holds a genuine NaN (integer elements, integer constants, guarded integer arithmetic), so NaN stands for undefined exactly; any consumer that takes the value whole (an argument, a stored or returned value, a literal element, concatenation) gets the exact `number | undefined` rebuilt, and the optional-read analysis treats that occurrence as optional, so it lowers as before; or - every consumer is NaN-insensitive. Equality of two NaN-coded values that never hold a genuine NaN also answers true for two NaNs, as undefined === undefined does. Any other slot keeps the established union lowering; asserted reads (`t[i]!`) are unchanged. tsc-ts best-v1 (scriptc main + this commit vs main, Linux sandbox, Xeon 2.5 GHz, interleaved, medians of 5, diagnostics identical): | app | parse | total (single-threaded) | wall --checkers 8 | | --- | --- | --- | --- | | tRPC | 1.263 -> 0.866 s (-31.4%) | 3.035 -> 2.527 s (-16.7%) | -13.0% | | Excalidraw | 2.637 -> 1.865 s (-29.3%) | 14.99 -> 14.04 s (-6.3%) | -16.2% | | Playwright | 3.150 -> 2.202 s (-30.1%) | 12.93 -> 12.14 s (-6.1%) | -12.4% | | TypeORM | 2.562 -> 2.036 s (-20.5%) | 10.93 -> 10.46 s (-4.3%) | -8.6% | | self-check | 2.080 -> 1.529 s (-26.5%) | 7.06 -> 6.68 s (-5.4%) | -15.1% | The tsc-ts IR has 646 instead of 697 scr_union_new_f64 sites (the rest are cold), 22 instead of 168 typed-read helper calls, and 217 instead of 572 scr_union_get_f64 calls; the scanner's hot functions allocate no union boxes. Binary size -0.2%.