Skip to content

Borrow the bound receiver of optional chains - #840

Open
cramforce wants to merge 3 commits into
perf/length-to-double-nnegfrom
perf/borrow-optional-chain-receivers
Open

cramforce wants to merge 3 commits into
perf/length-to-double-nnegfrom
perf/borrow-optional-chain-receivers

Conversation

@cramforce

Copy link
Copy Markdown
Contributor

An optional chain such as resolved.members?.get(name) took three references to its receiver: the owned receiver value, a +1 extraction into the chain's bind slot, and a +1 copy for every use of the bound receiver, each released out of line. The bind slot now borrows the payload whenever another owner outlives the body (the statement frame owns the receiver value), uses of the bound receiver are borrowable receivers and call arguments, and a receiver projected from a borrowable owner is not retained at all when the body preserves reference edges. Stack receivers, multi-arm unions and bodies that may remove an edge keep the owned forms. Corpus 4620 pins chains whose body clears or replaces the receiver's field, drops the last other reference, nested and missing links, call and element receivers, self-clearing optional calls, and values that outlive later stores; ignoring the body check makes it fail under ASan.

Second of three; stacked on the length conversion PR.

An optional chain such as `resolved.members?.get(name)` took three references to its receiver: the owned receiver value, a +1 extraction into the bind slot, and a +1 copy for every chainRecv use, each released out of line (scr_map_release for maps). Now the bind slot borrows the payload whenever another owner outlives the body (the statement frame owns the receiver value), chainRecv reads are borrowable receivers and call arguments, and a receiver projected from a borrowable owner is not retained at all when the body preserves reference edges. Optional chains and chain receivers count as edge-preserving themselves; their children decide. Stack receivers, multi-arm unions and bodies that may remove an edge keep the owned forms.

Corpus 4620 covers chains whose body clears or replaces the receiver field, drops the last other reference, nested and missing links, call and element receivers, self-clearing optional calls, and values that outlive later stores; a mutation that ignores the body check is caught by ASan (heap-use-after-free).
…eserving

A function is edge-preserving when it cannot remove a reference edge; callers then pass field projections borrowed. tsc-ts lost the property for its whole type-ordering family because compareTypeLists reads a module binding behind an import-cycle TDZ check (module.tdzCheck), and for compareSymbols because getSymbolId bumps a shared id counter with Atomics.add (atomics.op). Fresh array literals without spreads and the array operations that only read, copy into a fresh array or append (push and pushSpread retain the new element; moving the slot storage releases nothing) were rejected too. All of these may allocate or throw, which the summary already allows. Removals (pop, shift, splice), truncation, overwrites and Atomics.wait keep the conservative answer.

compareTypes now passes its field arguments borrowed: 42 retains and 118 releases in its body become 4 and 4, and compareSymbols, compareTypeNames and binarySearchTypes need none. Corpus 4621 covers a comparator behind a real import-cycle TDZ error, an atomic id counter, appends that move the storage of the array owning a borrowed argument, loop bindings over appending and draining calls, and callees that shift or truncate the owning array.
@vercel

vercel Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
scriptc Ready Ready Preview, v0 Oct 11, 2026 3:41am UTC

Count module TDZ checks, atomic counters and array appends as edge-preserving

This branch was successfully deployed

1 active (outdated) deployment
Preview — 11359602 Deployed Oct 11, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants