You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
perf: layout_note_slot is 39% of a spill-slot store (73 of ~187 runtime instructions), and 17.7 of it is element-shape bookkeeping on a NAMED-property store to an ordinary object #10872
A store to a property that lives past the object's inline region ("spill" / overflow storage) costs 269 instructions against node's 5.1 and bun's 1.2, and 73 of them — 39% of the runtime work — are GC layout bookkeeping that a named-property store to an ordinary object should not be doing.
Measured (v0.5.1628, perf stat -e instructions:u, min of 3, fitted 500k→5M, perry flat across the range, output identical to node)
Lane 4b's spill fixture, with and without a second store to the spill-located key (O.b8, index 18 of an object grown to 20 keys by adds, so b8/b9 are in the spill buffer):
perry
node
bun
O.a0=k; h+=O.b8;
228.00
17.31
9.85
O.a0=k; O.b8=k; h+=O.b8;
497.00
22.43
11.09
marginal: one store to a spill slot
269.00
5.12
1.24
For scale, the marginal store to an inline slot of the same kind of object on the same build is 59.33, and the marginal read is 37.33. A spill store is 4.5× an inline store.
Attribution (callgrind --separate-callers=1, --debug-symbols build, per iteration of the loop)
So the store itself (overflow_set, which does the bounds check, the spill-buffer store and the barrier) is 71, the emitted call into it is 43, and the layout note is 73 on top — more than the store.
The part that looks wrong rather than merely expensive
note_element_store_with_bit is element-shape bookkeeping — the machinery that tracks whether an Array's indexed elements are still packed/raw-f64. The receiver here is an ordinary {} grown by twenty named property adds. It has no elements. It is reached because layout_note_slot is called unconditionally from overflow_set and does its own dispatch afterwards, so the key-kind question is asked after the call rather than before it.
That is the same shape as the miss-ladder finding in #10843 (the elements-backed Array-subclass probe reading the meta record for every miss until it was gated on the key first): a probe that can only apply to an integer-indexed store, paid by every named-property store.
Suggested direction
Gate the element-shape half of layout_note_slot on the key kind at the call site in spill::overflow_set, the way key_of_header gates the subclass probe on the miss ladder. That is the 17.7 and it should be free for a named key.
Then ask whether the remaining 55 of layout_note_slot is needed per spill store at all: the emitted inline-slot hit path skips the clearing half of the layout note entirely (emit_jsvalue_slot_store_pointer_tested, with the argument recorded at proxy_reflect.rs that a stale-SET mask bit is strictly weaker than GC_LAYOUT_UNKNOWN and can never strand a child). The spill store does not get that treatment and it is not obvious why the argument does not carry over.
Filed from the property-WRITE attribution pass; self-contained and not blocking that lane's staged work.
Activity