Problem
#1001 removed the generic [[Get]] pipeline for a current ordinary own data field, but the direct path still calls namedOwnPropertySnapshot(key) and therefore repeats a full name-to-slot shape lookup for every key that SerializeJSONObject just enumerated.
The executed symbolized JSON workload identified Shape.lookupState as the largest leaf (672 samples), ahead of generic property dispatch (307). After #1001, seven exact-parent pairs still retire about 7.03 billion instructions on each frozen 2,200 x 90 JSON row and remain far behind JavaScriptCore.
Proposed boundary
For a direct ordinary object whose key snapshot proves the simple all-data/default-attribute shape:
- capture insertion-ordered immutable shape names together with their slots and expected Shape;
- on each live value read, take
property_lock, require the same Shape and no accessor shadow, and copy the current slot value; - if Shape or descriptor representation changed, fall back to the #1001 descriptor snapshot and then full
[[Get]]as needed; - keep PropertyList, Proxy, dense-index, accessor, attribute, deletion/re-add history, module namespace, typed-array, and host-class paths on the generic key machinery.
This must not freeze values at key-enumeration time. A prior child toJSON or replacer can still update a later data value, convert it to an accessor, or delete it to expose an inherited replacement.
Completion
Add API-level snapshot/revalidation tests plus production witnesses that mutate later parent fields from an earlier child toJSON. Preserve JSON Test262, required VM/tree agreement, OOM/deep/cycle/GC and no-GIL TSan gates. Compare exact-parent alternating samples on both frozen JSON rows with exact checksums; land only if retired work measurably falls without a control regression.