Title: [277250] trunk
Revision
277250
Author
[email protected]
Date
2021-05-09 11:57:20 -0700 (Sun, 09 May 2021)

Log Message

IPC testing API should have the ability to send and receive shared memory
https://bugs.webkit.org/show_bug.cgi?id=225576

Reviewed by Wenson Hsieh.

Source/WebKit:

This patch adds the capability to send & receive shared memory for IPC testing purposes.
It adds IPC.createSharedMemory which creates a _javascript_ object representing a newly
allocated IPC-sharable memory. It has readBytes and writeBytes methods. Both takes offset
and the number of bytes to read / write. readBytes will return a new ArrayBuffer and
writeBytes takes an ArrayBuffer or a typed array as the first argument.

IPC.sendMessage and IPC.sendSyncMessage now supprts encoding this SharedMemory _javascript_
object. It supports the type specific arguments of "protection" and "dataSize" in addition
to the regular "value" property for the SharedMemory object.

This patch also adds the support for sending Semaphore object over IPC created via
IPC.createSemaphore, which was supposed to be added in r277199.

Finally, this patch also exposes the VM page size via IPC.vmPageSize to facilitate
the allocation of a sharable memory of an interesting size for testing purposes.

Tests: TestWebKitAPI.IPCTestingAPI.CanReceiveSharedMemory
       TestWebKitAPI.IPCTestingAPI.CanCreateSharedMemory
       TestWebKitAPI.IPCTestingAPI.CanSendSemaphpre
       TestWebKitAPI.IPCTestingAPI.CanSendSharedMemory

* GPUProcess/graphics/RemoteRenderingBackend.cpp:
(WebKit::RemoteRenderingBackend::updateSharedMemoryForGetImageData): Use uint32_t instead
of size_t since the latter depends on the specific architecture (e.g. 32-bit vs 64-bit).
(WebKit::RemoteRenderingBackend::updateSharedMemoryAndSemaphoreForGetImageData): Ditto.
* GPUProcess/graphics/RemoteRenderingBackend.h:
* GPUProcess/graphics/RemoteRenderingBackend.messages.in: Ditto.
* Platform/IPC/JSIPCBinding.h: Added a specialization for SharedMemory::IPCHandle.
* WebProcess/WebPage/IPCTestingAPI.cpp:
(WebKit::IPCTestingAPI::JSIPCSemaphore::encode const): Added.
(WebKit::IPCTestingAPI::JSSharedMemory): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::create): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::size): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::JSSharedMemory): Added.
(WebKit::IPCTestingAPI::convertToUint64): Moved up here.
(WebKit::IPCTestingAPI::JSIPCSemaphore::signal): Fixed a typo.
(WebKit::IPCTestingAPI::JSIPCSemaphore::waitFor): Ditto.
(WebKit::IPCTestingAPI::JSSharedMemory::createHandle): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::createJSWrapper): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::wrapperClass): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::unwrap): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::toWrapped): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::initialize): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::finalize): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::staticFunctions): Added.
(WebKit::IPCTestingAPI::JSSharedMemory::readBytes): Added.
(WebKit::IPCTestingAPI::arrayBufferDataFromValueRef): Extracted out of encodeTypedArray.
(WebKit::IPCTestingAPI::JSSharedMemory::writeBytes): Added.
(WebKit::IPCTestingAPI::JSIPC::staticFunctions): Added IPC.createSharedMemory.
(WebKit::IPCTestingAPI::JSIPC::staticValues): Added IPC.vmPageSize.
(WebKit::IPCTestingAPI::encodeTypedArray):
(WebKit::IPCTestingAPI::getObjectIdentifierFromProperty): Now uses convertToUint64.
(WebKit::IPCTestingAPI::encodeSharedMemory): Added.
(WebKit::IPCTestingAPI::encodeSemaphore): Added.
(WebKit::IPCTestingAPI::encodeArgument): Added the support for encoding SharedMemory and
Semaphore.
(WebKit::IPCTestingAPI::JSIPC::createSharedMemory): Added.
(WebKit::IPCTestingAPI::JSIPC::vmPageSize): Added.
(IPC::jsValueForDecodedArgumentValue): Added. Creates a newly added SharedMemory _javascript_
object for SharedMemory::IPCHandle. It also exposes dataSize and protection value.
This decoder detects whether the shared memory is writable or not by attempting to map it
as Protection::ReadWrite and falling back to Protection::ReadOnly if the former fails.

Tools:

Added tests for sending and receiving shared memory in the IPC testing API.
Also added a test to send semaphore, which was missing in r277199.

* TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm:
(IPCTestingAPI.CanReceiveSharedMemory): Added.
(IPCTestingAPI.CanCreateSharedMemory): Added.
(IPCTestingAPI.CanSendSemaphpre): Added after r277199.
(IPCTestingAPI.CanSendSharedMemory): Added.

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (277249 => 277250)


