Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 4ed5ff4bf1eeaa3c1c76abc87644016fe7a61203
https://github.com/WebKit/WebKit/commit/4ed5ff4bf1eeaa3c1c76abc87644016fe7a61203
Author: Ben Nham <[email protected]>
Date: 2026-03-23 (Mon, 23 Mar 2026)
Changed paths:
M Source/WebCore/page/UserScript.cpp
M Source/WebCore/page/UserScript.h
M Source/WebCore/page/UserStyleSheet.cpp
M Source/WebCore/page/UserStyleSheet.h
M Source/WebKit/Platform/IPC/TransferString.cpp
M Source/WebKit/Platform/IPC/TransferString.h
M Source/WebKit/Platform/IPC/cocoa/TransferStringCocoa.mm
M Source/WebKit/Scripts/webkit/messages.py
M Source/WebKit/Shared/WebUserContentControllerDataTypes.h
M Source/WebKit/Shared/WebUserContentControllerDataTypes.serialization.in
M Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionCocoa.mm
M Source/WebKit/UIProcess/Extensions/WebExtension.cpp
M Source/WebKit/UIProcess/Extensions/WebExtension.h
M Source/WebKit/UIProcess/Extensions/glib/WebExtensionGLib.cpp
M Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.cpp
M Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.h
M Source/WebKit/WebProcess/UserContent/WebUserContentController.cpp
M Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtensionAPIScripting.mm
Log Message:
-----------
Reduce memory overhead of user scripts and user styles in extensions with
many distinct match patterns
https://bugs.webkit.org/show_bug.cgi?id=310393
rdar://169436824
Reviewed by Timothy Hatcher.
Extensions can specify user scripts and user styles with many distinct match
patterns, either
directly via the extension manifest or due to user behavior (e.g. if the user
decides to load
extensions only selectively on certain origins, and that origin list is very
long).
In the current implementation of web extensions, this can lead to memory
explosion because each
distinct match pattern carries its own copy of the same exact user script and
user style strings
(see how `WebExtensionContext::addInjectedContent` loops over each pattern and
creates an
`API::UserScript` object for each pattern). We have seen users that eventually
accumulate match
lists of 300+ origins, which leads to 300+ copies of user scripts and user
styles and which can
cause WebContent to OOM.
This patch fixes the issue by addressing three places where we are
unnecessarily duplicating strings:
1. In `WebExtension`, we keep a cached copy of data and string resources.
However, if a data
resource is already cached for a path, then we always create a new string
instance from that cached
data resource. So 100 calls to `WebExtension::resourceStringForPath` can lead
to 100 String
instances backed by 100 distinct StringImpls even if CacheResult::Yes is used.
To fix this, we
separate the cached data and cached string hash maps in WebExtension so that
cached strings are
always associated with a single String instance.
2. `WebUserContentControllerProxy` in UIProcess IPCs user script and user style
strings to
`WebUserContentController` in WebProcess. The same strings are sent to all
processes in the process
pool, but in the current implementation each process will have its own private
copy of the
string. To fix this, use `IPC::TransferString` to transfer the string across
processes, which allows
the strings in UIProcess and all WebProcesses to be backed by the same single
memory allocation (see
SharedSpan8 and SharedSpan16 in TransferString).
3. Within the same WebContent process, there can be duplicate user script or
user style strings,
because each distinct match pattern is associated with a separate UserScript
object with a differing
match pattern but the same source string. To fix this, we now intern source
strings in both
UserScript and UserStyleSheet.
Test: Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtensionAPIScripting.mm
* Source/WebCore/page/UserScript.cpp: Implement WebProcess user script string
interning.
(WebCore::sourceStrings):
(WebCore::internedSourceString):
(WebCore::UserScript::UserScript):
(WebCore::UserScript::~UserScript):
* Source/WebCore/page/UserScript.h:
* Source/WebCore/page/UserStyleSheet.cpp: Implement WebProcess user style
string interning.
(WebCore::styleStrings):
(WebCore::internedStyleString):
(WebCore::UserStyleSheet::UserStyleSheet):
(WebCore::UserStyleSheet::~UserStyleSheet):
* Source/WebCore/page/UserStyleSheet.h:
* Source/WebKit/Platform/IPC/TransferString.cpp: Make TransferString copyable.
It was already copyable previously in a roundabout way using toIPCData.
(IPC::TransferString::TransferString):
(IPC::TransferString::operator=):
(IPC::TransferString::shouldCache const):
* Source/WebKit/Platform/IPC/TransferString.h:
* Source/WebKit/Platform/IPC/cocoa/TransferStringCocoa.mm:
(IPC::TransferString::createCached):
* Source/WebKit/Scripts/webkit/messages.py: Use TransferString to IPC user
script and user style strings to WebProcess. This requires keeping a cache of
TransferStrings in WebUserContentControllerProxy.
(headers_for_type):
* Source/WebKit/Shared/WebUserContentControllerDataTypes.h:
* Source/WebKit/Shared/WebUserContentControllerDataTypes.serialization.in:
* Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.cpp:
(WebKit::WebUserContentControllerProxy::cachedTransferString const):
(WebKit::WebUserContentControllerProxy::resetTransferStringCache):
(WebKit::WebUserContentControllerProxy::dataFromUserScript const):
(WebKit::WebUserContentControllerProxy::dataFromUserStyleSheet const):
(WebKit::WebUserContentControllerProxy::parametersForProcess const):
(WebKit::WebUserContentControllerProxy::addUserScript):
(WebKit::WebUserContentControllerProxy::removeUserScript):
(WebKit::WebUserContentControllerProxy::removeAllUserScripts):
(WebKit::WebUserContentControllerProxy::addUserStyleSheet):
(WebKit::WebUserContentControllerProxy::removeUserStyleSheet):
(WebKit::WebUserContentControllerProxy::removeAllUserStyleSheets):
* Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.h:
* Source/WebKit/WebProcess/UserContent/WebUserContentController.cpp:
(WebKit::userScriptFromData):
(WebKit::userStyleSheetFromData):
(WebKit::WebUserContentController::addUserScripts):
(WebKit::WebUserContentController::addUserStyleSheets):
* Source/WebKit/UIProcess/Extensions/WebExtension.cpp: Cache extension data and
string resources separately, so that cached strings are always backed by the
same string instance.
(WebKit::WebExtension::toDataResources):
(WebKit::WebExtension::toStringResources):
(WebKit::WebExtension::WebExtension):
(WebKit::WebExtension::resourceStringForPath):
(WebKit::WebExtension::supportedLocales):
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionCocoa.mm:
(WebKit::WebExtension::WebExtension):
(WebKit::WebExtension::resourceDataForPath):
* Source/WebKit/UIProcess/Extensions/WebExtension.h:
* Source/WebKit/UIProcess/Extensions/glib/WebExtensionGLib.cpp:
(WebKit::WebExtension::WebExtension):
(WebKit::WebExtension::resourceDataForPath):
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtensionAPIScripting.mm:
(TestWebKitAPI::TEST(WKWebExtensionAPIScripting,
ContentScriptsAndStyleSheetsWithManyMatchPatterns)):
Canonical link: https://commits.webkit.org/309775@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications