Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 24527bbb9ac882ec69bbb900711d5ca479d12316
      
https://github.com/WebKit/WebKit/commit/24527bbb9ac882ec69bbb900711d5ca479d12316
  Author: Keith Miller <[email protected]>
  Date:   2026-08-01 (Sat, 01 Aug 2026)

  Changed paths:
    M Source/JavaScriptCore/assembler/ARM64Assembler.h
    M Source/JavaScriptCore/assembler/ARMv7Assembler.h
    M Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
    M Source/JavaScriptCore/assembler/LinkBuffer.cpp
    M Source/JavaScriptCore/assembler/LinkBuffer.h
    M Source/JavaScriptCore/assembler/RISCV64Assembler.h
    M Source/JavaScriptCore/assembler/X86Assembler.h
    M Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
    M Source/JavaScriptCore/wasm/WasmCalleeGroup.cpp
    M Source/JavaScriptCore/wasm/WasmCalleeGroup.h
    M Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
    M Source/JavaScriptCore/wasm/WasmEntryPlan.h
    M Source/JavaScriptCore/wasm/WasmIPIntPlan.cpp
    M Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.cpp
    M Source/JavaScriptCore/wasm/WasmMachineThreads.cpp
    M Source/JavaScriptCore/wasm/WasmMachineThreads.h
    M Source/JavaScriptCore/wasm/WasmOMGPlan.cpp
    M Source/JavaScriptCore/wasm/WasmOSREntryPlan.cpp
    M Source/JavaScriptCore/wasm/WasmOSREntryPlan.h
    M Source/WTF/wtf/ThreadMessage.h
    M Source/WTF/wtf/Threading.h
    M Source/WTF/wtf/posix/ThreadingPOSIX.cpp
    M Source/WTF/wtf/win/ThreadingWin.cpp

  Log Message:
  -----------
  [Wasm] Optimize JITCallee publication
https://bugs.webkit.org/show_bug.cgi?id=320747
rdar://183747593

Reviewed by Yusuke Suzuki.

Publishing a freshly compiled wasm function held CalleeGroup::m_lock across the 
two most
expensive steps in the sequence: a per-callsite icache flush for every outgoing 
call, and
barrierCacheOnAllThreads(), which forces a kernel round-trip per tracked wasm 
thread.
Neither reads nor mutates CalleeGroup state, yet every other compiler thread 
blocked
behind them.

This does three things.

First, correctness: Relying on LinkBuffer's finalize flush to cover a 
function's outgoing
call sites is unsafe: those targets are written after finalization, so an 
adjacent live
instruction sharing a cache line with a call site can pull the stale pre-link 
bytes into
the instruction cache. relink{Jump,Call,TailCall} and repatchNearCall gain a
RepatchingInfo template parameter so a repatch can skip its flush, with
flush{Jump,Call,TailCall} counterparts to perform it later, and wasm's 
LinkBuffers are
constructed with CacheFlushOnFinalize::No. A single whole-range cacheFlush then 
runs after
every outgoing call is linked. machineCodeCopy already static_asserts that a 
memcpy
repatch carries no Flush bit, so the split cannot be quietly broken.

Second, the critical section: installOptimizedCallee now links outgoing calls 
under the
lock, drops it via DropLockForScope to flush and synchronize, then re-acquires 
to publish
and relink callers. The window is safe because the callee is not yet in 
m_optimizedCallees,
so no execution thread can reach unflushed code. It is not, however, 
undiscoverable:
m_pendingPublishCallees keeps it findable as a direct-call target, so a thread 
that retires
one of its callees during the window still relinks it rather than leaving it 
calling code
that is about to be freed. Since an OMG install for the same index can land 
mid-window,
the decision to redirect callers is recomputed after re-acquiring; acting on 
the stale one
would relink callers to BBQ over a newer OMG and tier the function back down.

Third, the readers: Maintains the lock-free tier-up peeks from 299970@main for 
the two hot
paths — the IPInt loop back-edge and the BBQ loop's OMG check — now that the 
critical
section they contended with is short. Both are sound because a callee only 
appears in
m_optimizedCallees after its code is flushed and published. The staging slot 
that commit
needed is gone: m_pendingPublishCallees subsumes it, and more cleanly, since an 
unpublished
callee is simply absent rather than visible-but-half-baked. m_bbqCalleeLock has 
to stay
because ThreadSafeWeakOrStrongPtr is a tagged union whose strong->weak 
transition and
assignment are both non-atomic. The IPInt prologue reader deliberately stays on 
m_lock: it
is only reached when IPInt cannot interpret the function at all, so it must 
find whichever
JIT callee exists, and it is disabled in the default configuration.

barrierCacheOnAllThreads() no longer "claims" to invalidate any instruction 
cache, only
context-synchronizes, and is rewritten on top of a new 
Thread::barrierInstructionCache().
The old implementation passed crossModifyingCodeFence() to sendMessage, which 
runs the functor
on the calling thread, not the target, so it only ever worked via the 
suspend/resume the
message mechanism performs incidentally. On ARM64 Darwin the new primitive 
reads the target's
register state instead, whose returning ERET is the context-synchronizing 
event. Elsewhere it
stays as a thread suspend/resume sequence.

OSR entry installation shares all of this rather than duplicating it, as it did 
before. An
OMGOSREntryCallee is not the function's entrypoint even though it shares its 
index, so one
predicate gates both the recursive-call resolution and the caller relinking; 
its reservation
in m_osrEntryCallees also registers it, which is safe because that map is 
relinking
bookkeeping and only BBQCallee::setOSREntryCallee, after the flush, makes the 
code enterable.

Also removes EntryPlan::m_unlinkedWasmToWasmCalls and IPIntPlan's relink loop 
over it,
which were dead (parseAndCompileMetadata never populated the vector).

No new tests, no behavior change. Covered by existing tests.

Canonical link: https://commits.webkit.org/318386@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to