WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-220038-20210819104037.patch (text/plain), 35.85 KB, created by
Chris Dumez
on 2021-08-19 10:40:38 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Chris Dumez
Created:
2021-08-19 10:40:38 PDT
Size:
35.85 KB
patch
obsolete
>Subversion Revision: 281235 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 63daa97de4cd3b97335576fb4d67244252c5dfc3..dec7ea33b68a5f578a9c6f7aa3f95164408388cb 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,83 @@ >+2021-08-19 Chris Dumez <cdumez@apple.com> >+ >+ Unable to postMessage a WebAssembly module to a worklet >+ https://bugs.webkit.org/show_bug.cgi?id=220038 >+ <rdar://problem/72596556> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Because of service worker support, and because we have no way to know >+ who the destination is when calling MessagePort.postMessage(), every >+ message gets routed via the network process, even if the destination >+ ends up being in the same process. This is an issue because some of >+ the SerializedScriptValue's data members cannot be serialized and >+ sent to a different process. In particular, this is an issue for >+ WASM modules and memory handles. >+ >+ to address this issue, I introduced a SerializedScriptValue cache. >+ Each SerializedScriptValue gets assigned a globally unique >+ identifier (unique across all WebProcesses). When sending a >+ SerializedScriptValue via IPC, we also serialized its identifier >+ and add the SerializedScriptValue to the in-process cache. Upon >+ deserialization from IPC, we check if the SerializedScriptValue is >+ in the cache by using its deserialized identifier. If it is in the >+ cache, we reuse it so that we don't lose the data members that >+ couldn't be serialized over IPC. >+ >+ When the source and the destination process are the same (common case), >+ the SerializedScriptValue only stays in the cache for a short amount of >+ time (it gets added to the cache on serialization and removed upon >+ deserialization at the destination). In case the destination process >+ ends up being a different process, cached serialized script values only >+ live for 30 seconds at most in the cache, to avoid wasting memory. >+ >+ Note that, as per the specification, it shouldn't be possible to send >+ WASM modules / memory handles across agent clusters [1]. I had to >+ implement this behavior in order to not regress the following test: >+ - imported/w3c/web-platform-tests/wasm/serialization/module/window-serviceworker-failure.https.html >+ In particular, service workers should belong to a different agent cluster, >+ even if they run in the same process. >+ >+ [1] https://tc39.es/ecma262/#sec-agent-clusters >+ [2] https://webassembly.github.io/spec/web-api/index.html#serialization >+ >+ No new tests, rebaselined existing test. >+ >+ * Headers.cmake: >+ * WebCore.xcodeproj/project.pbxproj: >+ * bindings/js/JSDOMGlobalObject.cpp: >+ (WebCore::JSDOMGlobalObject::defaultAgentClusterID): >+ (WebCore::JSDOMGlobalObject::agentClusterID const): >+ * bindings/js/JSDOMGlobalObject.h: >+ * bindings/js/SerializedScriptValue.cpp: >+ (WebCore::agentClusterIDFromGlobalObject): >+ (WebCore::CloneSerializer::dumpIfTerminal): >+ (WebCore::CloneDeserializer::readTerminal): >+ (WebCore::generateIdentifier): >+ (WebCore::SerializedScriptValue::SerializedScriptValue): >+ (WebCore::SerializedScriptValue::Cache::singleton): >+ (WebCore::SerializedScriptValue::Cache::CachedValue::takeValue): >+ (WebCore::SerializedScriptValue::Cache::CachedValue::CachedValue): >+ (WebCore::SerializedScriptValue::Cache::add): >+ (WebCore::SerializedScriptValue::Cache::take): >+ (WebCore::SerializedScriptValue::Cache::CachedValue::expirationTimerFired): >+ * bindings/js/SerializedScriptValue.h: >+ (WebCore::SerializedScriptValue::identifier const): >+ (WebCore::SerializedScriptValue::encode const): >+ (WebCore::SerializedScriptValue::decode): >+ * bindings/js/SerializedScriptValueIdentifier.h: Added. >+ (WebCore::SerializedScriptValueIdentifier::hash const): >+ (WebCore::operator==): >+ (WebCore::SerializedScriptValueIdentifier::encode const): >+ (WebCore::SerializedScriptValueIdentifier::decode): >+ (WTF::SerializedScriptValueIdentifierHash::hash): >+ (WTF::SerializedScriptValueIdentifierHash::equal): >+ (WTF::HashTraits<WebCore::SerializedScriptValueIdentifier>::emptyValue): >+ (WTF::HashTraits<WebCore::SerializedScriptValueIdentifier>::constructDeletedValue): >+ (WTF::HashTraits<WebCore::SerializedScriptValueIdentifier>::isDeletedValue): >+ * dom/MessagePort.cpp: >+ (WebCore::MessagePort::postMessage): >+ > 2021-08-19 Youenn Fablet <youenn@apple.com> > > RTCPeerConnection::m_transceiverSet does not need to be allocated separately from its RTCPeerConnection >diff --git a/Source/WebCore/Headers.cmake b/Source/WebCore/Headers.cmake >index 62b6ee16d4c106ee78e0510646bd69deb2c2cfcf..9d12b4de21a70e297e50c5d9183e504ecfc98352 100644 >--- a/Source/WebCore/Headers.cmake >+++ b/Source/WebCore/Headers.cmake >@@ -290,6 +290,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS > bindings/js/ScriptWrappable.h > bindings/js/ScriptWrappableInlines.h > bindings/js/SerializedScriptValue.h >+ bindings/js/SerializedScriptValueIdentifier.h > bindings/js/StringAdaptors.h > bindings/js/WebCoreJITOperations.h > bindings/js/WebCoreTypedArrayController.h >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index f648b84e10c64f93a169f9d9313615f0c120bb98..5b4708a4ced059bbab7b14ae8d0d4c12884163e6 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -1287,6 +1287,7 @@ > 4672AA9826B0943300E6EC38 /* CrossOriginEmbedderPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4672AA9626B0942100E6EC38 /* CrossOriginEmbedderPolicy.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 4672AA9926B0943F00E6EC38 /* CrossOriginOpenerPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4672AA9726B0942100E6EC38 /* CrossOriginOpenerPolicy.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 467302021C4EFE7800BCB357 /* IgnoreOpensDuringUnloadCountIncrementer.h in Headers */ = {isa = PBXBuildFile; fileRef = 467302011C4EFE6600BCB357 /* IgnoreOpensDuringUnloadCountIncrementer.h */; }; >+ 4680600E26CDA8B500A1A5BF /* SerializedScriptValueIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 4680600C26CDA8A500A1A5BF /* SerializedScriptValueIdentifier.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 4682D2001F79783000C863DB /* StoredCredentialsPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4682D1FF1F79782300C863DB /* StoredCredentialsPolicy.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 468344E01EDDFAAA00B7795B /* DOMRectList.h in Headers */ = {isa = PBXBuildFile; fileRef = 468344DE1EDDFA5F00B7795B /* DOMRectList.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 469CCCFE269D021C006E0314 /* BroadcastChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 469CCCFC269D0202006E0314 /* BroadcastChannel.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -8304,6 +8305,7 @@ > 4672AA9626B0942100E6EC38 /* CrossOriginEmbedderPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrossOriginEmbedderPolicy.h; sourceTree = "<group>"; }; > 4672AA9726B0942100E6EC38 /* CrossOriginOpenerPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrossOriginOpenerPolicy.h; sourceTree = "<group>"; }; > 467302011C4EFE6600BCB357 /* IgnoreOpensDuringUnloadCountIncrementer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IgnoreOpensDuringUnloadCountIncrementer.h; sourceTree = "<group>"; }; >+ 4680600C26CDA8A500A1A5BF /* SerializedScriptValueIdentifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SerializedScriptValueIdentifier.h; sourceTree = "<group>"; }; > 4682D1FF1F79782300C863DB /* StoredCredentialsPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StoredCredentialsPolicy.h; sourceTree = "<group>"; }; > 468344DC1EDDFA5F00B7795B /* DOMRectList.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = DOMRectList.idl; sourceTree = "<group>"; }; > 468344DD1EDDFA5F00B7795B /* DOMRectList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DOMRectList.cpp; sourceTree = "<group>"; }; >@@ -27036,6 +27038,7 @@ > 1400D7A717136EA70077CE05 /* ScriptWrappableInlines.h */, > A75E497510752ACB00C9B896 /* SerializedScriptValue.cpp */, > A75E497410752ACB00C9B896 /* SerializedScriptValue.h */, >+ 4680600C26CDA8A500A1A5BF /* SerializedScriptValueIdentifier.h */, > 7C5266961F1B02FC000F068B /* StringAdaptors.h */, > 414B82021D6DF0D90077EBE3 /* StructuredClone.cpp */, > 414B82031D6DF0D90077EBE3 /* StructuredClone.h */, >@@ -34498,6 +34501,7 @@ > 077AF14318F4B1BB0001ED61 /* SerializedPlatformDataCueMac.h in Headers */, > 076D1C1F23F6EB5B00D95B06 /* SerializedPlatformDataCueValue.h in Headers */, > A75E497610752ACB00C9B896 /* SerializedScriptValue.h in Headers */, >+ 4680600E26CDA8B500A1A5BF /* SerializedScriptValueIdentifier.h in Headers */, > 516F7F6D1C31E39A00F111DC /* ServerOpenDBRequest.h in Headers */, > 2D93AEE319DF5641002A86C3 /* ServicesOverlayController.h in Headers */, > 51F1755D1F3EBC8300C74950 /* ServiceWorker.h in Headers */, >diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp >index 916d33d9de74f2213dbe3343eff3d02a3ac353cd..37fcd76de03f0be7166d9ae1548eb05dac343657 100644 >--- a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp >+++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp >@@ -46,9 +46,11 @@ > #include "JSRemoteDOMWindow.h" > #include "JSWorkerGlobalScope.h" > #include "JSWorkletGlobalScope.h" >+#include "ProcessIdentifier.h" > #include "RejectedPromiseTracker.h" > #include "RuntimeEnabledFeatures.h" > #include "ScriptModuleLoader.h" >+#include "ServiceWorkerGlobalScope.h" > #include "StructuredClone.h" > #include "WebCoreJSClientData.h" > #include "WorkerGlobalScope.h" >@@ -63,6 +65,7 @@ > #include <JavaScriptCore/VMTrapsInlines.h> > #include <JavaScriptCore/WasmStreamingCompiler.h> > #include <JavaScriptCore/WeakGCMapInlines.h> >+#include <wtf/text/StringConcatenateNumbers.h> > > namespace WebCore { > using namespace JSC; >@@ -548,6 +551,19 @@ JSC::JSObject* JSDOMGlobalObject::moduleLoaderCreateImportMetaProperties(JSC::JS > return constructEmptyObject(globalObject->vm(), globalObject->nullPrototypeObjectStructure()); > } > >+String JSDOMGlobalObject::defaultAgentClusterID() >+{ >+ return makeString(Process::identifier().toUInt64(), "-default"); >+} >+ >+String JSDOMGlobalObject::agentClusterID() const >+{ >+ // Service workers may run in process but they need to be in a separate agent cluster. >+ if (is<ServiceWorkerGlobalScope>(scriptExecutionContext())) >+ return makeString(Process::identifier().toUInt64(), "-serviceworker"); >+ return defaultAgentClusterID(); >+} >+ > JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext& context, DOMWrapperWorld& world) > { > if (is<Document>(context)) >diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.h b/Source/WebCore/bindings/js/JSDOMGlobalObject.h >index f9235d6b16399f07d40bcae79271175fec9cbd8f..028ef469dc15607214722307e55a10858d5f5ba2 100644 >--- a/Source/WebCore/bindings/js/JSDOMGlobalObject.h >+++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.h >@@ -74,6 +74,10 @@ public: > > ScriptExecutionContext* scriptExecutionContext() const; > >+ // https://tc39.es/ecma262/#sec-agent-clusters >+ String agentClusterID() const; >+ static String defaultAgentClusterID(); >+ > // Make binding code generation easier. > JSDOMGlobalObject* globalObject() { return this; } > >diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp >index 504785c96d8f5643a961826855954de0657d6cc5..8bf84c867732da9fa11b1bf79b65935b8df5a7bb 100644 >--- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp >+++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp >@@ -58,6 +58,7 @@ > #include "ScriptExecutionContext.h" > #include "ScriptState.h" > #include "SharedBuffer.h" >+#include "Timer.h" > #include "WebCoreJSClientData.h" > #include <JavaScriptCore/APICast.h> > #include <JavaScriptCore/BigIntObject.h> >@@ -89,7 +90,9 @@ > #include <JavaScriptCore/YarrFlags.h> > #include <limits> > #include <wtf/CompletionHandler.h> >+#include <wtf/Hasher.h> > #include <wtf/MainThread.h> >+#include <wtf/NeverDestroyed.h> > #include <wtf/RunLoop.h> > #include <wtf/Vector.h> > #include <wtf/threads/BinarySemaphore.h> >@@ -110,7 +113,8 @@ using namespace JSC; > > DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(SerializedScriptValue); > >-static const unsigned maximumFilterRecursion = 40000; >+constexpr unsigned maximumFilterRecursion = 40000; >+constexpr Seconds cachedSerializedScriptValueLifetime { 30_s }; > > enum class SerializationReturnCode { > SuccessfullyCompleted, >@@ -235,6 +239,15 @@ static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag) > } > } > >+#if ENABLE(WEBASSEMBLY) >+static String agentClusterIDFromGlobalObject(JSGlobalObject& globalObject) >+{ >+ if (!globalObject.inherits<JSDOMGlobalObject>(globalObject.vm())) >+ return JSDOMGlobalObject::defaultAgentClusterID(); >+ return jsCast<JSDOMGlobalObject*>(&globalObject)->agentClusterID(); >+} >+#endif >+ > enum class PredefinedColorSpaceTag : uint8_t { > SRGB = 0 > #if ENABLE(DESTINATION_COLOR_SPACE_DISPLAY_P3) >@@ -322,7 +335,7 @@ static unsigned countUsages(CryptoKeyUsageBitmap usages) > * Version 7. added support for File's lastModified attribute. > * Version 8. added support for ImageData's colorSpace attribute. > */ >-static const unsigned CurrentVersion = 8; >+static const unsigned CurrentVersion = 9; > static const unsigned TerminatorTag = 0xFFFFFFFF; > static const unsigned StringPoolTag = 0xFFFFFFFE; > static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD; >@@ -1348,6 +1361,7 @@ private: > uint32_t index = m_wasmModules.size(); > m_wasmModules.append(makeRef(module->module())); > write(WasmModuleTag); >+ write(agentClusterIDFromGlobalObject(*m_lexicalGlobalObject)); > write(index); > return true; > } >@@ -1363,6 +1377,7 @@ private: > uint32_t index = m_wasmMemoryHandles.size(); > m_wasmMemoryHandles.append(makeRef(memory->memory().handle())); > write(WasmMemoryTag); >+ write(agentClusterIDFromGlobalObject(*m_lexicalGlobalObject)); > write(index); > return true; > } >@@ -3498,6 +3513,15 @@ private: > } > #if ENABLE(WEBASSEMBLY) > case WasmModuleTag: { >+ if (m_version >= 9) { >+ // https://webassembly.github.io/spec/web-api/index.html#serialization >+ CachedStringRef agentClusterID; >+ bool agentClusterIDSuccessfullyRead = readStringData(agentClusterID); >+ if (!agentClusterIDSuccessfullyRead || agentClusterID->string() != agentClusterIDFromGlobalObject(*m_globalObject)) { >+ fail(); >+ return JSValue(); >+ } >+ } > uint32_t index; > bool indexSuccessfullyRead = read(index); > if (!indexSuccessfullyRead || !m_wasmModules || index >= m_wasmModules->size()) { >@@ -3514,6 +3538,14 @@ private: > return result; > } > case WasmMemoryTag: { >+ if (m_version >= 9) { >+ CachedStringRef agentClusterID; >+ bool agentClusterIDSuccessfullyRead = readStringData(agentClusterID); >+ if (!agentClusterIDSuccessfullyRead || agentClusterID->string() != agentClusterIDFromGlobalObject(*m_globalObject)) { >+ fail(); >+ return JSValue(); >+ } >+ } > uint32_t index; > bool indexSuccessfullyRead = read(index); > if (!indexSuccessfullyRead || !m_wasmMemoryHandles || index >= m_wasmMemoryHandles->size()) { >@@ -3895,18 +3927,28 @@ error: > > SerializedScriptValue::~SerializedScriptValue() = default; > >+static SerializedScriptValue::Identifier generateIdentifier() >+{ >+ return { >+ Process::identifier(), >+ SerializedScriptValue::Identifier::ValueIdentifier::generateThreadSafe() >+ }; >+} >+ > SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer) >- : m_data(WTFMove(buffer)) >+ : m_identifier(generateIdentifier()) >+ , m_data(WTFMove(buffer)) > { > m_memoryCost = computeMemoryCost(); > } > >-SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, std::unique_ptr<ArrayBufferContentsArray>&& arrayBufferContentsArray >+SerializedScriptValue::SerializedScriptValue(Identifier identifier, Vector<uint8_t>&& buffer, std::unique_ptr<ArrayBufferContentsArray>&& arrayBufferContentsArray > #if ENABLE(WEB_RTC) > , Vector<std::unique_ptr<DetachedRTCDataChannel>>&& detachedRTCDataChannels > #endif > ) >- : m_data(WTFMove(buffer)) >+ : m_identifier(identifier) >+ , m_data(WTFMove(buffer)) > , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray)) > #if ENABLE(WEB_RTC) > , m_detachedRTCDataChannels(WTFMove(detachedRTCDataChannels)) >@@ -3927,7 +3969,8 @@ SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, const Vec > , std::unique_ptr<WasmMemoryHandleArray> wasmMemoryHandlesArray > #endif > ) >- : m_data(WTFMove(buffer)) >+ : m_identifier(generateIdentifier()) >+ , m_data(WTFMove(buffer)) > , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray)) > , m_sharedBufferContentsArray(WTFMove(sharedBufferContentsArray)) > , m_backingStores(WTFMove(backingStores)) >@@ -4412,4 +4455,53 @@ IDBValue SerializedScriptValue::writeBlobsToDiskForIndexedDBSynchronously() > return value; > } > >+auto SerializedScriptValue::Cache::singleton() -> Cache& >+{ >+ static NeverDestroyed<Cache> cache; >+ return cache; >+} >+ >+class SerializedScriptValue::Cache::CachedValue { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ CachedValue(RefPtr<SerializedScriptValue>&&); >+ RefPtr<SerializedScriptValue> takeValue() { return std::exchange(m_value, nullptr); } >+ >+private: >+ void expirationTimerFired(); >+ >+ Timer m_expirationTimer; >+ RefPtr<SerializedScriptValue> m_value; >+}; >+ >+SerializedScriptValue::Cache::CachedValue::CachedValue(RefPtr<SerializedScriptValue>&& value) >+ : m_expirationTimer(*this, &CachedValue::expirationTimerFired) >+ , m_value(WTFMove(value)) >+{ >+ ASSERT(isMainThread()); >+ m_expirationTimer.startOneShot(cachedSerializedScriptValueLifetime); >+} >+ >+void SerializedScriptValue::Cache::add(RefPtr<SerializedScriptValue>&& serializedScriptValue) >+{ >+ ASSERT(isMainThread()); >+ m_values.add(serializedScriptValue->identifier(), makeUnique<CachedValue>(WTFMove(serializedScriptValue))); >+} >+ >+RefPtr<SerializedScriptValue> SerializedScriptValue::Cache::take(Identifier identifier) >+{ >+ ASSERT(isMainThread()); >+ auto cachedValue = m_values.take(identifier); >+ return cachedValue ? cachedValue->takeValue() : nullptr; >+} >+ >+void SerializedScriptValue::Cache::CachedValue::expirationTimerFired() >+{ >+ if (!m_value) >+ return; >+ >+ auto removedValue = Cache::singleton().take(m_value->identifier()); >+ ASSERT_UNUSED(removedValue, removedValue); >+} >+ > } // namespace WebCore >diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.h b/Source/WebCore/bindings/js/SerializedScriptValue.h >index fb757a4d74f60e2ffcdb829c152030a6699c14cf..54872d67ae823ff9160dc0b2d6fef5819b1839d8 100644 >--- a/Source/WebCore/bindings/js/SerializedScriptValue.h >+++ b/Source/WebCore/bindings/js/SerializedScriptValue.h >@@ -29,6 +29,7 @@ > #include "Blob.h" > #include "DetachedRTCDataChannel.h" > #include "ExceptionOr.h" >+#include "SerializedScriptValueIdentifier.h" > #include <JavaScriptCore/ArrayBuffer.h> > #include <JavaScriptCore/JSCJSValue.h> > #include <JavaScriptCore/Strong.h> >@@ -115,9 +116,12 @@ public: > > WEBCORE_EXPORT ~SerializedScriptValue(); > >+ using Identifier = SerializedScriptValueIdentifier; >+ Identifier identifier() const { return m_identifier; } >+ > private: > WEBCORE_EXPORT SerializedScriptValue(Vector<unsigned char>&&); >- WEBCORE_EXPORT SerializedScriptValue(Vector<unsigned char>&&, std::unique_ptr<ArrayBufferContentsArray>&& >+ WEBCORE_EXPORT SerializedScriptValue(Identifier, Vector<unsigned char>&&, std::unique_ptr<ArrayBufferContentsArray>&& > #if ENABLE(WEB_RTC) > , Vector<std::unique_ptr<DetachedRTCDataChannel>>&& > #endif >@@ -136,8 +140,24 @@ private: > #endif > ); > >+ class Cache { >+ public: >+ WEBCORE_EXPORT static Cache& singleton(); >+ >+ WEBCORE_EXPORT void add(RefPtr<SerializedScriptValue>&&); >+ WEBCORE_EXPORT RefPtr<SerializedScriptValue> take(Identifier); >+ >+ private: >+ friend class NeverDestroyed<Cache>; >+ Cache() = default; >+ >+ class CachedValue; >+ HashMap<Identifier, std::unique_ptr<CachedValue>> m_values; >+ }; >+ > size_t computeMemoryCost() const; > >+ Identifier m_identifier; > Vector<unsigned char> m_data; > std::unique_ptr<ArrayBufferContentsArray> m_arrayBufferContentsArray; > std::unique_ptr<ArrayBufferContentsArray> m_sharedBufferContentsArray; >@@ -177,6 +197,9 @@ void SerializedScriptValue::encode(Encoder& encoder) const > for (const auto &channel : m_detachedRTCDataChannels) > encoder << *channel; > #endif >+ >+ Cache::singleton().add(const_cast<SerializedScriptValue*>(this)); >+ encoder << m_identifier; > } > > template<class Decoder> >@@ -230,7 +253,16 @@ RefPtr<SerializedScriptValue> SerializedScriptValue::decode(Decoder& decoder) > } > #endif > >- return adoptRef(*new SerializedScriptValue(WTFMove(data), WTFMove(arrayBufferContentsArray) >+ Identifier identifier; >+ if (!decoder.decode(identifier)) >+ return nullptr; >+ >+ // We are not able to serialize things like WASM modules so reuse the existing SerializedScriptValue if still alive >+ // upon deserialization instead of constructing a new SerializedScriptValue from deserialized data. >+ if (auto existingValue = Cache::singleton().take(identifier)) >+ return existingValue.releaseNonNull(); >+ >+ return adoptRef(*new SerializedScriptValue(identifier, WTFMove(data), WTFMove(arrayBufferContentsArray) > #if ENABLE(WEB_RTC) > , WTFMove(detachedRTCDataChannels) > #endif >diff --git a/Source/WebCore/bindings/js/SerializedScriptValueIdentifier.h b/Source/WebCore/bindings/js/SerializedScriptValueIdentifier.h >new file mode 100644 >index 0000000000000000000000000000000000000000..fd33bf612efad55fda73dfea7f9fe5ad44b181e0 >--- /dev/null >+++ b/Source/WebCore/bindings/js/SerializedScriptValueIdentifier.h >@@ -0,0 +1,93 @@ >+/* >+ * Copyright (C) 2021 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ * >+ */ >+ >+#pragma once >+ >+#include "ProcessIdentifier.h" >+#include <wtf/Hasher.h> >+ >+namespace WebCore { >+ >+struct SerializedScriptValueIdentifier { >+ ProcessIdentifier processIdentifier; >+ >+ enum ValueIdentifierType { }; >+ using ValueIdentifier = ObjectIdentifier<ValueIdentifierType>; >+ ValueIdentifier valueIdentifier; >+ >+ unsigned hash() const { return computeHash(processIdentifier.toUInt64(), valueIdentifier.toUInt64()); } >+ >+ template<class Encoder> void encode(Encoder&) const; >+ template<class Decoder> static std::optional<SerializedScriptValueIdentifier> decode(Decoder&); >+}; >+ >+inline bool operator==(const SerializedScriptValueIdentifier& a, const SerializedScriptValueIdentifier& b) >+{ >+ return a.processIdentifier == b.processIdentifier && a.valueIdentifier == b.valueIdentifier; >+} >+ >+template<class Encoder> >+void SerializedScriptValueIdentifier::encode(Encoder& encoder) const >+{ >+ encoder << processIdentifier << valueIdentifier; >+} >+ >+template<class Decoder> >+std::optional<SerializedScriptValueIdentifier> SerializedScriptValueIdentifier::decode(Decoder& decoder) >+{ >+ std::optional<ProcessIdentifier> processIdentifier; >+ decoder >> processIdentifier; >+ if (!processIdentifier) >+ return std::nullopt; >+ >+ std::optional<ValueIdentifier> valueIdentifier; >+ decoder >> valueIdentifier; >+ if (!valueIdentifier) >+ return std::nullopt; >+ >+ return { { *processIdentifier, *valueIdentifier } }; >+} >+ >+} // namespace WebCore >+ >+namespace WTF { >+ >+struct SerializedScriptValueIdentifierHash { >+ static unsigned hash(const WebCore::SerializedScriptValueIdentifier& key) { return key.hash(); } >+ static bool equal(const WebCore::SerializedScriptValueIdentifier& a, const WebCore::SerializedScriptValueIdentifier& b) { return a == b; } >+ static const bool safeToCompareToEmptyOrDeleted = true; >+}; >+ >+template<> struct HashTraits<WebCore::SerializedScriptValueIdentifier> : GenericHashTraits<WebCore::SerializedScriptValueIdentifier> { >+ static WebCore::SerializedScriptValueIdentifier emptyValue() { return { }; } >+ >+ static void constructDeletedValue(WebCore::SerializedScriptValueIdentifier& slot) { new (NotNull, &slot.processIdentifier) WebCore::ProcessIdentifier(WTF::HashTableDeletedValue); } >+ static bool isDeletedValue(const WebCore::SerializedScriptValueIdentifier& slot) { return slot.processIdentifier.isHashTableDeletedValue(); } >+}; >+ >+template<> struct DefaultHash<WebCore::SerializedScriptValueIdentifier> : SerializedScriptValueIdentifierHash { }; >+ >+} // namespace WTF >diff --git a/Source/WebCore/dom/MessagePort.cpp b/Source/WebCore/dom/MessagePort.cpp >index c1c5dc986acb72342ed100d6fdc9d9160fd8c927..90f95b9c9999a3f8a4867f45778f1ef3c19a5167 100644 >--- a/Source/WebCore/dom/MessagePort.cpp >+++ b/Source/WebCore/dom/MessagePort.cpp >@@ -139,7 +139,11 @@ ExceptionOr<void> MessagePort::postMessage(JSC::JSGlobalObject& state, JSC::JSVa > registerLocalActivity(); > > Vector<RefPtr<MessagePort>> ports; >- auto messageData = SerializedScriptValue::create(state, messageValue, WTFMove(options.transfer), ports); >+ >+ // FIXME: At the time of serialization, we don't know if the target is a window, a worker or something else. We will only know at the time of >+ // deserialization. This is an issue since SerializedScriptValue::create() will return an exception if Wasm modules / memory handles are present and the context >+ // is not WorkerPostMessage. >+ auto messageData = SerializedScriptValue::create(state, messageValue, WTFMove(options.transfer), ports, SerializationContext::WorkerPostMessage); > if (messageData.hasException()) > return messageData.releaseException(); > >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 3308ab0daa1046ac58346794c1769ceb0ec51461..34a1caa79c4d658a1ea262cfb803f08d347aeaa1 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,15 @@ >+2021-08-19 Chris Dumez <cdumez@apple.com> >+ >+ Unable to postMessage a WebAssembly module to a worklet >+ https://bugs.webkit.org/show_bug.cgi?id=220038 >+ <rdar://problem/72596556> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Update SerializedScriptValue serialization version in the test. >+ >+ * fast/storage/serialized-script-value.html: >+ > 2021-08-19 Kate Cheney <katherine_cheney@apple.com> > > [App Privacy Report] Some HTTP Redirects from non app initiated requests are marked app initiated >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index 1f1359bdf69613a86f6c042d028600a198cd1530..ba7e445c155dad2a78b6feed6377b038470464a4 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,15 @@ >+2021-08-19 Chris Dumez <cdumez@apple.com> >+ >+ Unable to postMessage a WebAssembly module to a worklet >+ https://bugs.webkit.org/show_bug.cgi?id=220038 >+ <rdar://problem/72596556> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Rebaseline WPT test that is now passing. >+ >+ * web-platform-tests/wasm/serialization/module/window-messagechannel-success-expected.txt: >+ > 2021-08-19 Tim Nguyen <ntim@apple.com> > > Implement ::backdrop pseudo element >diff --git a/LayoutTests/fast/storage/serialized-script-value.html b/LayoutTests/fast/storage/serialized-script-value.html >index eb1663fb00c4e579ef7f62b7be53ec4947c22fbf..554a02df17ad500d1aa03346720f623fca791441 100644 >--- a/LayoutTests/fast/storage/serialized-script-value.html >+++ b/LayoutTests/fast/storage/serialized-script-value.html >@@ -6,7 +6,7 @@ > <body> > <script> > >-const currentVersion = 0x08; >+const currentVersion = 0x09; > > // Here's a little Q&D helper for future adventurers needing to rebaseline this. > >diff --git a/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-wasm-module.https-expected.txt b/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-wasm-module.https-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..92748894f93e8b1a064258cc1aad20bf0acebb06 >--- /dev/null >+++ b/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-wasm-module.https-expected.txt >@@ -0,0 +1,9 @@ >+ >+PASS # AUDIT TASK RUNNER STARTED. >+PASS Executing "Test postMessage from AudioWorkletProcessor to AudioWorkletNode" >+PASS Audit report >+PASS > [Test postMessage from AudioWorkletProcessor to AudioWorkletNode] >+PASS event.module from main thread is an valid WASM module is true. >+PASS < [Test postMessage from AudioWorkletProcessor to AudioWorkletNode] All assertions passed. (total 1 assertions) >+PASS # AUDIT TASK RUNNER FINISHED: 1 tasks ran successfully. >+ >diff --git a/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-wasm-module.https.html b/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-wasm-module.https.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f2313676ab792e1cd6b5d9c2b8953173db2d68dc >--- /dev/null >+++ b/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-wasm-module.https.html >@@ -0,0 +1,74 @@ >+<!DOCTYPE html> >+<html> >+ <head> >+ <title> >+ Test passing WASM module to an AudioWorklet >+ </title> >+ <meta charset="utf-8"> >+ <script src="/resources/testharness.js"></script> >+ <script src="/resources/testharnessreport.js"></script> >+ <script src="/webaudio/resources/audit.js"></script> >+ </head> >+ <body> >+ <script id="layout-test-code"> >+ let audit = Audit.createTaskRunner(); >+ >+ let context = new AudioContext(); >+ let module = null; >+ >+ let filePath = 'processors/wasm-module-processor.js'; >+ >+ function createWasmModule() { >+ return fetch('/wasm/serialization/module/resources/incrementer.wasm') >+ .then(response => { >+ if (!response.ok) >+ throw new Error(response.statusText); >+ return response.arrayBuffer(); >+ }) >+ .then(WebAssembly.compile); >+ } >+ >+ audit.define( >+ 'Test postMessage from AudioWorkletProcessor to AudioWorkletNode', >+ (task, should) => { >+ let workletNode = >+ new AudioWorkletNode(context, 'wasm-module-processor'); >+ >+ workletNode.port.onmessage = (event) => { >+ let data = event.data; >+ switch (data.state) { >+ case 'created': >+ // Send a WASM module back to the worklet. >+ createWasmModule().then(module => { >+ workletNode.port.postMessage({ message: "send module", module }); >+ }); >+ break; >+ >+ case 'received message': >+ should(data.isValidModule, 'event.module from main thread is an valid WASM module') >+ .beTrue(); >+ task.done(); >+ break; >+ >+ default: >+ should(false, >+ `Got unexpected message from worklet: ${data.state}`) >+ .beTrue(); >+ task.done(); >+ break; >+ } >+ }; >+ >+ workletNode.port.onmessageerror = (event) => { >+ should(false, 'Got messageerror from worklet').beTrue(); >+ task.done(); >+ }; >+ }); >+ >+ context.audioWorklet.addModule(filePath).then(() => { >+ audit.run(); >+ }); >+ </script> >+ </body> >+</html> >+ >diff --git a/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/processors/wasm-module-processor.js b/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/processors/wasm-module-processor.js >new file mode 100644 >index 0000000000000000000000000000000000000000..6f67884be42dd636b7bde57d436d061121fe1301 >--- /dev/null >+++ b/LayoutTests/http/wpt/webaudio/the-audio-api/the-audioworklet-interface/processors/wasm-module-processor.js >@@ -0,0 +1,47 @@ >+/** >+ * @class WASMModuleProcessor >+ * @extends AudioWorkletProcessor >+ * >+ * This processor class demonstrates passing WASM modules to and from >+ * audio worklets. >+ */ >+class WASMModuleProcessor extends AudioWorkletProcessor { >+ constructor() { >+ super(); >+ this.port.onmessage = this.handleMessage.bind(this); >+ this.port.onmessageerror = this.handleMessageError.bind(this); >+ this.port.postMessage({state: 'created'}); >+ } >+ >+ testModule(module) { >+ try { >+ let instance = new WebAssembly.Instance(module); >+ let increment = instance.exports["increment"]; >+ if (typeof increment != "function") >+ return false; >+ let result = increment(42); >+ return result == 43; >+ } catch (e) { >+ return false; >+ } >+ } >+ >+ handleMessage(event) { >+ this.port.postMessage({ >+ state: 'received message', >+ isValidModule: this.testModule(event.data.module) >+ }); >+ } >+ >+ handleMessageError(event) { >+ this.port.postMessage({ >+ state: 'received messageerror' >+ }); >+ } >+ >+ process() { >+ return true; >+ } >+} >+ >+registerProcessor('wasm-module-processor', WASMModuleProcessor); >diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/serialization/module/window-messagechannel-success-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/serialization/module/window-messagechannel-success-expected.txt >index d30b7e6e27e62da4cc35295e328aa54b76465af1..0ace1e6f629357510fd36696f1caa760dbe34f5d 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/wasm/serialization/module/window-messagechannel-success-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/serialization/module/window-messagechannel-success-expected.txt >@@ -1,3 +1,3 @@ > >-FAIL postMessaging to a dedicated worker via MessageChannel allows them to instantiate promise_test: Unhandled rejection with value: object "DataCloneError: The object can not be cloned." >+PASS postMessaging to a dedicated worker via MessageChannel allows them to instantiate >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 220038
:
418682
|
435429
|
435798
|
435799
|
435812
|
435820
|
435860
|
435862
|
435865
|
435882
|
436196
|
436207