diff --git a/src/bun.js/bindings/webcore/EventEmitter.cpp b/src/bun.js/bindings/webcore/EventEmitter.cpp index 1c71f9b7218789..2c80e9cc2dbe04 100644 --- a/src/bun.js/bindings/webcore/EventEmitter.cpp +++ b/src/bun.js/bindings/webcore/EventEmitter.cpp @@ -4,7 +4,6 @@ #include "EventEmitter.h" -#include "AddEventListenerOptions.h" #include "DOMWrapperWorld.h" #include "EventNames.h" #include "JSErrorHandler.h" @@ -26,15 +25,15 @@ Ref EventEmitter::create(ScriptExecutionContext& context) return adoptRef(*new EventEmitter(context)); } -bool EventEmitter::addListener(const AtomString& eventType, Ref&& listener, bool once, bool prepend) +bool EventEmitter::addListener(const Identifier& eventType, Ref&& listener, bool once, bool prepend) { bool listenerCreatedFromScript = is(listener) && !downcast(listener.get()).wasCreatedFromMarkup(); if (prepend) { - if (!ensureEventEmitterData().eventListenerMap.prepend(eventType, listener.copyRef(), { false, false, once })) + if (!ensureEventEmitterData().eventListenerMap.prepend(eventType, listener.copyRef(), once)) return false; } else { - if (!ensureEventEmitterData().eventListenerMap.add(eventType, listener.copyRef(), { false, false, once })) + if (!ensureEventEmitterData().eventListenerMap.add(eventType, listener.copyRef(), once)) return false; } @@ -43,7 +42,7 @@ bool EventEmitter::addListener(const AtomString& eventType, Ref&& return true; } -void EventEmitter::addListenerForBindings(const AtomString& eventType, RefPtr&& listener, bool once, bool prepend) +void EventEmitter::addListenerForBindings(const Identifier& eventType, RefPtr&& listener, bool once, bool prepend) { if (!listener) return; @@ -51,7 +50,7 @@ void EventEmitter::addListenerForBindings(const AtomString& eventType, RefPtr&& listener) +void EventEmitter::removeListenerForBindings(const Identifier& eventType, RefPtr&& listener) { if (!listener) return; @@ -59,50 +58,44 @@ void EventEmitter::removeListenerForBindings(const AtomString& eventType, RefPtr removeListener(eventType, *listener); } -bool EventEmitter::removeListener(const AtomString& eventType, EventListener& listener) +bool EventEmitter::removeListener(const Identifier& eventType, EventListener& listener) { auto* data = eventTargetData(); if (!data) return false; - if (data->eventListenerMap.remove(eventType, listener, false)) { - if (eventNames().isWheelEventType(eventType)) - invalidateEventListenerRegions(); - + if (data->eventListenerMap.remove(eventType, listener)) { eventListenersDidChange(); return true; } return false; } -void EventEmitter::removeAllListenersForBindings(const AtomString& eventType) +void EventEmitter::removeAllListenersForBindings(const Identifier& eventType) { removeAllListeners(eventType); } -bool EventEmitter::removeAllListeners(const AtomString& eventType) +bool EventEmitter::removeAllListeners(const Identifier& eventType) { auto* data = eventTargetData(); if (!data) return false; if (data->eventListenerMap.removeAll(eventType)) { - if (eventNames().isWheelEventType(eventType)) - invalidateEventListenerRegions(); - eventListenersDidChange(); return true; } return false; } -bool EventEmitter::hasActiveEventListeners(const AtomString& eventType) const +bool EventEmitter::hasActiveEventListeners(const Identifier& eventType) const { auto* data = eventTargetData(); return data && data->eventListenerMap.containsActive(eventType); } -bool EventEmitter::emitForBindings(const AtomString& eventType, const MarkedArgumentBuffer& arguments) +bool EventEmitter::emitForBindings(const Identifier& eventType, const MarkedArgumentBuffer& arguments) { if (!scriptExecutionContext()) return false; @@ -111,7 +104,7 @@ bool EventEmitter::emitForBindings(const AtomString& eventType, const MarkedArgu return true; } -void EventEmitter::emit(const AtomString& eventType, const MarkedArgumentBuffer& arguments) +void EventEmitter::emit(const Identifier& eventType, const MarkedArgumentBuffer& arguments) { fireEventListeners(eventType, arguments); } @@ -120,7 +113,7 @@ void EventEmitter::uncaughtExceptionInEventHandler() { } -Vector EventEmitter::getEventNames() +Vector EventEmitter::getEventNames() { auto* data = eventTargetData(); if (!data) @@ -128,7 +121,7 @@ Vector EventEmitter::getEventNames() return data->eventListenerMap.eventTypes(); } -int EventEmitter::listenerCount(const AtomString& eventType) +int EventEmitter::listenerCount(const Identifier& eventType) { auto* data = eventTargetData(); if (!data) @@ -147,7 +140,7 @@ int EventEmitter::listenerCount(const AtomString& eventType) return result; } -Vector EventEmitter::getListeners(const AtomString& eventType) +Vector EventEmitter::getListeners(const Identifier& eventType) { auto* data = eventTargetData(); if (!data) @@ -166,14 +159,8 @@ Vector EventEmitter::getListeners(const AtomString& eventType) return listeners; } -static const AtomString& legacyType(const Event& event) -{ - - return nullAtom(); -} - // https://dom.spec.whatwg.org/#concept-event-listener-invoke -void EventEmitter::fireEventListeners(const AtomString& eventType, const MarkedArgumentBuffer& arguments) +void EventEmitter::fireEventListeners(const Identifier& eventType, const MarkedArgumentBuffer& arguments) { ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::isEventAllowedInMainThread()); @@ -192,7 +179,7 @@ void EventEmitter::fireEventListeners(const AtomString& eventType, const MarkedA // Intentionally creates a copy of the listeners vector to avoid event listeners added after this point from being run. // Note that removal still has an effect due to the removed field in RegisteredEventListener. // https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke -void EventEmitter::innerInvokeEventListeners(const AtomString& eventType, EventListenerVector listeners, const MarkedArgumentBuffer& arguments) +void EventEmitter::innerInvokeEventListeners(const Identifier& eventType, SimpleEventListenerVector listeners, const MarkedArgumentBuffer& arguments) { Ref protectedThis(*this); ASSERT(!listeners.isEmpty()); @@ -223,18 +210,18 @@ void EventEmitter::innerInvokeEventListeners(const AtomString& eventType, EventL } } -Vector EventEmitter::eventTypes() +Vector EventEmitter::eventTypes() { if (auto* data = eventTargetData()) return data->eventListenerMap.eventTypes(); return {}; } -const EventListenerVector& EventEmitter::eventListeners(const AtomString& eventType) +const SimpleEventListenerVector& EventEmitter::eventListeners(const Identifier& eventType) { auto* data = eventTargetData(); auto* listenerVector = data ? data->eventListenerMap.find(eventType) : nullptr; - static NeverDestroyed emptyVector; + static NeverDestroyed emptyVector; return listenerVector ? *listenerVector : emptyVector.get(); } diff --git a/src/bun.js/bindings/webcore/EventEmitter.h b/src/bun.js/bindings/webcore/EventEmitter.h index 35650f3806ac28..d6fd20c652dbe7 100644 --- a/src/bun.js/bindings/webcore/EventEmitter.h +++ b/src/bun.js/bindings/webcore/EventEmitter.h @@ -1,7 +1,6 @@ #pragma once -#include "EventListenerMap.h" -#include "EventListenerOptions.h" +#include "IdentifierEventListenerMap.h" #include "ExceptionOr.h" #include "ContextDestructionObserver.h" #include "ScriptWrappable.h" @@ -20,7 +19,6 @@ class JSObject; namespace WebCore { -struct AddEventListenerOptions; class DOMWrapperWorld; class JSEventListener; @@ -30,7 +28,7 @@ struct EventEmitterData { public: EventEmitterData() = default; - EventListenerMap eventListenerMap; + IdentifierEventListenerMap eventListenerMap; bool isFiringEventListeners { false }; }; @@ -48,34 +46,32 @@ class EventEmitter final : public ScriptWrappable, public CanMakeWeakPtr&&, bool, bool); - WEBCORE_EXPORT void removeListenerForBindings(const AtomString& eventType, RefPtr&&); - WEBCORE_EXPORT void removeAllListenersForBindings(const AtomString& eventType); - WEBCORE_EXPORT bool emitForBindings(const AtomString&, const MarkedArgumentBuffer&); + WEBCORE_EXPORT void addListenerForBindings(const Identifier& eventType, RefPtr&&, bool, bool); + WEBCORE_EXPORT void removeListenerForBindings(const Identifier& eventType, RefPtr&&); + WEBCORE_EXPORT void removeAllListenersForBindings(const Identifier& eventType); + WEBCORE_EXPORT bool emitForBindings(const Identifier&, const MarkedArgumentBuffer&); - WEBCORE_EXPORT bool addListener(const AtomString& eventType, Ref&&, bool, bool); - WEBCORE_EXPORT bool removeListener(const AtomString& eventType, EventListener&); - WEBCORE_EXPORT bool removeAllListeners(const AtomString& eventType); + WEBCORE_EXPORT bool addListener(const Identifier& eventType, Ref&&, bool, bool); + WEBCORE_EXPORT bool removeListener(const Identifier& eventType, EventListener&); + WEBCORE_EXPORT bool removeAllListeners(const Identifier& eventType); - WEBCORE_EXPORT void emit(const AtomString&, const MarkedArgumentBuffer&); + WEBCORE_EXPORT void emit(const Identifier&, const MarkedArgumentBuffer&); WEBCORE_EXPORT void uncaughtExceptionInEventHandler(); - WEBCORE_EXPORT Vector getEventNames(); - WEBCORE_EXPORT Vector getListeners(const AtomString& eventType); - WEBCORE_EXPORT int listenerCount(const AtomString& eventType); + WEBCORE_EXPORT Vector getEventNames(); + WEBCORE_EXPORT Vector getListeners(const Identifier& eventType); + WEBCORE_EXPORT int listenerCount(const Identifier& eventType); bool hasEventListeners() const; - bool hasEventListeners(const AtomString& eventType) const; - bool hasCapturingEventListeners(const AtomString& eventType); - bool hasActiveEventListeners(const AtomString& eventType) const; + bool hasEventListeners(const Identifier& eventType) const; + bool hasActiveEventListeners(const Identifier& eventType) const; - Vector eventTypes(); - const EventListenerVector& eventListeners(const AtomString& eventType); + Vector eventTypes(); + const SimpleEventListenerVector& eventListeners(const Identifier& eventType); - void fireEventListeners(const AtomString& eventName, const MarkedArgumentBuffer& arguments); + void fireEventListeners(const Identifier& eventName, const MarkedArgumentBuffer& arguments); bool isFiringEventListeners() const; - template void visitJSEventListeners(Visitor&); void invalidateJSEventListeners(JSC::JSObject*); const EventEmitterData* eventTargetData() const; @@ -90,7 +86,7 @@ class EventEmitter final : public ScriptWrappable, public CanMakeWeakPtreventListenerMap.isEmpty(); } -inline bool EventEmitter::hasEventListeners(const AtomString& eventType) const +inline bool EventEmitter::hasEventListeners(const Identifier& eventType) const { auto* data = eventTargetData(); return data && data->eventListenerMap.contains(eventType); } -inline bool EventEmitter::hasCapturingEventListeners(const AtomString& eventType) -{ - auto* data = eventTargetData(); - return data && data->eventListenerMap.containsCapturing(eventType); -} - -template -void EventEmitter::visitJSEventListeners(Visitor& visitor) -{ - if (auto* data = eventTargetDataConcurrently()) - data->eventListenerMap.visitJSEventListeners(visitor); -} - } // namespace WebCore diff --git a/src/bun.js/bindings/webcore/EventListenerMap.cpp b/src/bun.js/bindings/webcore/EventListenerMap.cpp index bb6cf0a21c0b28..5014cfa00dde6f 100644 --- a/src/bun.js/bindings/webcore/EventListenerMap.cpp +++ b/src/bun.js/bindings/webcore/EventListenerMap.cpp @@ -129,21 +129,6 @@ bool EventListenerMap::add(const AtomString& eventType, Ref&& lis return true; } -bool EventListenerMap::prepend(const AtomString& eventType, Ref&& listener, const RegisteredEventListener::Options& options) -{ - Locker locker { m_lock }; - - if (auto* listeners = find(eventType)) { - if (findListener(*listeners, listener, options.capture) != notFound) - return false; // Duplicate listener. - listeners->insert(0, RegisteredEventListener::create(WTFMove(listener), options)); - return true; - } - - m_entries.append({ eventType, EventListenerVector { RegisteredEventListener::create(WTFMove(listener), options) } }); - return true; -} - static bool removeListenerFromVector(EventListenerVector& listeners, EventListener& listener, bool useCapture) { size_t indexOfRemovedListener = findListener(listeners, listener, useCapture); @@ -171,20 +156,6 @@ bool EventListenerMap::remove(const AtomString& eventType, EventListener& listen return false; } -bool EventListenerMap::removeAll(const AtomString& eventType) -{ - Locker locker { m_lock }; - - for (unsigned i = 0; i < m_entries.size(); ++i) { - if (m_entries[i].first == eventType) { - m_entries.remove(i); - return true; - } - } - - return false; -} - EventListenerVector* EventListenerMap::find(const AtomString& eventType) { for (auto& entry : m_entries) { diff --git a/src/bun.js/bindings/webcore/EventListenerMap.h b/src/bun.js/bindings/webcore/EventListenerMap.h index 3467e8403cbd1d..d5b83c2205000f 100644 --- a/src/bun.js/bindings/webcore/EventListenerMap.h +++ b/src/bun.js/bindings/webcore/EventListenerMap.h @@ -58,9 +58,7 @@ class EventListenerMap { void replace(const AtomString& eventType, EventListener& oldListener, Ref&& newListener, const RegisteredEventListener::Options&); bool add(const AtomString& eventType, Ref&&, const RegisteredEventListener::Options&); - bool prepend(const AtomString& eventType, Ref&&, const RegisteredEventListener::Options&); bool remove(const AtomString& eventType, EventListener&, bool useCapture); - bool removeAll(const AtomString& eventType); WEBCORE_EXPORT EventListenerVector* find(const AtomString& eventType); const EventListenerVector* find(const AtomString& eventType) const { return const_cast(this)->find(eventType); } Vector eventTypes() const; diff --git a/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp b/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp new file mode 100644 index 00000000000000..2a5d5f831efded --- /dev/null +++ b/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp @@ -0,0 +1,156 @@ +#include "config.h" +#include "IdentifierEventListenerMap.h" + +#include "Event.h" +#include "EventTarget.h" +#include "JSEventListener.h" +#include +#include +#include + + +namespace WebCore { + +IdentifierEventListenerMap::IdentifierEventListenerMap() = default; + +bool IdentifierEventListenerMap::containsActive(const JSC::Identifier& eventType) const +{ + return false; +} + +void IdentifierEventListenerMap::clear() +{ + Locker locker { m_lock }; + + for (auto& entry : m_entries) { + for (auto& listener : entry.second) + listener->markAsRemoved(); + } + + m_entries.clear(); +} + +Vector IdentifierEventListenerMap::eventTypes() const +{ + return m_entries.map([](auto& entry) { + return entry.first; + }); +} + +static inline size_t findListener(const SimpleEventListenerVector& listeners, EventListener& listener) +{ + for (size_t i = 0; i < listeners.size(); ++i) { + auto& registeredListener = listeners[i]; + if (registeredListener->callback() == listener) + return i; + } + return notFound; +} + +void IdentifierEventListenerMap::replace(const JSC::Identifier& eventType, EventListener& oldListener, Ref&& newListener, bool once) +{ + Locker locker { m_lock }; + + auto* listeners = find(eventType); + ASSERT(listeners); + size_t index = findListener(*listeners, oldListener); + ASSERT(index != notFound); + auto& registeredListener = listeners->at(index); + registeredListener->markAsRemoved(); + registeredListener = SimpleRegisteredEventListener::create(WTFMove(newListener), once); +} + +bool IdentifierEventListenerMap::add(const JSC::Identifier& eventType, Ref&& listener, bool once) +{ + Locker locker { m_lock }; + + if (auto* listeners = find(eventType)) { + if (findListener(*listeners, listener) != notFound) + return false; // Duplicate listener. + listeners->append(SimpleRegisteredEventListener::create(WTFMove(listener), once)); + return true; + } + + m_entries.append({ eventType, SimpleEventListenerVector { SimpleRegisteredEventListener::create(WTFMove(listener), once) } }); + return true; +} + +bool IdentifierEventListenerMap::prepend(const JSC::Identifier& eventType, Ref&& listener, bool once) +{ + Locker locker { m_lock }; + + if (auto* listeners = find(eventType)) { + if (findListener(*listeners, listener) != notFound) + return false; // Duplicate listener. + listeners->insert(0, SimpleRegisteredEventListener::create(WTFMove(listener), once)); + return true; + } + + m_entries.append({ eventType, SimpleEventListenerVector { SimpleRegisteredEventListener::create(WTFMove(listener), once) } }); + return true; +} + +static bool removeListenerFromVector(SimpleEventListenerVector& listeners, EventListener& listener) +{ + size_t indexOfRemovedListener = findListener(listeners, listener); + if (UNLIKELY(indexOfRemovedListener == notFound)) + return false; + + listeners[indexOfRemovedListener]->markAsRemoved(); + listeners.remove(indexOfRemovedListener); + return true; +} + +bool IdentifierEventListenerMap::remove(const JSC::Identifier& eventType, EventListener& listener) +{ + Locker locker { m_lock }; + + for (unsigned i = 0; i < m_entries.size(); ++i) { + if (m_entries[i].first == eventType) { + bool wasRemoved = removeListenerFromVector(m_entries[i].second, listener); + if (m_entries[i].second.isEmpty()) + m_entries.remove(i); + return wasRemoved; + } + } + + return false; +} + +bool IdentifierEventListenerMap::removeAll(const JSC::Identifier& eventType) +{ + Locker locker { m_lock }; + + for (unsigned i = 0; i < m_entries.size(); ++i) { + if (m_entries[i].first == eventType) { + m_entries.remove(i); + return true; + } + } + + return false; +} + +SimpleEventListenerVector* IdentifierEventListenerMap::find(const JSC::Identifier& eventType) +{ + for (auto& entry : m_entries) { + if (entry.first == eventType) + return &entry.second; + } + + return nullptr; +} + +static void removeFirstListenerCreatedFromMarkup(SimpleEventListenerVector& listenerVector) +{ + bool foundListener = listenerVector.removeFirstMatching([] (const auto& registeredListener) { + if (JSEventListener::wasCreatedFromMarkup(registeredListener->callback())) { + registeredListener->markAsRemoved(); + return true; + } + return false; + }); + ASSERT_UNUSED(foundListener, foundListener); +} + +} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/IdentifierEventListenerMap.h b/src/bun.js/bindings/webcore/IdentifierEventListenerMap.h new file mode 100644 index 00000000000000..34da21122f20a7 --- /dev/null +++ b/src/bun.js/bindings/webcore/IdentifierEventListenerMap.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "EventListener.h" + +namespace WebCore { + +class SimpleRegisteredEventListener : public RefCounted { +public: + static Ref create(Ref&& listener, bool once) + { + return adoptRef(*new SimpleRegisteredEventListener(WTFMove(listener), once)); + } + + EventListener& callback() const { return m_callback; } + bool isOnce() const { return m_isOnce; } + bool wasRemoved() const { return m_wasRemoved; } + + void markAsRemoved() { m_wasRemoved = true; } + +private: + SimpleRegisteredEventListener(Ref&& listener, bool once) + : m_isOnce(once) + , m_wasRemoved(false) + , m_callback(WTFMove(listener)) + { + } + + bool m_isOnce : 1; + bool m_wasRemoved : 1; + Ref m_callback; +}; + +using SimpleEventListenerVector = Vector, 1, CrashOnOverflow, 2>; + +class IdentifierEventListenerMap { +public: + IdentifierEventListenerMap(); + + bool isEmpty() const { return m_entries.isEmpty(); } + bool contains(const JSC::Identifier& eventType) const { return find(eventType); } + bool containsActive(const JSC::Identifier& eventType) const; + + void clear(); + + void replace(const JSC::Identifier& eventType, EventListener& oldListener, Ref&& newListener, bool once); + bool add(const JSC::Identifier& eventType, Ref&&, bool once); + bool prepend(const JSC::Identifier& eventType, Ref&&, bool once); + bool remove(const JSC::Identifier& eventType, EventListener&); + bool removeAll(const JSC::Identifier& eventType); + WEBCORE_EXPORT SimpleEventListenerVector* find(const JSC::Identifier& eventType); + const SimpleEventListenerVector* find(const JSC::Identifier& eventType) const { return const_cast(this)->find(eventType); } + Vector eventTypes() const; + + Lock& lock() { return m_lock; } + +private: + Vector> m_entries; + Lock m_lock; +}; + +} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.cpp b/src/bun.js/bindings/webcore/JSEventEmitter.cpp index 3971243f9724e6..2b4edb17821f19 100644 --- a/src/bun.js/bindings/webcore/JSEventEmitter.cpp +++ b/src/bun.js/bindings/webcore/JSEventEmitter.cpp @@ -27,6 +27,7 @@ #include "WebCoreJSClientData.h" #include #include +#include #include #include #include @@ -217,12 +218,12 @@ static inline JSC::EncodedJSValue addListener(JSC::JSGlobalObject* lexicalGlobal if (UNLIKELY(callFrame->argumentCount() < 2)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto type = convert>(*lexicalGlobalObject, argument0.value()); + auto eventType = argument0.value().toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1); auto listener = convert>>(*lexicalGlobalObject, argument1.value(), *castedThis, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 1, "listener", "EventEmitter", "addListener"); }); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto result = JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.addListenerForBindings(WTFMove(type), WTFMove(listener), once, prepend); })); + auto result = JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.addListenerForBindings(WTFMove(eventType), WTFMove(listener), once, prepend); })); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); vm.writeBarrier(&static_cast(*castedThis), argument1.value()); return result; @@ -278,12 +279,12 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_removeListener if (UNLIKELY(callFrame->argumentCount() < 2)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto type = convert>(*lexicalGlobalObject, argument0.value()); + auto eventType = argument0.value().toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1); auto listener = convert>>(*lexicalGlobalObject, argument1.value(), *castedThis, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 1, "listener", "EventEmitter", "removeListener"); }); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto result = JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.removeListenerForBindings(WTFMove(type), WTFMove(listener)); })); + auto result = JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.removeListenerForBindings(WTFMove(eventType), WTFMove(listener)); })); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); vm.writeBarrier(&static_cast(*castedThis), argument1.value()); return result; @@ -304,9 +305,9 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_removeAllListe if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto type = convert>(*lexicalGlobalObject, argument0.value()); + auto eventType = argument0.value().toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto result = JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.removeAllListenersForBindings(WTFMove(type)); })); + auto result = JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.removeAllListenersForBindings(WTFMove(eventType)); })); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); return result; } @@ -326,13 +327,12 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_emitBody(JSC:: size_t argumentCount = callFrame->argumentCount(); if (UNLIKELY(argumentCount < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - auto* argument0 = callFrame->uncheckedArgument(0).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(0).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); JSC::MarkedArgumentBuffer args; for (size_t i = 1; i < argumentCount; ++i) { args.append(callFrame->uncheckedArgument(i)); } - auto eventType = argument0->toAtomString(lexicalGlobalObject); RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, impl.emitForBindings(eventType, args)))); } @@ -350,7 +350,7 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_eventNamesBody auto& impl = castedThis->wrapped(); JSC::MarkedArgumentBuffer args; for (auto& name : impl.getEventNames()) { - args.append(jsOwnedString(vm, name)); + args.append(JSC::identifierToSafePublicJSValue(vm, name)); } RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::constructArray(lexicalGlobalObject, static_cast(nullptr), WTFMove(args)))); } @@ -369,9 +369,8 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_listenerCountB auto& impl = castedThis->wrapped(); if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - auto* argument0 = callFrame->uncheckedArgument(0).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(0).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto eventType = argument0->toAtomString(lexicalGlobalObject); RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(impl.listenerCount(eventType)))); } @@ -389,9 +388,8 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_listenersBody( auto& impl = castedThis->wrapped(); if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - auto* argument0 = callFrame->uncheckedArgument(0).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(0).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto eventType = argument0->toAtomString(lexicalGlobalObject); JSC::MarkedArgumentBuffer args; for (auto* listener : impl.getListeners(eventType)) { args.append(listener); @@ -480,9 +478,8 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionGetEventListeners, return JSValue::encode(JSC::jsUndefined()); } auto* impl = JSEventEmitter::toWrapped(vm, argument0); - auto* argument1 = callFrame->uncheckedArgument(1).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto eventType = argument1->toAtomString(lexicalGlobalObject); JSC::MarkedArgumentBuffer args; for (auto* listener : impl->getListeners(eventType)) { args.append(listener); @@ -505,9 +502,8 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionListenerCount, return JSValue::encode(JSC::jsUndefined()); } auto* impl = JSEventEmitter::toWrapped(vm, argument0); - auto* argument1 = callFrame->uncheckedArgument(1).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto eventType = argument1->toAtomString(lexicalGlobalObject); RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(impl->listenerCount(eventType)))); } @@ -527,9 +523,8 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionOnce, return JSValue::encode(JSC::jsUndefined()); } auto* impl = JSEventEmitter::toWrapped(vm, argument0); - auto* argument1 = callFrame->uncheckedArgument(1).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto eventType = argument1->toAtomString(lexicalGlobalObject); EnsureStillAliveScope argument2 = callFrame->uncheckedArgument(2); auto listener = convert>>(*lexicalGlobalObject, argument2.value(), *argument0, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 2, "listener", "EventEmitter", "removeListener"); }); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); @@ -555,9 +550,8 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionOn, return JSValue::encode(JSC::jsUndefined()); } auto* impl = JSEventEmitter::toWrapped(vm, argument0); - auto* argument1 = callFrame->uncheckedArgument(1).toString(lexicalGlobalObject); + auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto eventType = argument1->toAtomString(lexicalGlobalObject); EnsureStillAliveScope argument2 = callFrame->uncheckedArgument(2); auto listener = convert>>(*lexicalGlobalObject, argument2.value(), *argument0, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 2, "listener", "EventEmitter", "removeListener"); }); RETURN_IF_EXCEPTION(throwScope, encodedJSValue());