Skip to content

feat(runtime): ShapeObjectKind::Dictionary, in ShapeRecord padding that was already paid for (#10868 step 2.5 stage 1a) - #10967

Closed
proggeramlug wants to merge 1 commit into
feat/dictionary-modefrom
l8-stage1a
Closed

proggeramlug wants to merge 1 commit into
feat/dictionary-modefrom
l8-stage1a

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

ShapeObjectKind could represent exactly two values: the kind round-tripped through ONE flag bit (RECORD_FLAG_KIND_CLASS) and facts_key folded it as a bool. A third variant on that footing would have read back as Ordinary from object_kind() — and since facts_match compares the full enum, that is a wrong identity match, not a hash collision.

This replaces flags: u8 + _pad: [u8; 3] with one flags_and_kind: u32the same four bytes in the same place — holding the flag byte in bits 0-7 and a 2-bit kind in bits 8-9. The record stays 32 bytes and 8-aligned, both const assertions hold unchanged, and the slab geometry is untouched: the kind costs no memory, it lives in padding that was already allocated. facts_key folds the kind discriminant rather than == Class, so Ordinary and Dictionary no longer share a hash contribution.

Why this is worth landing on its own

Measured by lane 16b in three arms, which is the argument — a fact on the shape retiring a hand-maintained list of guards, including ones that were wrong:

arm result
latch off 0 rows differing from node
latch on, zero hand guards, with the kind 7 rows, one root cause
latch on, six hand guards, no kind three defects

Eight of nine hand-written guards became unnecessary. The deletions include the memory-unsafe out-of-bounds store at fast_paths.rs:87 (bound taken from the descriptor, keys pointer from object_keys_array — different arrays, so a write that lands is out of bounds). And js_shape_ordinary_inline_slot_for_key turned out to be correct by accident — its conjunct passing on 0 == 0 — and is now correct by construction.

That is the case for a kind rather than a side-table predicate: a keyless shape otherwise reads as "this receiver has no own properties" to a long tail of consumers, and a set whose membership is partly accidental cannot be secured by enumerating it.

The clean build WAS the finding

I expected the new variant to break exhaustive matches and NAME its consumers. It broke none — because every consumer guards with == Ordinary / != Ordinary rather than a match: mod.rs:1725, ic_miss.rs:1067 (literally let is_regular = shape.object_kind == Ordinary), fast_paths.rs:87,371, delete_rest.rs:484,883, native_get.rs:84. So a Dictionary shape declines all seven fast-path sites with no further edit. I verified the polarity of the two positive-sense guards rather than assuming it, because "it compiled" is not "the compiler found everything" when catch-all arms exist.

Tests

Record geometry and the O(1) probe property asserted together, so a future field cannot quietly make the kind cost memory; every kind reaches the fold distinctly; a record round-trips all three kinds beside its flags.

Must-fail verified: restoring the bool fold reddens every_object_kind_reaches_the_facts_fold with its own message ("Ordinary and Dictionary collide — the bool fold is back") and leaves the round-trip test green — targeted, not blanket.

object::shapes single-threaded on this base: 48 passed / 0 failed.

Scope

Two files, +128/−21. No latch trigger, no record re-layout, no ObjectMeta change. Stacked on feat/dictionary-mode (#10938), which consumes the variant. The canonical-keys half of step 2.5 (#10868) continues separately and is not entangled with this.

…ng that was already paid for (#10868 step 2.5 stage 1a)

The object kind was encoded as ONE flag bit (RECORD_FLAG_KIND_CLASS), so it
could represent exactly two values, and facts_key folded it as a bool. A third
variant added on that footing would have read back as Ordinary from
object_kind() — and since facts_match compares the full enum, that is a wrong
identity match, not a hash collision.

Replace flags: u8 + _pad: [u8; 3] with one flags_and_kind: u32 — the same four
bytes in the same place — holding the flag byte in bits 0-7 and a 2-bit kind
in bits 8-9. The record stays 32 bytes and 8-aligned, both const assertions
hold unchanged, and the slab geometry is untouched: the kind lives in padding
that was already allocated.

facts_key now folds the kind discriminant rather than == Class, so Ordinary
and Dictionary no longer share a hash contribution.

Every existing consumer guards with == Ordinary or != Ordinary rather than a
match, so a Dictionary shape declines all seven fast-path sites with no
further edit — including ic_miss.rs is_regular and delete_rest.rs
stable_candidate. That is the point: a keyless shape otherwise reads as this
receiver has no own properties to a long tail of consumers, two of whose
members are correct only by accident, and a set with accidental membership
cannot be secured by enumerating it.

Tests (single-threaded): record geometry and the O(1) probe property asserted
together, so a future field cannot quietly make the kind cost memory; every
kind reaches the fold distinctly; a record round-trips all three kinds beside
its flags. Must-fail verified: restoring the bool fold reddens
every_object_kind_reaches_the_facts_fold with Ordinary and Dictionary collide
and leaves the round-trip test green.
@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: e679a19c-c38e-4b0b-9acc-9265f7565c56

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

Landed on main in merge train 256 (#11018, v0.5.1638), main f5cfbff882.

Carried at head 53fe8f9330. The landed tree is byte-identical to the validated train tree (9b108dd3c9), and CI on the train head passed every job except the known public-baseline lint step: all 6 gap shards, cargo-test, e2e-scoped, gc-stress, check, warnings and security-audit green.

Trains rebase-merge, so commits get new SHAs and GitHub cannot mark this PR merged. Closed as landed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants