aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-05 00:19:23 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-05 00:19:23 -0800
commit682af03cdce591d2a91cb78103b91f05325b8921 (patch)
treec126b032cb6e1656d804b39212ce18430aeaec5d /src
parent1564f75d06a5b361b1f9be98233b9f797d2ea7e2 (diff)
downloadbun-682af03cdce591d2a91cb78103b91f05325b8921.tar.gz
bun-682af03cdce591d2a91cb78103b91f05325b8921.tar.zst
bun-682af03cdce591d2a91cb78103b91f05325b8921.zip
"Fix" monkey-patching EventEmitter prototype
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitter.cpp24
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitterCustom.cpp65
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitterCustom.h18
-rw-r--r--src/bun.js/builtins/BunBuiltinNames.h1
4 files changed, 73 insertions, 35 deletions
diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.cpp b/src/bun.js/bindings/webcore/JSEventEmitter.cpp
index bcd0d9a50..8ef858166 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitter.cpp
+++ b/src/bun.js/bindings/webcore/JSEventEmitter.cpp
@@ -517,16 +517,16 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionGetEventListeners,
UNUSED_PARAM(callFrame);
if (UNLIKELY(callFrame->argumentCount() < 2))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
- auto* argument0 = JSC::jsDynamicCast<JSEventEmitter*>(callFrame->uncheckedArgument(0));
+ auto argument0 = jsEventEmitterCast(vm, lexicalGlobalObject, callFrame->uncheckedArgument(0));
if (UNLIKELY(!argument0)) {
throwException(lexicalGlobalObject, throwScope, createError(lexicalGlobalObject, "Expected EventEmitter"_s));
return JSValue::encode(JSC::jsUndefined());
}
- auto* impl = JSEventEmitter::toWrapped(vm, argument0);
+ auto& impl = argument0->wrapped();
auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
JSC::MarkedArgumentBuffer args;
- for (auto* listener : impl->getListeners(eventType)) {
+ for (auto* listener : impl.getListeners(eventType)) {
args.append(listener);
}
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::constructArray(lexicalGlobalObject, static_cast<JSC::ArrayAllocationProfile*>(nullptr), WTFMove(args))));
@@ -541,15 +541,15 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionListenerCount,
UNUSED_PARAM(callFrame);
if (UNLIKELY(callFrame->argumentCount() < 2))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
- auto* argument0 = JSC::jsDynamicCast<JSEventEmitter*>(callFrame->uncheckedArgument(0));
+ auto argument0 = jsEventEmitterCast(vm, lexicalGlobalObject, callFrame->uncheckedArgument(0));
if (UNLIKELY(!argument0)) {
throwException(lexicalGlobalObject, throwScope, createError(lexicalGlobalObject, "Expected EventEmitter"_s));
return JSValue::encode(JSC::jsUndefined());
}
- auto* impl = JSEventEmitter::toWrapped(vm, argument0);
+ auto& impl = argument0->wrapped();
auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(impl->listenerCount(eventType))));
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(impl.listenerCount(eventType))));
}
JSC_DEFINE_HOST_FUNCTION(Events_functionOnce,
@@ -562,18 +562,18 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionOnce,
if (UNLIKELY(callFrame->argumentCount() < 3))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
- auto* argument0 = JSC::jsDynamicCast<JSEventEmitter*>(callFrame->uncheckedArgument(0));
+ auto argument0 = jsEventEmitterCastFast(vm, lexicalGlobalObject, callFrame->uncheckedArgument(0));
if (UNLIKELY(!argument0)) {
throwException(lexicalGlobalObject, throwScope, createError(lexicalGlobalObject, "Expected EventEmitter"_s));
return JSValue::encode(JSC::jsUndefined());
}
- auto* impl = JSEventEmitter::toWrapped(vm, argument0);
+ auto& impl = argument0->wrapped();
auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
EnsureStillAliveScope argument2 = callFrame->uncheckedArgument(2);
auto listener = convert<IDLNullable<IDLEventListener<JSEventListener>>>(*lexicalGlobalObject, argument2.value(), *argument0, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 2, "listener", "EventEmitter", "removeListener"); });
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- auto result = JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl->addListenerForBindings(WTFMove(eventType), WTFMove(listener), true, false); }));
+ auto result = JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.addListenerForBindings(WTFMove(eventType), WTFMove(listener), true, false); }));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
vm.writeBarrier(argument0, argument2.value());
return result;
@@ -589,18 +589,18 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionOn,
if (UNLIKELY(callFrame->argumentCount() < 3))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
- auto* argument0 = JSC::jsDynamicCast<JSEventEmitter*>(callFrame->uncheckedArgument(0));
+ auto argument0 = jsEventEmitterCastFast(vm, lexicalGlobalObject, callFrame->uncheckedArgument(0));
if (UNLIKELY(!argument0)) {
throwException(lexicalGlobalObject, throwScope, createError(lexicalGlobalObject, "Expected EventEmitter"_s));
return JSValue::encode(JSC::jsUndefined());
}
- auto* impl = JSEventEmitter::toWrapped(vm, argument0);
+ auto& impl = argument0->wrapped();
auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
EnsureStillAliveScope argument2 = callFrame->uncheckedArgument(2);
auto listener = convert<IDLNullable<IDLEventListener<JSEventListener>>>(*lexicalGlobalObject, argument2.value(), *argument0, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 2, "listener", "EventEmitter", "removeListener"); });
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- auto result = JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl->addListenerForBindings(WTFMove(eventType), WTFMove(listener), false, false); }));
+ auto result = JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.addListenerForBindings(WTFMove(eventType), WTFMove(listener), false, false); }));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
vm.writeBarrier(argument0, argument2.value());
return result;
diff --git a/src/bun.js/bindings/webcore/JSEventEmitterCustom.cpp b/src/bun.js/bindings/webcore/JSEventEmitterCustom.cpp
index 64ae6e1c8..15284fe6c 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitterCustom.cpp
+++ b/src/bun.js/bindings/webcore/JSEventEmitterCustom.cpp
@@ -4,6 +4,17 @@
#include "EventEmitter.h"
#include "JSDOMWrapperCache.h"
#include "JSEventListener.h"
+#include "ZigGlobalObject.h"
+
+#include "JSDOMConstructor.h"
+#include "JSDOMConvertBase.h"
+#include "JSDOMConvertBoolean.h"
+#include "JSDOMConvertDictionary.h"
+#include "JSDOMConvertInterface.h"
+#include "JSDOMConvertNullable.h"
+#include "JSDOMConvertNumbers.h"
+#include "JSDOMConvertSequences.h"
+#include "JSDOMConvertStrings.h"
namespace WebCore {
using namespace JSC;
@@ -22,25 +33,51 @@ EventEmitter* JSEventEmitter::toWrapped(VM& vm, JSValue value)
std::unique_ptr<JSEventEmitterWrapper> jsEventEmitterCast(VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSValue thisValue)
{
- if (auto* target = jsDynamicCast<JSEventEmitter*>(thisValue))
- return makeUnique<JSEventEmitterWrapper>(target->wrapped(), *target);
- if (auto* object = jsDynamicCast<JSNonFinalObject*>(thisValue)) {
- // need to create a EventEmitter for Object.
- // use `mapPrivateName` as it is not occupied.
- auto emitterTag = WebCore::clientData(vm)->builtinNames().mapPrivateName();
- JSC::JSValue value = object->getDirect(vm, emitterTag);
- if (!value) {
- Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
- value = WebCore::toJSNewlyCreated(lexicalGlobalObject, globalObject, EventEmitter::create(*globalObject->scriptExecutionContext()));
- object->putDirect(vm, emitterTag, value);
- }
- auto* target = jsCast<JSEventEmitter*>(value);
- return makeUnique<JSEventEmitterWrapper>(target->wrapped(), *target);
+ if (auto* emitter = jsEventEmitterCastFast(vm, lexicalGlobalObject, thisValue)) {
+ return std::make_unique<JSEventEmitterWrapper>(emitter->wrapped(), asObject(thisValue));
}
return nullptr;
}
+JSEventEmitter* jsEventEmitterCastFast(VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSValue thisValue)
+{
+ if (thisValue.inherits<JSEventEmitter>())
+ return jsCast<JSEventEmitter*>(asObject(thisValue));
+
+ if (UNLIKELY(thisValue.isUndefinedOrNull() || !thisValue.isObject())) {
+ return nullptr;
+ }
+
+ auto* thisObject = asObject(thisValue);
+
+ auto clientData = WebCore::clientData(vm);
+ auto name = clientData->builtinNames()._eventsPublicName();
+ if (JSValue _events = thisObject->getIfPropertyExists(lexicalGlobalObject, name)) {
+ if (!_events.isUndefinedOrNull() && _events.inherits<JSEventEmitter>()) {
+ return jsCast<JSEventEmitter*>(asObject(_events));
+ }
+ }
+
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto impl = EventEmitter::create(*globalObject->scriptExecutionContext());
+
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto result = toJSNewlyCreated<IDLInterface<EventEmitter>>(*lexicalGlobalObject, *globalObject, throwScope, WTFMove(impl));
+
+ thisObject->putDirect(vm, name, result, 0);
+
+ if (scope.exception()) {
+ scope.clearException();
+ return nullptr;
+ }
+
+ RETURN_IF_EXCEPTION(throwScope, nullptr);
+
+ return jsCast<JSEventEmitter*>(asObject(result));
+}
+
template<typename Visitor>
void JSEventEmitter::visitAdditionalChildren(Visitor& visitor)
{
diff --git a/src/bun.js/bindings/webcore/JSEventEmitterCustom.h b/src/bun.js/bindings/webcore/JSEventEmitterCustom.h
index ed2ffed0c..b75ee5774 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitterCustom.h
+++ b/src/bun.js/bindings/webcore/JSEventEmitterCustom.h
@@ -10,7 +10,7 @@ class JSEventEmitterWrapper {
WTF_MAKE_FAST_ALLOCATED;
public:
- JSEventEmitterWrapper(EventEmitter& wrapped, JSC::JSObject& wrapper)
+ JSEventEmitterWrapper(EventEmitter& wrapped, JSC::JSObject* wrapper)
: m_wrapped(wrapped)
, m_wrapper(wrapper)
{
@@ -18,18 +18,20 @@ public:
EventEmitter& wrapped() { return m_wrapped; }
- operator JSC::JSObject&() { return m_wrapper; }
+ operator JSC::JSObject&() { return *m_wrapper; }
private:
EventEmitter& m_wrapped;
- JSC::JSObject& m_wrapper;
+ JSC::JSObject* m_wrapper;
};
std::unique_ptr<JSEventEmitterWrapper> jsEventEmitterCast(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue thisValue);
+JSEventEmitter* jsEventEmitterCastFast(VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSValue thisValue);
-template<> class IDLOperation<JSEventEmitter> {
+template<>
+class IDLOperation<JSEventEmitter> {
public:
- using ClassParameter = JSEventEmitterWrapper*;
+ using ClassParameter = JSEventEmitter*;
using Operation = JSC::EncodedJSValue(JSC::JSGlobalObject*, JSC::CallFrame*, ClassParameter);
template<Operation operation, CastedThisErrorBehavior = CastedThisErrorBehavior::Throw>
@@ -39,13 +41,11 @@ public:
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto thisValue = callFrame.thisValue().toThis(&lexicalGlobalObject, JSC::ECMAMode::strict());
- auto thisObject = jsEventEmitterCast(vm, &lexicalGlobalObject, thisValue.isUndefinedOrNull() ? JSC::JSValue(&lexicalGlobalObject) : thisValue);
+ auto* thisObject = jsEventEmitterCastFast(vm, &lexicalGlobalObject, thisValue);
if (UNLIKELY(!thisObject))
return throwThisTypeError(lexicalGlobalObject, throwScope, "EventEmitter", operationName);
- auto& wrapped = thisObject->wrapped();
-
- RELEASE_AND_RETURN(throwScope, (operation(&lexicalGlobalObject, &callFrame, thisObject.get())));
+ RELEASE_AND_RETURN(throwScope, (operation(&lexicalGlobalObject, &callFrame, thisObject)));
}
};
diff --git a/src/bun.js/builtins/BunBuiltinNames.h b/src/bun.js/builtins/BunBuiltinNames.h
index 5977f05dd..ba4e659ec 100644
--- a/src/bun.js/builtins/BunBuiltinNames.h
+++ b/src/bun.js/builtins/BunBuiltinNames.h
@@ -247,6 +247,7 @@ using namespace JSC;
macro(writer) \
macro(writing) \
macro(written) \
+ macro(_events) \
BUN_ADDITIONAL_PRIVATE_IDENTIFIERS(macro) \
class BunBuiltinNames {