Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: ecc38014aa111ed3ef7e47e73b4dc67fe512b0c3
https://github.com/WebKit/WebKit/commit/ecc38014aa111ed3ef7e47e73b4dc67fe512b0c3
Author: Adrian Taylor <[email protected]>
Date: 2025-12-05 (Fri, 05 Dec 2025)
Changed paths:
M Source/WebKit/Configurations/WebKit.xcconfig
M Source/WebKit/DerivedSources-input.xcfilelist
M Source/WebKit/DerivedSources-output.xcfilelist
M Source/WebKit/DerivedSources.make
M Source/WebKit/Modules/Internal/WebKitInternalCxx.h
M Source/WebKit/Platform/IPC/HandleMessage.h
M Source/WebKit/Scripts/generate-message-receiver.py
M Source/WebKit/Scripts/webkit/messages.py
M Source/WebKit/Scripts/webkit/messages_unittest.py
M Source/WebKit/Scripts/webkit/model.py
M Source/WebKit/Scripts/webkit/parser.py
M Source/WebKit/Scripts/webkit/tests/MessageArgumentDescriptions.cpp
M Source/WebKit/Scripts/webkit/tests/MessageNames.cpp
M Source/WebKit/Scripts/webkit/tests/MessageNames.h
A Source/WebKit/Scripts/webkit/tests/TestWithSwift.messages.in
A Source/WebKit/Scripts/webkit/tests/TestWithSwiftMessageReceiver.cpp
A Source/WebKit/Scripts/webkit/tests/TestWithSwiftMessageReceiver.swift
A Source/WebKit/Scripts/webkit/tests/TestWithSwiftMessages.h
M Source/WebKit/Shared/IPCTester.cpp
M Source/WebKit/Shared/IPCTester.h
M Source/WebKit/Shared/IPCTester.messages.in
A Source/WebKit/Shared/IPCTesterReceiverSwift.messages.in
A Source/WebKit/Shared/IPCTesterReceiverSwift.swift
A Source/WebKit/Shared/IPCTesterReceiverSwiftTypes.h
M Source/WebKit/Shared/WebKit-Swift.h
M Source/WebKit/SourcesCocoa.txt
M Source/WebKit/UIProcess/WebPageProxy.cpp
M Source/WebKit/WebKit.xcodeproj/project.pbxproj
M Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp
Log Message:
-----------
IPC can call directly into Swift
https://bugs.webkit.org/show_bug.cgi?id=302950
rdar://165213339
Reviewed by Richard Robinson.
This adds the ability for our CoreIPC message dispatch to call directly
into Swift handlers.
GOALS:
The goals of this approach are:
* We do not duplicate all the message decoding code. The existing C++
autogenerated decoding code continues to be used; however the dispatch
mechanism then passes its results into Swift handler
functions, by means of Swift/C++ interop.
* Messages can be defined, as now, within .in files, and each message calls
directly into Swift handler functions, with no need for manually-written
intermediate C++ shim functions for each message.
The key part is there's no need for manually-written C++ code for EVERY
MESSAGE.
USER EXPERIENCE:
To make a Swift message handler, you must:
* Mark your messages.in with a new attribute, SwiftReceiver.
* Create a Swift class with suitable functions for each message. It does
not need any particular inheritance or conformance to any particular
protocol. It needs to be named the same as the type named in the
messages.in, just as if you were using C++.
* Within that class, create a new message _forwarder_ class
(this is explained below) using code like this:
WebKit.IPCTesterReceiverSwiftMessageForwarder.create(target: self);
(the implementation of that 'create' function is autogenerated; you
don't have to do that)
* Register _that_ object to receive messages, rather than the Swift
class itself.
* Keep that forwarder object referenced until you don't need to
receive messages any more.
All of this is explained below, but users don't really need to know
anything more than the above.
An example is included in this PR - see IPCTesterReceiverSwift.
OBJECTS INVOLVED:
Somewhere, we have a Swift type, which actually handles the messsages.
Let's assume this is called IPCTesterReceiverSwift. This is a Swift class, thus
subject to reference counting. Note it's a pure Swift type, not some
hybrid C++/Swift type.
It contains methods which handle messages. Examples:
@_expose(Cxx)
internal func asyncMessage(data: UInt32, completionHandler:
IntCompletionHandler) {
We want the autogenerated code to call such methods.
However, our code generation currently generates C++ member functions
such as ::didReceiveMessage. As IPCTesterReceiverSwift is a Swift type, we can't
possibly attach C++ member functions to this type.
As such, we need an extra type. We're going to autogenerate this within
our Python code generation. We will call it
IPCTesterReceiverSwiftMessageForwarder.
It's a pure C++ type. It exists to accommodate the ::didReceiveMessage
(and similar) member functions. It does not have member functions for
each individual message; it's entirely autogenerated. It knows how to
forward actual individual method calls onto the real IPCTesterReceiverSwift
(more
details on that later).
The code which registers IPCTesterReceiverSwift as a message receiver can no
longer register the IPCTesterReceiverSwift itself. Instead, it needs to
register the IPCTesterReceiverSwiftMessageForwarder.
OWNERSHIP:
The ownership here is a little fiddly.
The IPCTesterReceiverSwift OWNS the IPCTesterReceiverSwiftMessageForwarder, via
a Ref<T>. This is necessary because the IPC message infrastructure only retains
weak references to message receiver objects, so if it's not owned
elsewhere, it would be deallocated and no messages would be
received.
But, of course, the IPCTesterReceiverSwiftMessageForwarder needs to call
methods on the Swift IPCTesterReceiverSwift itself. To avoid a reference loop,
the IPCTesterReceiverSwiftMessageForwarder has a weak reference to
IPCTesterReceiverSwift. Unfortunately, Swift/C++ interop does not yet have
built-in facilities for C++ to keep a weak Swift reference (this is
rdar://165068975) so an extra IPCTesterReceiverSwiftWeakRef class needs to be
created to fulfil this purpose. But it's essentially just a weak
reference.
When the IPCTesterReceiverSwiftMessageForwarder wants to call a
IPCTesterReceiverSwift method, it first calls
IPCTesterReceiverSwiftMessageForwarder::getTarget().
This will briefly turn the weak reference into a strong reference
while the method call occurs.
DISPATCH:
So, when C++ calls IPCTesterReceiverSwiftMessageForwarder::didReceiveMessage,
that decodes the message body in the normal way, and then
all this happens:
* didReceiveMessage calls IPCTesterReceiverSwiftMessageForwarder::getTarget
* that converts the weak reference briefly into a strong
reference
* that strong reference is used to call the actual message
dispatch function on the Swift IPCTesterReceiverSwift.
* Swift handles the message.
MESSAGES.IN CHANGES:
There's only one change to messages.in file, which is an optional
SwiftReceiver attribute. It's a Boolean. If that's enabled, all
the above stuff happens.
PASSING IPC CONNECTIONS:
Some message handlers like to receive an IPC::Connection. Currently,
they're passed as a C++ reference, which is not compatible with
Swift/C++ interop. So, if these functions are Swift, we need to pass
a pointer instead.
PASSING COMPLETION HANDLERS:
The pre-existing code passed completion handlers using C++ move
semantics. This is not yet supported by Swift/C++ interop
(rdar://162361370) so instead we have a wrap it in a
RefCountable wrapper.
RESTRICTIONS ON SWIFT TYPE USE:
The types in Swift can be forward-declared anywhere, but to actually
use them or know their size, we must include <WebKit-Swift.h>.
That may ONLY be done from .cpp files rather than .h files, to avoid
the risk of circular dependencies. (The generation of WebKit-Swift.h
depends on Swift being able to read potentially all of WebKit's header
files).
This constraint explains some of the delicate dance we do where
references to the Swift types are actually stored in std::unique_ptr;
this means the size of those types needs only be known by .cpp files
not by .h files. It's a bit of a pain and requires a few more heap
allocations, but for now, this is not performance-critical.
WHAT IS IN THIS COMMIT:
This commit contains all the above, but also a few other things
that merit explanation.
* More overloads of callMemberFunction which accept these two
changes:
* Use of a RefCountable<CompletionHandler> rather than CompletionHandler
* Passing an IPC::Connection* rather than IPC::Connection&
(We may not need so many overloads).
* messages.py supports receivers outside namespaces since Swift
code is not namespaced
* messages.py code to generate the IPCTesterReceiverSwiftMessageForwarder
and IPCTesterReceiverSwiftWeakRef
* messages.py code to dispatch the handler function call to 'target'
rather than 'this', which is the same thing unless Swift is in use,
in which case it's the thing returned by
IPCTesterReceiverSwiftMessageForwarder::getTarget
* messages.py includes WebKit-Swift.h if the handler is in Swift code
not C++
* a flag to enable us to expose 'internal' visibility Swift things to C++
Canonical link: https://commits.webkit.org/303980@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications