Repository navigation
Conversation
…y fields Two uses of the construction-only facts outside the collector (backend/immutability.ts): - Publication guards: a store into the constructor's own `this` that lies before the constructor's escape point, in a constructor no ancestor of which lets `this` escape and that is never invoked directly on an existing object, cannot target a published object. It loses its rc == SIZE_MAX guard and no longer seeds may-throw, so constructors that could only throw through guards lose their pending checks at every `new`. Storing `this` into one of its own fields does not expose it. - Borrowed reads: `x.f` holding an object, record, array or string is borrowed as a call argument, receiver or stable alias when `f` is construction-only and `x` is itself borrowable (unchanged local, borrowed parameter, or such a projection): nothing can replace and release it while `x` lives. Not inside constructors, which may still write their own fields. Module constants (immutable, not TDZ-checked, assigned at most once) are borrowable too. No object is frozen or marked at run time; publication errors, store order and reflection are unchanged. tsc-ts (e469e33), static: published-field guards 6,528 -> 4,462, sc_release calls 146,056 -> 129,756, sc_retain calls 26,215 -> 22,123, scr_arr_release 29,865 -> 25,617, binary 23.68 -> 22.96 MB (both commits). Self-check single-threaded, executed: guards 96.1M -> 60.8M, retains 273.5M -> 247.2M, releases 340.3M -> 314.0M. Linux sandbox, interleaved medians, both commits against perf/alloc-hugepages: single-threaded (6 runs) base new change Excalidraw 8.62 s 8.34 s -3.2% Playwright 7.83 s 7.71 s -1.5% tsc-ts self-check 4.36 s 4.22 s -3.0% tRPC 1.63 s 1.58 s -3.1% TypeORM 6.68 s 6.50 s -2.5% --checkers 8 (10 runs): -2.3% .. +0.7% (neutral) Runtime suite (--layouts=4 --runs=16): geomean -1.9%; ast-interp -4.4%, validate-errors -3.8%, regex-logs -1.7% faster, template-render +1.4% slower, the rest neutral; sizes unchanged.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
cramforce
force-pushed
the
perf/trace-cycle-candidates
branch
from
October 11, 2026 03:40
44f4d0b to
095fdca
Compare
cramforce
force-pushed
the
perf/static-immutability
branch
from
October 11, 2026 03:41
6ddaa2a to
2ae8459
Compare
cramforce
force-pushed
the
perf/trace-cycle-candidates
branch
from
October 11, 2026 03:45
095fdca to
44f4d0b
Compare
cramforce
force-pushed
the
perf/static-immutability
branch
from
October 11, 2026 03:45
2ae8459 to
6ddaa2a
Compare
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.
Two uses of the construction-only facts outside the collector, in
backend/immutability.ts:thisthat is not yet observable cannot target a published object. The conditions: the store comes before the constructor's escape point, no ancestor constructor escapes, and the constructor is never invoked directly on an existing object. Such a store loses itsrc == SIZE_MAXguard. It also stops seeding may-throw, so constructors that could only throw through guards lose their pending checks at everynew.x.f(an object, record, array or string) is borrowed as a call argument, receiver or stable alias whenfis construction-only andxis itself borrowable. Nothing can replace and release it whilexlives. This does not apply inside constructors. Module constants (immutable, not TDZ-checked, assigned at most once) are borrowable too.Nothing is frozen or marked at run time.
Object.isFrozen, publication errors and store order are unchanged.Measured on tsc-ts, both PRs against #830, Linux sandbox, interleaved medians:
Static counts: published-field guards 6,528 → 4,462,
sc_releasecalls −11%,sc_retaincalls −16%. Binary 23.68 → 22.96 MB.Executed on the self-check: guards 96.1M → 60.8M, retains −9.6%, releases −7.7%.
Removing every publication guard (unsound, measurement only) stays within noise, so the time comes from borrowing and tracing, not from the guards.
Runtime suite (
--layouts=4 --runs=16): geomean −1.9%. ast-interp −4.4%, validate-errors −3.8% and regex-logs −1.7% are faster. template-render is +1.4% slower. The rest are neutral, and sizes are unchanged.Tests: new
immutability.test.tsunit tests, and an adjustedstring-lifetimestest (its record field was never written, so the borrow is sound; the test now adds a writer to keep covering the snapshot path). New corpus programs:4598-publish-constructor-stores: escaping constructors must still throw Node's frozen-object errors.4599-construction-only-field-borrows: callees drop every other reference before using a borrowed field; a field written by a method; a constructor reading its own field while a later operand replaces it.4600-construction-only-fields-dynamic-writes: writes throughanyand structural casts while the field is being read.All pass the plain and sanitized lanes. Preflight/order baselines are recorded for the five new fixtures.
Known risk: borrowed field reads rely on every field write being visible in the IR or in the untyped-store audit; a runtime helper writing class fields directly would become a use-after-free. Stacked on the cycle-tracing PR.