#pragma once #include "root.h" #include "ActiveDOMObject.h" #include #include #include #include #include #include #include #include "CachedScript.h" #include "wtf/ThreadSafeWeakPtr.h" #include #include namespace uWS { template struct WebSocketContext; } struct us_socket_t; struct us_socket_context_t; struct us_loop_t; namespace WebCore { class WebSocket; class BunBroadcastChannelRegistry; class MessagePort; class ScriptExecutionContext; class EventLoopTask; class ContextDestructionObserver; using ScriptExecutionContextIdentifier = uint32_t; #if ENABLE(MALLOC_BREAKDOWN) DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(ScriptExecutionContext); #endif class ScriptExecutionContext : public CanMakeWeakPtr, public RefCounted { #if ENABLE(MALLOC_BREAKDOWN) WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(ScriptExecutionContext); #else WTF_MAKE_TZONE_ALLOCATED(ScriptExecutionContext); #endif public: ScriptExecutionContext(JSC::VM* vm, JSC::JSGlobalObject* globalObject); ScriptExecutionContext(JSC::VM* vm, JSC::JSGlobalObject* globalObject, ScriptExecutionContextIdentifier identifier); ~ScriptExecutionContext(); static ScriptExecutionContextIdentifier generateIdentifier(); JSC::JSGlobalObject* jsGlobalObject() { return m_globalObject; } template us_socket_context_t* webSocketContext() { if constexpr (isSSL) { return this->webSocketContextSSL(); } else { return this->webSocketContextNoSSL(); } } static ScriptExecutionContext* getScriptExecutionContext(ScriptExecutionContextIdentifier identifier); void refEventLoop(); void unrefEventLoop(); using RefCounted::deref; using RefCounted::ref; const WTF::URL& url() const { return m_url; } bool isMainThread() const { return m_identifier == 1; } bool activeDOMObjectsAreSuspended() { return false; } bool activeDOMObjectsAreStopped() { return false; } bool isContextThread(); bool isDocument() { return false; } bool isWorkerGlobalScope() { return true; } bool isJSExecutionForbidden(); void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception* exception, RefPtr&&, CachedScript* = nullptr, bool = false) { } // void reportUnhandledPromiseRejection(JSC::JSGlobalObject&, JSC::JSPromise&, RefPtr&&) // { // } #if ENABLE(WEB_CRYPTO) // These two methods are used when CryptoKeys are serialized into IndexedDB. As a side effect, it is also // used for things that utilize the same structure clone algorithm, for example, message passing between // worker and document. // For now these will return false. In the future, we will want to implement these similar to how WorkerGlobalScope.cpp does. // virtual bool wrapCryptoKey(const Vector& key, Vector& wrappedKey) = 0; // virtual bool unwrapCryptoKey(const Vector& wrappedKey, Vector& key) = 0; bool wrapCryptoKey(const Vector& key, Vector& wrappedKey) { return false; } bool unwrapCryptoKey(const Vector& wrappedKey, Vector& key) { return false; } #endif WEBCORE_EXPORT static bool postTaskTo(ScriptExecutionContextIdentifier identifier, Function&& task); WEBCORE_EXPORT static bool ensureOnContextThread(ScriptExecutionContextIdentifier, Function&& task); WEBCORE_EXPORT static bool ensureOnMainThread(Function&& task); WEBCORE_EXPORT JSC::JSGlobalObject* globalObject(); void didCreateDestructionObserver(ContextDestructionObserver&); void willDestroyDestructionObserver(ContextDestructionObserver&); void processMessageWithMessagePortsSoon(CompletionHandler&&); void createdMessagePort(MessagePort&); void destroyedMessagePort(MessagePort&); void dispatchMessagePortEvents(); void checkConsistency() const; void regenerateIdentifier(); void addToContextsMap(); void removeFromContextsMap(); void postTaskConcurrently(Function&& lambda); // Executes the task on context's thread asynchronously. void postTask(Function&& lambda); // Executes the task on context's thread asynchronously. void postTask(EventLoopTask* task); // Executes the task on context's thread asynchronously. void postTaskOnTimeout(EventLoopTask* task, Seconds timeout); // Executes the task on context's thread asynchronously. void postTaskOnTimeout(Function&& lambda, Seconds timeout); template void postCrossThreadTask(Arguments&&... arguments) { postTask([crossThreadTask = createCrossThreadTask(arguments...)](ScriptExecutionContext&) mutable { crossThreadTask.performTask(); }); } JSC::VM& vm() { return *m_vm; } ScriptExecutionContextIdentifier identifier() const { return m_identifier; } bool isWorker = false; void setGlobalObject(JSC::JSGlobalObject* globalObject) { m_globalObject = globalObject; m_vm = &globalObject->vm(); } BunBroadcastChannelRegistry& broadcastChannelRegistry() { return m_broadcastChannelRegistry.get(*this); } static ScriptExecutionContext* getMainThreadScriptExecutionContext(); private: JSC::VM* m_vm = nullptr; JSC::JSGlobalObject* m_globalObject = nullptr; WTF::URL m_url = WTF::URL(); ScriptExecutionContextIdentifier m_identifier; UncheckedKeyHashSet m_messagePorts; UncheckedKeyHashSet m_destructionObservers; Vector> m_processMessageWithMessagePortsSoonHandlers; LazyRef m_broadcastChannelRegistry; bool m_willProcessMessageWithMessagePortsSoon { false }; us_socket_context_t* webSocketContextSSL(); us_socket_context_t* webSocketContextNoSSL(); us_socket_context_t* connectedWebSocketKindClientSSL(); us_socket_context_t* connectedWebSocketKindClient(); us_socket_context_t* m_ssl_client_websockets_ctx = nullptr; us_socket_context_t* m_client_websockets_ctx = nullptr; us_socket_context_t* m_connected_ssl_client_websockets_ctx = nullptr; us_socket_context_t* m_connected_client_websockets_ctx = nullptr; public: template us_socket_context_t* connectedWebSocketContext() { if constexpr (isSSL) { if (!m_connected_ssl_client_websockets_ctx) { m_connected_ssl_client_websockets_ctx = connectedWebSocketKindClientSSL(); } return m_connected_ssl_client_websockets_ctx; } else { if (!m_connected_client_websockets_ctx) { m_connected_client_websockets_ctx = connectedWebSocketKindClient(); } return m_connected_client_websockets_ctx; } } #if ASSERT_ENABLED bool m_inScriptExecutionContextDestructor = false; #endif }; ScriptExecutionContext* executionContext(JSC::JSGlobalObject*); }