Commit 0a2bf15
* perf(array): gate the Map/Set registry probes on the receiver's own GC tag (#7768)
`js_array_get_f64` and `js_array_length` asked both collection registries
whether an ordinary array was secretly a Set or a Map on every element read.
On `gc-handoff/apps/asyncpipe.ts` those two probes were 13.5% of the run: the
program uses Map and Set, so the #7474 latch is armed and each probe really
resolved a thread-local and hashed.
Every registered Map/Set IS its `arena_alloc_gc(_, _, GC_TYPE_MAP|GC_TYPE_SET)`
header, so the object's own `obj_type` answers in one byte. ABA-proof by
construction — the tag lives inside the candidate bytes, so recycling the
address rewrites it — which is what an address-keyed negative memo could not
offer (#7755). The registry stays authoritative for the positive answer.
The same header read now also supplies the descriptor flags that
`array_object_flags` re-derived through a second `clean_arr_ptr`.
* perf(array): serve the object keys walk from the array's own words (#7768)
The object field-get funnel already proves `keys` is a live `GC_TYPE_ARRAY` and
caps the index below its capacity, then called `js_array_get` per key — which
re-establishes both facts from scratch: a `clean_arr_ptr` forwarding walk, a
lazy-header probe, the exotic-receiver classifications and a descriptor-flag
read. That funnel was 78% of all `js_array_get_f64` samples on
`gc-handoff/apps/asyncpipe_big.ts`. `keys_array_len_capped_to_capacity` paid the
same toll through `js_array_length` once per property read.
`keys_array_slot` serves the dense, descriptor-free, non-forwarded case from the
array's own words and delegates everything else — a hole, an out-of-range index,
a forwarded or descriptor-carrying array, a null pointer — so no general
semantics move. A test-only per-thread fallback counter pins both directions, so
a fast path that stopped applying and one that started swallowing a shape it
should have delegated are equally red.
Also switches the #7768 receiver-tag read to `addr_class::try_read_gc_header`:
this file's usual `>= GC_HEADER_SIZE + 0x1000` floor sits BELOW the handle band,
and `js_array_length` reaches it before proxy/handle receivers are routed. Keeps
the addr-class ratchet green too.
* docs(array): point the #7768 placeholders at the real PR number (#7765)
* docs: fold the keys-walk pass and the measured numbers into the #7765 fragment
* docs(array): separate the per-thread note in the fallback-counter doc
* docs: rebase the #7765 fragment's numbers onto c2a96b6 and record the interleaving requirement
* test: classify the recycled-bytes stores for the GC store-site inventory
Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
* chore: bump version to 0.5.1455
Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
---------
Co-authored-by: Ralph Küpper <ralph@skelpo.com>
1 parent ad21e84 commit 0a2bf15
14 files changed
Lines changed: 737 additions & 103 deletions
File tree
- changelog.d
- crates/perry-runtime/src
- array
- object/field_get_set
- scripts
| 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