BBS:      TELESC.NET.BR
Assunto:  get_all_msg_headers(): cold *_NULL fields read undefined via dot-acces
De:       Rob Swindell
Data:     Thu, 21 May 2026 14:38:28 -0700
-----------------------------------------------------------
https://gitlab.synchro.net/main/sbbs/-/issues/1143#note_8987

**SpiderMonkey 1.8.5 per-shape property-cache implementation  references**

All paths relative to the vendored tree `3rdp/src/mozjs/js-1.8.5/js/src/`.

Canonical doc (cited in the header itself, `jspropertycache.h:51-53`): MDN *SpiderMonkey/Internals/Property cache*  `https://developer.mozilla.org/en/SpiderMonkey/Internals/Property_cache` (now in archived Mozilla wiki content).

**Data structures  `jspropertycache.h`**
- `class PropertyCache`  `:160`; fixed-size direct-mapped table, `SIZE_LOG2 = 12`  4096 entries (`:164-169`).
- `struct PropertyCacheEntry`  `:121`; key = `kpc` (testing bytecode pc, `:123`) + `kshape` (shape of the key object, `:124`); value = `vcap`/`vword`.
- hash over **(pc, kshape)**  `hash()` `:215` (`((pc>>SIZE_LOG2 ^ pc) + kshape) & MASK`).
- entry kinds: `adding()` `:128` (kshapevshape, predicted shape transition) vs `directHit()` `:129` (kshape==vshape).
- `PCVal` tagged union (slot / shape / fun-obj)  `:81`.

**Hit/lookup path  `jspropertycacheinlines.h`**, `PropertyCache::test()` `:73`
- `kshape = obj->shape()` `:78`; `entry = table[hash(pc, kshape)]` `:79`.
- validated by `entry->kpc == pc && entry->kshape == kshape` `:84`, then `matchShape(cx, pobj, entry->vshape())` `:92`.
- **On a validated hit it returns the cached PCVal and never calls the resolve hook**  the entry is keyed purely on `(pc, shape)`, and all bulk header objects share one shape lineage. This is the crux.

**Fill  `jspropertycache.cpp`**, `PropertyCache::fill()` `:51`
- where entries are created (the predicted-transition / `adding` bookkeeping), with bail-outs `:62-128` (cache disabled, `!nativeContains`, dictionary-mode `:84`, non-native protos, overdeep chains).

**GETPROP wiring  `jsobj.cpp`**
- found-path fill: `JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, shape)`  `:5438` (under `JSGET_CACHE_RESULT`).
- miss path that explicitly does **not** fill (`nofills++`)  `:5366`.

**Shapes  `jsscope.cpp`**: `js_GenerateShape()` `:74` / `:99`; `Shape` in `jsscope.h`.

The empirically-anchored part is just the first half: `test()` keys on `(pc, obj->shape())` and a validated hit bypasses resolve. The exact entry-transition bookkeeping that lets a same-shape header get mis-served `undefined` lives in the interplay of `fill()` (`:51`) and the `adding()`/`directHit()` validation in `test()`  that's the spot to confirm the precise misprediction.
n
---
  mSynchronetn  hgVertrauen n hHome of Synchronet n gh[vert/cvs/bbs].synchro.net

-----------------------------------------------------------
[Voltar]