Parent: #493 Related: #478, #482, #480
Problem
ThreadLocal stores its per-thread values in std.AutoHashMapUnmanaged(u64, Value), keyed by the current OS thread ID. The default integer hash has fixed, public bucket placement while JavaScript controls thread creation and ThreadLocal.value insert/read/remove schedules. Collision-amplified probes therefore execute while holding map_lock, turning predictable placement into an avoidable shared-realm latency and denial-of-service surface.
Required implementation
- Replace the fixed-hash table with an exact-u64 map whose bucket placement is seeded from the engine secure RNG.
- Install entropy lazily on the first non-undefined store so constructing or reading an empty
ThreadLocalremains allocation- and entropy-free. - Publish the hash context only after the first backing allocation succeeds; entropy or allocation failure must follow the existing OOM path with no clock/address/constant fallback and no half-published value.
- Preserve exact thread-ID equality, owner-thread cleanup, wrapper ownership/barriers, root tracing, moving relocation, and the existing
map_locksynchronization ruling. - Do not weaken locking, retain exited-thread values, add unbounded reserves, or recognize test/benchmark inputs.
Acceptance
- A deterministic collision witness shows legacy integer-bucket collisions disperse under a nonzero installed seed.
- Empty get/remove paths consume no entropy; first-store entropy/allocation failures publish neither a context nor a value.
- Repeated stores reuse the installed context and exact thread IDs remain the equality authority.
- Thread exit removes its exact value and does not disturb peer values.
- Focused ThreadLocal lifecycle/GC tests pass in Debug, ReleaseSafe, and suppression-free TSan.
- Relevant threadfuzz profiles and the full unit suite pass with zero failures/leaks.
- The change is documented in the public concurrency contract and changes 0 Test262 cases because
ThreadLocalis a zig-js extension.