--- trunk/Source/WebKit/ChangeLog	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Source/WebKit/ChangeLog	2021-05-09 18:57:20 UTC (rev 277250)
@@ -1,3 +1,73 @@
+2021-05-09  Ryosuke Niwa  <[email protected]>
+
+        IPC testing API should have the ability to send and receive shared memory
+        https://bugs.webkit.org/show_bug.cgi?id=225576
+
+        Reviewed by Wenson Hsieh.
+
+        This patch adds the capability to send & receive shared memory for IPC testing purposes.
+        It adds IPC.createSharedMemory which creates a _javascript_ object representing a newly
+        allocated IPC-sharable memory. It has readBytes and writeBytes methods. Both takes offset
+        and the number of bytes to read / write. readBytes will return a new ArrayBuffer and
+        writeBytes takes an ArrayBuffer or a typed array as the first argument.
+
+        IPC.sendMessage and IPC.sendSyncMessage now supprts encoding this SharedMemory _javascript_
+        object. It supports the type specific arguments of "protection" and "dataSize" in addition
+        to the regular "value" property for the SharedMemory object.
+
+        This patch also adds the support for sending Semaphore object over IPC created via
+        IPC.createSemaphore, which was supposed to be added in r277199.
+
+        Finally, this patch also exposes the VM page size via IPC.vmPageSize to facilitate
+        the allocation of a sharable memory of an interesting size for testing purposes.
+
+        Tests: TestWebKitAPI.IPCTestingAPI.CanReceiveSharedMemory
+               TestWebKitAPI.IPCTestingAPI.CanCreateSharedMemory
+               TestWebKitAPI.IPCTestingAPI.CanSendSemaphpre
+               TestWebKitAPI.IPCTestingAPI.CanSendSharedMemory
+
+        * GPUProcess/graphics/RemoteRenderingBackend.cpp:
+        (WebKit::RemoteRenderingBackend::updateSharedMemoryForGetImageData): Use uint32_t instead
+        of size_t since the latter depends on the specific architecture (e.g. 32-bit vs 64-bit).
+        (WebKit::RemoteRenderingBackend::updateSharedMemoryAndSemaphoreForGetImageData): Ditto.
+        * GPUProcess/graphics/RemoteRenderingBackend.h:
+        * GPUProcess/graphics/RemoteRenderingBackend.messages.in: Ditto.
+        * Platform/IPC/JSIPCBinding.h: Added a specialization for SharedMemory::IPCHandle.
+        * WebProcess/WebPage/IPCTestingAPI.cpp:
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::encode const): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::create): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::size): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::JSSharedMemory): Added.
+        (WebKit::IPCTestingAPI::convertToUint64): Moved up here.
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::signal): Fixed a typo.
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::waitFor): Ditto.
+        (WebKit::IPCTestingAPI::JSSharedMemory::createHandle): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::createJSWrapper): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::wrapperClass): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::unwrap): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::toWrapped): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::initialize): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::finalize): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::staticFunctions): Added.
+        (WebKit::IPCTestingAPI::JSSharedMemory::readBytes): Added.
+        (WebKit::IPCTestingAPI::arrayBufferDataFromValueRef): Extracted out of encodeTypedArray.
+        (WebKit::IPCTestingAPI::JSSharedMemory::writeBytes): Added.
+        (WebKit::IPCTestingAPI::JSIPC::staticFunctions): Added IPC.createSharedMemory.
+        (WebKit::IPCTestingAPI::JSIPC::staticValues): Added IPC.vmPageSize.
+        (WebKit::IPCTestingAPI::encodeTypedArray): 
+        (WebKit::IPCTestingAPI::getObjectIdentifierFromProperty): Now uses convertToUint64.
+        (WebKit::IPCTestingAPI::encodeSharedMemory): Added.
+        (WebKit::IPCTestingAPI::encodeSemaphore): Added.
+        (WebKit::IPCTestingAPI::encodeArgument): Added the support for encoding SharedMemory and
+        Semaphore.
+        (WebKit::IPCTestingAPI::JSIPC::createSharedMemory): Added.
+        (WebKit::IPCTestingAPI::JSIPC::vmPageSize): Added.
+        (IPC::jsValueForDecodedArgumentValue): Added. Creates a newly added SharedMemory _javascript_
+        object for SharedMemory::IPCHandle. It also exposes dataSize and protection value.
+        This decoder detects whether the shared memory is writable or not by attempting to map it
+        as Protection::ReadWrite and falling back to Protection::ReadOnly if the former fails.
+
 2021-05-09  Myles C. Maxfield  <[email protected]>
 
         [GPU Process] Simplify DisplayList::Iterator part 6: Migrate ItemBufferWritingClient from ItemHandle to a const Variant&

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp (277249 => 277250)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp	2021-05-09 18:57:20 UTC (rev 277250)
@@ -332,7 +332,7 @@
     return SharedMemory::IPCHandle { WTFMove(handle), m_getImageDataSharedMemory ? m_getImageDataSharedMemory->size() : 0 };
 }
 
-void RemoteRenderingBackend::updateSharedMemoryForGetImageData(size_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&)>&& completionHandler)
+void RemoteRenderingBackend::updateSharedMemoryForGetImageData(uint32_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&)>&& completionHandler)
 {
     ASSERT(!RunLoop::isMain());
 
@@ -348,7 +348,7 @@
     completionHandler(m_getImageDataSemaphore);
 }
 
-void RemoteRenderingBackend::updateSharedMemoryAndSemaphoreForGetImageData(size_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&, const IPC::Semaphore&)>&& completionHandler)
+void RemoteRenderingBackend::updateSharedMemoryAndSemaphoreForGetImageData(uint32_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&, const IPC::Semaphore&)>&& completionHandler)
 {
     ASSERT(!RunLoop::isMain());
 

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h (277249 => 277250)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h	2021-05-09 18:57:20 UTC (rev 277250)
@@ -123,9 +123,9 @@
     // Messages to be received.
     void createImageBuffer(const WebCore::FloatSize& logicalSize, WebCore::RenderingMode, float resolutionScale, WebCore::DestinationColorSpace, WebCore::PixelFormat, WebCore::RenderingResourceIdentifier);
     void wakeUpAndApplyDisplayList(const GPUProcessWakeupMessageArguments&);
-    void updateSharedMemoryForGetImageData(size_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&)>&&);
+    void updateSharedMemoryForGetImageData(uint32_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&)>&&);
     void semaphoreForGetImageData(CompletionHandler<void(const IPC::Semaphore&)>&&);
