aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/bun-types/globals.d.ts146
-rw-r--r--src/bun.js/bindings/BunJSCModule.cpp5
-rw-r--r--src/bun.js/bindings/BunWorkerGlobalScope.cpp8
-rw-r--r--src/bun.js/bindings/BunWorkerGlobalScope.h15
-rw-r--r--src/bun.js/bindings/ScriptExecutionContext.cpp137
-rw-r--r--src/bun.js/bindings/ScriptExecutionContext.h29
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp51
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h8
-rw-r--r--src/bun.js/bindings/webcore/ContextDestructionObserver.cpp65
-rw-r--r--src/bun.js/bindings/webcore/ContextDestructionObserver.h20
-rw-r--r--src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h6
-rw-r--r--src/bun.js/bindings/webcore/DOMIsoSubspaces.h7
-rw-r--r--src/bun.js/bindings/webcore/EventListenerMap.cpp3
-rw-r--r--src/bun.js/bindings/webcore/EventListenerMap.h2
-rw-r--r--src/bun.js/bindings/webcore/EventTargetFactory.cpp4
-rw-r--r--src/bun.js/bindings/webcore/EventTargetHeaders.h4
-rw-r--r--src/bun.js/bindings/webcore/JSMessageChannel.cpp323
-rw-r--r--src/bun.js/bindings/webcore/JSMessageChannel.h102
-rw-r--r--src/bun.js/bindings/webcore/JSMessageChannelCustom.cpp52
-rw-r--r--src/bun.js/bindings/webcore/JSMessageEvent.cpp43
-rw-r--r--src/bun.js/bindings/webcore/JSMessageEvent.h2
-rw-r--r--src/bun.js/bindings/webcore/JSMessageEventCustom.cpp25
-rw-r--r--src/bun.js/bindings/webcore/JSMessagePort.cpp440
-rw-r--r--src/bun.js/bindings/webcore/JSMessagePort.h103
-rw-r--r--src/bun.js/bindings/webcore/JSMessagePortCustom.cpp46
-rw-r--r--src/bun.js/bindings/webcore/JSStructuredSerializeOptions.cpp58
-rw-r--r--src/bun.js/bindings/webcore/JSStructuredSerializeOptions.h30
-rw-r--r--src/bun.js/bindings/webcore/JSValueInWrappedObject.h14
-rw-r--r--src/bun.js/bindings/webcore/MessageChannel.cpp64
-rw-r--r--src/bun.js/bindings/webcore/MessageChannel.h51
-rw-r--r--src/bun.js/bindings/webcore/MessageEvent.cpp48
-rw-r--r--src/bun.js/bindings/webcore/MessageEvent.h35
-rw-r--r--src/bun.js/bindings/webcore/MessagePort.cpp419
-rw-r--r--src/bun.js/bindings/webcore/MessagePort.h140
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannel.cpp190
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannel.h84
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp69
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannelProvider.h58
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.cpp93
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.h49
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp164
-rw-r--r--src/bun.js/bindings/webcore/MessagePortChannelRegistry.h58
-rw-r--r--src/bun.js/bindings/webcore/MessagePortIdentifier.h83
-rw-r--r--src/bun.js/bindings/webcore/MessageWithMessagePorts.h39
-rw-r--r--src/bun.js/bindings/webcore/PortIdentifier.h35
-rw-r--r--src/bun.js/bindings/webcore/SerializedScriptValue.cpp212
-rw-r--r--src/bun.js/bindings/webcore/SerializedScriptValue.h14
-rw-r--r--src/bun.js/bindings/webcore/TransferredMessagePort.h36
-rw-r--r--src/bun.js/bindings/webcore/Worker.cpp28
-rw-r--r--src/bun.js/bindings/webcore/Worker.h1
-rw-r--r--src/bun.js/scripts/class-definitions.ts2
-rw-r--r--src/bun.js/scripts/generate-classes.ts6
-rw-r--r--src/bun.js/webcore/response.classes.ts2
-rw-r--r--test/js/web/workers/create-port-worker.js6
-rw-r--r--test/js/web/workers/message-channel.test.ts254
-rw-r--r--test/js/web/workers/receive-port-worker.js9
-rw-r--r--test/js/web/workers/structured-clone.test.ts2
57 files changed, 3752 insertions, 247 deletions
diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts
index ed22be080..bf374adfe 100644
--- a/packages/bun-types/globals.d.ts
+++ b/packages/bun-types/globals.d.ts
@@ -366,6 +366,152 @@ declare function structuredClone<T>(
options?: StructuredSerializeOptions,
): T;
+/**
+ * This Channel Messaging API interface allows us to create a new message channel and send data through it via its two MessagePort properties.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel)
+ */
+interface MessageChannel {
+ /**
+ * Returns the first MessagePort object.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port1)
+ */
+ readonly port1: MessagePort;
+ /**
+ * Returns the second MessagePort object.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port2)
+ */
+ readonly port2: MessagePort;
+}
+
+declare var MessageChannel: {
+ prototype: MessageChannel;
+ new (): MessageChannel;
+};
+
+/**
+ * A message received by a target object.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent)
+ */
+interface MessageEvent<T = any> extends Event {
+ /**
+ * Returns the data of the message.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data)
+ */
+ readonly data: T;
+ /**
+ * Returns the last event ID string, for server-sent events.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/lastEventId)
+ */
+ readonly lastEventId: string;
+ /**
+ * Returns the origin of the message, for server-sent events and cross-document messaging.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/origin)
+ */
+ readonly origin: string;
+ /**
+ * Returns the MessagePort array sent with the message, for cross-document messaging and channel messaging.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/ports)
+ */
+ readonly ports: ReadonlyArray<MessagePort>;
+ /**
+ * Returns the WindowProxy of the source window, for cross-document messaging, and the MessagePort being attached, in the connect event fired at SharedWorkerGlobalScope objects.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/source)
+ */
+ readonly source: MessageEventSource | null;
+ /**
+ * @deprecated
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/initMessageEvent)
+ */
+ initMessageEvent(
+ type: string,
+ bubbles?: boolean,
+ cancelable?: boolean,
+ data?: any,
+ origin?: string,
+ lastEventId?: string,
+ source?: MessageEventSource | null,
+ ports?: MessagePort[],
+ ): void;
+}
+
+declare var MessageEvent: {
+ prototype: MessageEvent;
+ new <T>(type: string, eventInitDict?: MessageEventInit<T>): MessageEvent<T>;
+};
+
+interface MessagePortEventMap {
+ message: MessageEvent;
+ messageerror: MessageEvent;
+}
+
+/**
+ * This Channel Messaging API interface represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort)
+ */
+interface MessagePort extends EventTarget {
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/message_event) */
+ onmessage: ((this: MessagePort, ev: MessageEvent) => any) | null;
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/messageerror_event) */
+ onmessageerror: ((this: MessagePort, ev: MessageEvent) => any) | null;
+ /**
+ * Disconnects the port, so that it is no longer active.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/close)
+ */
+ close(): void;
+ /**
+ * Posts a message through the channel. Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
+ *
+ * Throws a "DataCloneError" DOMException if transfer contains duplicate objects or port, or if message could not be cloned.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/postMessage)
+ */
+ postMessage(message: any, transfer: Transferable[]): void;
+ postMessage(message: any, options?: StructuredSerializeOptions): void;
+ /**
+ * Begins dispatching messages received on the port.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/start)
+ */
+ start(): void;
+ addEventListener<K extends keyof MessagePortEventMap>(
+ type: K,
+ listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any,
+ options?: boolean | AddEventListenerOptions,
+ ): void;
+ addEventListener(
+ type: string,
+ listener: EventListenerOrEventListenerObject,
+ options?: boolean | AddEventListenerOptions,
+ ): void;
+ removeEventListener<K extends keyof MessagePortEventMap>(
+ type: K,
+ listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any,
+ options?: boolean | EventListenerOptions,
+ ): void;
+ removeEventListener(
+ type: string,
+ listener: EventListenerOrEventListenerObject,
+ options?: boolean | EventListenerOptions,
+ ): void;
+}
+
+declare var MessagePort: {
+ prototype: MessagePort;
+ new (): MessagePort;
+};
+
interface EncodeIntoResult {
/**
* The read Unicode code units of input.
diff --git a/src/bun.js/bindings/BunJSCModule.cpp b/src/bun.js/bindings/BunJSCModule.cpp
index a145f51c5..5e7a047ea 100644
--- a/src/bun.js/bindings/BunJSCModule.cpp
+++ b/src/bun.js/bindings/BunJSCModule.cpp
@@ -26,6 +26,7 @@
#include "JavaScriptCore/VMTrapsInlines.h"
#include "SerializedScriptValue.h"
#include "ExceptionOr.h"
+#include "MessagePort.h"
#if ENABLE(REMOTE_INSPECTOR)
#include "JavaScriptCore/RemoteInspectorServer.h"
@@ -552,8 +553,8 @@ JSC_DEFINE_HOST_FUNCTION(functionSerialize, (JSGlobalObject * lexicalGlobalObjec
}
Vector<JSC::Strong<JSC::JSObject>> transferList;
-
- ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList));
+ Vector<RefPtr<MessagePort>> dummyPorts;
+ ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList), dummyPorts);
if (serialized.hasException()) {
WebCore::propagateException(*globalObject, throwScope, serialized.releaseException());
diff --git a/src/bun.js/bindings/BunWorkerGlobalScope.cpp b/src/bun.js/bindings/BunWorkerGlobalScope.cpp
index 60b615e18..ef1f70fdf 100644
--- a/src/bun.js/bindings/BunWorkerGlobalScope.cpp
+++ b/src/bun.js/bindings/BunWorkerGlobalScope.cpp
@@ -1,10 +1,14 @@
#include "config.h"
#include "BunWorkerGlobalScope.h"
+#include "MessagePortChannelProviderImpl.h"
-namespace Bun {
-using namespace WebCore;
+namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(GlobalScope);
+MessagePortChannelProvider& GlobalScope::messagePortChannelProvider()
+{
+ return *reinterpret_cast<MessagePortChannelProvider*>(&MessagePortChannelProviderImpl::singleton());
+}
} \ No newline at end of file
diff --git a/src/bun.js/bindings/BunWorkerGlobalScope.h b/src/bun.js/bindings/BunWorkerGlobalScope.h
index 767289716..fff50d6ec 100644
--- a/src/bun.js/bindings/BunWorkerGlobalScope.h
+++ b/src/bun.js/bindings/BunWorkerGlobalScope.h
@@ -1,3 +1,5 @@
+#pragma once
+
#include "root.h"
#include "EventTarget.h"
@@ -7,8 +9,12 @@
#include <wtf/HashSet.h>
#include <wtf/Lock.h>
-namespace Bun {
-class GlobalScope final : public RefCounted<GlobalScope>, public EventTargetWithInlineData {
+namespace WebCore {
+
+class MessagePortChannelProvider;
+class MessagePortChannelProviderImpl;
+
+class GlobalScope : public RefCounted<GlobalScope>, public EventTargetWithInlineData {
WTF_MAKE_ISO_ALLOCATED(GlobalScope);
public:
@@ -33,6 +39,11 @@ public:
void derefEventTarget() final { deref(); }
void eventListenersDidChange() final {}
+ MessagePortChannelProvider& messagePortChannelProvider();
+
ScriptExecutionContext* m_context;
+
+private:
+ MessagePortChannelProviderImpl* m_messagePortChannelProvider;
};
} \ No newline at end of file
diff --git a/src/bun.js/bindings/ScriptExecutionContext.cpp b/src/bun.js/bindings/ScriptExecutionContext.cpp
index 47908b385..d9adbeb98 100644
--- a/src/bun.js/bindings/ScriptExecutionContext.cpp
+++ b/src/bun.js/bindings/ScriptExecutionContext.cpp
@@ -1,6 +1,7 @@
#include "root.h"
#include "headers.h"
#include "ScriptExecutionContext.h"
+#include "MessagePort.h"
#include "webcore/WebSocket.h"
#include "libusockets.h"
@@ -70,6 +71,23 @@ void ScriptExecutionContext::unrefEventLoop()
Bun__eventLoop__incrementRefConcurrently(WebCore::clientData(vm())->bunVM, -1);
}
+ScriptExecutionContext::~ScriptExecutionContext()
+{
+ checkConsistency();
+
+ {
+ Locker locker { allScriptExecutionContextsMapLock };
+ ASSERT_WITH_MESSAGE(!allScriptExecutionContextsMap().contains(m_identifier), "A ScriptExecutionContext subclass instance implementing postTask should have already removed itself from the map");
+ }
+
+ auto postMessageCompletionHandlers = WTFMove(m_processMessageWithMessagePortsSoonHandlers);
+ for (auto& completionHandler : postMessageCompletionHandlers)
+ completionHandler();
+
+ while (auto* destructionObserver = m_destructionObservers.takeAny())
+ destructionObserver->contextDestroyed();
+}
+
bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identifier, Function<void(ScriptExecutionContext&)>&& task)
{
Locker locker { allScriptExecutionContextsMapLock };
@@ -82,6 +100,125 @@ bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identif
return true;
}
+void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver& observer)
+{
+ ASSERT(!m_inScriptExecutionContextDestructor);
+ m_destructionObservers.add(&observer);
+}
+
+void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver& observer)
+{
+ m_destructionObservers.remove(&observer);
+}
+
+extern "C" void* Bun__getVM();
+
+bool ScriptExecutionContext::isContextThread()
+{
+ auto clientData = WebCore::clientData(vm());
+ return clientData->bunVM == Bun__getVM();
+}
+
+bool ScriptExecutionContext::ensureOnContextThread(ScriptExecutionContextIdentifier identifier, Function<void(ScriptExecutionContext&)>&& task)
+{
+ ScriptExecutionContext* context = nullptr;
+ {
+ Locker locker { allScriptExecutionContextsMapLock };
+ context = allScriptExecutionContextsMap().get(identifier);
+
+ if (!context)
+ return false;
+
+ if (!context->isContextThread()) {
+ context->postTaskConcurrently(WTFMove(task));
+ return true;
+ }
+ }
+
+ task(*context);
+ return true;
+}
+
+bool ScriptExecutionContext::ensureOnMainThread(Function<void(ScriptExecutionContext&)>&& task)
+{
+ Locker locker { allScriptExecutionContextsMapLock };
+ auto* context = allScriptExecutionContextsMap().get(1);
+
+ if (!context) {
+ return false;
+ }
+
+ context->postTaskConcurrently(WTFMove(task));
+ return true;
+}
+
+void ScriptExecutionContext::processMessageWithMessagePortsSoon(CompletionHandler<void()>&& completionHandler)
+{
+ ASSERT(isContextThread());
+ m_processMessageWithMessagePortsSoonHandlers.append(WTFMove(completionHandler));
+
+ if (m_willProcessMessageWithMessagePortsSoon) {
+ return;
+ }
+
+ m_willProcessMessageWithMessagePortsSoon = true;
+
+ postTask([](ScriptExecutionContext& context) {
+ context.dispatchMessagePortEvents();
+ });
+}
+
+void ScriptExecutionContext::dispatchMessagePortEvents()
+{
+ ASSERT(isContextThread());
+ checkConsistency();
+
+ ASSERT(m_willprocessMessageWithMessagePortsSoon);
+ m_willProcessMessageWithMessagePortsSoon = false;
+
+ auto completionHandlers = std::exchange(m_processMessageWithMessagePortsSoonHandlers, Vector<CompletionHandler<void()>> {});
+
+ // Make a frozen copy of the ports so we can iterate while new ones might be added or destroyed.
+ for (auto* messagePort : copyToVector(m_messagePorts)) {
+ // The port may be destroyed, and another one created at the same address,
+ // but this is harmless. The worst that can happen as a result is that
+ // dispatchMessages() will be called needlessly.
+ if (m_messagePorts.contains(messagePort) && messagePort->started())
+ messagePort->dispatchMessages();
+ }
+
+ for (auto& completionHandler : completionHandlers)
+ completionHandler();
+}
+
+void ScriptExecutionContext::checkConsistency() const
+{
+ for (auto* messagePort : m_messagePorts)
+ ASSERT(messagePort->scriptExecutionContext() == this);
+
+ for (auto* destructionObserver : m_destructionObservers)
+ ASSERT(destructionObserver->scriptExecutionContext() == this);
+
+ // for (auto* activeDOMObject : m_activeDOMObjects) {
+ // ASSERT(activeDOMObject->scriptExecutionContext() == this);
+ // activeDOMObject->assertSuspendIfNeededWasCalled();
+ // }
+}
+
+void ScriptExecutionContext::createdMessagePort(MessagePort& messagePort)
+{
+ ASSERT(isContextThread());
+
+ m_messagePorts.add(&messagePort);
+}
+
+void ScriptExecutionContext::destroyedMessagePort(MessagePort& messagePort)
+{
+ ASSERT(isContextThread());
+
+ m_messagePorts.remove(&messagePort);
+}
+
us_socket_context_t* ScriptExecutionContext::webSocketContextNoSSL()
{
if (!m_client_websockets_ctx) {
diff --git a/src/bun.js/bindings/ScriptExecutionContext.h b/src/bun.js/bindings/ScriptExecutionContext.h
index b0e4e2096..23c44ab51 100644
--- a/src/bun.js/bindings/ScriptExecutionContext.h
+++ b/src/bun.js/bindings/ScriptExecutionContext.h
@@ -2,12 +2,14 @@
#include "root.h"
#include "ActiveDOMObject.h"
+#include "ContextDestructionObserver.h"
#include <wtf/CrossThreadTask.h>
#include <wtf/Function.h>
#include <wtf/HashSet.h>
#include <wtf/ObjectIdentifier.h>
#include <wtf/WeakPtr.h>
#include <wtf/text/WTFString.h>
+#include <wtf/CompletionHandler.h>
#include "CachedScript.h"
#include "wtf/URL.h"
@@ -27,6 +29,7 @@ struct us_loop_t;
namespace WebCore {
class WebSocket;
+class MessagePort;
class ScriptExecutionContext;
@@ -89,6 +92,8 @@ public:
addToContextsMap();
}
+ ~ScriptExecutionContext();
+
static ScriptExecutionContextIdentifier generateIdentifier();
JSC::JSGlobalObject* jsGlobalObject()
@@ -117,7 +122,7 @@ public:
bool isMainThread() const { return static_cast<unsigned>(m_identifier) == 1; }
bool activeDOMObjectsAreSuspended() { return false; }
bool activeDOMObjectsAreStopped() { return false; }
- bool isContextThread() { return true; }
+ bool isContextThread();
bool isDocument() { return false; }
bool isWorkerGlobalScope() { return true; }
bool isJSExecutionForbidden() { return false; }
@@ -140,7 +145,21 @@ public:
bool unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) { return false; }
#endif
- static bool postTaskTo(ScriptExecutionContextIdentifier identifier, Function<void(ScriptExecutionContext&)>&& task);
+ WEBCORE_EXPORT static bool postTaskTo(ScriptExecutionContextIdentifier identifier, Function<void(ScriptExecutionContext&)>&& task);
+ WEBCORE_EXPORT static bool ensureOnContextThread(ScriptExecutionContextIdentifier, Function<void(ScriptExecutionContext&)>&& task);
+ WEBCORE_EXPORT static bool ensureOnMainThread(Function<void(ScriptExecutionContext&)>&& task);
+
+ WEBCORE_EXPORT JSC::JSGlobalObject* globalObject();
+
+ void didCreateDestructionObserver(ContextDestructionObserver&);
+ void willDestroyDestructionObserver(ContextDestructionObserver&);
+
+ void processMessageWithMessagePortsSoon(CompletionHandler<void()>&&);
+ void createdMessagePort(MessagePort&);
+ void destroyedMessagePort(MessagePort&);
+
+ void dispatchMessagePortEvents();
+ void checkConsistency() const;
void regenerateIdentifier();
void addToContextsMap();
@@ -196,6 +215,12 @@ private:
WTF::URL m_url = WTF::URL();
ScriptExecutionContextIdentifier m_identifier;
+ HashSet<MessagePort*> m_messagePorts;
+ HashSet<ContextDestructionObserver*> m_destructionObservers;
+ Vector<CompletionHandler<void()>> m_processMessageWithMessagePortsSoonHandlers;
+
+ bool m_willProcessMessageWithMessagePortsSoon { false };
+
us_socket_context_t* webSocketContextSSL();
us_socket_context_t* webSocketContextNoSSL();
us_socket_context_t* connectedWebSocketKindClientSSL();
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index b7171b21c..1aefe476c 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -119,6 +119,9 @@
#include "DOMIsoSubspaces.h"
#include "BunWorkerGlobalScope.h"
#include "JSWorker.h"
+#include "JSMessageChannel.h"
+#include "JSMessagePort.h"
+// #include "JSBroadcastChannel.h"
#if ENABLE(REMOTE_INSPECTOR)
#include "JavaScriptCore/RemoteInspectorServer.h"
@@ -718,6 +721,7 @@ GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure)
, m_scriptExecutionContext(new WebCore::ScriptExecutionContext(&vm, this))
, globalEventScope(*new Bun::GlobalScope(m_scriptExecutionContext))
{
+ // m_scriptExecutionContext = globalEventScope.m_context;
mockModule = Bun::JSMockModule::create(this);
globalEventScope.m_context = m_scriptExecutionContext;
}
@@ -732,6 +736,7 @@ GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::Scri
, m_scriptExecutionContext(new WebCore::ScriptExecutionContext(&vm, this, contextId))
, globalEventScope(*new Bun::GlobalScope(m_scriptExecutionContext))
{
+ // m_scriptExecutionContext = globalEventScope.m_context;
mockModule = Bun::JSMockModule::create(this);
globalEventScope.m_context = m_scriptExecutionContext;
}
@@ -931,6 +936,15 @@ WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSDOMFormData);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSWorker);
WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSWorker);
+WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSMessageChannel);
+WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSMessageChannel);
+
+WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSMessagePort);
+WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSMessagePort);
+
+// WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSBroadcastChannel);
+// WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSBroadcastChannel);
+
JSC_DECLARE_CUSTOM_GETTER(JSEvent_getter);
JSC_DEFINE_CUSTOM_GETTER(JSEvent_getter,
@@ -1285,13 +1299,14 @@ JSC_DEFINE_HOST_FUNCTION(functionStructuredClone,
}
}
- ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList));
+ Vector<RefPtr<MessagePort>> ports;
+ ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList), ports);
if (serialized.hasException()) {
WebCore::propagateException(*globalObject, throwScope, serialized.releaseException());
return JSValue::encode(jsUndefined());
}
- JSValue deserialized = serialized.releaseReturnValue()->deserialize(*globalObject, globalObject);
+ JSValue deserialized = serialized.releaseReturnValue()->deserialize(*globalObject, globalObject, ports);
return JSValue::encode(deserialized);
}
@@ -3665,26 +3680,28 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPostMessage,
}
}
- ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList));
+ Vector<RefPtr<MessagePort>> ports;
+ ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList), ports);
if (serialized.hasException()) {
WebCore::propagateException(*globalObject, throwScope, serialized.releaseException());
return JSValue::encode(jsUndefined());
}
- RefPtr<SerializedScriptValue> message = serialized.releaseReturnValue();
- ScriptExecutionContext::postTaskTo(context->identifier(), [message = WTFMove(message), protectedThis = Ref { *worker }](ScriptExecutionContext& context) {
+ ExceptionOr<Vector<TransferredMessagePort>> disentangledPorts = MessagePort::disentanglePorts(WTFMove(ports));
+ if (disentangledPorts.hasException()) {
+ WebCore::propagateException(*globalObject, throwScope, serialized.releaseException());
+ return JSValue::encode(jsUndefined());
+ }
+
+ MessageWithMessagePorts messageWithMessagePorts { serialized.releaseReturnValue(), disentangledPorts.releaseReturnValue() };
+
+ ScriptExecutionContext::postTaskTo(context->identifier(), [message = messageWithMessagePorts, protectedThis = Ref { *worker }, ports](ScriptExecutionContext& context) mutable {
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(context.jsGlobalObject());
- bool didFail = false;
- JSValue value = message->deserialize(*globalObject, globalObject, SerializationErrorMode::NonThrowing, &didFail);
- if (didFail) {
- protectedThis->dispatchEvent(MessageEvent::create(eventNames().messageerrorEvent, MessageEvent::Init {}, MessageEvent::IsTrusted::Yes));
- return;
- }
+ auto ports = MessagePort::entanglePorts(context, WTFMove(message.transferredPorts));
+ auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), std::nullopt, WTFMove(ports));
- WebCore::MessageEvent::Init init;
- init.data = value;
- protectedThis->dispatchEvent(MessageEvent::create(eventNames().messageEvent, WTFMove(init), MessageEvent::IsTrusted::Yes));
+ protectedThis->dispatchEvent(event.event);
});
return JSValue::encode(jsUndefined());
@@ -4227,6 +4244,9 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
PUT_WEBCORE_GENERATED_CONSTRUCTOR("Headers"_s, JSFetchHeaders);
PUT_WEBCORE_GENERATED_CONSTRUCTOR("URLSearchParams"_s, JSURLSearchParams);
PUT_WEBCORE_GENERATED_CONSTRUCTOR("Worker"_s, JSWorker);
+ PUT_WEBCORE_GENERATED_CONSTRUCTOR("MessageChannel"_s, JSMessageChannel);
+ PUT_WEBCORE_GENERATED_CONSTRUCTOR("MessagePort"_s, JSMessagePort);
+ // PUT_WEBCORE_GENERATED_CONSTRUCTOR("BroadcastChannel"_s, JSBroadcastChannel);
putDirectCustomAccessor(vm, builtinNames.TransformStreamPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum)));
putDirectCustomAccessor(vm, builtinNames.TransformStreamPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum)));
@@ -4619,6 +4639,9 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.append(thisObject->m_JSURLSearchParamsSetterValue);
visitor.append(thisObject->m_JSDOMFormDataSetterValue);
visitor.append(thisObject->m_JSWorkerSetterValue);
+ visitor.append(thisObject->m_JSMessageChannelSetterValue);
+ visitor.append(thisObject->m_JSMessagePortSetterValue);
+ visitor.append(thisObject->m_JSBroadcastChannelSetterValue);
thisObject->m_JSArrayBufferSinkClassStructure.visit(visitor);
thisObject->m_JSBufferListClassStructure.visit(visitor);
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index e4364d248..9d04786d5 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -43,11 +43,8 @@ class DOMWrapperWorld;
#include "BunPlugin.h"
#include "JSMockFunction.h"
-namespace Bun {
-class GlobalScope;
-}
-
namespace WebCore {
+class GlobalScope;
class SubtleCrypto;
class EventTarget;
}
@@ -386,6 +383,9 @@ public:
mutable WriteBarrier<Unknown> m_JSWebSocketSetterValue;
mutable WriteBarrier<Unknown> m_JSDOMFormDataSetterValue;
mutable WriteBarrier<Unknown> m_JSWorkerSetterValue;
+ mutable WriteBarrier<Unknown> m_JSMessageChannelSetterValue;
+ mutable WriteBarrier<Unknown> m_JSMessagePortSetterValue;
+ mutable WriteBarrier<Unknown> m_JSBroadcastChannelSetterValue;
mutable WriteBarrier<Unknown> m_BunCommonJSModuleValue;
mutable WriteBarrier<JSFunction> m_thenables[promiseFunctionsSize + 1];
diff --git a/src/bun.js/bindings/webcore/ContextDestructionObserver.cpp b/src/bun.js/bindings/webcore/ContextDestructionObserver.cpp
new file mode 100644
index 000000000..72e6a85c4
--- /dev/null
+++ b/src/bun.js/bindings/webcore/ContextDestructionObserver.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ */
+
+#include "config.h"
+#include "ContextDestructionObserver.h"
+
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+ContextDestructionObserver::ContextDestructionObserver(ScriptExecutionContext* scriptExecutionContext)
+ : m_context(nullptr)
+{
+ observeContext(scriptExecutionContext);
+}
+
+ContextDestructionObserver::~ContextDestructionObserver()
+{
+ observeContext(nullptr);
+}
+
+void ContextDestructionObserver::observeContext(ScriptExecutionContext* scriptExecutionContext)
+{
+ if (m_context) {
+ ASSERT(m_context->isContextThread());
+ m_context->willDestroyDestructionObserver(*this);
+ }
+
+ m_context = scriptExecutionContext;
+
+ if (m_context) {
+ ASSERT(m_context->isContextThread());
+ m_context->didCreateDestructionObserver(*this);
+ }
+}
+
+void ContextDestructionObserver::contextDestroyed()
+{
+ m_context = nullptr;
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/ContextDestructionObserver.h b/src/bun.js/bindings/webcore/ContextDestructionObserver.h
index ccf20f301..7408b5f27 100644
--- a/src/bun.js/bindings/webcore/ContextDestructionObserver.h
+++ b/src/bun.js/bindings/webcore/ContextDestructionObserver.h
@@ -4,29 +4,23 @@
#include "root.h"
-#include "ScriptExecutionContext.h"
-
namespace WebCore {
-// TODO:
+class ScriptExecutionContext;
+
class ContextDestructionObserver {
public:
- WEBCORE_EXPORT void contextDestroyed() {}
+ WEBCORE_EXPORT virtual void contextDestroyed();
ScriptExecutionContext* scriptExecutionContext() const { return m_context; }
- ContextDestructionObserver(ScriptExecutionContext* context)
- : m_context(context)
- {
- }
- ContextDestructionObserver(ContextDestructionObserver& context)
- : m_context(context.m_context)
- {
- }
+protected:
+ WEBCORE_EXPORT ContextDestructionObserver(ScriptExecutionContext*);
+ WEBCORE_EXPORT virtual ~ContextDestructionObserver();
+ void observeContext(ScriptExecutionContext*);
private:
- int m_junk = 0;
ScriptExecutionContext* m_context;
};
diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
index 740c6d9a9..391060426 100644
--- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
@@ -410,7 +410,7 @@ public:
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForAnimationEvent;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForAttr;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBeforeUnloadEvent;
- // std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBroadcastChannel;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBroadcastChannel;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCDATASection;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCharacterData;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForClipboardEvent;
@@ -443,9 +443,9 @@ public:
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForIdleDeadline;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForInputEvent;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForKeyboardEvent;
- // std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMessageChannel;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMessageChannel;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMessageEvent;
- // std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMessagePort;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMessagePort;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMouseEvent;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMutationEvent;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMutationObserver;
diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
index 52be5872a..01f202a81 100644
--- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
@@ -401,7 +401,7 @@ public:
// std::unique_ptr<IsoSubspace> m_subspaceForAnimationEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForAttr;
// std::unique_ptr<IsoSubspace> m_subspaceForBeforeUnloadEvent;
- // std::unique_ptr<IsoSubspace> m_subspaceForBroadcastChannel;
+ std::unique_ptr<IsoSubspace> m_subspaceForBroadcastChannel;
// std::unique_ptr<IsoSubspace> m_subspaceForCDATASection;
// std::unique_ptr<IsoSubspace> m_subspaceForCharacterData;
// std::unique_ptr<IsoSubspace> m_subspaceForClipboardEvent;
@@ -409,7 +409,6 @@ public:
// std::unique_ptr<IsoSubspace> m_subspaceForCompositionEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForCustomElementRegistry;
std::unique_ptr<IsoSubspace> m_subspaceForCustomEvent;
- // std::unique_ptr<IsoSubspace> m_subspaceForDOMException;
// std::unique_ptr<IsoSubspace> m_subspaceForDOMImplementation;
// std::unique_ptr<IsoSubspace> m_subspaceForDOMPoint;
// std::unique_ptr<IsoSubspace> m_subspaceForDOMPointReadOnly;
@@ -436,9 +435,9 @@ public:
// std::unique_ptr<IsoSubspace> m_subspaceForIdleDeadline;
// std::unique_ptr<IsoSubspace> m_subspaceForInputEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForKeyboardEvent;
- // std::unique_ptr<IsoSubspace> m_subspaceForMessageChannel;
+ std::unique_ptr<IsoSubspace> m_subspaceForMessageChannel;
std::unique_ptr<IsoSubspace> m_subspaceForMessageEvent;
- // std::unique_ptr<IsoSubspace> m_subspaceForMessagePort;
+ std::unique_ptr<IsoSubspace> m_subspaceForMessagePort;
// std::unique_ptr<IsoSubspace> m_subspaceForMouseEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForMutationEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForMutationObserver;
diff --git a/src/bun.js/bindings/webcore/EventListenerMap.cpp b/src/bun.js/bindings/webcore/EventListenerMap.cpp
index 5014cfa00..540f498e0 100644
--- a/src/bun.js/bindings/webcore/EventListenerMap.cpp
+++ b/src/bun.js/bindings/webcore/EventListenerMap.cpp
@@ -41,7 +41,6 @@
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
-
namespace WebCore {
EventListenerMap::EventListenerMap() = default;
@@ -168,7 +167,7 @@ EventListenerVector* EventListenerMap::find(const AtomString& eventType)
static void removeFirstListenerCreatedFromMarkup(EventListenerVector& listenerVector)
{
- bool foundListener = listenerVector.removeFirstMatching([] (const auto& registeredListener) {
+ bool foundListener = listenerVector.removeFirstMatching([](const auto& registeredListener) {
if (JSEventListener::wasCreatedFromMarkup(registeredListener->callback())) {
registeredListener->markAsRemoved();
return true;
diff --git a/src/bun.js/bindings/webcore/EventListenerMap.h b/src/bun.js/bindings/webcore/EventListenerMap.h
index 572f999f9..690afd133 100644
--- a/src/bun.js/bindings/webcore/EventListenerMap.h
+++ b/src/bun.js/bindings/webcore/EventListenerMap.h
@@ -65,7 +65,7 @@ public:
void removeFirstEventListenerCreatedFromMarkup(const AtomString& eventType);
void copyEventListenersNotCreatedFromMarkupToTarget(EventTarget*);
-
+
template<typename Visitor> void visitJSEventListeners(Visitor&);
Lock& lock() { return m_lock; }
diff --git a/src/bun.js/bindings/webcore/EventTargetFactory.cpp b/src/bun.js/bindings/webcore/EventTargetFactory.cpp
index 97e66977b..867d007be 100644
--- a/src/bun.js/bindings/webcore/EventTargetFactory.cpp
+++ b/src/bun.js/bindings/webcore/EventTargetFactory.cpp
@@ -117,8 +117,8 @@ JSC::JSValue toJS(JSC::JSGlobalObject* state, JSDOMGlobalObject* globalObject, E
// case MediaStreamTrackEventTargetInterfaceType:
// return toJS(state, globalObject, static_cast<MediaStreamTrack&>(impl));
// #endif
- // case MessagePortEventTargetInterfaceType:
- // return toJS(state, globalObject, static_cast<MessagePort&>(impl));
+ case MessagePortEventTargetInterfaceType:
+ return toJS(state, globalObject, static_cast<MessagePort&>(impl));
// case NodeEventTargetInterfaceType:
// return toJS(state, globalObject, static_cast<Node&>(impl));
// #if ENABLE(NOTIFICATIONS)
diff --git a/src/bun.js/bindings/webcore/EventTargetHeaders.h b/src/bun.js/bindings/webcore/EventTargetHeaders.h
index b36e49a66..89c1f2393 100644
--- a/src/bun.js/bindings/webcore/EventTargetHeaders.h
+++ b/src/bun.js/bindings/webcore/EventTargetHeaders.h
@@ -106,8 +106,8 @@
// #include "JSMediaStreamTrack.h"
// #include "MediaStreamTrack.h"
// #endif
-// #include "MessagePort.h"
-// #include "JSMessagePort.h"
+#include "MessagePort.h"
+#include "JSMessagePort.h"
// #include "JSNode.h"
#include "Node.h"
// #if ENABLE(NOTIFICATIONS)
diff --git a/src/bun.js/bindings/webcore/JSMessageChannel.cpp b/src/bun.js/bindings/webcore/JSMessageChannel.cpp
new file mode 100644
index 000000000..2082bd9a8
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSMessageChannel.cpp
@@ -0,0 +1,323 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(CHANNEL_MESSAGING)
+
+#include "JSMessageChannel.h"
+
+#include "ActiveDOMObject.h"
+#include "ExtendedDOMClientIsoSubspaces.h"
+#include "ExtendedDOMIsoSubspaces.h"
+#include "JSDOMAttribute.h"
+#include "JSDOMBinding.h"
+#include "JSDOMConstructor.h"
+#include "JSDOMConvertInterface.h"
+#include "JSDOMExceptionHandling.h"
+#include "JSDOMGlobalObject.h"
+#include "JSDOMGlobalObjectInlines.h"
+#include "JSDOMWrapperCache.h"
+#include "JSMessagePort.h"
+#include "ScriptExecutionContext.h"
+#include "WebCoreJSClientData.h"
+#include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapAnalyzer.h>
+#include <JavaScriptCore/JSCInlines.h>
+#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
+#include <JavaScriptCore/SlotVisitorMacros.h>
+#include <JavaScriptCore/SubspaceInlines.h>
+#include <wtf/GetPtr.h>
+#include <wtf/PointerPreparations.h>
+#include <wtf/URL.h>
+
+namespace WebCore {
+using namespace JSC;
+
+// Attributes
+
+static JSC_DECLARE_CUSTOM_GETTER(jsMessageChannelConstructor);
+static JSC_DECLARE_CUSTOM_GETTER(jsMessageChannel_port1);
+static JSC_DECLARE_CUSTOM_GETTER(jsMessageChannel_port2);
+
+class JSMessageChannelPrototype final : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+ static JSMessageChannelPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSMessageChannelPrototype* ptr = new (NotNull, JSC::allocateCell<JSMessageChannelPrototype>(vm)) JSMessageChannelPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMessageChannelPrototype, Base);
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSMessageChannelPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
+ : JSC::JSNonFinalObject(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMessageChannelPrototype, JSMessageChannelPrototype::Base);
+
+using JSMessageChannelDOMConstructor = JSDOMConstructor<JSMessageChannel>;
+
+template<> EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSMessageChannelDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame)
+{
+ VM& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* castedThis = jsCast<JSMessageChannelDOMConstructor*>(callFrame->jsCallee());
+ ASSERT(castedThis);
+ auto* context = castedThis->scriptExecutionContext();
+ if (UNLIKELY(!context))
+ return throwConstructorScriptExecutionContextUnavailableError(*lexicalGlobalObject, throwScope, "MessageChannel");
+ auto object = MessageChannel::create(*context);
+ if constexpr (IsExceptionOr<decltype(object)>)
+ RETURN_IF_EXCEPTION(throwScope, {});
+ static_assert(TypeOrExceptionOrUnderlyingType<decltype(object)>::isRef);
+ auto jsValue = toJSNewlyCreated<IDLInterface<MessageChannel>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object));
+ if constexpr (IsExceptionOr<decltype(object)>)
+ RETURN_IF_EXCEPTION(throwScope, {});
+ setSubclassStructureIfNeeded<MessageChannel>(lexicalGlobalObject, callFrame, asObject(jsValue));
+ RETURN_IF_EXCEPTION(throwScope, {});
+ return JSValue::encode(jsValue);
+}
+JSC_ANNOTATE_HOST_FUNCTION(JSMessageChannelDOMConstructorConstruct, JSMessageChannelDOMConstructor::construct);
+
+template<> const ClassInfo JSMessageChannelDOMConstructor::s_info = { "MessageChannel"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMessageChannelDOMConstructor) };
+
+template<> JSValue JSMessageChannelDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
+{
+ UNUSED_PARAM(vm);
+ return globalObject.functionPrototype();
+}
+
+template<> void JSMessageChannelDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ JSString* nameString = jsNontrivialString(vm, "MessageChannel"_s);
+ m_originalName.set(vm, this, nameString);
+ putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ putDirect(vm, vm.propertyNames->prototype, JSMessageChannel::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
+}
+
+/* Hash table for prototype */
+
+static const HashTableValue JSMessageChannelPrototypeTableValues[] = {
+ { "constructor"_s, static_cast<unsigned>(PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsMessageChannelConstructor, 0 } },
+ { "port1"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsMessageChannel_port1, 0 } },
+ { "port2"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsMessageChannel_port2, 0 } },
+};
+
+const ClassInfo JSMessageChannelPrototype::s_info = { "MessageChannel"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMessageChannelPrototype) };
+
+void JSMessageChannelPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSMessageChannel::info(), JSMessageChannelPrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+const ClassInfo JSMessageChannel::s_info = { "MessageChannel"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMessageChannel) };
+
+JSMessageChannel::JSMessageChannel(Structure* structure, JSDOMGlobalObject& globalObject, Ref<MessageChannel>&& impl)
+ : JSDOMWrapper<MessageChannel>(structure, globalObject, WTFMove(impl))
+{
+}
+
+// static_assert(!std::is_base_of<ActiveDOMObject, MessageChannel>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject.");
+
+JSObject* JSMessageChannel::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ auto* structure = JSMessageChannelPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype());
+ structure->setMayBePrototype(true);
+ return JSMessageChannelPrototype::create(vm, &globalObject, structure);
+}
+
+JSObject* JSMessageChannel::prototype(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ return getDOMPrototype<JSMessageChannel>(vm, globalObject);
+}
+
+JSValue JSMessageChannel::getConstructor(VM& vm, const JSGlobalObject* globalObject)
+{
+ return getDOMConstructor<JSMessageChannelDOMConstructor, DOMConstructorID::MessageChannel>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
+}
+
+void JSMessageChannel::destroy(JSC::JSCell* cell)
+{
+ JSMessageChannel* thisObject = static_cast<JSMessageChannel*>(cell);
+ thisObject->JSMessageChannel::~JSMessageChannel();
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsMessageChannelConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* prototype = jsDynamicCast<JSMessageChannelPrototype*>(JSValue::decode(thisValue));
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(JSMessageChannel::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject()));
+}
+
+static inline JSValue jsMessageChannel_port1Getter(JSGlobalObject& lexicalGlobalObject, JSMessageChannel& thisObject)
+{
+ auto& vm = JSC::getVM(&lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto& impl = thisObject.wrapped();
+ RELEASE_AND_RETURN(throwScope, (toJS<IDLInterface<MessagePort>>(lexicalGlobalObject, *thisObject.globalObject(), throwScope, impl.port1())));
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsMessageChannel_port1, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ return IDLAttribute<JSMessageChannel>::get<jsMessageChannel_port1Getter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
+}
+
+static inline JSValue jsMessageChannel_port2Getter(JSGlobalObject& lexicalGlobalObject, JSMessageChannel& thisObject)
+{
+ auto& vm = JSC::getVM(&lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto& impl = thisObject.wrapped();
+ RELEASE_AND_RETURN(throwScope, (toJS<IDLInterface<MessagePort>>(lexicalGlobalObject, *thisObject.globalObject(), throwScope, impl.port2())));
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsMessageChannel_port2, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ return IDLAttribute<JSMessageChannel>::get<jsMessageChannel_port2Getter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
+}
+
+JSC::GCClient::IsoSubspace* JSMessageChannel::subspaceForImpl(JSC::VM& vm)
+{
+ return WebCore::subspaceForImpl<JSMessageChannel, UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForMessageChannel.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForMessageChannel = std::forward<decltype(space)>(space); },
+ [](auto& spaces) { return spaces.m_subspaceForMessageChannel.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForMessageChannel = std::forward<decltype(space)>(space); });
+}
+
+template<typename Visitor>
+void JSMessageChannel::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ auto* thisObject = jsCast<JSMessageChannel*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ thisObject->visitAdditionalChildren(visitor);
+}
+
+DEFINE_VISIT_CHILDREN(JSMessageChannel);
+
+template<typename Visitor>
+void JSMessageChannel::visitOutputConstraints(JSCell* cell, Visitor& visitor)
+{
+ auto* thisObject = jsCast<JSMessageChannel*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitOutputConstraints(thisObject, visitor);
+ thisObject->visitAdditionalChildren(visitor);
+}
+
+template void JSMessageChannel::visitOutputConstraints(JSCell*, AbstractSlotVisitor&);
+template void JSMessageChannel::visitOutputConstraints(JSCell*, SlotVisitor&);
+void JSMessageChannel::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSMessageChannel*>(cell);
+ analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped());
+ if (thisObject->scriptExecutionContext())
+ analyzer.setLabelForCell(cell, "url "_s + thisObject->scriptExecutionContext()->url().string());
+ Base::analyzeHeap(cell, analyzer);
+}
+
+bool JSMessageChannelOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, AbstractSlotVisitor& visitor, const char** reason)
+{
+ UNUSED_PARAM(handle);
+ UNUSED_PARAM(visitor);
+ UNUSED_PARAM(reason);
+ return false;
+}
+
+void JSMessageChannelOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
+{
+ auto* jsMessageChannel = static_cast<JSMessageChannel*>(handle.slot()->asCell());
+ auto& world = *static_cast<DOMWrapperWorld*>(context);
+ uncacheWrapper(world, &jsMessageChannel->wrapped(), jsMessageChannel);
+}
+
+#if ENABLE(BINDING_INTEGRITY)
+#if PLATFORM(WIN)
+#pragma warning(disable : 4483)
+extern "C" {
+extern void (*const __identifier("??_7MessageChannel@WebCore@@6B@")[])();
+}
+#else
+extern "C" {
+extern void* _ZTVN7WebCore14MessageChannelE[];
+}
+#endif
+#endif
+
+JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref<MessageChannel>&& impl)
+{
+
+ if constexpr (std::is_polymorphic_v<MessageChannel>) {
+#if ENABLE(BINDING_INTEGRITY)
+ const void* actualVTablePointer = getVTablePointer(impl.ptr());
+#if PLATFORM(WIN)
+ void* expectedVTablePointer = __identifier("??_7MessageChannel@WebCore@@6B@");
+#else
+ void* expectedVTablePointer = &_ZTVN7WebCore14MessageChannelE[2];
+#endif
+
+ // If you hit this assertion you either have a use after free bug, or
+ // MessageChannel has subclasses. If MessageChannel has subclasses that get passed
+ // to toJS() we currently require MessageChannel you to opt out of binding hardening
+ // by adding the SkipVTableValidation attribute to the interface IDL definition
+ RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
+#endif
+ }
+ return createWrapper<MessageChannel>(globalObject, WTFMove(impl));
+}
+
+JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, MessageChannel& impl)
+{
+ return wrap(lexicalGlobalObject, globalObject, impl);
+}
+
+MessageChannel* JSMessageChannel::toWrapped(JSC::VM&, JSC::JSValue value)
+{
+ if (auto* wrapper = jsDynamicCast<JSMessageChannel*>(value))
+ return &wrapper->wrapped();
+ return nullptr;
+}
+
+}
+
+#endif // ENABLE(CHANNEL_MESSAGING)
diff --git a/src/bun.js/bindings/webcore/JSMessageChannel.h b/src/bun.js/bindings/webcore/JSMessageChannel.h
new file mode 100644
index 000000000..551be7459
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSMessageChannel.h
@@ -0,0 +1,102 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#if ENABLE(CHANNEL_MESSAGING)
+
+#include "JSDOMWrapper.h"
+#include "MessageChannel.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+class JSMessageChannel : public JSDOMWrapper<MessageChannel> {
+public:
+ using Base = JSDOMWrapper<MessageChannel>;
+ static JSMessageChannel* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<MessageChannel>&& impl)
+ {
+ JSMessageChannel* ptr = new (NotNull, JSC::allocateCell<JSMessageChannel>(globalObject->vm())) JSMessageChannel(structure, *globalObject, WTFMove(impl));
+ ptr->finishCreation(globalObject->vm());
+ return ptr;
+ }
+
+ static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);
+ static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
+ static MessageChannel* toWrapped(JSC::VM&, JSC::JSValue);
+ static void destroy(JSC::JSCell*);
+
+ DECLARE_INFO;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), JSC::NonArray);
+ }
+
+ static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return subspaceForImpl(vm);
+ }
+ static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
+ DECLARE_VISIT_CHILDREN;
+ template<typename Visitor> void visitAdditionalChildren(Visitor&);
+
+ template<typename Visitor> static void visitOutputConstraints(JSCell*, Visitor&);
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+
+protected:
+ JSMessageChannel(JSC::Structure*, JSDOMGlobalObject&, Ref<MessageChannel>&&);
+
+ DECLARE_DEFAULT_FINISH_CREATION;
+};
+
+class JSMessageChannelOwner final : public JSC::WeakHandleOwner {
+public:
+ bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::AbstractSlotVisitor&, const char**) final;
+ void finalize(JSC::Handle<JSC::Unknown>, void* context) final;
+};
+
+inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, MessageChannel*)
+{
+ static NeverDestroyed<JSMessageChannelOwner> owner;
+ return &owner.get();
+}
+
+inline void* wrapperKey(MessageChannel* wrappableObject)
+{
+ return wrappableObject;
+}
+
+JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, MessageChannel&);
+inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, MessageChannel* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); }
+JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref<MessageChannel>&&);
+inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr<MessageChannel>&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }
+
+template<> struct JSDOMWrapperConverterTraits<MessageChannel> {
+ using WrapperClass = JSMessageChannel;
+ using ToWrappedReturnType = MessageChannel*;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CHANNEL_MESSAGING)
diff --git a/src/bun.js/bindings/webcore/JSMessageChannelCustom.cpp b/src/bun.js/bindings/webcore/JSMessageChannelCustom.cpp
new file mode 100644
index 000000000..75b074048
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSMessageChannelCustom.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008-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.
+ */
+
+#include "config.h"
+
+#if ENABLE(CHANNEL_MESSAGING)
+
+#include "DOMWrapperWorld.h"
+#include "JSMessageChannel.h"
+// #include "JSNodeCustom.h"
+#include "MessagePort.h"
+// #include "WebCoreOpaqueRootInlines.h"
+#include <JavaScriptCore/SlotVisitorInlines.h>
+
+namespace WebCore {
+
+template<typename Visitor>
+void JSMessageChannel::visitAdditionalChildren(Visitor& visitor)
+{
+ visitor.addOpaqueRoot(WTF::getPtr(wrapped().port1()));
+ visitor.addOpaqueRoot(WTF::getPtr(wrapped().port2()));
+ // addWebCoreOpaqueRoot(visitor, wrapped().port1());
+ // addWebCoreOpaqueRoot(visitor, wrapped().port2());
+}
+
+DEFINE_VISIT_ADDITIONAL_CHILDREN(JSMessageChannel);
+
+} // namespace WebCore
+
+#endif // ENABLE(CHANNEL_MESSAGING)
diff --git a/src/bun.js/bindings/webcore/JSMessageEvent.cpp b/src/bun.js/bindings/webcore/JSMessageEvent.cpp
index e797e3af2..f6090bd91 100644
--- a/src/bun.js/bindings/webcore/JSMessageEvent.cpp
+++ b/src/bun.js/bindings/webcore/JSMessageEvent.cpp
@@ -41,7 +41,7 @@
#include "JSDOMGlobalObjectInlines.h"
#include "JSDOMOperation.h"
#include "JSDOMWrapperCache.h"
-// #include "JSMessagePort.h"
+#include "JSMessagePort.h"
#include "JSServiceWorker.h"
#include "JSWindowProxy.h"
#include "ScriptExecutionContext.h"
@@ -143,18 +143,18 @@ template<> MessageEvent::Init convertDictionary<MessageEvent::Init>(JSGlobalObje
RETURN_IF_EXCEPTION(throwScope, {});
} else
result.origin = emptyString();
- // JSValue portsValue;
- // if (isNullOrUndefined)
- // portsValue = jsUndefined();
- // else {
- // portsValue = object->get(&lexicalGlobalObject, Identifier::fromString(vm, "ports"_s));
- // RETURN_IF_EXCEPTION(throwScope, { });
- // }
- // if (!portsValue.isUndefined()) {
- // result.ports = convert<IDLSequence<IDLInterface<MessagePort>>>(lexicalGlobalObject, portsValue);
- // RETURN_IF_EXCEPTION(throwScope, { });
- // } else
- // result.ports = Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType{ };
+ JSValue portsValue;
+ if (isNullOrUndefined)
+ portsValue = jsUndefined();
+ else {
+ portsValue = object->get(&lexicalGlobalObject, Identifier::fromString(vm, "ports"_s));
+ RETURN_IF_EXCEPTION(throwScope, {});
+ }
+ if (!portsValue.isUndefined()) {
+ result.ports = convert<IDLSequence<IDLInterface<MessagePort>>>(lexicalGlobalObject, portsValue);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ } else
+ result.ports = Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {};
JSValue sourceValue;
if (isNullOrUndefined)
sourceValue = jsUndefined();
@@ -377,9 +377,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsMessageEvent_data, (JSGlobalObject * lexicalGlobalObj
static inline JSValue jsMessageEvent_portsGetter(JSGlobalObject& lexicalGlobalObject, JSMessageEvent& thisObject)
{
UNUSED_PARAM(lexicalGlobalObject);
- // TODO:
- return JSArray::create(lexicalGlobalObject.vm(), lexicalGlobalObject.arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
- // return thisObject.ports(lexicalGlobalObject);
+ return thisObject.ports(lexicalGlobalObject);
}
JSC_DEFINE_CUSTOM_GETTER(jsMessageEvent_ports, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -416,13 +414,12 @@ static inline JSC::EncodedJSValue jsMessageEventPrototypeFunction_initMessageEve
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
EnsureStillAliveScope argument6 = callFrame->argument(6);
auto source = WebCore::MessageEventSource();
- // RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- // EnsureStillAliveScope argument7 = callFrame->argument(7);
- // auto messagePorts = JSArray::create(lexicalGlobalObject.vm(), lexicalGlobalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
- // auto messagePorts = Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {};
+ // auto source = argument6.value().isUndefined() ? std::nullopt : convert<IDLNullable<IDLUnion<IDLInterface<WindowProxy>, IDLInterface<MessagePort>, IDLInterface<ServiceWorker>>>>(*lexicalGlobalObject, argument6.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ EnsureStillAliveScope argument7 = callFrame->argument(7);
+ auto messagePorts = argument7.value().isUndefined() ? Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {} : convert<IDLSequence<IDLInterface<MessagePort>>>(*lexicalGlobalObject, argument7.value());
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- // RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.initMessageEvent(WTFMove(type), WTFMove(bubbles), WTFMove(cancelable), WTFMove(data), WTFMove(originArg), WTFMove(lastEventId), WTFMove(source), WTFMove(messagePorts)); })));
- RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.initMessageEvent(WTFMove(type), WTFMove(bubbles), WTFMove(cancelable), WTFMove(data), WTFMove(originArg), WTFMove(lastEventId), WTFMove(source)); })));
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.initMessageEvent(WTFMove(type), WTFMove(bubbles), WTFMove(cancelable), WTFMove(data), WTFMove(originArg), WTFMove(lastEventId), WTFMove(source), WTFMove(messagePorts)); })));
}
JSC_DEFINE_HOST_FUNCTION(jsMessageEventPrototypeFunction_initMessageEvent, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
@@ -474,7 +471,7 @@ void JSMessageEvent::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
auto* thisObject = jsCast<JSMessageEvent*>(cell);
analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped());
if (thisObject->scriptExecutionContext())
- analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ analyzer.setLabelForCell(cell, "url "_s + thisObject->scriptExecutionContext()->url().string());
Base::analyzeHeap(cell, analyzer);
}
diff --git a/src/bun.js/bindings/webcore/JSMessageEvent.h b/src/bun.js/bindings/webcore/JSMessageEvent.h
index 85424d9ec..8f48568f7 100644
--- a/src/bun.js/bindings/webcore/JSMessageEvent.h
+++ b/src/bun.js/bindings/webcore/JSMessageEvent.h
@@ -70,6 +70,7 @@ public:
{
return static_cast<MessageEvent&>(Base::wrapped());
}
+
protected:
JSMessageEvent(JSC::Structure*, JSDOMGlobalObject&, Ref<MessageEvent>&&);
@@ -87,5 +88,4 @@ template<> struct JSDOMWrapperConverterTraits<MessageEvent> {
};
template<> MessageEvent::Init convertDictionary<MessageEvent::Init>(JSC::JSGlobalObject&, JSC::JSValue);
-
} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/JSMessageEventCustom.cpp b/src/bun.js/bindings/webcore/JSMessageEventCustom.cpp
index 66390f86b..772a1b3c4 100644
--- a/src/bun.js/bindings/webcore/JSMessageEventCustom.cpp
+++ b/src/bun.js/bindings/webcore/JSMessageEventCustom.cpp
@@ -45,26 +45,21 @@ namespace WebCore {
JSC::JSValue JSMessageEvent::ports(JSC::JSGlobalObject& lexicalGlobalObject) const
{
- return JSC::jsUndefined();
+ auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm());
+ return cachedPropertyValue(lexicalGlobalObject, *this, wrapped().cachedPorts(), [&] {
+ JSC::JSValue ports = toJS<IDLFrozenArray<IDLInterface<MessagePort>>>(lexicalGlobalObject, *globalObject(), throwScope, wrapped().ports());
+ return ports;
+ });
}
-// auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm());
-// return cachedPropertyValue(lexicalGlobalObject, *this, wrapped().cachedPorts(), [&] {
-// JSC::JSValue ports = toJS<IDLFrozenArray<IDLInterface<MessagePort>>>(lexicalGlobalObject, *globalObject(), throwScope, wrapped().ports());
-// return ports;
-// });
-// }
JSC::JSValue JSMessageEvent::data(JSC::JSGlobalObject& lexicalGlobalObject) const
{
- return cachedPropertyValue(lexicalGlobalObject, *this, wrapped().cachedData(), [this, &lexicalGlobalObject] {
+ auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm());
+ return cachedPropertyValue(throwScope, lexicalGlobalObject, *this, wrapped().cachedData(), [this, &lexicalGlobalObject](JSC::ThrowScope&) {
return WTF::switchOn(
- wrapped().data(), [this](MessageEvent::JSValueTag) -> JSC::JSValue { return wrapped().jsData().getValue(JSC::jsNull()); },
- // [this, &lexicalGlobalObject](const Ref<SerializedScriptValue>& data) {
- // // FIXME: Is it best to handle errors by returning null rather than throwing an exception?
- // return data->deserialize(lexicalGlobalObject, globalObject(), wrapped().ports(), SerializationErrorMode::NonThrowing); },
- [&lexicalGlobalObject](const String& data) { return toJS<IDLDOMString>(lexicalGlobalObject, data); },
- // [this, &lexicalGlobalObject](const Ref<Blob>& data) { return toJS<IDLInterface<Blob>>(lexicalGlobalObject, *globalObject(), data); },
- [this, &lexicalGlobalObject](const Ref<ArrayBuffer>& data) { return toJS<IDLInterface<ArrayBuffer>>(lexicalGlobalObject, *globalObject(), data); });
+ wrapped().data(), [this](MessageEvent::JSValueTag) -> JSC::JSValue { return wrapped().jsData().getValue(JSC::jsNull()); }, [this, &lexicalGlobalObject](const Ref<SerializedScriptValue>& data) {
+ // FIXME: Is it best to handle errors by returning null rather than throwing an exception?
+ return data->deserialize(lexicalGlobalObject, globalObject(), wrapped().ports(), SerializationErrorMode::NonThrowing); }, [&lexicalGlobalObject](const String& data) { return toJS<IDLDOMString>(lexicalGlobalObject, data); }, [this, &lexicalGlobalObject](const Ref<ArrayBuffer>& data) { return toJS<IDLInterface<ArrayBuffer>>(lexicalGlobalObject, *globalObject(), data); });
});
}
diff --git a/src/bun.js/bindings/webcore/JSMessagePort.cpp b/src/bun.js/bindings/webcore/JSMessagePort.cpp
new file mode 100644
index 000000000..d957e32ce
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSMessagePort.cpp
@@ -0,0 +1,440 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "JSMessagePort.h"
+
+#include "ActiveDOMObject.h"
+#include "EventNames.h"
+#include "ExtendedDOMClientIsoSubspaces.h"
+#include "ExtendedDOMIsoSubspaces.h"
+#include "IDLTypes.h"
+#include "JSDOMAttribute.h"
+#include "JSDOMBinding.h"
+#include "JSDOMConstructorNotConstructable.h"
+#include "JSDOMConvertAny.h"
+#include "JSDOMConvertBase.h"
+#include "JSDOMConvertDictionary.h"
+#include "JSDOMConvertObject.h"
+#include "JSDOMConvertSequences.h"
+#include "JSDOMExceptionHandling.h"
+#include "JSDOMGlobalObjectInlines.h"
+#include "JSDOMOperation.h"
+#include "JSDOMWrapperCache.h"
+#include "JSEventListener.h"
+#include "JSStructuredSerializeOptions.h"
+#include "ScriptExecutionContext.h"
+#include "WebCoreJSClientData.h"
+// #include "WebCoreOpaqueRootInlines.h"
+#include <JavaScriptCore/HeapAnalyzer.h>
+#include <JavaScriptCore/IteratorOperations.h>
+#include <JavaScriptCore/JSArray.h>
+#include <JavaScriptCore/JSCInlines.h>
+#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
+#include <JavaScriptCore/SlotVisitorMacros.h>
+#include <JavaScriptCore/SubspaceInlines.h>
+#include <wtf/GetPtr.h>
+#include <wtf/PointerPreparations.h>
+#include <wtf/URL.h>
+
+namespace WebCore {
+using namespace JSC;
+
+// Functions
+
+static JSC_DECLARE_HOST_FUNCTION(jsMessagePortPrototypeFunction_postMessage);
+static JSC_DECLARE_HOST_FUNCTION(jsMessagePortPrototypeFunction_start);
+static JSC_DECLARE_HOST_FUNCTION(jsMessagePortPrototypeFunction_close);
+
+// Attributes
+
+static JSC_DECLARE_CUSTOM_GETTER(jsMessagePortConstructor);
+static JSC_DECLARE_CUSTOM_GETTER(jsMessagePort_onmessage);
+static JSC_DECLARE_CUSTOM_SETTER(setJSMessagePort_onmessage);
+static JSC_DECLARE_CUSTOM_GETTER(jsMessagePort_onmessageerror);
+static JSC_DECLARE_CUSTOM_SETTER(setJSMessagePort_onmessageerror);
+
+class JSMessagePortPrototype final : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+ static JSMessagePortPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSMessagePortPrototype* ptr = new (NotNull, JSC::allocateCell<JSMessagePortPrototype>(vm)) JSMessagePortPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMessagePortPrototype, Base);
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSMessagePortPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
+ : JSC::JSNonFinalObject(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMessagePortPrototype, JSMessagePortPrototype::Base);
+
+using JSMessagePortDOMConstructor = JSDOMConstructorNotConstructable<JSMessagePort>;
+
+template<> const ClassInfo JSMessagePortDOMConstructor::s_info = { "MessagePort"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMessagePortDOMConstructor) };
+
+template<> JSValue JSMessagePortDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
+{
+ return JSEventTarget::getConstructor(vm, &globalObject);
+}
+
+template<> void JSMessagePortDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ JSString* nameString = jsNontrivialString(vm, "MessagePort"_s);
+ m_originalName.set(vm, this, nameString);
+ putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ putDirect(vm, vm.propertyNames->prototype, JSMessagePort::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
+}
+
+/* Hash table for prototype */
+
+static const HashTableValue JSMessagePortPrototypeTableValues[] = {
+ { "constructor"_s, static_cast<unsigned>(PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsMessagePortConstructor, 0 } },
+ { "onmessage"_s, JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsMessagePort_onmessage, setJSMessagePort_onmessage } },
+ { "onmessageerror"_s, JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsMessagePort_onmessageerror, setJSMessagePort_onmessageerror } },
+ { "postMessage"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMessagePortPrototypeFunction_postMessage, 1 } },
+ { "start"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMessagePortPrototypeFunction_start, 0 } },
+ { "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMessagePortPrototypeFunction_close, 0 } },
+};
+
+const ClassInfo JSMessagePortPrototype::s_info = { "MessagePort"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMessagePortPrototype) };
+
+void JSMessagePortPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSMessagePort::info(), JSMessagePortPrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+const ClassInfo JSMessagePort::s_info = { "MessagePort"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMessagePort) };
+
+JSMessagePort::JSMessagePort(Structure* structure, JSDOMGlobalObject& globalObject, Ref<MessagePort>&& impl)
+ : JSEventTarget(structure, globalObject, WTFMove(impl))
+{
+}
+
+// static_assert(std::is_base_of<ActiveDOMObject, MessagePort>::value, "Interface is marked as [ActiveDOMObject] but implementation class does not subclass ActiveDOMObject.");
+
+JSObject* JSMessagePort::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ auto* structure = JSMessagePortPrototype::createStructure(vm, &globalObject, JSEventTarget::prototype(vm, globalObject));
+ structure->setMayBePrototype(true);
+ return JSMessagePortPrototype::create(vm, &globalObject, structure);
+}
+
+JSObject* JSMessagePort::prototype(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ return getDOMPrototype<JSMessagePort>(vm, globalObject);
+}
+
+JSValue JSMessagePort::getConstructor(VM& vm, const JSGlobalObject* globalObject)
+{
+ return getDOMConstructor<JSMessagePortDOMConstructor, DOMConstructorID::MessagePort>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsMessagePortConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* prototype = jsDynamicCast<JSMessagePortPrototype*>(JSValue::decode(thisValue));
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(JSMessagePort::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject()));
+}
+
+static inline JSValue jsMessagePort_onmessageGetter(JSGlobalObject& lexicalGlobalObject, JSMessagePort& thisObject)
+{
+ UNUSED_PARAM(lexicalGlobalObject);
+ return eventHandlerAttribute(thisObject.wrapped(), eventNames().messageEvent, worldForDOMObject(thisObject));
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsMessagePort_onmessage, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ return IDLAttribute<JSMessagePort>::get<jsMessagePort_onmessageGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
+}
+
+static inline bool setJSMessagePort_onmessageSetter(JSGlobalObject& lexicalGlobalObject, JSMessagePort& thisObject, JSValue value)
+{
+ auto& vm = JSC::getVM(&lexicalGlobalObject);
+ UNUSED_PARAM(vm);
+ setEventHandlerAttribute<JSEventListener>(thisObject.wrapped(), eventNames().messageEvent, value, thisObject);
+ vm.writeBarrier(&thisObject, value);
+ ensureStillAliveHere(value);
+
+ return true;
+}
+
+JSC_DEFINE_CUSTOM_SETTER(setJSMessagePort_onmessage, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ return IDLAttribute<JSMessagePort>::set<setJSMessagePort_onmessageSetter>(*lexicalGlobalObject, thisValue, encodedValue, attributeName);
+}
+
+static inline JSValue jsMessagePort_onmessageerrorGetter(JSGlobalObject& lexicalGlobalObject, JSMessagePort& thisObject)
+{
+ UNUSED_PARAM(lexicalGlobalObject);
+ return eventHandlerAttribute(thisObject.wrapped(), eventNames().messageerrorEvent, worldForDOMObject(thisObject));
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsMessagePort_onmessageerror, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ return IDLAttribute<JSMessagePort>::get<jsMessagePort_onmessageerrorGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
+}
+
+static inline bool setJSMessagePort_onmessageerrorSetter(JSGlobalObject& lexicalGlobalObject, JSMessagePort& thisObject, JSValue value)
+{
+ auto& vm = JSC::getVM(&lexicalGlobalObject);
+ UNUSED_PARAM(vm);
+ setEventHandlerAttribute<JSEventListener>(thisObject.wrapped(), eventNames().messageerrorEvent, value, thisObject);
+ vm.writeBarrier(&thisObject, value);
+ ensureStillAliveHere(value);
+
+ return true;
+}
+
+JSC_DEFINE_CUSTOM_SETTER(setJSMessagePort_onmessageerror, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ return IDLAttribute<JSMessagePort>::set<setJSMessagePort_onmessageerrorSetter>(*lexicalGlobalObject, thisValue, encodedValue, attributeName);
+}
+
+static inline JSC::EncodedJSValue jsMessagePortPrototypeFunction_postMessage1Body(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSMessagePort>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto message = convert<IDLAny>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1);
+ auto transfer = convert<IDLSequence<IDLObject>>(*lexicalGlobalObject, argument1.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.postMessage(*jsCast<JSDOMGlobalObject*>(lexicalGlobalObject), WTFMove(message), WTFMove(transfer)); })));
+}
+
+static inline JSC::EncodedJSValue jsMessagePortPrototypeFunction_postMessage2Body(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSMessagePort>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto message = convert<IDLAny>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ EnsureStillAliveScope argument1 = callFrame->argument(1);
+ auto options = convert<IDLDictionary<StructuredSerializeOptions>>(*lexicalGlobalObject, argument1.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.postMessage(*jsCast<JSDOMGlobalObject*>(lexicalGlobalObject), WTFMove(message), WTFMove(options)); })));
+}
+
+static inline JSC::EncodedJSValue jsMessagePortPrototypeFunction_postMessageOverloadDispatcher(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSMessagePort>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ size_t argsCount = std::min<size_t>(2, callFrame->argumentCount());
+ if (argsCount == 1) {
+ RELEASE_AND_RETURN(throwScope, (jsMessagePortPrototypeFunction_postMessage2Body(lexicalGlobalObject, callFrame, castedThis)));
+ }
+ if (argsCount == 2) {
+ JSValue distinguishingArg = callFrame->uncheckedArgument(1);
+ if (distinguishingArg.isUndefined())
+ RELEASE_AND_RETURN(throwScope, (jsMessagePortPrototypeFunction_postMessage2Body(lexicalGlobalObject, callFrame, castedThis)));
+ if (distinguishingArg.isUndefinedOrNull())
+ RELEASE_AND_RETURN(throwScope, (jsMessagePortPrototypeFunction_postMessage2Body(lexicalGlobalObject, callFrame, castedThis)));
+ {
+ bool success = hasIteratorMethod(lexicalGlobalObject, distinguishingArg);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ if (success)
+ RELEASE_AND_RETURN(throwScope, (jsMessagePortPrototypeFunction_postMessage1Body(lexicalGlobalObject, callFrame, castedThis)));
+ }
+ if (distinguishingArg.isObject())
+ RELEASE_AND_RETURN(throwScope, (jsMessagePortPrototypeFunction_postMessage2Body(lexicalGlobalObject, callFrame, castedThis)));
+ }
+ return argsCount < 1 ? throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)) : throwVMTypeError(lexicalGlobalObject, throwScope);
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsMessagePortPrototypeFunction_postMessage, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSMessagePort>::call<jsMessagePortPrototypeFunction_postMessageOverloadDispatcher>(*lexicalGlobalObject, *callFrame, "postMessage");
+}
+
+static inline JSC::EncodedJSValue jsMessagePortPrototypeFunction_startBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSMessagePort>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.start(); })));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsMessagePortPrototypeFunction_start, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSMessagePort>::call<jsMessagePortPrototypeFunction_startBody>(*lexicalGlobalObject, *callFrame, "start");
+}
+
+static inline JSC::EncodedJSValue jsMessagePortPrototypeFunction_closeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSMessagePort>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.close(); })));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsMessagePortPrototypeFunction_close, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSMessagePort>::call<jsMessagePortPrototypeFunction_closeBody>(*lexicalGlobalObject, *callFrame, "close");
+}
+
+JSC::GCClient::IsoSubspace* JSMessagePort::subspaceForImpl(JSC::VM& vm)
+{
+ return WebCore::subspaceForImpl<JSMessagePort, UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForMessagePort.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForMessagePort = std::forward<decltype(space)>(space); },
+ [](auto& spaces) { return spaces.m_subspaceForMessagePort.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForMessagePort = std::forward<decltype(space)>(space); });
+}
+
+template<typename Visitor>
+void JSMessagePort::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ auto* thisObject = jsCast<JSMessagePort*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ thisObject->visitAdditionalChildren(visitor);
+}
+
+DEFINE_VISIT_CHILDREN(JSMessagePort);
+
+template<typename Visitor>
+void JSMessagePort::visitOutputConstraints(JSCell* cell, Visitor& visitor)
+{
+ auto* thisObject = jsCast<JSMessagePort*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitOutputConstraints(thisObject, visitor);
+ thisObject->visitAdditionalChildren(visitor);
+}
+
+template void JSMessagePort::visitOutputConstraints(JSCell*, AbstractSlotVisitor&);
+template void JSMessagePort::visitOutputConstraints(JSCell*, SlotVisitor&);
+void JSMessagePort::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSMessagePort*>(cell);
+ analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped());
+ if (thisObject->scriptExecutionContext())
+ analyzer.setLabelForCell(cell, "url "_s + thisObject->scriptExecutionContext()->url().string());
+ Base::analyzeHeap(cell, analyzer);
+}
+
+bool JSMessagePortOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, AbstractSlotVisitor& visitor, const char** reason)
+{
+ auto* jsMessagePort = jsCast<JSMessagePort*>(handle.slot()->asCell());
+ auto& wrapped = jsMessagePort->wrapped();
+ if (wrapped.hasPendingActivity()) {
+ if (UNLIKELY(reason))
+ *reason = "ActiveDOMObject with pending activity";
+ return true;
+ }
+ MessagePort* owner = &jsMessagePort->wrapped();
+ if (UNLIKELY(reason))
+ *reason = "Reachable from MessagePort";
+
+ return visitor.containsOpaqueRoot(owner);
+}
+
+void JSMessagePortOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
+{
+ auto* jsMessagePort = static_cast<JSMessagePort*>(handle.slot()->asCell());
+ auto& world = *static_cast<DOMWrapperWorld*>(context);
+ uncacheWrapper(world, &jsMessagePort->wrapped(), jsMessagePort);
+}
+
+#if ENABLE(BINDING_INTEGRITY)
+#if PLATFORM(WIN)
+#pragma warning(disable : 4483)
+extern "C" {
+extern void (*const __identifier("??_7MessagePort@WebCore@@6B@")[])();
+}
+#else
+extern "C" {
+extern void* _ZTVN7WebCore11MessagePortE[];
+}
+#endif
+#endif
+
+JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref<MessagePort>&& impl)
+{
+
+ if constexpr (std::is_polymorphic_v<MessagePort>) {
+#if ENABLE(BINDING_INTEGRITY)
+ const void* actualVTablePointer = getVTablePointer(impl.ptr());
+#if PLATFORM(WIN)
+ void* expectedVTablePointer = __identifier("??_7MessagePort@WebCore@@6B@");
+#else
+ void* expectedVTablePointer = &_ZTVN7WebCore11MessagePortE[2];
+#endif
+
+ // If you hit this assertion you either have a use after free bug, or
+ // MessagePort has subclasses. If MessagePort has subclasses that get passed
+ // to toJS() we currently require MessagePort you to opt out of binding hardening
+ // by adding the SkipVTableValidation attribute to the interface IDL definition
+ RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
+#endif
+ }
+ return createWrapper<MessagePort>(globalObject, WTFMove(impl));
+}
+
+JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, MessagePort& impl)
+{
+ return wrap(lexicalGlobalObject, globalObject, impl);
+}
+
+MessagePort* JSMessagePort::toWrapped(JSC::VM&, JSC::JSValue value)
+{
+ if (auto* wrapper = jsDynamicCast<JSMessagePort*>(value))
+ return &wrapper->wrapped();
+ return nullptr;
+}
+
+}
diff --git a/src/bun.js/bindings/webcore/JSMessagePort.h b/src/bun.js/bindings/webcore/JSMessagePort.h
new file mode 100644
index 000000000..44c928050
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSMessagePort.h
@@ -0,0 +1,103 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include "JSDOMWrapper.h"
+#include "JSEventTarget.h"
+#include "MessagePort.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+class WEBCORE_EXPORT JSMessagePort : public JSEventTarget {
+public:
+ using Base = JSEventTarget;
+ using DOMWrapped = MessagePort;
+ static JSMessagePort* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<MessagePort>&& impl)
+ {
+ JSMessagePort* ptr = new (NotNull, JSC::allocateCell<JSMessagePort>(globalObject->vm())) JSMessagePort(structure, *globalObject, WTFMove(impl));
+ ptr->finishCreation(globalObject->vm());
+ return ptr;
+ }
+
+ static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);
+ static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
+ static MessagePort* toWrapped(JSC::VM&, JSC::JSValue);
+
+ DECLARE_INFO;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), JSC::NonArray);
+ }
+
+ static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return subspaceForImpl(vm);
+ }
+ static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
+ DECLARE_VISIT_CHILDREN;
+ template<typename Visitor> void visitAdditionalChildren(Visitor&);
+
+ template<typename Visitor> static void visitOutputConstraints(JSCell*, Visitor&);
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+ MessagePort& wrapped() const
+ {
+ return static_cast<MessagePort&>(Base::wrapped());
+ }
+
+protected:
+ JSMessagePort(JSC::Structure*, JSDOMGlobalObject&, Ref<MessagePort>&&);
+
+ DECLARE_DEFAULT_FINISH_CREATION;
+};
+
+class WEBCORE_EXPORT JSMessagePortOwner final : public JSC::WeakHandleOwner {
+public:
+ bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::AbstractSlotVisitor&, const char**) final;
+ void finalize(JSC::Handle<JSC::Unknown>, void* context) final;
+};
+
+inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, MessagePort*)
+{
+ static NeverDestroyed<JSMessagePortOwner> owner;
+ return &owner.get();
+}
+
+inline void* wrapperKey(MessagePort* wrappableObject)
+{
+ return wrappableObject;
+}
+
+WEBCORE_EXPORT JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, MessagePort&);
+inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, MessagePort* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); }
+JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref<MessagePort>&&);
+inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr<MessagePort>&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }
+
+template<> struct JSDOMWrapperConverterTraits<MessagePort> {
+ using WrapperClass = JSMessagePort;
+ using ToWrappedReturnType = MessagePort*;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/JSMessagePortCustom.cpp b/src/bun.js/bindings/webcore/JSMessagePortCustom.cpp
new file mode 100644
index 000000000..56031dd60
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSMessagePortCustom.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008-2021 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2011 Google 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.
+ */
+
+#include "config.h"
+#include "JSMessagePort.h"
+// #include "WebCoreOpaqueRootInlines.h"
+
+namespace WebCore {
+using namespace JSC;
+
+template<typename Visitor>
+void JSMessagePort::visitAdditionalChildren(Visitor& visitor)
+{
+ // If we have a locally entangled port, we can directly mark it as reachable. Ports that are remotely entangled are marked in-use by markActiveObjectsForContext().
+ if (auto* port = wrapped().locallyEntangledPort()) {
+ visitor.addOpaqueRoot(port);
+ // addWebCoreOpaqueRoot(visitor, *port);
+ }
+}
+
+DEFINE_VISIT_ADDITIONAL_CHILDREN(JSMessagePort);
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/JSStructuredSerializeOptions.cpp b/src/bun.js/bindings/webcore/JSStructuredSerializeOptions.cpp
new file mode 100644
index 000000000..4311426e6
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSStructuredSerializeOptions.cpp
@@ -0,0 +1,58 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "JSStructuredSerializeOptions.h"
+
+#include "JSDOMConvertObject.h"
+#include "JSDOMConvertSequences.h"
+#include <JavaScriptCore/JSArray.h>
+#include <JavaScriptCore/JSCInlines.h>
+
+namespace WebCore {
+using namespace JSC;
+
+template<> StructuredSerializeOptions convertDictionary<StructuredSerializeOptions>(JSGlobalObject& lexicalGlobalObject, JSValue value)
+{
+ VM& vm = JSC::getVM(&lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ bool isNullOrUndefined = value.isUndefinedOrNull();
+ auto* object = isNullOrUndefined ? nullptr : value.getObject();
+ if (UNLIKELY(!isNullOrUndefined && !object)) {
+ throwTypeError(&lexicalGlobalObject, throwScope);
+ return {};
+ }
+ StructuredSerializeOptions result;
+ JSValue transferValue;
+ if (isNullOrUndefined)
+ transferValue = jsUndefined();
+ else {
+ transferValue = object->get(&lexicalGlobalObject, Identifier::fromString(vm, "transfer"_s));
+ RETURN_IF_EXCEPTION(throwScope, {});
+ }
+ if (!transferValue.isUndefined()) {
+ result.transfer = convert<IDLSequence<IDLObject>>(lexicalGlobalObject, transferValue);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ } else
+ result.transfer = Converter<IDLSequence<IDLObject>>::ReturnType {};
+ return result;
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/JSStructuredSerializeOptions.h b/src/bun.js/bindings/webcore/JSStructuredSerializeOptions.h
new file mode 100644
index 000000000..8fc8fddd0
--- /dev/null
+++ b/src/bun.js/bindings/webcore/JSStructuredSerializeOptions.h
@@ -0,0 +1,30 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include "JSDOMConvertDictionary.h"
+#include "StructuredSerializeOptions.h"
+
+namespace WebCore {
+
+template<> StructuredSerializeOptions convertDictionary<StructuredSerializeOptions>(JSC::JSGlobalObject&, JSC::JSValue);
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/JSValueInWrappedObject.h b/src/bun.js/bindings/webcore/JSValueInWrappedObject.h
index d05fdb8fd..d11796912 100644
--- a/src/bun.js/bindings/webcore/JSValueInWrappedObject.h
+++ b/src/bun.js/bindings/webcore/JSValueInWrappedObject.h
@@ -61,6 +61,7 @@ private:
JSC::Weak<JSC::JSCell> m_cell {};
};
+JSC::JSValue cachedPropertyValue(JSC::ThrowScope&, JSC::JSGlobalObject&, const JSDOMObject& owner, JSValueInWrappedObject& cacheSlot, const Function<JSC::JSValue(JSC::ThrowScope&)>&);
JSC::JSValue cachedPropertyValue(JSC::JSGlobalObject&, const JSDOMObject& owner, JSValueInWrappedObject& cacheSlot, const Function<JSC::JSValue()>&);
inline JSValueInWrappedObject::JSValueInWrappedObject(JSC::JSValue value)
@@ -132,4 +133,17 @@ inline JSC::JSValue cachedPropertyValue(JSC::JSGlobalObject& lexicalGlobalObject
return cachedValue.getValue();
}
+inline JSC::JSValue cachedPropertyValue(JSC::ThrowScope& throwScope, JSC::JSGlobalObject& lexicalGlobalObject, const JSDOMObject& owner, JSValueInWrappedObject& cachedValue, const Function<JSC::JSValue(JSC::ThrowScope&)>& function)
+{
+ if (cachedValue && isWorldCompatible(lexicalGlobalObject, cachedValue.getValue()))
+ return cachedValue.getValue();
+
+ auto value = function(throwScope);
+ RETURN_IF_EXCEPTION(throwScope, {});
+
+ cachedValue.set(lexicalGlobalObject.vm(), &owner, cloneAcrossWorlds(lexicalGlobalObject, owner, value));
+ ASSERT(isWorldCompatible(lexicalGlobalObject, cachedValue.getValue()));
+ return cachedValue.getValue();
+}
+
} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessageChannel.cpp b/src/bun.js/bindings/webcore/MessageChannel.cpp
new file mode 100644
index 000000000..67407b9c0
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessageChannel.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ */
+
+#include "config.h"
+#include "MessageChannel.h"
+
+#include "MessagePort.h"
+#include "MessagePortChannelProvider.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+static std::pair<Ref<MessagePort>, Ref<MessagePort>> generateMessagePorts(ScriptExecutionContext& context)
+{
+ MessagePortIdentifier id1 = { ProcessIdent::identifier(), PortIdentifier::generate() };
+ MessagePortIdentifier id2 = { ProcessIdent::identifier(), PortIdentifier::generate() };
+
+ return { MessagePort::create(context, id1, id2), MessagePort::create(context, id2, id1) };
+}
+
+Ref<MessageChannel> MessageChannel::create(ScriptExecutionContext& context)
+{
+ return adoptRef(*new MessageChannel(context));
+}
+
+MessageChannel::MessageChannel(ScriptExecutionContext& context)
+ : m_ports(generateMessagePorts(context))
+{
+ if (!context.activeDOMObjectsAreStopped()) {
+ ASSERT(!port1().isDetached());
+ ASSERT(!port2().isDetached());
+ MessagePortChannelProvider::fromContext(context).createNewMessagePortChannel(port1().identifier(), port2().identifier());
+ } else {
+ ASSERT(port1().isDetached());
+ ASSERT(port2().isDetached());
+ }
+}
+
+MessageChannel::~MessageChannel() = default;
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessageChannel.h b/src/bun.js/bindings/webcore/MessageChannel.h
new file mode 100644
index 000000000..1cc936094
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessageChannel.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 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 <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class MessagePort;
+class ScriptExecutionContext;
+
+class MessageChannel : public RefCounted<MessageChannel> {
+public:
+ static Ref<MessageChannel> create(ScriptExecutionContext&);
+ ~MessageChannel();
+
+ MessagePort& port1() const { return m_ports.first; }
+ MessagePort& port2() const { return m_ports.second; }
+
+private:
+ explicit MessageChannel(ScriptExecutionContext&);
+
+ std::pair<Ref<MessagePort>, Ref<MessagePort>> m_ports;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessageEvent.cpp b/src/bun.js/bindings/webcore/MessageEvent.cpp
index b210f4cec..b5a96a4a2 100644
--- a/src/bun.js/bindings/webcore/MessageEvent.cpp
+++ b/src/bun.js/bindings/webcore/MessageEvent.cpp
@@ -30,7 +30,10 @@
// #include "Blob.h"
#include "EventNames.h"
+#include "JSDOMConvert.h"
+#include "JSMessageEvent.h"
#include <JavaScriptCore/JSCInlines.h>
+
// #include <wtf/IsoMallocInlines.h>
namespace WebCore {
@@ -47,29 +50,29 @@ inline MessageEvent::MessageEvent(const AtomString& type, Init&& initializer, Is
, m_origin(initializer.origin)
, m_lastEventId(initializer.lastEventId)
, m_source(WTFMove(initializer.source))
- // , m_ports(WTFMove(initializer.ports))
+ , m_ports(WTFMove(initializer.ports))
, m_jsData(initializer.data)
{
}
-inline MessageEvent::MessageEvent(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source /*, Vector<RefPtr<MessagePort>>&& ports*/)
+inline MessageEvent::MessageEvent(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
: Event(type, CanBubble::No, IsCancelable::No)
, m_data(WTFMove(data))
, m_origin(origin)
, m_lastEventId(lastEventId)
, m_source(WTFMove(source))
-// , m_ports(WTFMove(ports))
+ , m_ports(WTFMove(ports))
{
}
-Ref<MessageEvent> MessageEvent::create(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source /*, Vector<RefPtr<MessagePort>>&& ports*/)
+Ref<MessageEvent> MessageEvent::create(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
{
- return adoptRef(*new MessageEvent(type, WTFMove(data), origin, lastEventId, WTFMove(source) /*, /*WTFMove(ports)*/));
+ return adoptRef(*new MessageEvent(type, WTFMove(data), origin, lastEventId, WTFMove(source), WTFMove(ports)));
}
-Ref<MessageEvent> MessageEvent::create(DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source /*, Vector<RefPtr<MessagePort>>&& ports*/)
+Ref<MessageEvent> MessageEvent::create(DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
{
- return create(eventNames().messageEvent, WTFMove(data), origin, lastEventId, WTFMove(source) /*, /*WTFMove(ports)*/);
+ return create(eventNames().messageEvent, WTFMove(data), origin, lastEventId, WTFMove(source), WTFMove(ports));
}
Ref<MessageEvent> MessageEvent::createForBindings()
@@ -84,7 +87,32 @@ Ref<MessageEvent> MessageEvent::create(const AtomString& type, Init&& initialize
MessageEvent::~MessageEvent() = default;
-void MessageEvent::initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSValue data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source /*, Vector<RefPtr<MessagePort>>&& ports*/)
+auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScriptValue>&& data, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports) -> MessageEventWithStrongData
+{
+ return create(globalObject, WTFMove(data), {}, {}, WTFMove(source), WTFMove(ports));
+}
+
+auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScriptValue>&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports) -> MessageEventWithStrongData
+{
+ auto& vm = globalObject.vm();
+ // Locker<JSC::JSLock> locker(vm.apiLock());
+
+ bool didFail = false;
+
+ auto deserialized = data->deserialize(globalObject, &globalObject, ports, SerializationErrorMode::NonThrowing, &didFail);
+ JSC::Strong<JSC::Unknown> strongData(vm, deserialized);
+
+ auto& eventType = didFail ? eventNames().messageerrorEvent : eventNames().messageEvent;
+ auto event = adoptRef(*new MessageEvent(eventType, WTFMove(data), origin, lastEventId, WTFMove(source), WTFMove(ports)));
+ JSC::Strong<JSC::JSObject> strongWrapper(vm, JSC::jsCast<JSC::JSObject*>(toJS(&globalObject, JSC::jsCast<JSDOMGlobalObject*>(&globalObject), event.get())));
+ // Since we've already deserialized the SerializedScriptValue, cache the result so we don't have to deserialize
+ // again the next time JSMessageEvent::data() gets called by the main world.
+ event->cachedData().set(vm, strongWrapper.get(), deserialized);
+
+ return MessageEventWithStrongData { event, WTFMove(strongWrapper) };
+}
+
+void MessageEvent::initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSValue data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
{
if (isBeingDispatched())
return;
@@ -102,7 +130,7 @@ void MessageEvent::initMessageEvent(const AtomString& type, bool canBubble, bool
m_origin = origin;
m_lastEventId = lastEventId;
m_source = WTFMove(source);
- // m_ports = WTFMove(ports);
+ m_ports = WTFMove(ports);
m_cachedPorts.clear();
}
@@ -116,7 +144,7 @@ size_t MessageEvent::memoryCost() const
Locker { m_concurrentDataAccessLock };
return WTF::switchOn(
m_data, [](JSValueTag) -> size_t { return 0; },
- // [](const Ref<SerializedScriptValue>& data) -> size_t { return data->memoryCost(); },
+ [](const Ref<SerializedScriptValue>& data) -> size_t { return data->memoryCost(); },
[](const String& string) -> size_t { return string.sizeInBytes(); },
// [](const Ref<Blob>& blob) -> size_t { return blob->size(); },
[](const Ref<ArrayBuffer>& buffer) -> size_t { return buffer->byteLength(); });
diff --git a/src/bun.js/bindings/webcore/MessageEvent.h b/src/bun.js/bindings/webcore/MessageEvent.h
index 4089e2ca1..184aa63a1 100644
--- a/src/bun.js/bindings/webcore/MessageEvent.h
+++ b/src/bun.js/bindings/webcore/MessageEvent.h
@@ -29,17 +29,16 @@
#include "Event.h"
#include "JSValueInWrappedObject.h"
-// #include "MessagePort.h"
-// #include "SerializedScriptValue.h"
+#include "MessagePort.h"
+#include "SerializedScriptValue.h"
+#include "MessagePort.h"
+// #include "JSMessageEvent.h"
// #include "ServiceWorker.h"
// #include "WindowProxy.h"
#include <variant>
namespace WebCore {
-class MessagePort : public RefCounted<MessagePort> {
-};
-
class MessageEventSource {
};
@@ -50,9 +49,10 @@ public:
struct JSValueTag {
};
// using DataType = std::variant<JSValueTag, Ref<SerializedScriptValue>, String, Ref<Blob>, Ref<ArrayBuffer>>;
- using DataType = std::variant<JSValueTag, String, Ref<ArrayBuffer>>;
- static Ref<MessageEvent> create(const AtomString& type, DataType&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt /*, Vector<RefPtr<MessagePort>>&& = {}*/);
- static Ref<MessageEvent> create(DataType&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt /*, Vector<RefPtr<MessagePort>>&& = {}*/);
+ using DataType = std::variant<JSValueTag, Ref<SerializedScriptValue>, String, Ref<ArrayBuffer>>;
+ static Ref<MessageEvent> create(const AtomString& type, DataType&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
+ static Ref<MessageEvent> create(DataType&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
+
static Ref<MessageEvent> createForBindings();
struct Init : EventInit {
@@ -60,18 +60,27 @@ public:
String origin;
String lastEventId;
std::optional<MessageEventSource> source;
- // Vector<RefPtr<MessagePort>> ports;
+ Vector<RefPtr<MessagePort>> ports;
};
static Ref<MessageEvent> create(const AtomString& type, Init&&, IsTrusted = IsTrusted::No);
+ struct MessageEventWithStrongData {
+ Ref<MessageEvent> event;
+ JSC::Strong<JSC::JSObject> strongWrapper; // Keep the wrapper alive until the event is fired, since it is what keeps `data` alive.
+ };
+
+ static MessageEventWithStrongData create(JSC::JSGlobalObject&, Ref<SerializedScriptValue>&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
+
+ static MessageEventWithStrongData create(JSC::JSGlobalObject&, Ref<SerializedScriptValue>&&, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
+
virtual ~MessageEvent();
- void initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSC::JSValue data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& /*, Vector<RefPtr<MessagePort>>&&*/);
+ void initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSC::JSValue data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&&, Vector<RefPtr<MessagePort>>&&);
const String& origin() const { return m_origin; }
const String& lastEventId() const { return m_lastEventId; }
const std::optional<MessageEventSource>& source() const { return m_source; }
- // const Vector<RefPtr<MessagePort>>& ports() const { return m_ports; }
+ const Vector<RefPtr<MessagePort>>& ports() const { return m_ports; }
const DataType& data() const { return m_data; }
@@ -84,7 +93,7 @@ public:
private:
MessageEvent();
MessageEvent(const AtomString& type, Init&&, IsTrusted);
- MessageEvent(const AtomString& type, DataType&&, const String& origin, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt /*, Vector<RefPtr<MessagePort>>&& = {}*/);
+ MessageEvent(const AtomString& type, DataType&&, const String& origin, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
EventInterface eventInterface() const final;
@@ -92,7 +101,7 @@ private:
String m_origin;
String m_lastEventId;
std::optional<MessageEventSource> m_source;
- // Vector<RefPtr<MessagePort>> m_ports;
+ Vector<RefPtr<MessagePort>> m_ports;
JSValueInWrappedObject m_jsData;
JSValueInWrappedObject m_cachedData;
diff --git a/src/bun.js/bindings/webcore/MessagePort.cpp b/src/bun.js/bindings/webcore/MessagePort.cpp
new file mode 100644
index 000000000..956143c80
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePort.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ */
+
+#include "config.h"
+#include "MessagePort.h"
+
+// #include "Document.h"
+#include "EventNames.h"
+// #include "Logging.h"
+#include "MessageEvent.h"
+#include "BunWorkerGlobalScope.h"
+#include "MessagePortChannelProvider.h"
+#include "MessageWithMessagePorts.h"
+#include "StructuredSerializeOptions.h"
+#include "WebCoreOpaqueRoot.h"
+// #include "WorkerGlobalScope.h"
+// #include "WorkerThread.h"
+#include "TaskSource.h"
+#include <wtf/CompletionHandler.h>
+#include <wtf/IsoMallocInlines.h>
+#include <wtf/Lock.h>
+#include <wtf/Scope.h>
+
+namespace WebCore {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(MessagePort);
+
+static Lock allMessagePortsLock;
+static HashMap<MessagePortIdentifier, MessagePort*>& allMessagePorts() WTF_REQUIRES_LOCK(allMessagePortsLock)
+{
+ static NeverDestroyed<HashMap<MessagePortIdentifier, MessagePort*>> map;
+ return map;
+}
+
+static HashMap<MessagePortIdentifier, ScriptExecutionContextIdentifier>& portToContextIdentifier() WTF_REQUIRES_LOCK(allMessagePortsLock)
+{
+ static NeverDestroyed<HashMap<MessagePortIdentifier, ScriptExecutionContextIdentifier>> map;
+ return map;
+}
+
+void MessagePort::ref() const
+{
+ ++m_refCount;
+}
+
+void MessagePort::deref() const
+{
+ // This custom deref() function ensures that as long as the lock to allMessagePortsLock is taken, no MessagePort will be destroyed.
+ // This allows notifyMessageAvailable to easily query the map and manipulate MessagePort instances.
+
+ if (!--m_refCount) {
+ Locker locker { allMessagePortsLock };
+
+ if (m_refCount)
+ return;
+
+ auto iterator = allMessagePorts().find(m_identifier);
+ if (iterator != allMessagePorts().end() && iterator->value == this) {
+ allMessagePorts().remove(iterator);
+ portToContextIdentifier().remove(m_identifier);
+ }
+
+ delete this;
+ }
+}
+
+bool MessagePort::hasPendingActivity() const
+{
+ return m_refCount > 0;
+}
+
+bool MessagePort::isMessagePortAliveForTesting(const MessagePortIdentifier& identifier)
+{
+ Locker locker { allMessagePortsLock };
+ return allMessagePorts().contains(identifier);
+}
+
+ScriptExecutionContextIdentifier MessagePort::contextIdForMessagePortId(MessagePortIdentifier messagePortId)
+{
+ Locker locker { allMessagePortsLock };
+ return portToContextIdentifier().get(messagePortId);
+}
+
+void MessagePort::notifyMessageAvailable(const MessagePortIdentifier& identifier)
+{
+ ASSERT(isMainThread());
+ ScriptExecutionContextIdentifier scriptExecutionContextIdentifier;
+ {
+ Locker locker { allMessagePortsLock };
+ scriptExecutionContextIdentifier = portToContextIdentifier().get(identifier);
+ }
+ if (!scriptExecutionContextIdentifier)
+ return;
+
+ ScriptExecutionContext::ensureOnContextThread(scriptExecutionContextIdentifier, [identifier](auto&) {
+ RefPtr<MessagePort> port;
+ {
+ Locker locker { allMessagePortsLock };
+ port = allMessagePorts().get(identifier);
+ }
+ if (port)
+ port->messageAvailable();
+ });
+}
+
+Ref<MessagePort> MessagePort::create(ScriptExecutionContext& scriptExecutionContext, const MessagePortIdentifier& local, const MessagePortIdentifier& remote)
+{
+ auto messagePort = adoptRef(*new MessagePort(scriptExecutionContext, local, remote));
+ // messagePort->suspendIfNeeded();
+ return messagePort;
+}
+
+MessagePort::MessagePort(ScriptExecutionContext& scriptExecutionContext, const MessagePortIdentifier& local, const MessagePortIdentifier& remote)
+ // : ActiveDOMObject(&scriptExecutionContext)
+ : ContextDestructionObserver(&scriptExecutionContext)
+ , m_identifier(local)
+ , m_remoteIdentifier(remote)
+{
+ LOG(MessagePorts, "Created MessagePort %s (%p) in process %" PRIu64, m_identifier.logString().utf8().data(), this, ProcessIdent::identifier().toUInt64());
+
+ Locker locker { allMessagePortsLock };
+ allMessagePorts().set(m_identifier, this);
+ portToContextIdentifier().set(m_identifier, scriptExecutionContext.identifier());
+
+ // Make sure the WeakPtrFactory gets initialized eagerly on the thread the MessagePort gets constructed on for thread-safety reasons.
+ initializeWeakPtrFactory();
+
+ scriptExecutionContext.createdMessagePort(*this);
+
+ // Don't need to call processMessageWithMessagePortsSoon() here, because the port will not be opened until start() is invoked.
+}
+
+MessagePort::~MessagePort()
+{
+ LOG(MessagePorts, "Destroyed MessagePort %s (%p) in process %" PRIu64, m_identifier.logString().utf8().data(), this, ProcessIdent::identifier().toUInt64());
+
+ ASSERT(allMessagePortsLock.isLocked());
+
+ if (m_entangled)
+ close();
+
+ if (auto contextId = portToContextIdentifier().get(m_identifier))
+ ScriptExecutionContext::getScriptExecutionContext(contextId)->destroyedMessagePort(*this);
+}
+
+void MessagePort::entangle()
+{
+ ScriptExecutionContext::ensureOnMainThread([identifier = m_identifier, remoteIdentifier = m_remoteIdentifier](ScriptExecutionContext& context) {
+ MessagePortChannelProvider::fromContext(context).entangleLocalPortInThisProcessToRemote(identifier, remoteIdentifier);
+ });
+}
+
+ExceptionOr<void> MessagePort::postMessage(JSC::JSGlobalObject& state, JSC::JSValue messageValue, StructuredSerializeOptions&& options)
+{
+ LOG(MessagePorts, "Attempting to post message to port %s (to be received by port %s)", m_identifier.logString().utf8().data(), m_remoteIdentifier.logString().utf8().data());
+
+ Vector<RefPtr<MessagePort>> ports;
+ auto messageData = SerializedScriptValue::create(state, messageValue, WTFMove(options.transfer), ports, SerializationForStorage::No, SerializationContext::WorkerPostMessage);
+ if (messageData.hasException())
+ return messageData.releaseException();
+
+ if (!isEntangled())
+ return {};
+ ASSERT(scriptExecutionContext());
+
+ Vector<TransferredMessagePort> transferredPorts;
+ // Make sure we aren't connected to any of the passed-in ports.
+ if (!ports.isEmpty()) {
+ for (auto& port : ports) {
+ if (port->identifier() == m_identifier || port->identifier() == m_remoteIdentifier)
+ return Exception { DataCloneError };
+ }
+
+ auto disentangleResult = MessagePort::disentanglePorts(WTFMove(ports));
+ if (disentangleResult.hasException())
+ return disentangleResult.releaseException();
+ transferredPorts = disentangleResult.releaseReturnValue();
+ }
+
+ MessageWithMessagePorts message { messageData.releaseReturnValue(), WTFMove(transferredPorts) };
+
+ LOG(MessagePorts, "Actually posting message to port %s (to be received by port %s)", m_identifier.logString().utf8().data(), m_remoteIdentifier.logString().utf8().data());
+
+ ScriptExecutionContextIdentifier contextId = contextIdForMessagePortId(m_remoteIdentifier);
+
+ MessagePortChannelProvider::fromContext(*ScriptExecutionContext::getScriptExecutionContext(contextId)).postMessageToRemote(WTFMove(message), m_remoteIdentifier);
+
+ return {};
+}
+
+TransferredMessagePort MessagePort::disentangle()
+{
+ ASSERT(m_entangled);
+ m_entangled = false;
+
+ auto& context = *scriptExecutionContext();
+ MessagePortChannelProvider::fromContext(context).messagePortDisentangled(m_identifier);
+
+ // We can't receive any messages or generate any events after this, so remove ourselves from the list of active ports.
+ context.destroyedMessagePort(*this);
+ // context.willDestroyActiveDOMObject(*this);
+ context.willDestroyDestructionObserver(*this);
+
+ observeContext(nullptr);
+
+ return { identifier(), remoteIdentifier() };
+}
+
+// Invoked to notify us that there are messages available for this port.
+// This code may be called from another thread, and so should not call any non-threadsafe APIs (i.e. should not call into the entangled channel or access mutable variables).
+void MessagePort::messageAvailable()
+{
+ // This MessagePort object might be disentangled because the port is being transferred,
+ // in which case we'll notify it that messages are available once a new end point is created.
+ auto* context = scriptExecutionContext();
+ if (!context || context->activeDOMObjectsAreSuspended())
+ return;
+
+ context->processMessageWithMessagePortsSoon([pendingActivity = Ref { *this }] {});
+}
+
+void MessagePort::start()
+{
+ // Do nothing if we've been cloned or closed.
+ if (!isEntangled())
+ return;
+
+ ASSERT(scriptExecutionContext());
+ if (m_started)
+ return;
+
+ m_started = true;
+ scriptExecutionContext()->processMessageWithMessagePortsSoon([pendingActivity = Ref { *this }] {});
+}
+
+void MessagePort::close()
+{
+ if (m_isDetached)
+ return;
+ m_isDetached = true;
+
+ ScriptExecutionContext::ensureOnMainThread([identifier = m_identifier, protectedThis = Ref { *this }](ScriptExecutionContext& context) {
+ MessagePortChannelProvider::singleton().messagePortClosed(identifier);
+ });
+
+ removeAllEventListeners();
+}
+
+void MessagePort::dispatchMessages()
+{
+ // Messages for contexts that are not fully active get dispatched too, but JSAbstractEventListener::handleEvent() doesn't call handlers for these.
+ // The HTML5 spec specifies that any messages sent to a document that is not fully active should be dropped, so this behavior is OK.
+ ASSERT(started());
+
+ auto* context = scriptExecutionContext();
+ if (!context || context->activeDOMObjectsAreSuspended() || !isEntangled())
+ return;
+
+ auto messagesTakenHandler = [this, protectedThis = Ref { *this }](Vector<MessageWithMessagePorts>&& messages, CompletionHandler<void()>&& completionCallback) mutable {
+ auto scopeExit = makeScopeExit(WTFMove(completionCallback));
+
+ LOG(MessagePorts, "MessagePort %s (%p) dispatching %zu messages", m_identifier.logString().utf8().data(), this, messages.size());
+
+ auto* context = scriptExecutionContext();
+ if (!context || !context->jsGlobalObject())
+ return;
+
+ ASSERT(context->isContextThread());
+
+ // bool contextIsWorker = is<WorkerGlobalScope>(*context);
+ for (auto& message : messages) {
+ // close() in Worker onmessage handler should prevent next message from dispatching.
+ // if (contextIsWorker && downcast<WorkerGlobalScope>(*context).isClosing())
+ // return;
+
+ auto ports = MessagePort::entanglePorts(*context, WTFMove(message.transferredPorts));
+
+ // Per specification, each MessagePort object has a task source called the port message queue.
+ // queueTaskKeepingObjectAlive(context, *this, TaskSource::PostedMessageQueue, [this, event = WTFMove(event)] {
+ // dispatchEvent(event.event);
+ // });
+
+ ScriptExecutionContext::postTaskTo(contextIdForMessagePortId(m_identifier), [protectedThis = Ref { *this }, ports = WTFMove(ports), message = WTFMove(message)](ScriptExecutionContext& context) mutable {
+ auto event = MessageEvent::create(*context.jsGlobalObject(), message.message.releaseNonNull(), {}, {}, {}, WTFMove(ports));
+ protectedThis->dispatchEvent(event.event);
+ });
+ }
+ };
+
+ MessagePortChannelProvider::fromContext(*context).takeAllMessagesForPort(m_identifier, WTFMove(messagesTakenHandler));
+}
+
+void MessagePort::dispatchEvent(Event& event)
+{
+ if (m_isDetached) {
+ return;
+ }
+
+ // auto* context = scriptExecutionContext();
+ // if (is<WebCore::GlobalScope>(*context) && downcast<WebCore::GlobalScope>(*context).isClosing())
+ // return;
+
+ EventTarget::dispatchEvent(event);
+}
+
+// https://html.spec.whatwg.org/multipage/web-messaging.html#ports-and-garbage-collection
+// bool MessagePort::virtualHasPendingActivity() const
+// {
+// // If the ScriptExecutionContext has been shut down on this object close()'ed, we can GC.
+// auto* context = scriptExecutionContext();
+// if (!context || m_isDetached)
+// return false;
+
+// // If this MessagePort has no message event handler then there is no point in keeping it alive.
+// if (!m_hasMessageEventListener)
+// return false;
+
+// return m_entangled;
+// }
+
+MessagePort* MessagePort::locallyEntangledPort()
+{
+ // FIXME: As the header describes, this is an optional optimization.
+ // Even in the new async model we should be able to get it right.
+ return nullptr;
+}
+
+ExceptionOr<Vector<TransferredMessagePort>> MessagePort::disentanglePorts(Vector<RefPtr<MessagePort>>&& ports)
+{
+ if (ports.isEmpty())
+ return Vector<TransferredMessagePort> {};
+
+ // Walk the incoming array - if there are any duplicate ports, or null ports or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec).
+ HashSet<MessagePort*> portSet;
+ for (auto& port : ports) {
+ if (!port || !port->m_entangled || !portSet.add(port.get()).isNewEntry)
+ return Exception { DataCloneError };
+ }
+
+ // Passed-in ports passed validity checks, so we can disentangle them.
+ return WTF::map(ports, [](auto& port) {
+ return port->disentangle();
+ });
+}
+
+Vector<RefPtr<MessagePort>> MessagePort::entanglePorts(ScriptExecutionContext& context, Vector<TransferredMessagePort>&& transferredPorts)
+{
+ LOG(MessagePorts, "Entangling %zu transferred ports to ScriptExecutionContext %s (%p)", transferredPorts.size(), context.url().string().utf8().data(), &context);
+
+ if (transferredPorts.isEmpty())
+ return {};
+
+ return WTF::map(transferredPorts, [&](auto& port) -> RefPtr<MessagePort> {
+ return MessagePort::entangle(context, WTFMove(port));
+ });
+}
+
+Ref<MessagePort> MessagePort::entangle(ScriptExecutionContext& context, TransferredMessagePort&& transferredPort)
+{
+ auto port = MessagePort::create(context, transferredPort.first, transferredPort.second);
+ port->entangle();
+ return port;
+}
+
+bool MessagePort::addEventListener(const AtomString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
+{
+ if (eventType == eventNames().messageEvent) {
+ if (listener->isAttribute())
+ start();
+ m_hasMessageEventListener = true;
+ }
+
+ return EventTarget::addEventListener(eventType, WTFMove(listener), options);
+}
+
+bool MessagePort::removeEventListener(const AtomString& eventType, EventListener& listener, const EventListenerOptions& options)
+{
+ auto result = EventTarget::removeEventListener(eventType, listener, options);
+
+ if (!hasEventListeners(eventNames().messageEvent))
+ m_hasMessageEventListener = false;
+
+ return result;
+}
+
+// const char* MessagePort::activeDOMObjectName() const
+// {
+// return "MessagePort";
+// }
+
+WebCoreOpaqueRoot root(MessagePort* port)
+{
+ return WebCoreOpaqueRoot { port };
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePort.h b/src/bun.js/bindings/webcore/MessagePort.h
new file mode 100644
index 000000000..18f0ba212
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePort.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 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 "ActiveDOMObject.h"
+#include "EventTarget.h"
+#include "ExceptionOr.h"
+#include "MessagePortChannel.h"
+#include "MessagePortIdentifier.h"
+#include "MessageWithMessagePorts.h"
+#include <wtf/WeakPtr.h>
+
+namespace JSC {
+class CallFrame;
+class JSObject;
+class JSValue;
+}
+
+namespace WebCore {
+
+class LocalFrame;
+class WebCoreOpaqueRoot;
+
+struct StructuredSerializeOptions;
+
+class MessagePort final : /* public ActiveDOMObject, */ public ContextDestructionObserver, public EventTarget {
+ WTF_MAKE_NONCOPYABLE(MessagePort);
+ WTF_MAKE_ISO_ALLOCATED(MessagePort);
+
+public:
+ static Ref<MessagePort> create(ScriptExecutionContext&, const MessagePortIdentifier& local, const MessagePortIdentifier& remote);
+ virtual ~MessagePort();
+
+ ExceptionOr<void> postMessage(JSC::JSGlobalObject&, JSC::JSValue message, StructuredSerializeOptions&&);
+
+ void start();
+ void close();
+ void entangle();
+
+ // Returns nullptr if the passed-in vector is empty.
+ static ExceptionOr<Vector<TransferredMessagePort>> disentanglePorts(Vector<RefPtr<MessagePort>>&&);
+ static Vector<RefPtr<MessagePort>> entanglePorts(ScriptExecutionContext&, Vector<TransferredMessagePort>&&);
+
+ WEBCORE_EXPORT static bool isMessagePortAliveForTesting(const MessagePortIdentifier&);
+ WEBCORE_EXPORT static void notifyMessageAvailable(const MessagePortIdentifier&);
+
+ WEBCORE_EXPORT void messageAvailable();
+ bool started() const { return m_started; }
+ bool isDetached() const { return m_isDetached; }
+
+ void dispatchMessages();
+
+ // Returns null if there is no entangled port, or if the entangled port is run by a different thread.
+ // This is used solely to enable a GC optimization. Some platforms may not be able to determine ownership
+ // of the remote port (since it may live cross-process) - those platforms may always return null.
+ MessagePort* locallyEntangledPort();
+
+ const MessagePortIdentifier& identifier() const { return m_identifier; }
+ const MessagePortIdentifier& remoteIdentifier() const { return m_remoteIdentifier; }
+
+ WEBCORE_EXPORT void ref() const;
+ WEBCORE_EXPORT void deref() const;
+
+ // EventTarget.
+ EventTargetInterface eventTargetInterface() const final
+ {
+ return MessagePortEventTargetInterfaceType;
+ }
+ ScriptExecutionContext* scriptExecutionContext() const final { return ScriptExecutionContext::getScriptExecutionContext(contextIdForMessagePortId(m_identifier)); }
+ void refEventTarget() final { ref(); }
+ void derefEventTarget() final { deref(); }
+
+ void dispatchEvent(Event&) final;
+
+ TransferredMessagePort disentangle();
+ static Ref<MessagePort> entangle(ScriptExecutionContext&, TransferredMessagePort&&);
+
+ bool hasPendingActivity() const;
+
+ static ScriptExecutionContextIdentifier contextIdForMessagePortId(MessagePortIdentifier);
+
+private:
+ explicit MessagePort(ScriptExecutionContext&, const MessagePortIdentifier& local, const MessagePortIdentifier& remote);
+
+ bool addEventListener(const AtomString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) final;
+ bool removeEventListener(const AtomString& eventType, EventListener&, const EventListenerOptions&) final;
+
+ // ActiveDOMObject
+ // const char* activeDOMObjectName() const final;
+ // void contextDestroyed() final;
+ // void stop() final { close(); }
+ // bool virtualHasPendingActivity() const final;
+
+ EventTargetData* eventTargetData() final { return &m_eventTargetData; }
+ EventTargetData* eventTargetDataConcurrently() final { return &m_eventTargetData; }
+ EventTargetData& ensureEventTargetData() final { return m_eventTargetData; }
+
+ EventTargetData m_eventTargetData;
+
+ // A port starts out its life entangled, and remains entangled until it is detached or is cloned.
+ bool isEntangled() const { return !m_isDetached && m_entangled; }
+
+ bool m_started { false };
+ bool m_isDetached { false };
+ bool m_entangled { true };
+ bool m_hasMessageEventListener { false };
+
+ MessagePortIdentifier m_identifier;
+ MessagePortIdentifier m_remoteIdentifier;
+
+ mutable std::atomic<unsigned> m_refCount { 1 };
+};
+
+WebCoreOpaqueRoot root(MessagePort*);
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannel.cpp b/src/bun.js/bindings/webcore/MessagePortChannel.cpp
new file mode 100644
index 000000000..4e0f44524
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannel.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "MessagePortChannel.h"
+
+// #include "Logging.h"
+#include "MessagePortChannelRegistry.h"
+#include <wtf/CompletionHandler.h>
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+Ref<MessagePortChannel> MessagePortChannel::create(MessagePortChannelRegistry& registry, const MessagePortIdentifier& port1, const MessagePortIdentifier& port2)
+{
+ return adoptRef(*new MessagePortChannel(registry, port1, port2));
+}
+
+MessagePortChannel::MessagePortChannel(MessagePortChannelRegistry& registry, const MessagePortIdentifier& port1, const MessagePortIdentifier& port2)
+ : m_registry(registry)
+{
+ ASSERT(isMainThread());
+
+ relaxAdoptionRequirement();
+
+ m_ports[0] = port1;
+ m_processes[0] = port1.processIdentifier;
+ m_entangledToProcessProtectors[0] = this;
+ m_ports[1] = port2;
+ m_processes[1] = port2.processIdentifier;
+ m_entangledToProcessProtectors[1] = this;
+
+ m_registry.messagePortChannelCreated(*this);
+}
+
+MessagePortChannel::~MessagePortChannel()
+{
+ m_registry.messagePortChannelDestroyed(*this);
+}
+
+std::optional<ProcessIdentifier> MessagePortChannel::processForPort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+ ASSERT(port == m_ports[0] || port == m_ports[1]);
+ size_t i = port == m_ports[0] ? 0 : 1;
+ return m_processes[i];
+}
+
+bool MessagePortChannel::includesPort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+
+ return m_ports[0] == port || m_ports[1] == port;
+}
+
+void MessagePortChannel::entanglePortWithProcess(const MessagePortIdentifier& port, ProcessIdentifier process)
+{
+ ASSERT(isMainThread());
+
+ ASSERT(port == m_ports[0] || port == m_ports[1]);
+ size_t i = port == m_ports[0] ? 0 : 1;
+
+ LOG(MessagePorts, "MessagePortChannel %s (%p) entangling port %s (that port has %zu messages available)", logString().utf8().data(), this, port.logString().utf8().data(), m_pendingMessages[i].size());
+
+ ASSERT(!m_processes[i] || *m_processes[i] == process);
+ m_processes[i] = process;
+ m_entangledToProcessProtectors[i] = this;
+ m_pendingMessagePortTransfers[i].remove(this);
+}
+
+void MessagePortChannel::disentanglePort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+
+ LOG(MessagePorts, "MessagePortChannel %s (%p) disentangling port %s", logString().utf8().data(), this, port.logString().utf8().data());
+
+ ASSERT(port == m_ports[0] || port == m_ports[1]);
+ size_t i = port == m_ports[0] ? 0 : 1;
+
+ ASSERT(m_processes[i] || m_isClosed[i]);
+ m_processes[i] = std::nullopt;
+ m_pendingMessagePortTransfers[i].add(this);
+
+ // This set of steps is to guarantee that the lock is unlocked before the
+ // last ref to this object is released.
+ auto protectedThis = WTFMove(m_entangledToProcessProtectors[i]);
+}
+
+void MessagePortChannel::closePort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+
+ ASSERT(port == m_ports[0] || port == m_ports[1]);
+ size_t i = port == m_ports[0] ? 0 : 1;
+
+ m_processes[i] = std::nullopt;
+ m_isClosed[i] = true;
+
+ // This set of steps is to guarantee that the lock is unlocked before the
+ // last ref to this object is released.
+ Ref protectedThis { *this };
+
+ m_pendingMessages[i].clear();
+ m_pendingMessagePortTransfers[i].clear();
+ m_pendingMessageProtectors[i] = nullptr;
+ m_entangledToProcessProtectors[i] = nullptr;
+}
+
+bool MessagePortChannel::postMessageToRemote(MessageWithMessagePorts&& message, const MessagePortIdentifier& remoteTarget)
+{
+ ASSERT(isMainThread());
+
+ ASSERT(remoteTarget == m_ports[0] || remoteTarget == m_ports[1]);
+ size_t i = remoteTarget == m_ports[0] ? 0 : 1;
+
+ m_pendingMessages[i].append(WTFMove(message));
+ LOG(MessagePorts, "MessagePortChannel %s (%p) now has %zu messages pending on port %s", logString().utf8().data(), this, m_pendingMessages[i].size(), remoteTarget.logString().utf8().data());
+
+ if (m_pendingMessages[i].size() == 1) {
+ m_pendingMessageProtectors[i] = this;
+ return true;
+ }
+
+ ASSERT(m_pendingMessageProtectors[i] == this);
+ return false;
+}
+
+void MessagePortChannel::takeAllMessagesForPort(const MessagePortIdentifier& port, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&& callback)
+{
+ ASSERT(isMainThread());
+
+ LOG(MessagePorts, "MessagePortChannel %p taking all messages for port %s", this, port.logString().utf8().data());
+
+ ASSERT(port == m_ports[0] || port == m_ports[1]);
+ size_t i = port == m_ports[0] ? 0 : 1;
+
+ if (m_pendingMessages[i].isEmpty()) {
+ callback({}, [] {});
+ return;
+ }
+
+ ASSERT(m_pendingMessageProtectors[i]);
+
+ Vector<MessageWithMessagePorts> result;
+ result.swap(m_pendingMessages[i]);
+
+ ++m_messageBatchesInFlight;
+
+ LOG(MessagePorts, "There are %zu messages to take for port %s. Taking them now, messages in flight is now %" PRIu64, result.size(), port.logString().utf8().data(), m_messageBatchesInFlight);
+
+ auto size = result.size();
+ callback(WTFMove(result), [size, this, port, protectedThis = WTFMove(m_pendingMessageProtectors[i])] {
+ UNUSED_PARAM(port);
+#if LOG_DISABLED
+ UNUSED_PARAM(size);
+#endif
+ --m_messageBatchesInFlight;
+ LOG(MessagePorts, "Message port channel %s was notified that a batch of %zu message port messages targeted for port %s just completed dispatch, in flight is now %" PRIu64, logString().utf8().data(), size, port.logString().utf8().data(), m_messageBatchesInFlight);
+ });
+}
+
+bool MessagePortChannel::hasAnyMessagesPendingOrInFlight() const
+{
+ ASSERT(isMainThread());
+ return m_messageBatchesInFlight || !m_pendingMessages[0].isEmpty() || !m_pendingMessages[1].isEmpty();
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannel.h b/src/bun.js/bindings/webcore/MessagePortChannel.h
new file mode 100644
index 000000000..787cc8f7a
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannel.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MessagePortChannelProvider.h"
+#include "MessagePortIdentifier.h"
+#include "MessageWithMessagePorts.h"
+#include "ProcessIdentifier.h"
+#include <wtf/HashSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class MessagePortChannelRegistry;
+
+class MessagePortChannel : public RefCounted<MessagePortChannel> {
+public:
+ static Ref<MessagePortChannel> create(MessagePortChannelRegistry&, const MessagePortIdentifier& port1, const MessagePortIdentifier& port2);
+
+ ~MessagePortChannel();
+
+ const MessagePortIdentifier& port1() const { return m_ports[0]; }
+ const MessagePortIdentifier& port2() const { return m_ports[1]; }
+
+ WEBCORE_EXPORT std::optional<ProcessIdentifier> processForPort(const MessagePortIdentifier&);
+ bool includesPort(const MessagePortIdentifier&);
+ void entanglePortWithProcess(const MessagePortIdentifier&, ProcessIdentifier);
+ void disentanglePort(const MessagePortIdentifier&);
+ void closePort(const MessagePortIdentifier&);
+ bool postMessageToRemote(MessageWithMessagePorts&&, const MessagePortIdentifier& remoteTarget);
+
+ void takeAllMessagesForPort(const MessagePortIdentifier&, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&&);
+
+ WEBCORE_EXPORT bool hasAnyMessagesPendingOrInFlight() const;
+
+ uint64_t beingTransferredCount();
+
+#if !LOG_DISABLED
+ String logString() const
+ {
+ return makeString(m_ports[0].logString(), ":", m_ports[1].logString());
+ }
+#endif
+
+private:
+ MessagePortChannel(MessagePortChannelRegistry&, const MessagePortIdentifier& port1, const MessagePortIdentifier& port2);
+
+ MessagePortIdentifier m_ports[2];
+ bool m_isClosed[2] { false, false };
+ std::optional<ProcessIdentifier> m_processes[2];
+ RefPtr<MessagePortChannel> m_entangledToProcessProtectors[2];
+ Vector<MessageWithMessagePorts> m_pendingMessages[2];
+ HashSet<RefPtr<MessagePortChannel>> m_pendingMessagePortTransfers[2];
+ RefPtr<MessagePortChannel> m_pendingMessageProtectors[2];
+ uint64_t m_messageBatchesInFlight { 0 };
+
+ MessagePortChannelRegistry& m_registry;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp b/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp
new file mode 100644
index 000000000..7675a2e75
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+// #include "MessagePortChannelProvider.h"
+
+// #include "Document.h"
+#include "MessagePortChannelProviderImpl.h"
+// #include "WorkerGlobalScope.h"
+// #include "WorkletGlobalScope.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+static MessagePortChannelProviderImpl* globalProvider;
+
+MessagePortChannelProvider& MessagePortChannelProvider::singleton()
+{
+ ASSERT(isMainThread());
+ static std::once_flag onceFlag;
+ std::call_once(onceFlag, [] {
+ if (!globalProvider)
+ globalProvider = new MessagePortChannelProviderImpl;
+ });
+
+ return *globalProvider;
+}
+
+// void MessagePortChannelProvider::setSharedProvider(MessagePortChannelProvider& provider)
+// {
+// RELEASE_ASSERT(isMainThread());
+// RELEASE_ASSERT(!globalProvider);
+// globalProvider = &provider;
+// }
+
+MessagePortChannelProvider& MessagePortChannelProvider::fromContext(ScriptExecutionContext& context)
+{
+ // if (auto document = dynamicDowncast<Document>(context))
+ // return document->messagePortChannelProvider();
+
+ // if (auto workletScope = dynamicDowncast<WorkletGlobalScope>(context))
+ // return workletScope->messagePortChannelProvider();
+
+ return jsCast<Zig::GlobalObject*>(context.jsGlobalObject())->globalEventScope.messagePortChannelProvider();
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannelProvider.h b/src/bun.js/bindings/webcore/MessagePortChannelProvider.h
new file mode 100644
index 000000000..2f9ab1787
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannelProvider.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "BunWorkerGlobalScope.h"
+#include <wtf/CompletionHandler.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+struct MessagePortIdentifier;
+struct MessageWithMessagePorts;
+
+class MessagePortChannelProvider {
+public:
+ static MessagePortChannelProvider& fromContext(ScriptExecutionContext&);
+ static MessagePortChannelProvider& singleton();
+ // WEBCORE_EXPORT static void setSharedProvider(MessagePortChannelProvider&);
+
+ virtual ~MessagePortChannelProvider() {}
+
+ // Operations that WebProcesses perform
+ virtual void createNewMessagePortChannel(const MessagePortIdentifier& local, const MessagePortIdentifier& remote) = 0;
+ virtual void entangleLocalPortInThisProcessToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote) = 0;
+ virtual void messagePortDisentangled(const MessagePortIdentifier& local) = 0;
+ virtual void messagePortClosed(const MessagePortIdentifier& local) = 0;
+
+ virtual void takeAllMessagesForPort(const MessagePortIdentifier&, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&&) = 0;
+
+ virtual void postMessageToRemote(MessageWithMessagePorts&&, const MessagePortIdentifier& remoteTarget) = 0;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.cpp b/src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.cpp
new file mode 100644
index 000000000..c33770dab
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "MessagePortChannelProviderImpl.h"
+
+#include "MessagePort.h"
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+
+namespace WebCore {
+
+MessagePortChannelProviderImpl::MessagePortChannelProviderImpl()
+{
+}
+
+MessagePortChannelProviderImpl::~MessagePortChannelProviderImpl()
+{
+ ASSERT_NOT_REACHED();
+}
+
+void MessagePortChannelProviderImpl::createNewMessagePortChannel(const MessagePortIdentifier& local, const MessagePortIdentifier& remote)
+{
+ ScriptExecutionContext::ensureOnMainThread([registry = &m_registry, local, remote](ScriptExecutionContext& context) mutable {
+ registry->didCreateMessagePortChannel(local, remote);
+ });
+}
+
+void MessagePortChannelProviderImpl::entangleLocalPortInThisProcessToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote)
+{
+ ScriptExecutionContext::ensureOnMainThread([registry = &m_registry, local, remote](ScriptExecutionContext& context) mutable {
+ registry->didEntangleLocalToRemote(local, remote, ProcessIdent::identifier());
+ });
+}
+
+void MessagePortChannelProviderImpl::messagePortDisentangled(const MessagePortIdentifier& local)
+{
+ ScriptExecutionContext::ensureOnMainThread([registry = &m_registry, local](ScriptExecutionContext& context) mutable {
+ registry->didDisentangleMessagePort(local);
+ });
+}
+
+void MessagePortChannelProviderImpl::messagePortClosed(const MessagePortIdentifier& local)
+{
+ ScriptExecutionContext::ensureOnMainThread([registry = &m_registry, local](ScriptExecutionContext& context) mutable {
+ registry->didCloseMessagePort(local);
+ });
+}
+
+void MessagePortChannelProviderImpl::postMessageToRemote(MessageWithMessagePorts&& message, const MessagePortIdentifier& remoteTarget)
+{
+ ScriptExecutionContext::ensureOnMainThread([message = WTFMove(message), registry = &m_registry, remoteTarget](ScriptExecutionContext& context) mutable {
+ if (registry->didPostMessageToRemote(WTFMove(message), remoteTarget))
+ MessagePort::notifyMessageAvailable(remoteTarget);
+ });
+}
+
+void MessagePortChannelProviderImpl::takeAllMessagesForPort(const MessagePortIdentifier& port, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&& outerCallback)
+{
+ // It is the responsibility of outerCallback to get itself to the appropriate thread (e.g. WebWorker thread)
+ auto callback = [outerCallback = WTFMove(outerCallback)](Vector<MessageWithMessagePorts>&& messages, CompletionHandler<void()>&& messageDeliveryCallback) mutable {
+ ASSERT(isMainThread());
+ outerCallback(WTFMove(messages), WTFMove(messageDeliveryCallback));
+ };
+
+ ScriptExecutionContext::ensureOnMainThread([registry = &m_registry, port, callback = WTFMove(callback)](ScriptExecutionContext& context) mutable {
+ registry->takeAllMessagesForPort(port, WTFMove(callback));
+ });
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.h b/src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.h
new file mode 100644
index 000000000..a6bcf79db
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MessagePortChannelProvider.h"
+#include "MessagePortChannelRegistry.h"
+
+namespace WebCore {
+
+class MessagePortChannelProviderImpl final : public MessagePortChannelProvider {
+public:
+ MessagePortChannelProviderImpl();
+ ~MessagePortChannelProviderImpl() final;
+
+private:
+ void createNewMessagePortChannel(const MessagePortIdentifier& local, const MessagePortIdentifier& remote) final;
+ void entangleLocalPortInThisProcessToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote) final;
+ void messagePortDisentangled(const MessagePortIdentifier& local) final;
+ void messagePortClosed(const MessagePortIdentifier& local) final;
+ void postMessageToRemote(MessageWithMessagePorts&&, const MessagePortIdentifier& remoteTarget) final;
+ void takeAllMessagesForPort(const MessagePortIdentifier&, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&&) final;
+
+ MessagePortChannelRegistry m_registry;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp b/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp
new file mode 100644
index 000000000..7675e0eab
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "MessagePortChannelRegistry.h"
+
+// #include "Logging.h"
+#include <wtf/CompletionHandler.h>
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+MessagePortChannelRegistry::MessagePortChannelRegistry() = default;
+
+MessagePortChannelRegistry::~MessagePortChannelRegistry()
+{
+ ASSERT(m_openChannels.isEmpty());
+}
+
+void MessagePortChannelRegistry::didCreateMessagePortChannel(const MessagePortIdentifier& port1, const MessagePortIdentifier& port2)
+{
+ LOG(MessagePorts, "Registry: Creating MessagePortChannel %p linking %s and %s", this, port1.logString().utf8().data(), port2.logString().utf8().data());
+ ASSERT(isMainThread());
+
+ MessagePortChannel::create(*this, port1, port2);
+}
+
+void MessagePortChannelRegistry::messagePortChannelCreated(MessagePortChannel& channel)
+{
+ ASSERT(isMainThread());
+
+ auto result = m_openChannels.ensure(channel.port1(), [channel = &channel] {
+ return channel;
+ });
+ ASSERT(result.isNewEntry);
+
+ result = m_openChannels.ensure(channel.port2(), [channel = &channel] {
+ return channel;
+ });
+ ASSERT(result.isNewEntry);
+}
+
+void MessagePortChannelRegistry::messagePortChannelDestroyed(MessagePortChannel& channel)
+{
+ ASSERT(isMainThread());
+
+ ASSERT(m_openChannels.get(channel.port1()) == &channel);
+ ASSERT(m_openChannels.get(channel.port2()) == &channel);
+
+ m_openChannels.remove(channel.port1());
+ m_openChannels.remove(channel.port2());
+
+ LOG(MessagePorts, "Registry: After removing channel %s there are %u channels left in the registry:", channel.logString().utf8().data(), m_openChannels.size());
+}
+
+void MessagePortChannelRegistry::didEntangleLocalToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote, ProcessIdentifier process)
+{
+ ASSERT(isMainThread());
+
+ // The channel might be gone if the remote side was closed.
+ auto* channel = m_openChannels.get(local);
+ if (!channel)
+ return;
+
+ ASSERT_UNUSED(remote, channel->includesPort(remote));
+
+ channel->entanglePortWithProcess(local, process);
+}
+
+void MessagePortChannelRegistry::didDisentangleMessagePort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+
+ // The channel might be gone if the remote side was closed.
+ auto* channel = m_openChannels.get(port);
+ if (!channel)
+ return;
+
+ channel->disentanglePort(port);
+}
+
+void MessagePortChannelRegistry::didCloseMessagePort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+
+ LOG(MessagePorts, "Registry: MessagePort %s closed in registry", port.logString().utf8().data());
+
+ auto* channel = m_openChannels.get(port);
+ if (!channel)
+ return;
+
+#ifndef NDEBUG
+ if (channel && channel->hasAnyMessagesPendingOrInFlight())
+ LOG(MessagePorts, "Registry: (Note) The channel closed for port %s had messages pending or in flight", port.logString().utf8().data());
+#endif
+
+ channel->closePort(port);
+
+ // FIXME: When making message ports be multi-process, this should probably push a notification
+ // to the remaining port to tell it this port closed.
+}
+
+bool MessagePortChannelRegistry::didPostMessageToRemote(MessageWithMessagePorts&& message, const MessagePortIdentifier& remoteTarget)
+{
+ ASSERT(isMainThread());
+
+ LOG(MessagePorts, "Registry: Posting message to MessagePort %s in registry", remoteTarget.logString().utf8().data());
+
+ // The channel might be gone if the remote side was closed.
+ auto* channel = m_openChannels.get(remoteTarget);
+ if (!channel) {
+ LOG(MessagePorts, "Registry: Could not find MessagePortChannel for port %s; It was probably closed. Message will be dropped.", remoteTarget.logString().utf8().data());
+ return false;
+ }
+
+ return channel->postMessageToRemote(WTFMove(message), remoteTarget);
+}
+
+void MessagePortChannelRegistry::takeAllMessagesForPort(const MessagePortIdentifier& port, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&& callback)
+{
+ ASSERT(isMainThread());
+
+ LOG(MessagePorts, "Registry: Taking all messages for MessagePort %s", port.logString().utf8().data());
+
+ // The channel might be gone if the remote side was closed.
+ auto* channel = m_openChannels.get(port);
+ if (!channel) {
+ callback({}, [] {});
+ return;
+ }
+
+ channel->takeAllMessagesForPort(port, WTFMove(callback));
+}
+
+MessagePortChannel* MessagePortChannelRegistry::existingChannelContainingPort(const MessagePortIdentifier& port)
+{
+ ASSERT(isMainThread());
+
+ return m_openChannels.get(port);
+}
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortChannelRegistry.h b/src/bun.js/bindings/webcore/MessagePortChannelRegistry.h
new file mode 100644
index 000000000..334fb5f9c
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortChannelRegistry.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MessagePortChannel.h"
+#include "MessagePortChannelProvider.h"
+#include "MessagePortIdentifier.h"
+#include "ProcessIdentifier.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class MessagePortChannelRegistry {
+public:
+ WEBCORE_EXPORT MessagePortChannelRegistry();
+
+ WEBCORE_EXPORT ~MessagePortChannelRegistry();
+
+ WEBCORE_EXPORT void didCreateMessagePortChannel(const MessagePortIdentifier& port1, const MessagePortIdentifier& port2);
+ WEBCORE_EXPORT void didEntangleLocalToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote, ProcessIdentifier);
+ WEBCORE_EXPORT void didDisentangleMessagePort(const MessagePortIdentifier& local);
+ WEBCORE_EXPORT void didCloseMessagePort(const MessagePortIdentifier& local);
+ WEBCORE_EXPORT bool didPostMessageToRemote(MessageWithMessagePorts&&, const MessagePortIdentifier& remoteTarget);
+ WEBCORE_EXPORT void takeAllMessagesForPort(const MessagePortIdentifier&, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&&);
+
+ WEBCORE_EXPORT MessagePortChannel* existingChannelContainingPort(const MessagePortIdentifier&);
+
+ WEBCORE_EXPORT void messagePortChannelCreated(MessagePortChannel&);
+ WEBCORE_EXPORT void messagePortChannelDestroyed(MessagePortChannel&);
+
+private:
+ HashMap<MessagePortIdentifier, MessagePortChannel*> m_openChannels;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/MessagePortIdentifier.h b/src/bun.js/bindings/webcore/MessagePortIdentifier.h
new file mode 100644
index 000000000..eac8546de
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessagePortIdentifier.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "PortIdentifier.h"
+#include "ProcessIdentifier.h"
+#include <wtf/Hasher.h>
+#include <wtf/text/StringConcatenateNumbers.h>
+
+namespace WebCore {
+
+struct MessagePortIdentifier {
+ ProcessIdentifier processIdentifier;
+ PortIdentifier portIdentifier;
+
+#if !LOG_DISABLED
+ String logString() const;
+#endif
+};
+
+inline void add(Hasher& hasher, const MessagePortIdentifier& identifier)
+{
+ add(hasher, identifier.processIdentifier, identifier.portIdentifier);
+}
+
+inline bool operator==(const MessagePortIdentifier& a, const MessagePortIdentifier& b)
+{
+ return a.processIdentifier == b.processIdentifier && a.portIdentifier == b.portIdentifier;
+}
+
+#if !LOG_DISABLED
+
+inline String MessagePortIdentifier::logString() const
+{
+ return makeString(processIdentifier.toUInt64(), '-', portIdentifier.toUInt64());
+}
+
+#endif
+
+} // namespace WebCore
+
+namespace WTF {
+
+struct MessagePortIdentifierHash {
+ static unsigned hash(const WebCore::MessagePortIdentifier& key) { return computeHash(key); }
+ static bool equal(const WebCore::MessagePortIdentifier& a, const WebCore::MessagePortIdentifier& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+template<> struct HashTraits<WebCore::MessagePortIdentifier> : GenericHashTraits<WebCore::MessagePortIdentifier> {
+ static WebCore::MessagePortIdentifier emptyValue() { return {}; }
+
+ static void constructDeletedValue(WebCore::MessagePortIdentifier& slot) { new (NotNull, &slot.processIdentifier) WebCore::ProcessIdentifier(WTF::HashTableDeletedValue); }
+
+ static bool isDeletedValue(const WebCore::MessagePortIdentifier& slot) { return slot.processIdentifier.isHashTableDeletedValue(); }
+};
+
+template<> struct DefaultHash<WebCore::MessagePortIdentifier> : MessagePortIdentifierHash {};
+
+} // namespace WTF
diff --git a/src/bun.js/bindings/webcore/MessageWithMessagePorts.h b/src/bun.js/bindings/webcore/MessageWithMessagePorts.h
new file mode 100644
index 000000000..a986bfb4c
--- /dev/null
+++ b/src/bun.js/bindings/webcore/MessageWithMessagePorts.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "SerializedScriptValue.h"
+#include "TransferredMessagePort.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+struct MessageWithMessagePorts {
+ RefPtr<SerializedScriptValue> message;
+ Vector<TransferredMessagePort> transferredPorts;
+};
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/PortIdentifier.h b/src/bun.js/bindings/webcore/PortIdentifier.h
new file mode 100644
index 000000000..8b77e792e
--- /dev/null
+++ b/src/bun.js/bindings/webcore/PortIdentifier.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 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. AND ITS CONTRIBUTORS ``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 ITS 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"
+
+namespace WebCore {
+
+enum PortIdentifierType {};
+using PortIdentifier = AtomicObjectIdentifier<PortIdentifierType>;
+
+}
diff --git a/src/bun.js/bindings/webcore/SerializedScriptValue.cpp b/src/bun.js/bindings/webcore/SerializedScriptValue.cpp
index e80bc9493..9eeee155a 100644
--- a/src/bun.js/bindings/webcore/SerializedScriptValue.cpp
+++ b/src/bun.js/bindings/webcore/SerializedScriptValue.cpp
@@ -54,7 +54,7 @@
// #include "JSIDBSerializationGlobalObject.h"
// #include "JSImageBitmap.h"
// #include "JSImageData.h"
-// #include "JSMessagePort.h"
+#include "JSMessagePort.h"
// #include "JSNavigator.h"
// #include "JSRTCCertificate.h"
// #include "JSRTCDataChannel.h"
@@ -715,7 +715,7 @@ public:
// return serializer.serialize(value);
// }
- static SerializationReturnCode serialize(JSGlobalObject* lexicalGlobalObject, JSValue value, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers,
+ static SerializationReturnCode serialize(JSGlobalObject* lexicalGlobalObject, JSValue value, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
const Vector<RefPtr<OffscreenCanvas>>& offscreenCanvases,
#endif
@@ -733,7 +733,7 @@ public:
Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers,
SerializationForStorage forStorage)
{
- CloneSerializer serializer(lexicalGlobalObject, arrayBuffers,
+ CloneSerializer serializer(lexicalGlobalObject, messagePorts, arrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
offscreenCanvases,
#endif
@@ -815,7 +815,7 @@ private:
// #endif
// }
- CloneSerializer(JSGlobalObject* lexicalGlobalObject, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers,
+ CloneSerializer(JSGlobalObject* lexicalGlobalObject, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
const Vector<RefPtr<OffscreenCanvas>>& offscreenCanvases,
#endif
@@ -847,6 +847,7 @@ private:
, m_forStorage(forStorage)
{
write(CurrentVersion);
+ fillTransferMap(messagePorts, m_transferredMessagePorts);
fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
fillTransferMap(offscreenCanvases, m_transferredOffscreenCanvases);
@@ -1501,17 +1502,17 @@ private:
write(String::fromLatin1(JSC::Yarr::flagsString(regExp->regExp()->flags()).data()));
return true;
}
- // if (obj->inherits<JSMessagePort>()) {
- // auto index = m_transferredMessagePorts.find(obj);
- // if (index != m_transferredMessagePorts.end()) {
- // write(MessagePortReferenceTag);
- // write(index->value);
- // return true;
- // }
- // // MessagePort object could not be found in transferred message ports
- // code = SerializationReturnCode::ValidationError;
- // return true;
- // }
+ if (obj->inherits<JSMessagePort>()) {
+ auto index = m_transferredMessagePorts.find(obj);
+ if (index != m_transferredMessagePorts.end()) {
+ write(MessagePortReferenceTag);
+ write(index->value);
+ return true;
+ }
+ // MessagePort object could not be found in transferred message ports
+ code = SerializationReturnCode::ValidationError;
+ return true;
+ }
if (auto* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) {
if (arrayBuffer->isDetached()) {
code = SerializationReturnCode::ValidationError;
@@ -1570,7 +1571,7 @@ private:
write(CryptoKeyTag);
Vector<uint8_t> serializedKey;
// Vector<URLKeepingBlobAlive> dummyBlobHandles;
- // Vector<RefPtr<MessagePort>> dummyMessagePorts;
+ Vector<RefPtr<MessagePort>> dummyMessagePorts;
Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
#if ENABLE(WEB_CODECS)
Vector<RefPtr<WebCodecsEncodedVideoChunkStorage>> dummyVideoChunks;
@@ -1597,7 +1598,7 @@ private:
// dummyMemoryHandles,
// #endif
// dummyBlobHandles, serializedKey, SerializationContext::Default, dummySharedBuffers, m_forStorage);
- CloneSerializer rawKeySerializer(m_lexicalGlobalObject, dummyArrayBuffers,
+ CloneSerializer rawKeySerializer(m_lexicalGlobalObject, dummyMessagePorts, dummyArrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
{},
#endif
@@ -2518,7 +2519,7 @@ public:
// return deserializer.deserialize();
// }
- static DeserializationResult deserialize(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject
+ static DeserializationResult deserialize(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
Vector<std::unique_ptr<DetachedOffscreenCanvas>>&& detachedOffscreenCanvases
@@ -2541,7 +2542,7 @@ public:
{
if (!buffer.size())
return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError);
- CloneDeserializer deserializer(lexicalGlobalObject, globalObject, arrayBufferContentsArray, std::span<uint8_t> { buffer.begin(), buffer.end() }, blobURLs, blobFilePaths, sharedBuffers
+ CloneDeserializer deserializer(lexicalGlobalObject, globalObject, messagePorts, arrayBufferContentsArray, std::span<uint8_t> { buffer.begin(), buffer.end() }, blobURLs, blobFilePaths, sharedBuffers
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
WTFMove(detachedOffscreenCanvases)
@@ -2675,7 +2676,7 @@ private:
// m_version = 0xFFFFFFFF;
// }
- CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, ArrayBufferContentsArray* arrayBufferContents, const std::span<uint8_t>& buffer
+ CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const std::span<uint8_t>& buffer
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
Vector<std::unique_ptr<DetachedOffscreenCanvas>>&& detachedOffscreenCanvases = {}
@@ -2700,6 +2701,7 @@ private:
, m_ptr(buffer.data())
, m_end(buffer.data() + buffer.size())
, m_version(0xFFFFFFFF)
+ , m_messagePorts(messagePorts)
, m_arrayBufferContents(arrayBufferContents)
, m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
@@ -2781,7 +2783,7 @@ private:
// m_version = 0xFFFFFFFF;
// }
- CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, ArrayBufferContentsArray* arrayBufferContents, const std::span<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
+ CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const std::span<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
Vector<std::unique_ptr<DetachedOffscreenCanvas>>&& detachedOffscreenCanvases
@@ -2806,6 +2808,7 @@ private:
, m_ptr(buffer.data())
, m_end(buffer.data() + buffer.size())
, m_version(0xFFFFFFFF)
+ , m_messagePorts(messagePorts)
, m_arrayBufferContents(arrayBufferContents)
, m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
, m_blobURLs(blobURLs)
@@ -4391,15 +4394,15 @@ private:
}
return m_gcBuffer.at(index);
}
- // case MessagePortReferenceTag: {
- // uint32_t index;
- // bool indexSuccessfullyRead = read(index);
- // if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
- // fail();
- // return JSValue();
- // }
- // return getJSValue(m_messagePorts[index].get());
- // }
+ case MessagePortReferenceTag: {
+ uint32_t index;
+ bool indexSuccessfullyRead = read(index);
+ if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
+ fail();
+ return JSValue();
+ }
+ return getJSValue(m_messagePorts[index].get());
+ }
#if ENABLE(WEBASSEMBLY)
case WasmModuleTag: {
if (m_version >= 12) {
@@ -4554,7 +4557,7 @@ private:
JSValue cryptoKey;
// Vector<RefPtr<MessagePort>> dummyMessagePorts;
// CloneDeserializer rawKeyDeserializer(m_lexicalGlobalObject, m_globalObject, dummyMessagePorts, nullptr, {}, serializedKey);
- CloneDeserializer rawKeyDeserializer(m_lexicalGlobalObject, m_globalObject, nullptr, serializedKey);
+ CloneDeserializer rawKeyDeserializer(m_lexicalGlobalObject, m_globalObject, {}, nullptr, serializedKey);
if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) {
fail();
return JSValue();
@@ -4625,7 +4628,7 @@ private:
const uint8_t* const m_end;
unsigned m_version;
Vector<CachedString> m_constantPool;
- // const Vector<RefPtr<MessagePort>>& m_messagePorts;
+ const Vector<RefPtr<MessagePort>>& m_messagePorts;
ArrayBufferContentsArray* m_arrayBufferContents;
Vector<RefPtr<JSC::ArrayBuffer>> m_arrayBuffers;
Vector<String> m_blobURLs;
@@ -5117,9 +5120,9 @@ static bool canDetachRTCDataChannels(const Vector<Ref<RTCDataChannel>>& channels
RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::JSGlobalObject& globalObject, JSC::JSValue value, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext serializationContext)
{
- // Vector<RefPtr<MessagePort>> dummyPorts;
- // auto result = create(globalObject, value, {}, dummyPorts, forStorage, throwExceptions, serializationContext);
- auto result = create(globalObject, value, {}, forStorage, throwExceptions, serializationContext);
+ Vector<RefPtr<MessagePort>> dummyPorts;
+ auto result = create(globalObject, value, {}, dummyPorts, forStorage, throwExceptions, serializationContext);
+ // auto result = create(globalObject, value, {}, forStorage, throwExceptions, serializationContext);
if (result.hasException())
return nullptr;
return result.releaseReturnValue();
@@ -5130,13 +5133,13 @@ RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::JSGlobalObject&
// return create(globalObject, value, WTFMove(transferList), messagePorts, forStorage, SerializationErrorMode::NonThrowing, serializationContext);
// }
-ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& globalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, SerializationForStorage forStorage, SerializationContext serializationContext)
+ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& globalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationContext serializationContext)
{
- return create(globalObject, value, WTFMove(transferList), forStorage, SerializationErrorMode::Throwing, serializationContext);
+ return create(globalObject, value, WTFMove(transferList), messagePorts, forStorage, SerializationErrorMode::Throwing, serializationContext);
}
-// ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context)
-ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context)
+// ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context)
+ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context)
{
VM& vm = lexicalGlobalObject.vm();
Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers;
@@ -5166,12 +5169,12 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalOb
arrayBuffers.append(WTFMove(arrayBuffer));
continue;
}
- // if (auto port = JSMessagePort::toWrapped(vm, transferable.get())) {
- // if (port->isDetached())
- // return Exception { DataCloneError, "MessagePort is detached"_s };
- // messagePorts.append(WTFMove(port));
- // continue;
- // }
+ if (auto port = JSMessagePort::toWrapped(vm, transferable.get())) {
+ if (port->isDetached())
+ return Exception { DataCloneError, "MessagePort is detached"_s };
+ messagePorts.append(WTFMove(port));
+ continue;
+ }
// if (auto imageBitmap = JSImageBitmap::toWrapped(vm, transferable.get())) {
// if (imageBitmap->isDetached())
@@ -5247,7 +5250,7 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalOb
// #endif
// blobHandles, buffer, context, *sharedBuffers, forStorage);
- auto code = CloneSerializer::serialize(&lexicalGlobalObject, value, arrayBuffers,
+ auto code = CloneSerializer::serialize(&lexicalGlobalObject, value, messagePorts, arrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
offscreenCanvases,
#endif
@@ -5408,7 +5411,7 @@ JSC::JSValue SerializedScriptValue::fromArrayBuffer(JSC::JSGlobalObject& domGlob
auto size = std::min(arrayBuffer->byteLength(), maxByteLength);
auto span = std::span<uint8_t> { data, size };
- auto result = CloneDeserializer::deserialize(&domGlobal, globalObject, nullptr, span, blobURLs, blobFiles, nullptr
+ auto result = CloneDeserializer::deserialize(&domGlobal, globalObject, {}, nullptr, span, blobURLs, blobFiles, nullptr
#if ENABLE(WEBASSEMBLY)
,
nullptr, nullptr
@@ -5437,71 +5440,24 @@ JSC::JSValue SerializedScriptValue::fromArrayBuffer(JSC::JSGlobalObject& domGlob
// return deserialize(lexicalGlobalObject, globalObject, {}, throwExceptions, didFail);
// }
-// JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, SerializationErrorMode throwExceptions, bool* didFail)
-// {
-// Vector<String> dummyBlobs;
-// Vector<String> dummyPaths;
-// return deserialize(lexicalGlobalObject, globalObject, messagePorts, dummyBlobs, dummyPaths, throwExceptions, didFail);
-// }
+JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, SerializationErrorMode throwExceptions, bool* didFail)
+{
+ Vector<String> dummyBlobs;
+ Vector<String> dummyPaths;
+ return deserialize(lexicalGlobalObject, globalObject, messagePorts, dummyBlobs, dummyPaths, throwExceptions, didFail);
+}
JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions, bool* didFail)
{
Vector<String> dummyBlobs;
Vector<String> dummyPaths;
- return deserialize(lexicalGlobalObject, globalObject, dummyBlobs, dummyPaths, throwExceptions, didFail);
+ Vector<RefPtr<MessagePort>> dummyPorts;
+ return deserialize(lexicalGlobalObject, globalObject, dummyPorts, dummyBlobs, dummyPaths, throwExceptions, didFail);
}
-// JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions, bool* didFail)
-// {
-// DeserializationResult result = CloneDeserializer::deserialize(&lexicalGlobalObject, globalObject, messagePorts, WTFMove(m_backingStores)
-// #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
-// ,
-// WTFMove(m_detachedOffscreenCanvases)
-// #endif
-// #if ENABLE(WEB_RTC)
-// ,
-// WTFMove(m_detachedRTCDataChannels)
-// #endif
-// ,
-// m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths, m_sharedBufferContentsArray.get()
-// #if ENABLE(WEBASSEMBLY)
-// ,
-// m_wasmModulesArray.get(), m_wasmMemoryHandlesArray.get()
-// #endif
-// #if ENABLE(WEB_CODECS)
-// ,
-// WTFMove(m_serializedVideoChunks), WTFMove(m_serializedVideoFrames)
-// #endif
-// );
-// if (didFail)
-// *didFail = result.second != SerializationReturnCode::SuccessfullyCompleted;
-// if (throwExceptions == SerializationErrorMode::Throwing)
-// maybeThrowExceptionIfSerializationFailed(lexicalGlobalObject, result.second);
-// return result.first ? result.first : jsNull();
-// }
-JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions, bool* didFail)
+JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions, bool* didFail)
{
- // DeserializationResult result = CloneDeserializer::deserialize(&lexicalGlobalObject, globalObject, messagePorts, WTFMove(m_backingStores)
- // #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
- // ,
- // WTFMove(m_detachedOffscreenCanvases)
- // #endif
- // #if ENABLE(WEB_RTC)
- // ,
- // WTFMove(m_detachedRTCDataChannels)
- // #endif
- // ,
- // m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths, m_sharedBufferContentsArray.get()
- // #if ENABLE(WEBASSEMBLY)
- // ,
- // m_wasmModulesArray.get(), m_wasmMemoryHandlesArray.get()
- // #endif
- // #if ENABLE(WEB_CODECS)
- // ,
- // WTFMove(m_serializedVideoChunks), WTFMove(m_serializedVideoFrames)
- // #endif
- // );
- DeserializationResult result = CloneDeserializer::deserialize(&lexicalGlobalObject, globalObject
+ DeserializationResult result = CloneDeserializer::deserialize(&lexicalGlobalObject, globalObject, messagePorts
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
WTFMove(m_detachedOffscreenCanvases)
@@ -5527,6 +5483,54 @@ JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject,
maybeThrowExceptionIfSerializationFailed(lexicalGlobalObject, result.second);
return result.first ? result.first : jsNull();
}
+// JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions, bool* didFail)
+// {
+// // DeserializationResult result = CloneDeserializer::deserialize(&lexicalGlobalObject, globalObject, messagePorts, WTFMove(m_backingStores)
+// // #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
+// // ,
+// // WTFMove(m_detachedOffscreenCanvases)
+// // #endif
+// // #if ENABLE(WEB_RTC)
+// // ,
+// // WTFMove(m_detachedRTCDataChannels)
+// // #endif
+// // ,
+// // m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths, m_sharedBufferContentsArray.get()
+// // #if ENABLE(WEBASSEMBLY)
+// // ,
+// // m_wasmModulesArray.get(), m_wasmMemoryHandlesArray.get()
+// // #endif
+// // #if ENABLE(WEB_CODECS)
+// // ,
+// // WTFMove(m_serializedVideoChunks), WTFMove(m_serializedVideoFrames)
+// // #endif
+// // );
+// DeserializationResult result = CloneDeserializer::deserialize(&lexicalGlobalObject, globalObject
+// #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
+// ,
+// WTFMove(m_detachedOffscreenCanvases)
+// #endif
+// #if ENABLE(WEB_RTC)
+// ,
+// WTFMove(m_detachedRTCDataChannels)
+// #endif
+// ,
+// m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths, m_sharedBufferContentsArray.get()
+// #if ENABLE(WEBASSEMBLY)
+// ,
+// m_wasmModulesArray.get(), m_wasmMemoryHandlesArray.get()
+// #endif
+// #if ENABLE(WEB_CODECS)
+// ,
+// WTFMove(m_serializedVideoChunks), WTFMove(m_serializedVideoFrames)
+// #endif
+// );
+// if (didFail)
+// *didFail = result.second != SerializationReturnCode::SuccessfullyCompleted;
+// if (throwExceptions == SerializationErrorMode::Throwing)
+// maybeThrowExceptionIfSerializationFailed(lexicalGlobalObject, result.second);
+// return result.first ? result.first : jsNull();
+// }
JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
{
diff --git a/src/bun.js/bindings/webcore/SerializedScriptValue.h b/src/bun.js/bindings/webcore/SerializedScriptValue.h
index 189945d52..5d5e93854 100644
--- a/src/bun.js/bindings/webcore/SerializedScriptValue.h
+++ b/src/bun.js/bindings/webcore/SerializedScriptValue.h
@@ -60,7 +60,7 @@ namespace WebCore {
class DetachedOffscreenCanvas;
#endif
// class IDBValue;
-// class MessagePort;
+class MessagePort;
// class ImageBitmapBacking;
class CloneSerializer;
class FragmentedSharedBuffer;
@@ -87,8 +87,8 @@ class SerializedScriptValue : public ThreadSafeRefCounted<SerializedScriptValue>
public:
static void writeBytesForBun(CloneSerializer*, const uint8_t*, uint32_t);
- // WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::JSGlobalObject&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, Vector<RefPtr<MessagePort>>&, SerializationForStorage = SerializationForStorage::No, SerializationContext = SerializationContext::Default);
- WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::JSGlobalObject&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, SerializationForStorage = SerializationForStorage::No, SerializationContext = SerializationContext::Default);
+ WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::JSGlobalObject&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, Vector<RefPtr<MessagePort>>&, SerializationForStorage = SerializationForStorage::No, SerializationContext = SerializationContext::Default);
+ // WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::JSGlobalObject&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, SerializationForStorage = SerializationForStorage::No, SerializationContext = SerializationContext::Default);
WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(JSC::JSGlobalObject&, JSC::JSValue, SerializationForStorage = SerializationForStorage::No, SerializationErrorMode = SerializationErrorMode::Throwing, SerializationContext = SerializationContext::Default);
@@ -99,10 +99,10 @@ public:
static Ref<SerializedScriptValue> nullValue();
WEBCORE_EXPORT JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
- // WEBCORE_EXPORT JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector<RefPtr<MessagePort>>&, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
+ WEBCORE_EXPORT JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector<RefPtr<MessagePort>>&, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
- // JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector<RefPtr<MessagePort>>&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
- JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
+ JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector<RefPtr<MessagePort>>&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
+ // JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing, bool* didFail = nullptr);
static uint32_t wireFormatVersion();
@@ -146,7 +146,7 @@ private:
// Vector<RefPtr<WebCodecsEncodedVideoChunkStorage>>&& = {}, Vector<WebCodecsVideoFrameData>&& = {}
// #endif
// );
- static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::JSGlobalObject&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, SerializationForStorage, SerializationErrorMode, SerializationContext);
+ static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::JSGlobalObject&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, Vector<RefPtr<MessagePort>>&, SerializationForStorage, SerializationErrorMode, SerializationContext);
WEBCORE_EXPORT SerializedScriptValue(Vector<unsigned char>&&, std::unique_ptr<ArrayBufferContentsArray>&& = nullptr
#if ENABLE(WEB_RTC)
,
diff --git a/src/bun.js/bindings/webcore/TransferredMessagePort.h b/src/bun.js/bindings/webcore/TransferredMessagePort.h
new file mode 100644
index 000000000..19aa63746
--- /dev/null
+++ b/src/bun.js/bindings/webcore/TransferredMessagePort.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-2022 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MessagePortIdentifier.h"
+
+namespace WebCore {
+
+// When a message port is transferred, it is represented by a pair of identifiers.
+// The first identifier is the port being transferred and the second is its remote port.
+using TransferredMessagePort = std::pair<MessagePortIdentifier, MessagePortIdentifier>;
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp
index dfbc0e007..d9bd6f9b4 100644
--- a/src/bun.js/bindings/webcore/Worker.cpp
+++ b/src/bun.js/bindings/webcore/Worker.cpp
@@ -185,25 +185,25 @@ ExceptionOr<void> Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue m
if (m_wasTerminated)
return Exception { InvalidStateError, "Worker has been terminated"_s };
- auto message = SerializedScriptValue::create(state, messageValue, WTFMove(options.transfer), SerializationForStorage::No, SerializationContext::WorkerPostMessage);
- if (message.hasException())
- return message.releaseException();
+ Vector<RefPtr<MessagePort>> ports;
+ auto serialized = SerializedScriptValue::create(state, messageValue, WTFMove(options.transfer), ports);
+ if (serialized.hasException())
+ return serialized.releaseException();
+
+ ExceptionOr<Vector<TransferredMessagePort>> disentangledPorts = MessagePort::disentanglePorts(WTFMove(ports));
+ if (disentangledPorts.hasException()) {
+ return disentangledPorts.releaseException();
+ }
- RefPtr<SerializedScriptValue> result = message.releaseReturnValue();
+ MessageWithMessagePorts messageWithMessagePorts { serialized.releaseReturnValue(), disentangledPorts.releaseReturnValue() };
- this->postTaskToWorkerGlobalScope([message = WTFMove(result)](auto& context) {
+ this->postTaskToWorkerGlobalScope([message = messageWithMessagePorts](auto& context) mutable {
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(context.jsGlobalObject());
- bool didFail = false;
- JSValue value = message->deserialize(*globalObject, globalObject, SerializationErrorMode::NonThrowing, &didFail);
- if (didFail) {
- globalObject->globalEventScope.dispatchEvent(MessageEvent::create(eventNames().messageerrorEvent, MessageEvent::Init {}, MessageEvent::IsTrusted::Yes));
- return;
- }
+ auto ports = MessagePort::entanglePorts(context, WTFMove(message.transferredPorts));
+ auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), std::nullopt, WTFMove(ports));
- WebCore::MessageEvent::Init init;
- init.data = value;
- globalObject->globalEventScope.dispatchEvent(MessageEvent::create(eventNames().messageEvent, WTFMove(init), MessageEvent::IsTrusted::Yes));
+ globalObject->globalEventScope.dispatchEvent(event.event);
});
return {};
}
diff --git a/src/bun.js/bindings/webcore/Worker.h b/src/bun.js/bindings/webcore/Worker.h
index b0b8e0a2b..76607d8da 100644
--- a/src/bun.js/bindings/webcore/Worker.h
+++ b/src/bun.js/bindings/webcore/Worker.h
@@ -135,7 +135,6 @@ private:
bool m_isClosing { false };
const ScriptExecutionContextIdentifier m_clientIdentifier;
void* impl_ { nullptr };
- size_t m_pendingActivityCount { 0 };
};
} // namespace WebCore
diff --git a/src/bun.js/scripts/class-definitions.ts b/src/bun.js/scripts/class-definitions.ts
index 281cd62c5..d9c327f6b 100644
--- a/src/bun.js/scripts/class-definitions.ts
+++ b/src/bun.js/scripts/class-definitions.ts
@@ -41,7 +41,7 @@ export interface ClassDefinition {
configurable?: boolean;
enumerable?: boolean;
- structuredClone?: boolean | { transferrable: boolean; tag: number };
+ structuredClone?: boolean | { transferable: boolean; tag: number };
}
export interface CustomField {
diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts
index fb4419642..ec0021637 100644
--- a/src/bun.js/scripts/generate-classes.ts
+++ b/src/bun.js/scripts/generate-classes.ts
@@ -1249,7 +1249,7 @@ function generateZig(
if (structuredClone) {
exports.set("onStructuredCloneSerialize", symbolName(typeName, "onStructuredCloneSerialize"));
- if (structuredClone === "transferrable") {
+ if (structuredClone === "transferable") {
exports.set("onStructuredCloneTransfer", symbolName(typeName, "onStructuredCloneTransfer"));
}
@@ -1306,8 +1306,8 @@ function generateZig(
}
`;
- if (structuredClone === "transferrable") {
- exports.set("structuredClone", symbolName(typeName, "onTransferrableStructuredClone"));
+ if (structuredClone === "transferable") {
+ exports.set("structuredClone", symbolName(typeName, "onTransferableStructuredClone"));
output += `
if (@TypeOf(${typeName}.onStructuredCloneTransfer) != (fn(*${typeName}, globalThis: *JSC.JSGlobalObject, ctx: *anyopaque, write: *const fn(*anyopaque, ptr: [*]const u8, len: usize) callconv(.C) void) callconv(.C) void)) {
@compileLog("${typeName}.onStructuredCloneTransfer is not a structured clone transfer function");
diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts
index f0d6e1451..abd29c654 100644
--- a/src/bun.js/webcore/response.classes.ts
+++ b/src/bun.js/webcore/response.classes.ts
@@ -125,7 +125,7 @@ export default [
JSType: "0b11101110",
klass: {},
configurable: false,
- structuredClone: { transferrable: false, tag: 254 },
+ structuredClone: { transferable: false, tag: 254 },
proto: {
text: { fn: "getText" },
json: { fn: "getJSON" },
diff --git a/test/js/web/workers/create-port-worker.js b/test/js/web/workers/create-port-worker.js
new file mode 100644
index 000000000..6e8709de0
--- /dev/null
+++ b/test/js/web/workers/create-port-worker.js
@@ -0,0 +1,6 @@
+var channel = new MessageChannel();
+channel.port1.onmessage = e => {
+ channel.port1.postMessage("done!");
+};
+
+postMessage(channel.port2, { transfer: [channel.port2] });
diff --git a/test/js/web/workers/message-channel.test.ts b/test/js/web/workers/message-channel.test.ts
new file mode 100644
index 000000000..7d3e3cc25
--- /dev/null
+++ b/test/js/web/workers/message-channel.test.ts
@@ -0,0 +1,254 @@
+test("simple usage", done => {
+ var channel = new MessageChannel();
+ var port1 = channel.port1;
+ var port2 = channel.port2;
+
+ port2.onmessage = function (e) {
+ expect(e.data).toEqual("hello");
+ done();
+ };
+
+ port1.postMessage("hello");
+});
+
+test("transfer message port", done => {
+ var channel = new MessageChannel();
+ var anotherChannel = new MessageChannel();
+ var port1 = channel.port1;
+ var port2 = channel.port2;
+
+ port2.onmessage = function (e) {
+ expect(e.data).toEqual("hello");
+ expect(e.ports).toHaveLength(1);
+ expect(e.ports[0]).toBeInstanceOf(MessagePort);
+ done();
+ };
+
+ port1.postMessage("hello", [anotherChannel.port2]);
+});
+
+test("tranfer array buffer", done => {
+ var channel = new MessageChannel();
+ var port1 = channel.port1;
+ var port2 = channel.port2;
+
+ port2.onmessage = function (e) {
+ expect(e.data).toBeInstanceOf(ArrayBuffer);
+ expect(e.data.byteLength).toEqual(8);
+ done();
+ };
+
+ const buffer = new ArrayBuffer(8);
+
+ port1.postMessage(buffer, [buffer]);
+});
+
+test("non-transferable", () => {
+ var channel = new MessageChannel();
+ channel.port2.onmessage = function (e) {
+ // not reached
+ expect(1).toBe(2);
+ };
+ expect(() => {
+ channel.port1.postMessage("hello", [channel.port1]);
+ }).toThrow();
+ expect(() => {
+ channel.port1.postMessage("hello", [channel.port2]);
+ }).toThrow();
+});
+
+test("transfer message ports and post messages", done => {
+ var c1 = new MessageChannel();
+ var c2 = new MessageChannel();
+
+ c1.port1.onmessage = e => {
+ var port = e.ports[0];
+ expect(port).toBeInstanceOf(MessagePort);
+ expect(e.data).toEqual("hello from channel 1 port 2");
+ port.onmessage = e => {
+ expect(e.data).toEqual("hello from channel 1 port 2");
+ done();
+ };
+ port.postMessage("hello from channel 1 port 1", [c1.port1]);
+ };
+
+ c1.port2.onmessage = e => {
+ var port = e.ports[0];
+ expect(port).toBeInstanceOf(MessagePort);
+ expect(e.data).toEqual("hello from channel 2 port 1");
+ port.postMessage("hello from channel 1 port 2");
+ };
+
+ c2.port1.onmessage = e => {
+ var port = e.ports[0];
+ expect(port).toBeInstanceOf(MessagePort);
+ expect(e.data).toEqual("hello from channel 1 port 1");
+ port.postMessage("hello from channel 2 port 1", [c2.port1]);
+ };
+
+ c2.port2.onmessage = e => {
+ // should not be reached. onmessage defined in c1.port1 should be called instead
+ expect(1).toBe(2);
+ };
+
+ c1.port2.postMessage("hello from channel 1 port 2", [c2.port2]);
+});
+
+test("message channel created on main thread", done => {
+ var worker = new Worker(new URL("receive-port-worker.js", import.meta.url).href);
+ worker.onerror = e => {
+ expect(1).toBe(2);
+ done();
+ };
+ var channel = new MessageChannel();
+ channel.port1.onmessage = e => {
+ if (e.data === "done!") return done();
+ expect(e.data).toEqual("received port!");
+ channel.port1.postMessage("more message!");
+ };
+ worker.postMessage(channel.port2, { transfer: [channel.port2] });
+});
+
+test("message channel created on other thread", done => {
+ var worker = new Worker(new URL("create-port-worker.js", import.meta.url).href);
+ worker.onerror = e => {
+ expect(1).toBe(2);
+ done();
+ };
+ worker.onmessage = e => {
+ expect(e.data).toBeInstanceOf(MessagePort);
+ var port = e.data;
+ port.onmessage = e => {
+ expect(e.data).toEqual("done!");
+ done();
+ };
+ port.postMessage("hello from main thread");
+ };
+});
+
+test("many message channels", done => {
+ var channel = new MessageChannel();
+ var channel2 = new MessageChannel();
+ var channel3 = new MessageChannel();
+ var channel4 = new MessageChannel();
+
+ channel.port1.postMessage("noport");
+ channel.port1.postMessage("zero ports", []);
+ channel.port1.postMessage("two ports", [channel2.port1, channel2.port2]);
+
+ // Now test various failure cases
+ expect(() => {
+ channel.port1.postMessage("same port", [channel.port1]);
+ }).toThrow();
+ expect(() => {
+ channel.port1.postMessage("entangled port", [channel.port2]);
+ }).toThrow();
+ expect(() => {
+ channel.port1.postMessage("null port", [channel3.port1, null, channel3.port2]);
+ }).toThrow();
+ expect(() => {
+ channel.port1.postMessage("notAPort", [channel3.port1, {}, channel3.port2]);
+ }).toThrow();
+ expect(() => {
+ channel.port1.postMessage("duplicate port", [channel3.port1, channel3.port1]);
+ }).toThrow();
+
+ // Should be OK to send channel3.port1 (should not have been disentangled by the previous failed calls).
+ expect(() => {
+ channel.port1.postMessage("entangled ports", [channel3.port1, channel3.port2]);
+ }).not.toThrow();
+
+ expect(() => {
+ channel.port1.postMessage("notAnArray", "foo");
+ }).toThrow();
+ expect(() => {
+ channel.port1.postMessage("notASequence", [{ length: 3 }]);
+ }).toThrow();
+
+ // Should not crash (we should figure out that the array contains undefined
+ // entries).
+ var largePortArray = [];
+ largePortArray[1234567890] = channel4.port1;
+ expect(() => {
+ channel.port1.postMessage("largeSequence", largePortArray);
+ }).toThrow();
+
+ channel.port1.postMessage("done");
+
+ function testTransfers(done) {
+ var channel0 = new MessageChannel();
+
+ var c1 = new MessageChannel();
+ channel0.port1.postMessage({ id: "send-port", port: c1.port1 }, [c1.port1]);
+ var c2 = new MessageChannel();
+ channel0.port1.postMessage({ id: "send-port-twice", port0: c2.port1, port1: c2.port1 }, [c2.port1]);
+ var c3 = new MessageChannel();
+ channel0.port1.postMessage({ id: "send-two-ports", port0: c3.port1, port1: c3.port2 }, [c3.port1, c3.port2]);
+ var c4 = new MessageChannel();
+
+ // Sending host objects should throw
+ expect(() => {
+ channel0.port1.postMessage({ id: "host-object", hostObject: c3, port: c4.port1 }, [c4.port1]);
+ }).toThrow();
+
+ // Sending Function object should throw
+ expect(() => {
+ var f1 = function () {};
+ channel0.port1.postMessage({ id: "function-object", function: f1, port: c4.port1 }, [c4.port1]);
+ }).toThrow();
+
+ // Sending Error object should not throw
+ // expect(() => {
+ // var err = new Error();
+ // channel0.port1.postMessage({ id: "error-object", error: err, port: c4.port1 }, [c4.port1]);
+ // }).not.toThrow();
+
+ c4.port1.postMessage("Should succeed");
+ channel0.port1.postMessage({ id: "done" });
+
+ channel0.port2.onmessage = function (event) {
+ if (event.data.id == "send-port") {
+ expect(event.ports.length).toBeGreaterThan(0);
+ expect(event.ports[0]).toBe(event.data.port);
+ } else if (event.data.id == "error-object") {
+ expect(event.data.error).toBeInstanceOf(Error);
+ } else if (event.data.id == "send-port-twice") {
+ expect(event.ports).toBeDefined();
+ expect(event.ports.length).toBe(1);
+ expect(event.ports[0]).toBe(event.data.port0);
+ expect(event.ports[0]).toBe(event.data.port1);
+ } else if (event.data.id == "send-two-ports") {
+ expect(event.ports).toBeDefined();
+ expect(event.ports.length).toBe(2);
+ expect(event.ports[0]).toBe(event.data.port0);
+ expect(event.ports[1]).toBe(event.data.port1);
+ } else if (event.data.id == "done") {
+ done();
+ } else {
+ // should not be reached
+ expect(1).toBe(2);
+ }
+ };
+ }
+
+ channel.port2.onmessage = function (event) {
+ if (event.data == "noport") {
+ expect(event.ports).toBeDefined();
+ expect(event.ports.length).toBe(0);
+ } else if (event.data == "zero ports") {
+ expect(event.ports).toBeDefined();
+ expect(event.ports.length).toBe(0);
+ } else if (event.data == "two ports") {
+ expect(event.ports).toBeDefined();
+ expect(event.ports.length).toBe(2);
+ } else if (event.data == "entangled ports") {
+ expect(event.ports).toBeDefined();
+ expect(event.ports.length).toBe(2);
+ } else if (event.data == "done") {
+ testTransfers(done);
+ } else {
+ // should not be reached
+ expect(1).toBe(2);
+ }
+ };
+});
diff --git a/test/js/web/workers/receive-port-worker.js b/test/js/web/workers/receive-port-worker.js
new file mode 100644
index 000000000..871fc4405
--- /dev/null
+++ b/test/js/web/workers/receive-port-worker.js
@@ -0,0 +1,9 @@
+onmessage = e => {
+ if (e.data instanceof MessagePort) {
+ var port = e.data;
+ port.onmessage = e => {
+ port.postMessage("done!");
+ };
+ port.postMessage("received port!");
+ }
+};
diff --git a/test/js/web/workers/structured-clone.test.ts b/test/js/web/workers/structured-clone.test.ts
index 61a0c1320..bdc7fcfea 100644
--- a/test/js/web/workers/structured-clone.test.ts
+++ b/test/js/web/workers/structured-clone.test.ts
@@ -183,7 +183,7 @@ describe("structured clone", () => {
});
});
- describe("transferrables", () => {
+ describe("transferables", () => {
test("ArrayBuffer", () => {
const buffer = Uint8Array.from([1]).buffer;
const cloned = structuredClone(buffer, { transfer: [buffer] });