A const record whose field is made for it has storage, as a let does (#485) - #490
Merged
Merged
Conversation
…485) A record literal with a field known only at run time is built in a temporary slot and read out whole, and the literal takes no count for what its fields are given: its receiver does, as a `let` does with RetainSlot. A `const` of it was folded into that read unless a field was read out of another object or an owning local (#454, #460), so for a field made for the literal nothing took a count and nothing gave one back: - an array or tuple built in the literal (`{ items: [i, 2], n: i }`), a constant array copied for it, or a new array, born with no count, was never freed under rc and own (AOT, 1M iterations: 96.5 MB, 4.4 with `let`); - under own, a string, a call's result or a new instance made for it leaked as well (35.2 MB for `{ s: "a" + i, n: i }`), and the call and the instance did not compile. Such a const now has storage. A value taken out of another record (`{ ...o }`, ts.ExtractProperty / ts.DeconstructTuple) stays with that record's count, as before, and a literal string is immortal. Under own, a record whose field is a tuple or record holding an array gives the compile error a `let` of it already gave, where it used to compile and leak. Closes #485 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.
Fixes #485: a
constrecord literal leaked what was made for its fields under rc and own.The bug
A record literal with a field known only at run time is built in a temporary slot and read out whole, and the literal takes no count for what its fields are given: its receiver does, as a
letdoes withRetainSlot. Aconstof it was folded into that read unless a field was read out of another object or an owning local (#454, #460), so for a field made for the literal nothing took a count and nothing gave one back.Peak memory, AOT (
measure.ps1), 1M iterations of a function holdingconst o = { <field>, n: i }and one other owning local:items: [i, 2](the issue)t: [i, [i]]items: new Numbers(n)inner: { items: [i, 2], k: i }s: "a" + iitems: mk(i)c: new C()(
let owas flat in every row.)The fix (MLIRGen,
readsLiteralSlot)A
constof such a record now has storage, as aletdoes, when a field owns a block and is made for the literal: an array or tuple built there, a constant array copied for it, a new array, a string, a call's result, a new instance. A value taken out of another record ({ ...o },ts.ExtractProperty/ts.DeconstructTuple) stays with that record's count, as before, and a literal string is immortal.Under own, a record whose field is a tuple or record holding an array (
{ t: [i, [i]], n: i }) now gives the compile error aletof it already gave on main ("an object literal that holds a value it owns is moved only into a local ..."), where it used to compile and leak.Tests
00const_record_owned_fields.ts(compile, JIT, rc and none corpora): each field kind above, read after heap churn.test-rc-const-record-release(const-record-release.cmake): no run sees a leak, so the IR is read - under rc each of that file's seven records has ats.ReleaseSlotof its tuple slot. Main fails it (arrayFielddoes not release its record's slot).Gates
ctest -C Release -j 12 --timeout 300, staged default library)--emit=llvm -mm=own --no-default-lib, every file oftest/tester/tests)--opt: 457 / 457). No file goes from ok to failing;00types,callWithSpreadandconditionalTypes2change only a generated name or a union's member order in their first errormeasure.ps1, AOT)own_fresh_string,own_return_new,own_try_local,own_fresh_array,own_literals,own_array_param_pushunchangedweakref_basic, gc-only by design (#420)Closes #485
🤖 Generated with Claude Code