@@ -49,17 +49,27 @@ outstanding record at O(1) without enumerating arrays. Arrays built outside
4949the funnels (inline literals, ` JSON.parse ` , ` map ` ) re-earn the proof through
5050` ensure_element_shape ` , a rescan that mirrors ` ensure_array_numeric_raw_f64 ` .
5151
52- Two counters, both ` AtomicU64 ` starting at 1 like ` PROP_PLAN_EPOCH ` :
52+ Three ` AtomicU64 ` counters, all starting at 1 like ` PROP_PLAN_EPOCH ` .
5353` js_array_element_shape_epoch() ` advances on every clear anywhere and is the
54- one-load word a hoisted guard re-reads without rescanning, while the
55- per-array ` epoch ` in the record distinguishes "still the same proof" from
56- "re-established after a break". ` js_array_element_shape_check ` pins both.
54+ one-load word a hoisted guard re-reads without rescanning; a class-shape
55+ generation retires every record at once on prototype surgery; and a proof
56+ sequence hands each * established* proof an identity that is never reused.
57+ That last one is what makes address recycling safe — establishing takes a new
58+ number rather than reading back whatever record sits at the address, so a
59+ record that outlives its array (left by a fail-closed relocation, or by a
60+ death whose prune has not run yet) can never donate its identity to the next
61+ array proven there. ` js_array_element_shape_check ` pins class and identity
62+ together.
5763
58- 26 new tests. 24 cover the matrix row by row in
59- ` array/element_shape_tests.rs ` ; 2 in ` gc/tests/layout_trace/element_shape.rs `
60- put a proven array through a real copying minor and assert the subject was
61- live first — the collector actually copied, and the array actually moved —
62- so a run with zero copying minors cannot pass. One of them pushes * after* the
63- move and asserts the proof both extends on a match and retires on a
64- mismatch, which is what proves the record is reachable at the new key rather
65- than merely readable once.
64+ 29 new tests. 27 cover the matrix row by row in
65+ ` array/element_shape_tests.rs ` , including the two lifecycle hooks that stop a
66+ recycled address inheriting a stale record; 2 in
67+ ` gc/tests/layout_trace/element_shape.rs ` put a proven array through a real
68+ copying minor and assert the subject was live first — the collector actually
69+ copied, and the array actually moved — so a run with zero copying minors
70+ cannot pass. One of them pushes * after* the move and asserts the proof both
71+ extends on a match and retires on a mismatch, which is what proves the record
72+ is reachable at the new key rather than merely readable once. Both files
73+ serialize on a shared poison-tolerant lock, taken before any state-restoring
74+ guard, because the three counters are process-wide while the record table is
75+ thread-local (#7490 's failure shape).
0 commit comments