Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 5223ee5c243553bf6c99efd1b4fd1d06480f8d8a
      
https://github.com/WebKit/WebKit/commit/5223ee5c243553bf6c99efd1b4fd1d06480f8d8a
  Author: Keith Miller <[email protected]>
  Date:   2026-05-07 (Thu, 07 May 2026)

  Changed paths:
    A JSTests/wasm/stress/tail-call-cross-instance-gc.js
    A JSTests/wasm/stress/tail-call-cross-instance-memory-reload.js
    A JSTests/wasm/stress/tail-call-cross-instance-no-thunk-accumulation.js
    A JSTests/wasm/stress/tail-call-cross-instance-restore.js
    A JSTests/wasm/stress/tail-call-cross-instance-sampling-profiler.js
    A JSTests/wasm/stress/tail-call-cross-instance-stack-args.js
    A JSTests/wasm/stress/tail-call-cross-instance-stacktrace.js
    A JSTests/wasm/stress/tail-call-cross-instance-throw.js
    M Source/JavaScriptCore/assembler/MacroAssembler.h
    M Source/JavaScriptCore/assembler/MacroAssemblerARM64E.h
    M Source/JavaScriptCore/llint/InPlaceInterpreter.asm
    M Source/JavaScriptCore/llint/InPlaceInterpreter64.asm
    M Source/JavaScriptCore/llint/LLIntData.cpp
    M Source/JavaScriptCore/llint/LLIntThunks.cpp
    M Source/JavaScriptCore/llint/LLIntThunks.h
    M Source/JavaScriptCore/runtime/Gate.h
    M Source/JavaScriptCore/runtime/SamplingProfiler.cpp
    M Source/JavaScriptCore/wasm/WasmBBQJIT.cpp
    M Source/JavaScriptCore/wasm/WasmCallee.cpp
    M Source/JavaScriptCore/wasm/WasmCallee.h
    M Source/JavaScriptCore/wasm/WasmCalleeGroup.cpp
    M Source/JavaScriptCore/wasm/WasmCompilationMode.h
    M Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.cpp
    M Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.h
    M Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp
    M Source/JavaScriptCore/wasm/WasmIPIntPlan.cpp
    M Source/JavaScriptCore/wasm/WasmIPIntPlan.h
    M Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.cpp
    M Source/JavaScriptCore/wasm/WasmIRGeneratorHelpers.h
    M Source/JavaScriptCore/wasm/WasmInliningDecision.cpp
    M Source/JavaScriptCore/wasm/WasmModuleInformation.h
    M Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp

  Log Message:
  -----------
  [Wasm] Use a lazy restore frame when returning from tail calls
https://bugs.webkit.org/show_bug.cgi?id=313732
rdar://175935387

Reviewed by Yusuke Suzuki.

When a WebAssembly tail call crosses instance boundaries, the non-tail
caller's instance must be restored when the tail call chain eventually
returns. Previously this was handled by a compile-time transitive
analysis that marked functions whose callees could clobber the instance,
and callers of those functions would eagerly restore pinned registers
after every call. This was conservative and prevented inlining of those
functions.

This patch replaces that scheme with "restore frames", a small frame
inserted lazily at runtime on the first cross-instance tail call.
A restore frame captures the caller's instance and original return
address. A return thunk (_wasm_restore_frame_return) restores the
instance and memory registers before returning to the original caller.

The restore frame is 32 bytes (4 slots) and is placed just above
the caller's argument area. The entire frame below it (including
callee-saves) is shifted down by 32 bytes to make room. The restore
frame contains the original CallerFrameAndPC, as well as a copy of the
original instance and RestoreFrameCallee.

When the tail callee eventually returns, it returns through the
redirect at new cfr, which lands in _wasm_restore_frame_return.
The thunk loads the saved instance from the restore frame, reloads
the memory base/bounds registers, then returns to the original caller.

The existing-frame check (comparing ReturnPC against the thunk address)
ensures that repeated cross-instance tail calls reuse the same restore
frame rather than accumulating new ones. This is expected as otherwise
restore frames could grow unboundedly when repeatedly making
cross-instance tail calls, violating the spec.

emitRestoreInstanceFrameIfNeeded is the shared helper used by BBQ and
OMG to create restore frames. It takes a frameSize parameter to skip
the copy loop entirely when no stack-located sources exist, and uses a
do-while loop when copying is needed. On ARM64E, the original return
PC is resigned from the caller's frame context to the restore frame
context, with proper handling for !Options::allowNonSPTagging().

For JIT cage support, a wasmRestoreFrame gate thunk is registered so
that JIT-compiled code and IPInt use a consistent address for the
restore thunk. The gate thunk reproduces _wasm_restore_frame_return's
logic in JIT code, allowing it to untag JIT-key-signed return PCs.

This patch also removes the compile-time transitive tail call
clobbering analysis (ModuleInformation::m_clobberingTailCalls,
computeTransitiveTailCalls, callCanClobberInstance) and the inlining
restriction for functions that could transitively clobber the instance,
since restore frames handle this at runtime.

Tests: JSTests/wasm/stress/tail-call-cross-instance-gc.js
       JSTests/wasm/stress/tail-call-cross-instance-memory-reload.js
       JSTests/wasm/stress/tail-call-cross-instance-no-thunk-accumulation.js
       JSTests/wasm/stress/tail-call-cross-instance-restore.js
       JSTests/wasm/stress/tail-call-cross-instance-sampling-profiler.js
       JSTests/wasm/stress/tail-call-cross-instance-stack-args.js
       JSTests/wasm/stress/tail-call-cross-instance-stacktrace.js
       JSTests/wasm/stress/tail-call-cross-instance-throw.js

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



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

Reply via email to