Repository navigation
rc: a global object literal takes over what its fields were given (#461) - #470
Merged
Merged
Conversation
`let o = { s: mk() }` at module level was freed at start under rc (and own). The literal is built
in a temporary slot: the call's result is stored into its field, and the whole literal is read out
and given to ts.GlobalResult. The store took no reference, so the call's +1 was given back at the
end of the initializer region as a discarded temporary, and the global's field pointed at freed
memory. Inside a function the same literal survives only because the block it ends with is the
function's.
claimGlobalInitializers now follows a global's value read out of a literal's temporary slot (one
that owns nothing of its own) into the stores to that slot's fields: each owned producer stored
there, through the same views, is marked consumed, and a field that is itself such a literal is
followed into. The global then keeps each count.
Test: 00global_object_literal (compile and JIT, and in the rc/none corpus): a let and a const
literal global with class fields from calls, a nested literal, and a reassignment, read after
allocations of the same size have reused anything freed. It failed under rc before the change. The
#461 repro prints made1 under rc and own (it printed k15 and k31). The own corpus is unchanged.
Fixes #461.
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 #461.
Under rc and own, a module-level
let o = { s: mk() }was freed at start.The literal is built in a temporary slot:
ts.GlobalResult.The store in step 1 takes no reference, so the call's +1 was given back at the end of the initializer region as a discarded temporary, and the global's field pointed at freed memory. Inside a function the same literal survives only because the block it ends with is the function body itself.
claimGlobalInitializers(from #468) now follows a global's value, when it is read out of a literal's temporary slot that owns nothing itself, into the stores to that slot's fields:The global then keeps each count.
Tests
00global_object_literal.ts. It covers aletand aconstliteral global with class fields from calls, a nested literal, and a reassignment. Each field is read after allocations of the same size have reused anything freed. It is registered as compile and JIT tests and in the rc/none corpus, and it failed under rc before the change.made1under rc and own; it printedk15andk31before.test-compile-gc-defaultlib-collector, the known local LNK2005 against the stale installed default library, which fails on main the same way.🤖 Generated with Claude Code