This Week in WebKit — April 04–10, 2026
Featured
WebAnimation::tick() null-checked m_effect, called animationDidTick(), then reused that same pointer for animationBecameReady(). For CustomEffect, animationDidTick() runs the JS callback — and the callback can do animation.effect = null, clearing m_effect mid-tick. The cached pointer never gets re-checked, so the following virtual dispatch loads a vtable from address zero and faults. The fix grabs a fresh keyframeEffect() after the callback returns, and de-virtualises animationBecameReady() so the dispatch path is gone for good.
Every length store used to bottom out in operationPutByIdStrictGaveUp, with the full JSArray::put path running on every call. This commit caches the shrink case as an ArrayLengthStore IC stub: for Int32Shape/ContiguousShape arrays, emitted code zeros the butterfly tail slots and updates publicLength inline. The reward is 3.5–4.3x DFG/FTL on push-then-reset patterns; the cost is a new JIT write site whose guards must prove the array hasn't transitioned shape, been frozen, gone COW, or been targeted via Reflect.set with a mismatched receiver — every guard slip is a write into memory the stub didn't expect.
OMG used to lower Wasm array.get/set/new/len straight to raw loads and stores during IR generation, throwing away every fact B3 could optimise on. Four new opcodes — WasmArrayGet/Set/New/Length — keep array semantics alive through CSE and range analysis, with bounds checks expressed as separate WasmArrayLength nodes the optimizer can fold; allocations from WasmArrayNew let the null-trap be removed entirely. Final lowering moves late into B3LowerMacros. The audit angles are the standard JIT ones: alias-info errors, ValueKey collisions across different arrays, and packed-type sign extension can each silently drop a bounds check or return a wrong length.
SecurityOriginPolicy wraps the SecurityOrigin that enforces same-origin, and each document is supposed to own its own. Document::open() instead called setSecurityOriginPolicy with the caller's policy object — handing over the very same shared instance rather than constructing a new one. Because document.domain writes mutate that SecurityOrigin in place, a caller could rewrite its own domain and have the change reflect on the opened document with no explicit cross-document operation. The fix is a one-line deletion; the same-origin guard at the top of Document::open() was already the real barrier, and Gecko and Blink had never wired the alias in the first place.