rc: a getter read is settled like a call - #408
Merged
Merged
Conversation
A getter retains what it returns, as every function does (§9.24), but OwnedReturnConsumptionPass only looked at ts.CallIndirect. A getter read is one of the accessor ops (ts.Accessor, ThisAccessor, ThisIndirect*, BoundIndirect*) until the affine lowering turns it into a call, so its +1 was never taken over or given back: `h.cc.x` leaked the C, and `let b = h.cc` retained a second time. own_getter_borrow read 12.6 MB under rc; it now reads 4.8 MB, as gc's 6.5 and own's 4.8 do. The accessor ops are classified as calls are - the getter named outright, every method of that member name for a virtual slot, the vtables for an interface slot, or the whole-module answer - and then marked, consumed by their receiver, or released at the end of the block. A getter read with no live use is left alone: an assignment through an accessor builds a read before rebuilding the op as a setter, and a release would keep that read, a call the program never made. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Under
-mm=rc, a value read through a getter was never released. The first leftover from phase 4 (spec §15.3).Cause
A getter retains its result, as every function does (+1 convention, §9.24).
OwnedReturnConsumptionPasssettles who owns that reference, but it only looked atts.CallIndirect. A getter read stays an accessor op (ts.Accessor,ThisAccessor,ThisIndirect*,BoundIndirect*) until the affine lowering turns it into a call. So:h.cc.xkept the getter's reference, and nothing gave it back.let b = h.ccretained it a second time.Fix
Accessor reads are classified the way calls are:
Each classified read is then marked, taken over by its receiver, or released at the end of its block.
A getter read with no live use is skipped. Assigning through an accessor first builds a getter read, then rebuilds the op as a setter and leaves the read for the canonicalizer to delete. A release would keep that read alive, which would add a getter call the program never made.
Measured (AOT,
measure.ps1, MB)own_getter_borrowh.cc.xin a loopTests
New
own/rc_getter_temporary.ts, JIT + AOT under rc, gc and none. It covers:super;let, passed to a call, and assigned through.Each read comes after a
churn(), so a block freed too early would be reused.Windows Release: 3235/3235.
Linux (WSL): 3222/3222.
-mm=owncorpus: unchanged at 303 compiling files.Independent of #407. Both edit
interfaceCallReturnsOwned, so whichever lands second needs a small rebase.🤖 Generated with Claude Code