-    void updateSharedMemoryAndSemaphoreForGetImageData(size_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&, const IPC::Semaphore&)>&&);
+    void updateSharedMemoryAndSemaphoreForGetImageData(uint32_t byteCount, CompletionHandler<void(const SharedMemory::IPCHandle&, const IPC::Semaphore&)>&&);
     void destroyGetImageDataSharedMemory();
     void getDataURLForImageBuffer(const String& mimeType, Optional<double> quality, WebCore::PreserveResolution, WebCore::RenderingResourceIdentifier, CompletionHandler<void(String&&)>&&);
     void getDataForImageBuffer(const String& mimeType, Optional<double> quality, WebCore::RenderingResourceIdentifier, CompletionHandler<void(Vector<uint8_t>&&)>&&);

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.messages.in (277249 => 277250)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.messages.in	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.messages.in	2021-05-09 18:57:20 UTC (rev 277250)
@@ -25,9 +25,9 @@
 messages -> RemoteRenderingBackend {
     CreateImageBuffer(WebCore::FloatSize logicalSize, WebCore::RenderingMode renderingMode, float resolutionScale, WebCore::DestinationColorSpace colorSpace, enum:uint8_t WebCore::PixelFormat pixelFormat, WebCore::RenderingResourceIdentifier renderingResourceIdentifier)
     WakeUpAndApplyDisplayList(struct WebKit::GPUProcessWakeupMessageArguments arguments)
-    UpdateSharedMemoryForGetImageData(size_t byteCount) -> (WebKit::SharedMemory::IPCHandle handle) Synchronous
+    UpdateSharedMemoryForGetImageData(uint32_t byteCount) -> (WebKit::SharedMemory::IPCHandle handle) Synchronous
     SemaphoreForGetImageData() -> (IPC::Semaphore semaphore) Synchronous
-    UpdateSharedMemoryAndSemaphoreForGetImageData(size_t byteCount) -> (WebKit::SharedMemory::IPCHandle handle, IPC::Semaphore semaphore) Synchronous
+    UpdateSharedMemoryAndSemaphoreForGetImageData(uint32_t byteCount) -> (WebKit::SharedMemory::IPCHandle handle, IPC::Semaphore semaphore) Synchronous
     DestroyGetImageDataSharedMemory()
     GetDataURLForImageBuffer(String mimeType, Optional<double> quality, enum:uint8_t WebCore::PreserveResolution preserveResolution, WebCore::RenderingResourceIdentifier renderingResourceIdentifier) -> (String urlString) Synchronous
     GetDataForImageBuffer(String mimeType, Optional<double> quality, WebCore::RenderingResourceIdentifier renderingResourceIdentifier) -> (Vector<uint8_t> data) Synchronous

Modified: trunk/Source/WebKit/Platform/IPC/JSIPCBinding.h (277249 => 277250)


--- trunk/Source/WebKit/Platform/IPC/JSIPCBinding.h	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Source/WebKit/Platform/IPC/JSIPCBinding.h	2021-05-09 18:57:20 UTC (rev 277250)
@@ -29,6 +29,7 @@
 
 #include "Decoder.h"
 #include "HandleMessage.h"
+#include "SharedMemory.h"
 #include <_javascript_Core/JSArray.h>
 #include <_javascript_Core/JSArrayBuffer.h>
 #include <_javascript_Core/JSGlobalObject.h>
@@ -66,6 +67,7 @@
 template<> JSC::JSValue jsValueForDecodedArgumentValue(JSC::JSGlobalObject*, WebCore::RegistrableDomain&&);
 
 template<> JSC::JSValue jsValueForDecodedArgumentValue(JSC::JSGlobalObject*, IPC::Semaphore&&);
+template<> JSC::JSValue jsValueForDecodedArgumentValue(JSC::JSGlobalObject*, WebKit::SharedMemory::IPCHandle&&);
 
 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value>* = nullptr>
 JSC::JSValue jsValueForDecodedArgumentValue(JSC::JSGlobalObject*, T)

Modified: trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp (277249 => 277250)


--- trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp	2021-05-09 18:57:20 UTC (rev 277250)
@@ -67,9 +67,9 @@
     }
 
     JSObjectRef createJSWrapper(JSContextRef);
-
     static JSIPCSemaphore* toWrapped(JSContextRef, JSValueRef);
 
+    void encode(IPC::Encoder& encoder) const { m_semaphore.encode(encoder); }
     IPC::Semaphore exchange(IPC::Semaphore&& semaphore = { })
     {
         return std::exchange(m_semaphore, WTFMove(semaphore));
@@ -93,6 +93,47 @@
     IPC::Semaphore m_semaphore;
 };
 
