Skip to content

Commit 7f3ef82

Browse files
author
Ralph Küpper
committed
docs: fold the keys-walk pass and the measured numbers into the #7765 fragment
1 parent 558eb60 commit 7f3ef82

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

changelog.d/7765-array-receiver-tag-gates-collection-probes.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,30 @@ The same one header read also feeds the descriptor-flag check further down
4242
second `clean_arr_ptr` and a second header read (3.1% of the profile on its
4343
own).
4444

45+
**The adjacent cluster falls to the same argument.** `js_array_get_f64` was
46+
6.3%, and 78% of that came from one caller: the object field-get funnel walking
47+
an object's `keys_array`. That funnel has *already* proved `keys` is a live
48+
`GC_TYPE_ARRAY` — it reads the `GcHeader` and returns `undefined` otherwise —
49+
and capped the index below the array's capacity, which is precisely the pair of
50+
facts `js_array_get` re-established per key, per property read, through a
51+
`clean_arr_ptr` forwarding walk, a lazy-header probe, the exotic-receiver
52+
classifications and a descriptor-flag read. `keys_array_slot` serves the dense,
53+
descriptor-free, non-forwarded case from the array's own two words and delegates
54+
everything it cannot serve on those terms — a hole (which reads through the
55+
prototype chain), an out-of-range index, a forwarded or descriptor-carrying
56+
array, a null pointer — so no general semantics move.
57+
`keys_array_len_capped_to_capacity` stops paying the same toll through
58+
`js_array_length` once per property read.
59+
60+
Measured on the pinned mini, both arms timed back to back, min of 5 (the five
61+
benchmarks closest to their floor re-measured interleaved at 9):
62+
**`asyncpipe.ts` 0.9065 s → 0.7143 s, −21.2%** — it stops being the corpus's
63+
worst gap. `is_registered_map` + `is_registered_set` fall from **13.51% to
64+
1.2–1.4%** of the `asyncpipe_big.ts` profile (two agreeing runs), and
65+
`array_object_flags`, `js_array_get_f64` and `js_array_length` all leave the top
66+
of it. `shapes.ts` (−4.5%) and `interp.ts` improve as a side effect — same
67+
funnel. No protected benchmark regresses beyond run-to-run noise.
68+
4569
`crates/perry-runtime/src/array/collection_tag_tests.rs` asserts THE SUBJECT,
4670
not just the answer — the registry is a correct fallback, so a test that only
4771
compared values would still pass with the gates deleted (CLAUDE.md, "four ways a
@@ -56,6 +80,14 @@ confirmation at the end of `is_registered_map` is removed.
5680
`every_registered_collection_address_carries_its_own_type_tag` pins the
5781
invariant the gates rest on, across capacity growth, so a future registration
5882
path that forgot the tag goes red here rather than silently.
83+
`keys_array_slot` gets the same treatment from both sides: a per-thread
84+
fallback counter asserted at zero for the dense arrays the fast path exists for
85+
and at exactly one per refusal for every shape it must delegate, so "stopped
86+
applying" and "started swallowing something it should have delegated" are
87+
equally red. (Per-*thread*, because `cargo test` runs every case on its own
88+
thread in one process — a process-global counter is moved by whatever else
89+
happens to be running, which is how the first version of these assertions
90+
passed for the wrong reason.)
5991

6092
Two comments claiming Map/Set headers are `alloc()`-backed with no `GcHeader`
6193
— the stated reason the registries are consulted before any header read — are

0 commit comments

Comments
 (0)