Repository navigation
Cheaper checks for unproven typed-array and string indexes - #842
Merged
Merged
Conversation
A typed-array, inline ASCII charCodeAt, local array, constant-table or number-map read whose index is not a proven integer decided validity with two float compares against the converted length, then an fptoui/uitofp round trip. On x86-64 both unsigned conversions expand to long sequences, and the tsc-ts scanner pays them on every character it reads by position. exactIndexLines replaces them with fptosi, freeze, sitofp, one float equality and one unsigned integer compare against the length. A frozen out-of-range or NaN conversion is an arbitrary integer that never converts back to the index or is not below the length; below the length the round trip is exact, and -0 converts to 0 like ToPropertyKey(-0).
The hint is ToUint32 of the value, and ToUint32(NaN) is 0, so a read whose index may be invalid keeps it (the invalid arm already contributed 0); it was dropped unless the index was proven in bounds. Worker programs also dropped it at the join with the shared-buffer path, which now converts its integer result exactly. `hash ^ chars[i]` and similar operators then use the loaded integer instead of re-deriving ToInt32 from the double.
A reference field that only its class family's constructors write, through their own `this`, never changes outside them. While its object is held, the field's value is held too, so `this.scanner.scan()` and `const units = this.units` need no retain and release (and no collector buffering on the release). analyzeFinalFields finds such fields over the whole program. It looks through the derived constructor's guards on `this`, and disqualifies fields that live dynamic views can store into (the detection int32 slots already uses, now shared as dynamicFieldStores), fields of runtime-provided or generic classes, and every field in library builds. canBorrowCallArgument accepts a final field of a borrowable object, except in constructors, async functions and generators, and except for nullable-pointer fields, which have no box to lend.
`for (let i = start; i < end; i++)` kept a double counter when the start had no proven integer range, as in a hash over `[start, end)` whose bounds come from fields. Such a loop is now versioned like one with an unproven limit: when the start is an exact integer of at most 2^53 - 1 in magnitude (compared bit for bit, so -0 takes the original loop), the integer-counter copy runs. The usual bounds on duplicated bodies apply.
`const DOT = 0x2e` at module scope was a global that every reader loaded (a thread-local load in worker programs), hiding the value from integer ranges, switch dispatch and LLVM. foldConstantGlobals rewrites reads of an immutable number or boolean global that the program writes exactly once, with a literal, and that has neither a TDZ sentinel nor an initialization flag (globals that can be read early keep their checked load). The store stays, so namespace objects still find the value. Library builds keep their globals.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Borrow final reference fields without a retain
Run counted loops from an unproven start as integer loops
cramforce
force-pushed
the
perf/alloc-hugepages
branch
from
October 11, 2026 03:40
3afea88 to
9cdaa5b
Compare
cramforce
force-pushed
the
perf/exact-index-checks
branch
from
October 11, 2026 03:41
4ff3a74 to
c7e7d7d
Compare
cramforce
force-pushed
the
perf/alloc-hugepages
branch
from
October 11, 2026 03:44
9cdaa5b to
3afea88
Compare
cramforce
force-pushed
the
perf/exact-index-checks
branch
from
October 11, 2026 03:45
c7e7d7d to
4ff3a74
Compare
Conflicts, all resolved to this branch's side: - emitter.ts (numeric-table get, map index probe), expr-bytes.ts, local-array-reads.ts, string-reads.ts: the base only respelled the size-to-double conversions in the old range checks (uitofp nneg, now sitofp); exactIndexLines replaces those checks entirely. The base's other hunks in these files (host inline truncation, the remaining sitofp conversions) merge as they are. - int32-slots.ts: #837 and #843 both extracted dynamicFieldStores with identical bodies; keep this branch's signature, whose optional records/unions maps also serve #837's single-argument callers.
…inal-field-borrows
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A typed-array, inline ASCII
charCodeAt, local array, constant-table or number-map read whose index is not a proven integer checked validity with two float compares against the converted length, then anfptoui/uitofpround trip. On x86-64 both unsigned conversions expand to long instruction sequences, and the tsc-ts scanner pays them on every character it reads by position.exactIndexLinesemitsfptosi,freeze,sitofp, one float equality and one unsigned integer compare against the length. A frozen out-of-range or NaN conversion is an arbitrary integer that either doesn't convert back to the index or isn't below the length. Below the length the round trip is exact.-0converts to 0, likeToPropertyKey(-0).hash ^ chars[i]then uses the loaded integer instead of re-deriving ToInt32 from the double.tsc-ts parse-only CPU: Excalidraw −7.6%, self-check −4.6%, tRPC −2.5%, TypeORM −2.3%. tsc-ts binary −0.23%.
New corpus program
exact-index-round-trip.ts: fractional, negative, −0, NaN, ±Infinity, 2^31/2^32/2^53/2^63/2^64 and 1e300 indexes through typed-array reads (u8/u16/i32), inlinecharCodeAton ASCII and non-ASCII strings, local arrays with holes, numeric-keyed maps, and ToInt32/ToUint32 of missing reads.First of four stacked on #830 (parser hot paths).