+class JSSharedMemory : public RefCounted<JSSharedMemory> {
+public:
+    static Ref<JSSharedMemory> create(size_t size)
+    {
+        return adoptRef(*new JSSharedMemory(size));
+    }
+
+    static Ref<JSSharedMemory> create(Ref<SharedMemory>&& sharedMemory)
+    {
+        return adoptRef(*new JSSharedMemory(WTFMove(sharedMemory)));
+    }
+
+    size_t size() const { return m_sharedMemory->size(); }
+    SharedMemory::Handle createHandle(SharedMemory::Protection);
+
+    JSObjectRef createJSWrapper(JSContextRef);
+    static JSSharedMemory* toWrapped(JSContextRef, JSValueRef);
+
+private:
+    JSSharedMemory(size_t size)
+        : m_sharedMemory(*SharedMemory::allocate(size))
+    { }
+
+    JSSharedMemory(Ref<SharedMemory>&& sharedMemory)
+        : m_sharedMemory(WTFMove(sharedMemory))
+    {
+    }
+
+    static JSClassRef wrapperClass();
+    static JSSharedMemory* unwrap(JSObjectRef);
+    static void initialize(JSContextRef, JSObjectRef);
+    static void finalize(JSObjectRef);
+
+    static const JSStaticFunction* staticFunctions();
+
+    static JSValueRef readBytes(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+    static JSValueRef writeBytes(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+
+    Ref<SharedMemory> m_sharedMemory;
+};
+
 class JSIPC;
 
 class JSMessageListener final : public IPC::Connection::MessageObserver {
@@ -145,7 +186,9 @@
     static JSValueRef sendSyncMessage(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
 
     static JSValueRef createSemaphore(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+    static JSValueRef createSharedMemory(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
 
+    static JSValueRef vmPageSize(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
     static JSValueRef visitedLinkStoreID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
     static JSValueRef webPageProxyID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
     static JSValueRef sessionID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
@@ -166,6 +209,19 @@
     return toRef(JSC::createTypeError(toJS(context), message));
 }
 
+static Optional<uint64_t> convertToUint64(JSC::JSValue jsValue)
+{
+    if (jsValue.isNumber()) {
+        double value = jsValue.asNumber();
+        if (value < 0 || trunc(value) != value)
+            return WTF::nullopt;
+        return value;
+    }
+    if (jsValue.isBigInt())
+        return JSC::JSBigInt::toBigUInt64(jsValue);
+    return WTF::nullopt;
+}
+
 JSObjectRef JSIPCSemaphore::createJSWrapper(JSContextRef context)
 {
     auto* globalObject = toJS(context);
@@ -202,7 +258,7 @@
 {
     if (!context || !value || !JSValueIsObjectOfClass(context, value, wrapperClass()))
         return nullptr;
-    return unwrap(JSValueToObject(context, value, 0));
+    return unwrap(JSValueToObject(context, value, nullptr));
 }
 
 void JSIPCSemaphore::initialize(JSContextRef, JSObjectRef object)
@@ -229,13 +285,13 @@
 {
     auto* globalObject = toJS(context);
     JSC::JSLockHolder lock(globalObject->vm());
-    auto isIPCSemaphore = makeRefPtr(toWrapped(context, thisObject));
-    if (!isIPCSemaphore) {
+    auto jsIPCSemaphore = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsIPCSemaphore) {
         *exception = createTypeError(context, "Wrong type"_s);
         return JSValueMakeUndefined(context);
     }
 
-    isIPCSemaphore->m_semaphore.signal();
+    jsIPCSemaphore->m_semaphore.signal();
 
     return JSValueMakeUndefined(context);
 }
@@ -244,8 +300,8 @@
 {
     auto* globalObject = toJS(context);
     JSC::JSLockHolder lock(globalObject->vm());
-    auto isIPCSemaphore = makeRefPtr(toWrapped(context, thisObject));
-    if (!isIPCSemaphore) {
+    auto jsIPCSemaphore = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsIPCSemaphore) {
         *exception = createTypeError(context, "Wrong type"_s);
         return JSValueMakeUndefined(context);
     }
@@ -267,11 +323,214 @@
         return JSValueMakeUndefined(context);
     }
 
-    auto result = isIPCSemaphore->m_semaphore.waitFor(timeout);
+    auto result = jsIPCSemaphore->m_semaphore.waitFor(timeout);
 
     return JSValueMakeBoolean(context, result);
 }
 
+SharedMemory::Handle JSSharedMemory::createHandle(SharedMemory::Protection protection)
+{
+    SharedMemory::Handle handle;
+    m_sharedMemory->createHandle(handle, protection);
+    return handle;
+}
+
+JSObjectRef JSSharedMemory::createJSWrapper(JSContextRef context)
+{
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    JSObjectRef wrapperObject = JSObjectMake(toGlobalRef(globalObject), wrapperClass(), this);
+    scope.clearException();
+    return wrapperObject;
+}
+
+JSClassRef JSSharedMemory::wrapperClass()
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.className = "SharedMemory";
+        definition.parentClass = nullptr;
+        definition.staticValues = nullptr;
+        definition.staticFunctions = staticFunctions();
+        definition.initialize = initialize;
+        definition.finalize = finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+inline JSSharedMemory* JSSharedMemory::unwrap(JSObjectRef object)
+{
+    return static_cast<JSSharedMemory*>(JSObjectGetPrivate(object));
+}
+
+JSSharedMemory* JSSharedMemory::toWrapped(JSContextRef context, JSValueRef value)
+{
+    if (!context || !value || !JSValueIsObjectOfClass(context, value, wrapperClass()))
+        return nullptr;
+    return unwrap(JSValueToObject(context, value, 0));
+}
+
+void JSSharedMemory::initialize(JSContextRef, JSObjectRef object)
+{
+    unwrap(object)->ref();
+}
+
+void JSSharedMemory::finalize(JSObjectRef object)
+{
+    unwrap(object)->deref();
+}
+
+const JSStaticFunction* JSSharedMemory::staticFunctions()
+{
+    static const JSStaticFunction functions[] = {
+        { "readBytes", readBytes, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "writeBytes", writeBytes, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { 0, 0, 0 }
+    };
+    return functions;
+}
+
+JSValueRef JSSharedMemory::readBytes(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    auto jsSharedMemory = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsSharedMemory) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    size_t offset = 0;
+    size_t length = jsSharedMemory->m_sharedMemory->size();
+
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    if (argumentCount) {
+        auto offsetValue = convertToUint64(toJS(globalObject, arguments[0]));
+        if (!offsetValue) {
+            *exception = createTypeError(context, "The first argument must be a byte offset to read"_s);
+            return JSValueMakeUndefined(context);
+        }
+        if (*offsetValue > length)
+            offset = length;
+        else
+            offset = *offsetValue;
+        length -= offset;
+    }
+
+    if (argumentCount > 1) {
+        auto lengthValue = convertToUint64(toJS(globalObject, arguments[1]));
+        if (!lengthValue) {
+            *exception = createTypeError(context, "The second argument must be the number of bytes to read"_s);
+            return JSValueMakeUndefined(context);
+        }
+        if (*lengthValue < length)
+            length = *lengthValue;
+    }
+
+    auto arrayBuffer = JSC::ArrayBuffer::create(static_cast<uint8_t*>(jsSharedMemory->m_sharedMemory->data()) + offset, length);
+    JSC::JSArrayBuffer* jsArrayBuffer = nullptr;
+    if (auto* structure = globalObject->arrayBufferStructure(arrayBuffer->sharingMode()))
+        jsArrayBuffer = JSC::JSArrayBuffer::create(vm, structure, WTFMove(arrayBuffer));
+    if (!jsArrayBuffer) {
+        *exception = createTypeError(context, "Failed to create the array buffer for the read bytes"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    return toRef(jsArrayBuffer);
+}
+
+struct ArrayBufferData {
+    void* buffer { nullptr };
+    size_t length { 0 };
+};
+
+static ArrayBufferData arrayBufferDataFromValueRef(JSContextRef context, JSTypedArrayType type, JSValueRef valueRef, JSValueRef* exception)
+{
+    auto objectRef = JSValueToObject(context, valueRef, exception);
+    if (!objectRef)
+        return { };
+
+    void* buffer = nullptr;
+    if (type == kJSTypedArrayTypeArrayBuffer)
+        buffer = JSObjectGetArrayBufferBytesPtr(context, objectRef, exception);
+    else
+        buffer = JSObjectGetTypedArrayBytesPtr(context, objectRef, exception);
+
+    if (!buffer)
+        return { };
+
+    size_t length;
+    if (type == kJSTypedArrayTypeArrayBuffer)
+        length = JSObjectGetArrayBufferByteLength(context, objectRef, exception);
+    else
+        length = JSObjectGetTypedArrayByteLength(context, objectRef, exception);
+
+    return { buffer, length };
+}
+
+JSValueRef JSSharedMemory::writeBytes(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    auto jsSharedMemory = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsSharedMemory) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    auto type = argumentCount ? JSValueGetTypedArrayType(context, arguments[0], exception) : kJSTypedArrayTypeNone;
+    if (type == kJSTypedArrayTypeNone) {
+        *exception = createTypeError(context, "The first argument must be an array buffer or a typed array"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    auto data = "" type, arguments[0], exception);
+    if (!data.buffer) {
+        *exception = createTypeError(context, "Could not read the buffer"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    size_t offset = 0;
+    size_t length = data.length;
+    size_t sharedMemorySize = jsSharedMemory->m_sharedMemory->size();
+
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+
+    if (argumentCount > 1) {
+        auto offsetValue = convertToUint64(toJS(globalObject, arguments[1]));
+        if (!offsetValue) {
+            *exception = createTypeError(context, "The second argument must be a byte offset to write"_s);
+            return JSValueMakeUndefined(context);
+        }
+        if (*offsetValue >= sharedMemorySize) {
+            *exception = createTypeError(context, "Offset is too big"_s);
+            return JSValueMakeUndefined(context);
+        }
+        offset = *offsetValue;
+    }
+
+    if (argumentCount > 2) {
+        auto lengthValue = convertToUint64(toJS(globalObject, arguments[2]));
+        if (!lengthValue) {
+            *exception = createTypeError(context, "The third argument must be the number of bytes to write"_s);
+            return JSValueMakeUndefined(context);
+        }
+        if (*lengthValue >= sharedMemorySize - offset || *lengthValue > length) {
+            *exception = createTypeError(context, "The number of bytes to write is too big"_s);
+            return JSValueMakeUndefined(context);
+        }
+        length = *lengthValue;
+    }
+
+    memcpy(static_cast<uint8_t*>(jsSharedMemory->m_sharedMemory->data()) + offset, data.buffer, length);
+
+    return JSValueMakeUndefined(context);
+}
+
 JSClassRef JSIPC::wrapperClass()
 {
     static JSClassRef jsClass;
@@ -318,6 +577,7 @@
         { "sendMessage", sendMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "sendSyncMessage", sendSyncMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "createSemaphore", createSemaphore, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "createSharedMemory", createSharedMemory, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { 0, 0, 0 }
     };
     return functions;
@@ -326,6 +586,7 @@
 const JSStaticValue* JSIPC::staticValues()
 {
     static const JSStaticValue values[] = {
+        { "vmPageSize", vmPageSize, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "visitedLinkStoreID", visitedLinkStoreID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "frameID", frameID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "pageID", pageID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
@@ -337,19 +598,6 @@
     return values;
 }
 
-static Optional<uint64_t> convertToUint64(JSC::JSValue jsValue)
-{
-    if (jsValue.isNumber()) {
-        double value = jsValue.asNumber();
-        if (value < 0 || trunc(value) != value)
-            return WTF::nullopt;
-        return value;
-    }
-    if (jsValue.isBigInt())
-        return JSC::JSBigInt::toBigUInt64(jsValue);
-    return WTF::nullopt;
-}
-
 static RefPtr<IPC::Connection> processTargetFromArgument(JSC::JSGlobalObject* globalObject, JSValueRef valueRef, JSValueRef* exception)
 {
     auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
@@ -439,27 +687,11 @@
 {
     ASSERT(type != kJSTypedArrayTypeNone);
 
-    auto objectRef = JSValueToObject(context, valueRef, exception);
-    if (!objectRef)
+    auto data = "" type, valueRef, exception);
+    if (!data.buffer)
         return false;
 
-    void* buffer;
-    if (type == kJSTypedArrayTypeArrayBuffer)
-        buffer = JSObjectGetArrayBufferBytesPtr(context, objectRef, exception);
-    else
-        buffer = JSObjectGetTypedArrayBytesPtr(context, objectRef, exception);
-    if (!buffer)
-        return false;
-
-    size_t bufferSize;
-    if (type == kJSTypedArrayTypeArrayBuffer)
-        bufferSize = JSObjectGetArrayBufferByteLength(context, objectRef, exception);
-    else
-        bufferSize = JSObjectGetTypedArrayByteLength(context, objectRef, exception);
-    if (!bufferSize)
-        return false;
-
-    encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(buffer), bufferSize, 1);
+    encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(data.buffer), data.length, 1);
     return true;
 }
 
@@ -517,11 +749,10 @@
     auto jsPropertyValue = jsObject->get(globalObject, JSC::Identifier::fromString(globalObject->vm(), propertyName));
     if (scope.exception())
         return WTF::nullopt;
-    if (jsPropertyValue.isBigInt()) 
-        return makeObjectIdentifier<ObjectIdentifierType>(JSC::JSBigInt::toBigUInt64(jsPropertyValue));
-    if (jsPropertyValue.isNumber())
-        return makeObjectIdentifier<ObjectIdentifierType>(jsPropertyValue.asNumber());
-    return WTF::nullopt;
+    auto number = convertToUint64(jsPropertyValue);
+    if (!number)
+        return WTF::nullopt;
+    return makeObjectIdentifier<ObjectIdentifierType>(*number);
 }
 
 static bool encodeRemoteRenderingBackendCreationParameters(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject, JSC::CatchScope& scope)
@@ -553,6 +784,53 @@
 }
 #endif
 
+static bool encodeSharedMemory(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject, JSC::CatchScope& scope)
+{
+    auto jsSharedMemoryValue = jsObject->get(globalObject, JSC::Identifier::fromString(globalObject->vm(), "value"_s));
+    if (scope.exception())
+        return false;
+    auto jsSharedMemory = makeRefPtr(JSSharedMemory::toWrapped(toRef(globalObject), toRef(jsSharedMemoryValue)));
+    if (!jsSharedMemory)
+        return false;
+
+    uint32_t dataSize = jsSharedMemory->size();
+
+    auto jsDataSizeValue = jsObject->get(globalObject, JSC::Identifier::fromString(globalObject->vm(), "dataSize"_s));
+    if (scope.exception())
+        return false;
+    if (!jsDataSizeValue.isUndefined()) {
+        if (auto dataSizeValue = convertToUint64(jsDataSizeValue))
+            dataSize = *dataSizeValue;
+    }
+
+    auto jsProtectionValue = jsObject->get(globalObject, JSC::Identifier::fromString(globalObject->vm(), "protection"_s));
+    if (scope.exception())
+        return false;
+    if (jsProtectionValue.isUndefined())
+        return false;
+    auto protectionValue = jsProtectionValue.toWTFString(globalObject);
+    if (scope.exception())
+        return false;
+    auto protection = SharedMemory::Protection::ReadWrite;
+    if (equalLettersIgnoringASCIICase(protectionValue, "readonly"))
+        protection = SharedMemory::Protection::ReadOnly;
+    else if (equalLettersIgnoringASCIICase(protectionValue, "readwrite"))
+        return false;
+
+    encoder << SharedMemory::IPCHandle { jsSharedMemory->createHandle(protection), dataSize };
+    return true;
+}
+
+static bool encodeSemaphore(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSValue jsValue, JSC::CatchScope& scope)
+{
+    auto jsIPCSemaphore = makeRefPtr(JSIPCSemaphore::toWrapped(toRef(globalObject), toRef(jsValue)));
+    if (!jsIPCSemaphore)
+        return false;
+
+    jsIPCSemaphore->encode(encoder);
+    return true;
+}
+
 static bool encodeArgument(IPC::Encoder&, JSIPC&, JSContextRef, JSValueRef, JSValueRef* exception);
 
 struct VectorEncodeHelper {
@@ -675,6 +953,14 @@
     }
 #endif
 
+    if (type == "SharedMemory") {
+        if (!encodeSharedMemory(encoder, globalObject, jsObject, scope)) {
+            *exception = createTypeError(context, "Failed to convert SharedMemory"_s);
+            return false;
+        }
+        return true;
+    }
+
     if (type == "FrameInfoData") {
         auto webFrame = makeRefPtr(jsIPC.webFrame());
         if (!webFrame) {
@@ -689,6 +975,14 @@
     if (scope.exception())
         return false;
 
+    if (type == "Semaphore") {
+        if (!encodeSemaphore(encoder, globalObject, jsValue, scope)) {
+            *exception = createTypeError(context, "Failed to convert Semaphore"_s);
+            return false;
+        }
+        return true;
+    }
+
     if (type == "Vector") {
         if (!jsValue.isObject() || !jsValue.inherits<JSC::JSArray>(vm)) {
             *exception = createTypeError(context, "Vector value must be an array"_s);
@@ -965,6 +1259,36 @@
     return JSIPCSemaphore::create()->createJSWrapper(context);
 }
 
+JSValueRef JSIPC::createSharedMemory(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    if (!toWrapped(context, thisObject)) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+
+    auto size = argumentCount ? convertToUint64(toJS(globalObject, arguments[0])) : Optional<uint64_t> { };
+    if (!size) {
+        *exception = createTypeError(context, "Must specify the size"_s);
+        return JSValueMakeUndefined(context);
+    }
+
+    return JSSharedMemory::create(*size)->createJSWrapper(context);
+}
+
+JSValueRef JSIPC::vmPageSize(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
+{
+    auto jsIPC = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsIPC) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+    return JSValueMakeNumber(context, pageSize());
+}
+
 JSValueRef JSIPC::visitedLinkStoreID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
 {
     return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
@@ -1239,6 +1563,40 @@
     return object;
 }
 
+template<> JSC::JSValue jsValueForDecodedArgumentValue(JSC::JSGlobalObject* globalObject, WebKit::SharedMemory::IPCHandle&& value)
+{
+    using SharedMemory = WebKit::SharedMemory;
+    using Protection = WebKit::SharedMemory::Protection;
+
+    auto& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    auto* object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
+    RETURN_IF_EXCEPTION(scope, JSC::JSValue());
+    object->putDirect(vm, JSC::Identifier::fromString(vm, "type"_s), JSC::jsNontrivialString(vm, "SharedMemory"));
+    RETURN_IF_EXCEPTION(scope, JSC::JSValue());
+
+    auto protection = Protection::ReadWrite;
+    auto sharedMemory = SharedMemory::map(value.handle, protection);
+    if (!sharedMemory) {
+        protection = Protection::ReadOnly;
+        sharedMemory = SharedMemory::map(value.handle, protection);
+        if (!sharedMemory)
+            return JSC::JSValue();
+    }
+
+    auto jsValue = toJS(globalObject, WebKit::IPCTestingAPI::JSSharedMemory::create(sharedMemory.releaseNonNull())->createJSWrapper(toRef(globalObject)));
+    object->putDirect(vm, JSC::Identifier::fromString(vm, "value"_s), jsValue);
+    RETURN_IF_EXCEPTION(scope, JSC::JSValue());
+
+    object->putDirect(vm, JSC::Identifier::fromString(vm, "dataSize"_s), JSC::JSValue(value.dataSize));
+    RETURN_IF_EXCEPTION(scope, JSC::JSValue());
+
+    object->putDirect(vm, JSC::Identifier::fromString(vm, "protection"_s), JSC::jsNontrivialString(vm, protection == Protection::ReadWrite ? "ReadWrite" : "ReadOnly"));
+    RETURN_IF_EXCEPTION(scope, JSC::JSValue());
+
+    return object;
+}
+
 } // namespace IPC
 
 #endif

Modified: trunk/Tools/ChangeLog (277249 => 277250)


--- trunk/Tools/ChangeLog	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Tools/ChangeLog	2021-05-09 18:57:20 UTC (rev 277250)
@@ -1,3 +1,19 @@
+2021-05-09  Ryosuke Niwa  <[email protected]>
+
+        IPC testing API should have the ability to send and receive shared memory
+        https://bugs.webkit.org/show_bug.cgi?id=225576
+
+        Reviewed by Wenson Hsieh.
+
+        Added tests for sending and receiving shared memory in the IPC testing API.
+        Also added a test to send semaphore, which was missing in r277199.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm:
+        (IPCTestingAPI.CanReceiveSharedMemory): Added.
+        (IPCTestingAPI.CanCreateSharedMemory): Added.
+        (IPCTestingAPI.CanSendSemaphpre): Added after r277199.
+        (IPCTestingAPI.CanSendSharedMemory): Added.
+
 2021-05-09  Myles C. Maxfield  <[email protected]>
 
         [GPU Process] Simplify DisplayList::Iterator part 6: Migrate ItemBufferWritingClient from ItemHandle to a const Variant&

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm (277249 => 277250)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm	2021-05-09 18:54:10 UTC (rev 277249)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm	2021-05-09 18:57:20 UTC (rev 277250)
@@ -230,6 +230,32 @@
 
     EXPECT_STREQ([alertMessage UTF8String], "1:Semaphore:false");
 }
+
+TEST(IPCTestingAPI, CanReceiveSharedMemory)
+{
+    auto webView = createWebViewWithIPCTestingAPI();
+
+    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    auto* html = @R"HTML(<!DOCTYPE html>
+<script>
+IPC.sendMessage('GPU', 0, IPC.messages.GPUConnectionToWebProcess_CreateRenderingBackend.name,
+    [{type: 'RemoteRenderingBackendCreationParameters', 'identifier': 123, semaphore: IPC.createSemaphore(), 'pageProxyID': IPC.webPageProxyID, 'pageID': IPC.pageID}]);
+const result = IPC.sendSyncMessage('GPU', 123, IPC.messages.RemoteRenderingBackend_UpdateSharedMemoryForGetImageData.name, 100, [{type: 'uint32_t', value: 8}]);
+alert(result.arguments.length);
+</script>)HTML";
+
+    done = false;
+    [webView synchronouslyLoadHTMLString:html];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_EQ([alertMessage intValue], 1);
+    EXPECT_STREQ([webView stringByEvaluatingJavaScript:@"firstReply = result.arguments[0]; firstReply.type"].UTF8String, "SharedMemory");
+    EXPECT_STREQ([webView stringByEvaluatingJavaScript:@"firstReply.protection"].UTF8String, "ReadOnly");
+    EXPECT_STREQ([webView stringByEvaluatingJavaScript:@"Array.from(new Uint8Array(firstReply.value.readBytes(0, 8))).toString()"].UTF8String, "0,0,0,0,0,0,0,0");
+
+}
 #endif
 
 TEST(IPCTestingAPI, CanCreateIPCSemaphore)
@@ -246,6 +272,83 @@
     EXPECT_FALSE([alertMessage boolValue]);
 }
 
+TEST(IPCTestingAPI, CanCreateSharedMemory)
+{
+    auto webView = createWebViewWithIPCTestingAPI();
+
+    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    done = false;
+    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>const sharedMemory = IPC.createSharedMemory(8); alert(sharedMemory.toString());</script>"];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_STREQ([alertMessage UTF8String], "[object SharedMemory]");
+    EXPECT_EQ([webView stringByEvaluatingJavaScript:@"new Int8Array(sharedMemory.readBytes(0))[0]"].intValue, 0);
+    EXPECT_EQ([webView stringByEvaluatingJavaScript:@"sharedMemory.writeBytes(new Int8Array([1, 2, 4, 8, 16, 32]))"].intValue, 0);
+    EXPECT_STREQ([webView stringByEvaluatingJavaScript:@"Array.from(new Int8Array(sharedMemory.readBytes(1, 3))).toString()"].UTF8String, "2,4,8");
+    EXPECT_EQ([webView stringByEvaluatingJavaScript:@"sharedMemory.writeBytes(new Int8Array([101, 102, 103, 104, 105, 106]), 2, 3)"].intValue, 0);
+    EXPECT_STREQ([webView stringByEvaluatingJavaScript:@"Array.from(new Int8Array(sharedMemory.readBytes())).toString()"].UTF8String, "1,2,101,102,103,32,0,0");
+}
+
+TEST(IPCTestingAPI, CanSendSemaphore)
+{
+    auto webView = createWebViewWithIPCTestingAPI();
+
+    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    auto* html = @R"HTML(<!DOCTYPE html>
+<body>
+<script>
+const audioContext = new AudioContext;
+const destination = audioContext.createMediaStreamDestination();
+const semaphore = IPC.createSemaphore();
+const result = IPC.sendSyncMessage('GPU', 0, IPC.messages.RemoteAudioDestinationManager_CreateAudioDestination.name, 100,
+    [{type: 'String', value: 'some device'},
+    {type: 'uint32_t', value: destination.numberOfInputs},
+    {type: 'uint32_t', value: destination.channelCount},
+    {type: 'float', value: audioContext.sampleRate}, {type: 'float', value: audioContext.sampleRate},
+    {type: 'Semaphore', value: semaphore}]);
+alert(result.arguments[0].type);
+</script>
+</body>)HTML";
+
+    done = false;
+    [webView synchronouslyLoadHTMLString:html];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_STREQ([alertMessage UTF8String], "uint64_t");
+}
+
+#if PLATFORM(COCOA)
+TEST(IPCTestingAPI, CanSendSharedMemory)
+{
+    auto webView = createWebViewWithIPCTestingAPI();
+
+    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    auto* html = @R"HTML(<!DOCTYPE html>
+<body>
+<script>
+const sharedMemory = IPC.createSharedMemory(8);
+sharedMemory.writeBytes(new Uint8Array(Array.from('hello').map((char) => char.charCodeAt(0))));
+const result = IPC.sendSyncMessage('UI', 0, IPC.messages.WebPasteboardProxy_SetPasteboardBufferForType.name, 100, [
+    {type: 'String', value: 'Apple CFPasteboard general'}, {type: 'String', value: 'text/plain'},
+    {type: 'SharedMemory', value: sharedMemory, protection: 'ReadOnly'}, {type: 'bool', value: 1}, {type: 'uint64_t', value: IPC.pageID}]);
+alert(result.arguments.length + ':' + JSON.stringify(result.arguments[0]));
+</script>
+</body>)HTML";
+
+    done = false;
+    [webView synchronouslyLoadHTMLString:html];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_STREQ([alertMessage UTF8String], "1:{\"type\":\"int64_t\",\"value\":0}");
+}
+#endif
+
 TEST(IPCTestingAPI, DecodesReplyArgumentsForPrompt)
 {
     auto webView = createWebViewWithIPCTestingAPI();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to