Swift IPC handlers return replies and may be async
Component: WebKit IPC | 9fdd260
Source/WebKit/Scripts/webkit/messages.py
Configurations/CommonBase.xcconfig
WebKit generates IPC receiver glue from .messages.in files using messages.py. For a Swift receiver, a C++-callable wrapper decodes the arguments, calls the handler, and sends the reply. @MainActor members are not exported to the generated C++ header, so the wrapper has to be nonisolated and enter the actor itself. Dispatch order between Swift- and C++-handled messages also matters, so a handler must run inline up to its first suspension. Task.immediate guarantees that and Task.init does not.
This reland changes generated Swift handlers so they return their reply directly and may be async. The synchronous wrapper enters @MainActor through MainActor.assumeIsolated and starts the handler with Task.immediate. On systems before OS 26 it uses a back-deployed startOnMainActor SPI. The UIProcess WebBackForwardList handlers move to this path, and -Werror RegionIsolation is enabled. A Windows Swift compiler bug is worked around by packing arguments into a generated per-message Invocation class.
Significance
Swift IPC replies can no longer be forgotten or sent twice, but handlers can now suspend, which changes the ordering and reentrancy assumptions of UIProcess IPC. Real UIProcess handlers that take WebContent-controlled input now run on this path.
Audit directions
- State that goes stale across a suspension. In the migrated
WebBackForwardListhandlers (backForwardGoToItem,backForwardUpdateItem,backForwardItemAtIndexForWebContent, and others), look for assumptions about items, indices or the page that could become false across anawait. Also check whether other IPC can interleave while a handler is pending. - Ordering on older OS versions. The pre-OS 26 fallback calls a private mangled
startOnMainActorthrough a custom.swiftinterface. Confirm it matchesTask.immediatein inline execution and priority/actor inheritance. Any difference would produce ordering bugs that depend on OS version. - Lifetime across suspension. The
Invocationclass retainstarget,connection, the decoded parameters andcompletionHandler. Check that they stay valid when the connection closes or the receiver dies mid-handler. - Deferred replies that never fire. A leaked or never-resumed continuation (see
IPCTesterReceiver.pendingDeferredReply) can hang a synchronous sender. Check teardown, cancellation, and what happens to an earlier continuation when it is replaced. - Invalid messages after a suspension. Confirm that
markMessageInvalidpluscompleteWithDefaultReplyin the asyncrun()catchstill send exactly one default reply on a live connection when the throw happens after a suspension. - Escape hatches. Verify the "Safety:" comment behind
@unchecked Sendableon the generatedWeakRefand thesendingannotations:targetis written only in init, the main-thread assertion holds, and C++ does not reuse values it hands to dispatch.