diff options
author | 2023-07-18 20:48:51 -0700 | |
---|---|---|
committer | 2023-07-18 20:49:11 -0700 | |
commit | 8bd2b784a272f4ee571cbc924f8822d7ba6f7b51 (patch) | |
tree | 4f8515084f85ccf220738749187a0c8d7579eae2 | |
parent | f494e1b50d1d1b2d49998af0ef9b2b8f12b47620 (diff) | |
download | bun-8bd2b784a272f4ee571cbc924f8822d7ba6f7b51.tar.gz bun-8bd2b784a272f4ee571cbc924f8822d7ba6f7b51.tar.zst bun-8bd2b784a272f4ee571cbc924f8822d7ba6f7b51.zip |
more progress on fixing gc issue
-rw-r--r-- | src/bun.js/bindings/ScriptExecutionContext.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 178 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 10 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/JSEventTargetCustom.cpp | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/Worker.cpp | 29 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/Worker.h | 1 |
6 files changed, 162 insertions, 61 deletions
diff --git a/src/bun.js/bindings/ScriptExecutionContext.h b/src/bun.js/bindings/ScriptExecutionContext.h index c3fbd7c9b..520954c29 100644 --- a/src/bun.js/bindings/ScriptExecutionContext.h +++ b/src/bun.js/bindings/ScriptExecutionContext.h @@ -86,6 +86,7 @@ public: , m_globalObject(globalObject) , m_identifier(identifier) { + addToContextsMap(); } static ScriptExecutionContextIdentifier generateIdentifier(); @@ -183,6 +184,7 @@ public: void setGlobalObject(JSC::JSGlobalObject* globalObject) { m_globalObject = globalObject; + m_vm = &globalObject->vm(); } private: diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index a8d14e533..0262050ff 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -179,6 +179,17 @@ namespace JSCastingHelpers = JSC::JSCastingHelpers; #include "webcrypto/JSSubtleCrypto.h" #include "JSDOMFormData.h" +#include "JSDOMBinding.h" +#include "JSDOMConstructor.h" +#include "JSDOMConvertBase.h" +#include "JSDOMConvertBoolean.h" +#include "JSDOMConvertDictionary.h" +#include "JSDOMConvertEventListener.h" +#include "JSDOMConvertInterface.h" +#include "JSDOMConvertNullable.h" +#include "JSDOMConvertStrings.h" +#include "JSDOMConvertUnion.h" +#include "AddEventListenerOptions.h" #include "ErrorStackTrace.h" #include "CallSite.h" @@ -423,11 +434,10 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(JSClassRef* globalObje Zig::GlobalObject* globalObject; if (UNLIKELY(executionContextId > -1)) { - ScriptExecutionContext* context = new WebCore::ScriptExecutionContext(&vm, nullptr, static_cast<ScriptExecutionContextIdentifier>(executionContextId)); globalObject = Zig::GlobalObject::create( vm, Zig::GlobalObject::createStructure(vm, JSC::JSGlobalObject::create(vm, JSC::JSGlobalObject::createStructure(vm, JSC::jsNull())), JSC::jsNull()), - context); + static_cast<ScriptExecutionContextIdentifier>(executionContextId)); } else { globalObject = Zig::GlobalObject::create( vm, @@ -435,7 +445,7 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(JSClassRef* globalObje JSC::jsNull())); } - globalObject->setConsole(globalObject); + globalObject->setConsole(console_client); globalObject->isThreadLocalDefaultGlobalObject = true; globalObject->setStackTraceLimit(DEFAULT_ERROR_STACK_TRACE_LIMIT); // Node.js defaults to 10 vm.setOnComputeErrorInfo(computeErrorInfo); @@ -699,27 +709,25 @@ GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure) , m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal)) , m_worldIsNormal(true) , m_builtinInternalFunctions(vm) - , globalEventScope(Bun::GlobalScope::create(nullptr)) - + , m_scriptExecutionContext(new WebCore::ScriptExecutionContext(&vm, this)) + , globalEventScope(*new Bun::GlobalScope(m_scriptExecutionContext)) { - m_scriptExecutionContext = new WebCore::ScriptExecutionContext(&vm, this); - globalEventScope->m_context = m_scriptExecutionContext; mockModule = Bun::JSMockModule::create(this); + globalEventScope.m_context = m_scriptExecutionContext; } -GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContext* context) +GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContextIdentifier contextId) : JSC::JSGlobalObject(vm, structure, &s_globalObjectMethodTable) , m_bunVM(Bun__getVM()) , m_constructors(makeUnique<WebCore::DOMConstructors>()) , m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal)) , m_worldIsNormal(true) , m_builtinInternalFunctions(vm) - , globalEventScope(Bun::GlobalScope::create(context)) + , m_scriptExecutionContext(new WebCore::ScriptExecutionContext(&vm, this, contextId)) + , globalEventScope(*new Bun::GlobalScope(m_scriptExecutionContext)) { mockModule = Bun::JSMockModule::create(this); - m_scriptExecutionContext = context; - context->setGlobalObject(this); - context->addToContextsMap(); + globalEventScope.m_context = m_scriptExecutionContext; } GlobalObject::~GlobalObject() @@ -774,12 +782,9 @@ void GlobalObject::promiseRejectionTracker(JSGlobalObject* obj, JSC::JSPromise* } } -static Zig::ConsoleClient* m_console; - void GlobalObject::setConsole(void* console) { - m_console = new Zig::ConsoleClient(console); - this->setConsoleClient(m_console); + this->setConsoleClient(new Zig::ConsoleClient(console)); } #pragma mark - Globals @@ -826,7 +831,7 @@ JSC_DEFINE_CUSTOM_SETTER(globalSetterOnError, return true; } -Ref<WebCore::EventTarget> GlobalObject::eventTarget() +WebCore::EventTarget& GlobalObject::eventTarget() { return globalEventScope; } @@ -1689,6 +1694,84 @@ JSC: } } +static inline JSC::EncodedJSValue jsFunctionAddEventListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, Zig::GlobalObject* castedThis) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + UNUSED_PARAM(throwScope); + UNUSED_PARAM(callFrame); + auto& impl = castedThis->globalEventScope; + if (UNLIKELY(callFrame->argumentCount() < 2)) + return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); + auto type = convert<IDLAtomStringAdaptor<IDLDOMString>>(*lexicalGlobalObject, argument0.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1); + auto listener = convert<IDLNullable<IDLEventListener<JSEventListener>>>(*lexicalGlobalObject, argument1.value(), *castedThis, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 1, "listener", "EventTarget", "addEventListener"); }); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + EnsureStillAliveScope argument2 = callFrame->argument(2); + auto options = argument2.value().isUndefined() ? false : convert<IDLUnion<IDLDictionary<AddEventListenerOptions>, IDLBoolean>>(*lexicalGlobalObject, argument2.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + auto result = JSValue::encode(WebCore::toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.addEventListenerForBindings(WTFMove(type), WTFMove(listener), WTFMove(options)); })); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + vm.writeBarrier(&static_cast<JSObject&>(*castedThis), argument1.value()); + return result; +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionAddEventListener, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + return jsFunctionAddEventListenerBody(lexicalGlobalObject, callFrame, jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject)); +} + +static inline JSC::EncodedJSValue jsFunctionRemoveEventListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, Zig::GlobalObject* castedThis) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + UNUSED_PARAM(throwScope); + UNUSED_PARAM(callFrame); + auto& impl = castedThis->globalEventScope; + if (UNLIKELY(callFrame->argumentCount() < 2)) + return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); + auto type = convert<IDLAtomStringAdaptor<IDLDOMString>>(*lexicalGlobalObject, argument0.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1); + auto listener = convert<IDLNullable<IDLEventListener<JSEventListener>>>(*lexicalGlobalObject, argument1.value(), *castedThis, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 1, "listener", "EventTarget", "removeEventListener"); }); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + EnsureStillAliveScope argument2 = callFrame->argument(2); + auto options = argument2.value().isUndefined() ? false : convert<IDLUnion<IDLDictionary<EventListenerOptions>, IDLBoolean>>(*lexicalGlobalObject, argument2.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + auto result = JSValue::encode(WebCore::toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.removeEventListenerForBindings(WTFMove(type), WTFMove(listener), WTFMove(options)); })); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + vm.writeBarrier(&static_cast<JSObject&>(*castedThis), argument1.value()); + return result; +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionRemoveEventListener, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + return jsFunctionRemoveEventListenerBody(lexicalGlobalObject, callFrame, jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject)); +} + +static inline JSC::EncodedJSValue jsFunctionDispatchEventBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, Zig::GlobalObject* castedThis) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + UNUSED_PARAM(throwScope); + UNUSED_PARAM(callFrame); + auto& impl = castedThis->globalEventScope; + if (UNLIKELY(callFrame->argumentCount() < 1)) + return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); + auto event = convert<IDLInterface<Event>>(*lexicalGlobalObject, argument0.value(), [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentTypeError(lexicalGlobalObject, scope, 0, "event", "EventTarget", "dispatchEvent", "Event"); }); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + RELEASE_AND_RETURN(throwScope, JSValue::encode(WebCore::toJS<IDLBoolean>(*lexicalGlobalObject, throwScope, impl.dispatchEventForBindings(*event)))); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionDispatchEvent, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + return jsFunctionDispatchEventBody(lexicalGlobalObject, callFrame, jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject)); +} + static inline JSValue jsServiceWorkerGlobalScope_ByteLengthQueuingStrategyConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) { UNUSED_PARAM(lexicalGlobalObject); @@ -3463,11 +3546,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPostMessage, return JSValue::encode(jsUndefined()); } - ScriptExecutionContext::postTaskTo(context->identifier(), [message = serialized.releaseReturnValue(), protectedThis = Ref { *worker }](ScriptExecutionContext& context) { + RefPtr<SerializedScriptValue> message = serialized.releaseReturnValue(); + ScriptExecutionContext::postTaskTo(context->identifier(), [message = WTFMove(message), protectedThis = Ref { *worker }](ScriptExecutionContext& context) { Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(context.jsGlobalObject()); bool didFail = false; JSValue value = message->deserialize(*globalObject, globalObject, SerializationErrorMode::NonThrowing, &didFail); - message->deref(); if (didFail) { protectedThis->dispatchEvent(MessageEvent::create(eventNames().messageerrorEvent, MessageEvent::Init {}, MessageEvent::IsTrusted::Yes)); @@ -3774,7 +3857,6 @@ JSC_DEFINE_HOST_FUNCTION(functionGetDirectStreamDetails, (JSC::JSGlobalObject * return JSC::JSValue::encode(resultObject); } - JSC::GCClient::IsoSubspace* GlobalObject::subspaceForImpl(JSC::VM& vm) { return WebCore::subspaceForImpl<GlobalObject, WebCore::UseCustomHeapCellType::Yes>( @@ -3881,31 +3963,6 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); } - { - JSC::Identifier addEventListener = JSC::Identifier::fromString(vm, "addEventListener"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { addEventListener, - JSC::JSFunction::create(vm, this, 2, - "addEventListener"_s, WebCore::jsEventTargetPrototypeFunction_addEventListener, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - - { - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "dispatchEvent"_s), - JSC::JSFunction::create(vm, this, 1, - "dispatchEvent"_s, WebCore::jsEventTargetPrototypeFunction_dispatchEvent, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - - { - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "removeEventListener"_s), - JSC::JSFunction::create(vm, this, 1, - "removeEventListener"_s, WebCore::jsEventTargetPrototypeFunction_removeEventListener, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { builtinNames.startDirectStreamPrivateName(), JSC::JSFunction::create(vm, this, 1, @@ -4101,6 +4158,30 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CountQueuingStrategy"_s), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_CountQueuingStrategyConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "SubtleCrypto"_s), JSC::CustomGetterSetter::create(vm, getterSubtleCryptoConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CryptoKey"_s), JSC::CustomGetterSetter::create(vm, getterCryptoKeyConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + + putDirectNativeFunction(vm, this, + Identifier::fromString(vm, "addEventListener"_s), + 2, + jsFunctionAddEventListener, + ImplementationVisibility::Public, + NoIntrinsic, + JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + + putDirectNativeFunction(vm, this, + Identifier::fromString(vm, "dispatchEvent"_s), + 1, + jsFunctionDispatchEvent, + ImplementationVisibility::Public, + NoIntrinsic, + JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + + putDirectNativeFunction(vm, this, + Identifier::fromString(vm, "removeEventListener"_s), + 2, + jsFunctionRemoveEventListener, + ImplementationVisibility::Public, + NoIntrinsic, + JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); } // We set it in here since it's a global @@ -4474,8 +4555,6 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->visitGeneratedLazyClasses<Visitor>(thisObject, visitor); visitor.append(thisObject->m_BunCommonJSModuleValue); thisObject->visitAdditionalChildren<Visitor>(visitor); - ScriptExecutionContext* context = thisObject->scriptExecutionContext(); - visitor.addOpaqueRoot(context); } extern "C" bool JSGlobalObject__setTimeZone(JSC::JSGlobalObject* globalObject, const ZigString* timeZone) @@ -4547,7 +4626,10 @@ void GlobalObject::visitAdditionalChildren(Visitor& visitor) GlobalObject* thisObject = this; ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - thisObject->globalEventScope->visitJSEventListeners(visitor); + thisObject->globalEventScope.visitJSEventListeners(visitor); + + ScriptExecutionContext* context = thisObject->scriptExecutionContext(); + visitor.addOpaqueRoot(context); } DEFINE_VISIT_ADDITIONAL_CHILDREN(GlobalObject); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 5df1560b0..7501be89e 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -133,9 +133,9 @@ public: return ptr; } - static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContext* scriptExecutionContext) + static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, uint32_t scriptExecutionContextId) { - GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, scriptExecutionContext); + GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, scriptExecutionContextId); ptr->finishCreation(vm); return ptr; } @@ -312,8 +312,8 @@ public: EncodedJSValue assignToStream(JSValue stream, JSValue controller); - Ref<WebCore::EventTarget> eventTarget(); - Ref<Bun::GlobalScope> globalEventScope; + WebCore::EventTarget& eventTarget(); + Bun::GlobalScope& globalEventScope; enum class PromiseFunctions : uint8_t { Bun__HTTPRequestContext__onReject, @@ -448,7 +448,7 @@ private: friend void WebCore::JSBuiltinInternalFunctions::initialize(Zig::GlobalObject&); WebCore::JSBuiltinInternalFunctions m_builtinInternalFunctions; GlobalObject(JSC::VM& vm, JSC::Structure* structure); - GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContext*); + GlobalObject(JSC::VM& vm, JSC::Structure* structure, uint32_t); std::unique_ptr<WebCore::DOMConstructors> m_constructors; uint8_t m_worldIsNormal; JSDOMStructureMap m_structures WTF_GUARDED_BY_LOCK(m_gcLock); diff --git a/src/bun.js/bindings/webcore/JSEventTargetCustom.cpp b/src/bun.js/bindings/webcore/JSEventTargetCustom.cpp index 75ee90c9f..1b00dc987 100644 --- a/src/bun.js/bindings/webcore/JSEventTargetCustom.cpp +++ b/src/bun.js/bindings/webcore/JSEventTargetCustom.cpp @@ -36,6 +36,7 @@ // #include "JSWindowProxy.h" // #include "JSWorkerGlobalScope.h" // #include "WorkerGlobalScope.h" +#include "BunWorkerGlobalScope.h" #if ENABLE(OFFSCREEN_CANVAS) #include "OffscreenCanvas.h" @@ -56,7 +57,7 @@ EventTarget* JSEventTarget::toWrapped(VM& vm, JSValue value) // if (value.inherits<JSDOMWindow>()) // return &jsCast<JSDOMWindow*>(asObject(value))->wrapped(); if (value.inherits<JSDOMGlobalObject>()) - return jsCast<JSDOMGlobalObject*>(asObject(value))->eventTarget().ptr(); + return &jsCast<JSDOMGlobalObject*>(asObject(value))->globalEventScope; if (value.inherits<JSEventTarget>()) return &jsCast<JSEventTarget*>(asObject(value))->wrapped(); return nullptr; diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp index 4ffbc0684..d92b6e2e5 100644 --- a/src/bun.js/bindings/webcore/Worker.cpp +++ b/src/bun.js/bindings/webcore/Worker.cpp @@ -60,6 +60,7 @@ #include "JavaScriptCore/DeferredWorkTimer.h" #include "MessageEvent.h" #include <JavaScriptCore/HashMapImplInlines.h> +#include "BunWorkerGlobalScope.h" namespace WebCore { @@ -176,20 +177,21 @@ ExceptionOr<void> Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue m if (message.hasException()) return message.releaseException(); - this->postTaskToWorkerGlobalScope([message = message.releaseReturnValue()](auto& context) { + RefPtr<SerializedScriptValue> result = message.releaseReturnValue(); + + this->postTaskToWorkerGlobalScope([message = WTFMove(result)](auto& context) { Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(context.jsGlobalObject()); bool didFail = false; JSValue value = message->deserialize(*globalObject, globalObject, SerializationErrorMode::NonThrowing, &didFail); - message->deref(); if (didFail) { - globalObject->eventTarget()->dispatchEvent(MessageEvent::create(eventNames().messageerrorEvent, MessageEvent::Init {}, MessageEvent::IsTrusted::Yes)); + globalObject->globalEventScope.dispatchEvent(MessageEvent::create(eventNames().messageerrorEvent, MessageEvent::Init {}, MessageEvent::IsTrusted::Yes)); return; } WebCore::MessageEvent::Init init; init.data = value; - globalObject->eventTarget()->dispatchEvent(MessageEvent::create(eventNames().messageEvent, WTFMove(init), MessageEvent::IsTrusted::Yes)); + globalObject->globalEventScope.dispatchEvent(MessageEvent::create(eventNames().messageEvent, WTFMove(init), MessageEvent::IsTrusted::Yes)); }); return {}; } @@ -229,6 +231,10 @@ void Worker::terminate() bool Worker::hasPendingActivity() const { + if (this->refCount() > 0) { + return true; + } + if (this->m_isOnline) { return !this->m_isClosing; } @@ -241,7 +247,7 @@ void Worker::dispatchEvent(Event& event) if (m_wasTerminated) return; - EventTarget::dispatchEvent(event); + EventTargetWithInlineData::dispatchEvent(event); } #if ENABLE(WEB_RTC) @@ -259,6 +265,7 @@ void Worker::createRTCRtpScriptTransformer(RTCRtpScriptTransform& transform, Mes void Worker::drainEvents() { + Locker lock(this->m_pendingTasksMutex); for (auto& task : m_pendingTasks) postTaskToWorkerGlobalScope(WTFMove(task)); m_pendingTasks.clear(); @@ -277,19 +284,26 @@ void Worker::dispatchOnline(Zig::GlobalObject* workerGlobalObject) }); } + Locker lock(this->m_pendingTasksMutex); + this->m_isOnline = true; auto* thisContext = workerGlobalObject->scriptExecutionContext(); if (!thisContext) { return; } + RELEASE_ASSERT(&thisContext->vm() == &workerGlobalObject->vm()); + RELEASE_ASSERT(thisContext == workerGlobalObject->globalEventScope.scriptExecutionContext()); - if (workerGlobalObject->eventTarget()->hasActiveEventListeners(eventNames().messageEvent)) { + if (workerGlobalObject->globalEventScope.hasActiveEventListeners(eventNames().messageEvent)) { auto tasks = std::exchange(this->m_pendingTasks, {}); + lock.unlockEarly(); for (auto& task : tasks) { task(*thisContext); } } else { auto tasks = std::exchange(this->m_pendingTasks, {}); + lock.unlockEarly(); + thisContext->postTask([tasks = WTFMove(tasks)](auto& ctx) mutable { for (auto& task : tasks) { task(ctx); @@ -334,6 +348,7 @@ void Worker::dispatchExit() void Worker::postTaskToWorkerGlobalScope(Function<void(ScriptExecutionContext&)>&& task) { if (!this->m_isOnline) { + Locker lock(this->m_pendingTasksMutex); this->m_pendingTasks.append(WTFMove(task)); return; } @@ -388,7 +403,7 @@ extern "C" void WebWorker__dispatchError(Zig::GlobalObject* globalObject, Worker init.cancelable = false; init.bubbles = false; - globalObject->eventTarget()->dispatchEvent(ErrorEvent::create(eventNames().errorEvent, init, EventIsTrusted::Yes)); + globalObject->globalEventScope.dispatchEvent(ErrorEvent::create(eventNames().errorEvent, init, EventIsTrusted::Yes)); worker->dispatchError(Bun::toWTFString(message)); } diff --git a/src/bun.js/bindings/webcore/Worker.h b/src/bun.js/bindings/webcore/Worker.h index edd9f082d..99a54e37f 100644 --- a/src/bun.js/bindings/webcore/Worker.h +++ b/src/bun.js/bindings/webcore/Worker.h @@ -126,6 +126,7 @@ private: // bool m_isSuspendedForBackForwardCache { false }; // JSC::RuntimeFlags m_runtimeFlags; Deque<RefPtr<Event>> m_pendingEvents; + Lock m_pendingTasksMutex; Deque<Function<void(ScriptExecutionContext&)>> m_pendingTasks; bool m_wasTerminated { false }; bool m_didStartWorkerGlobalScope { false }; |