Commit 2ddbc7b
* gc: close the strhandle, derived-mask and new.target unrooted hazards (#7664)
`gc-root-dominance-statepoints`' `--max-unrooted` ratchet goes 21 -> 7.
#7663 pointed the root-dominance rule at the NATIVE root lowering -- the one
that ships since #7370 -- and reported 21 `unrooted` hazards. Fourteen were
shapes `root_reload.rs` looked straight through, because its rule is stated
over the load's own register and in both shapes the value at risk lives
somewhere else.
1. The root is a GLOBAL, not an alloca (10 hits). A string literal lowers to
`load double, ptr @<mod>_.str.N.handle`; the handle global is a registered
root, so the string is never swept, and an evacuating cycle REWRITES the
global while a register loaded beforehand keeps the pre-move address.
#7240's shape, whose fix covered call operands only.
2. The stale register is DERIVED from the load (3 of 7 unmasked receivers).
`this.count++` holds the unmasked receiver across the property GET; the
load's only use is the bitcast ABOVE the collecting call, so the window
was empty and the function took zero reloads.
3. `new.target`'s saved previous value (1 hit). `new.rs` saved
`js_new_target_get()` in a bare register across the whole constructor
body; the cell is a registered mutable root, so the restore publishes a
pre-move address back INTO a root the collector scans. #7226's
`prev_this` bug for `new.target`.
The window is anchored at the ROOT LOAD, not at the derived value. Anchoring at
the derivation looks more precise and is wrong: `main`'s class-object read has
the scope-end shadow-slot clear landing between the load and the mask, so a walk
starting at the mask never sees it and re-read a slot the program had just
nulled -- `(makeAnon(77) as any).v` became `undefined`. Caught by an A/B against
the branch point on `test_gap_class_expr_identity`, not by the dominance
checker, which cannot see a value-correctness bug.
The reload rule is restated over the value's derivation rather than its
register: for a value read out of a collector-rewritten location -- a shadow
slot or a string-handle global -- and any value derived from it by pure bit
ops, every use a collection point can reach re-materialises the whole
derivation. A recipe is extended only through ops that are pure functions of
their operands and whose every register operand is already in the same single
root's recipe, which makes it self-contained and materialisable anywhere.
Grouping by root load also puts the cost back at O(blocks x loads).
`new.target` gets `new_target_save`/`new_target_restore` in `crate::rooting`,
structurally `implicit_this_save`/`implicit_this_restore`. Re-reading the cell
would be the wrong repair: `js_new_target_set` has already overwritten it.
Measured on `Counter__increment`: before, all three statepoints carried an
EMPTY live set, so the receiver was marked by nothing; after, each carries a
"gc-live" bundle and a `gc.relocate`, and the SET reads a mask re-derived from
the relocated pointer plus a fresh load of the handle global.
Remaining 7, each its own slice: 4 unmasked are phi-mediated (the reload has to
go in the predecessor, on the edge); 2 `@perry_global_*` are module-level
variables the program assigns, so they need rooting rather than reloading
(pinned by `a_module_global_is_not_a_reload_source`); 1 capture read. #7664
stays open as the budget's referent.
Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
* chore: bump version to 0.5.1382
Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
---------
Co-authored-by: Ralph Küpper <ralph@skelpo.com>
1 parent db4a2d0 commit 2ddbc7b
9 files changed
Lines changed: 953 additions & 177 deletions
File tree
- .github/workflows
- changelog.d
- crates/perry-codegen/src
- lower_call
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
464 | 464 | | |
465 | 465 | | |
466 | 466 | | |
467 | | - | |
468 | | - | |
469 | | - | |
470 | | - | |
471 | | - | |
472 | | - | |
473 | | - | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
474 | 474 | | |
475 | | - | |
476 | | - | |
477 | | - | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
478 | 496 | | |
479 | 497 | | |
480 | 498 | | |
| |||
494 | 512 | | |
495 | 513 | | |
496 | 514 | | |
497 | | - | |
| 515 | + | |
498 | 516 | | |
499 | 517 | | |
500 | 518 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
0 commit comments