Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions builtins/web/abort/abort-signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "../event/event.h"
#include "../timers.h"

#include "js/ForOfIterator.h"


namespace builtins::web::abort {
Expand Down Expand Up @@ -102,9 +103,6 @@ bool AbortSignal::timeout(JSContext *cx, unsigned argc, JS::Value *vp) {
// https://dom.spec.whatwg.org/#dom-abortsignal-abort
bool AbortSignal::abort(JSContext *cx, unsigned argc, JS::Value *vp) {
CallArgs args = JS::CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, "abort", 1)) {
return false;
}

// The abort() method steps are inlined in the AbortSignal::create_with_reason method.
RootedObject self(cx, create_with_reason(cx, args.get(0)));
Expand All @@ -123,8 +121,35 @@ bool AbortSignal::any(JSContext *cx, unsigned argc, JS::Value *vp) {
return false;
}

// The any() method steps are inlined in the AbortSignal::create_with_signals method.
RootedObject self(cx, create_with_signals(cx, args));
RootedValue iterable(cx, args.get(0));
JS::ForOfIterator it(cx);
if (!it.init(iterable)) {
return false;
}

JS::RootedValueVector signals(cx);
RootedValue signal(cx);
while (true) {
bool done = false;
if (!it.next(&signal, &done)) {
return false;
}

if (done) {
break;
}

if (!is_instance(signal)) {
return api::throw_error(cx, api::Errors::TypeError, "AbortSignal.any", "signals",
"contain only AbortSignal objects");
}

if (!signals.append(signal)) {
return false;
}
}

RootedObject self(cx, create_with_signals(cx, signals));
if (!self) {
return false;
}
Expand All @@ -142,6 +167,7 @@ bool AbortSignal::throwIfAborted(JSContext *cx, unsigned argc, JS::Value *vp) {
if (is_aborted(self)) {
RootedValue reason(cx, JS::GetReservedSlot(self, std::to_underlying(Slots::Reason)));
JS_SetPendingException(cx, reason);
return false;
}

return true;
Expand Down Expand Up @@ -222,7 +248,10 @@ bool AbortSignal::abort(JSContext *cx, HandleObject self, HandleValue reason) {

// 2. Set signal's abort reason to reason if it is given;
// otherwise to a new "AbortError" DOMException.
set_reason(cx, self, reason);
if (!set_reason(cx, self, reason)) {
return false;
}
RootedValue abort_reason(cx, AbortSignal::reason(self));

// 3. Let dependentSignalsToAbort be a new list.
JS::RootedObjectVector dep_signals_to_abort(cx);
Expand All @@ -234,7 +263,9 @@ bool AbortSignal::abort(JSContext *cx, HandleObject self, HandleValue reason) {
// 1. If dependentSignal is not aborted:
if (!is_aborted(signal)) {
// 1. Set dependentSignal's abort reason to signal's abort reason.
set_reason(cx, signal, reason);
if (!set_reason(cx, signal, abort_reason)) {
return false;
}
// 2. Append dependentSignal to dependentSignalsToAbort.
if (!dep_signals_to_abort.append(signal)) {
return false;
Expand Down Expand Up @@ -276,7 +307,7 @@ bool AbortSignal::run_abort_steps(JSContext *cx, HandleObject self) {
RootedObject event(cx, Event::create(cx, type_val, JS::NullHandleValue));
RootedValue event_val(cx, JS::ObjectValue(*event));

return EventTarget::dispatch_event(cx, self, event_val, &res_val);
return EventTarget::dispatch_event(cx, self, event_val, &res_val, true);
}

// Set signal's abort reason to reason if it is given; otherwise to a new "AbortError" DOMException.
Expand Down Expand Up @@ -408,7 +439,9 @@ JSObject *AbortSignal::create_with_signals(JSContext *cx, HandleValueArray signa
// 2. For each signal of signals: if signal is aborted, then set resultSignal's abort reason to
// signal's abort reason and return resultSignal.
for (size_t i = 0; i < signals.length(); ++i) {
RootedObject signal(cx, &signals[i].toObject());
RootedValue signal_val(cx, signals[i]);
MOZ_ASSERT(is_instance(signal_val));
RootedObject signal(cx, &signal_val.toObject());

if (is_aborted(signal)) {
SetReservedSlot(self, std::to_underlying(Slots::Reason), reason(signal));
Expand All @@ -422,7 +455,8 @@ JSObject *AbortSignal::create_with_signals(JSContext *cx, HandleValueArray signa

// 4. For each signal of signals:
for (size_t i = 0; i < signals.length(); ++i) {
RootedObject signal(cx, &signals[i].toObject());
RootedValue signal_val(cx, signals[i]);
RootedObject signal(cx, &signal_val.toObject());

// 1. If signal's dependent is false:
if (!is_dependent(signal)) {
Expand Down Expand Up @@ -514,5 +548,3 @@ bool install(api::Engine *engine) {
JSString *AbortSignal::abort_type_atom = nullptr;

} // namespace builtins::web::abort


7 changes: 3 additions & 4 deletions builtins/web/event/event-target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ bool EventTarget::remove_listener(JSContext *cx, HandleObject self, HandleValue

// https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
bool EventTarget::dispatch_event(JSContext *cx, HandleObject self, HandleValue event_val,
MutableHandleValue rval) {
MutableHandleValue rval, bool trusted) {
MOZ_ASSERT(is_instance(self));

if (!Event::is_instance(event_val)) {
Expand All @@ -379,8 +379,8 @@ bool EventTarget::dispatch_event(JSContext *cx, HandleObject self, HandleValue e
"InvalidStateError");
}

// 2. Initialize event's isTrusted attribute to false.
Event::set_flag(event, EventFlag::Trusted, false);
// 2. Initialize event's isTrusted attribute.
Event::set_flag(event, EventFlag::Trusted, trusted);

// 3. Return the result of dispatching event to this.
return dispatch(cx, self, event, nullptr, rval);
Expand Down Expand Up @@ -651,4 +651,3 @@ bool EventTarget::init_class(JSContext *cx, JS::HandleObject global) {

} // namespace builtins::web::event


2 changes: 1 addition & 1 deletion builtins/web/event/event-target.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class EventTarget : public BuiltinImpl<EventTarget, TraceableClassPolicy> {
static bool remove_listener(JSContext *cx, HandleObject self, HandleValue type,
HandleValue callback, HandleValue opts);
static bool dispatch_event(JSContext *cx, HandleObject self, HandleValue event,
MutableHandleValue rval);
MutableHandleValue rval, bool trusted = false);

static JSObject *create(JSContext *cx);

Expand Down
17 changes: 17 additions & 0 deletions tests/wpt-harness/expectations/dom/abort/AbortSignal.any.js.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"the AbortSignal.abort() static returns an already aborted signal": {
"status": "PASS"
},
"signal returned by AbortSignal.abort() should not fire abort event": {
"status": "PASS"
},
"AbortSignal.timeout() returns a non-aborted signal": {
"status": "PASS"
},
"Signal returned by AbortSignal.timeout() times out": {
"status": "PASS"
},
"AbortSignal timeouts fire in order": {
"status": "PASS"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"AbortSignal.any() works with an empty array of signals": {
"status": "PASS"
},
"AbortSignal.any() follows a single signal (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() follows multiple signals (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() returns an aborted signal if passed an aborted signal (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() can be passed the same signal more than once (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() uses the first instance of a duplicate signal (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() signals are composable (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() works with signals returned by AbortSignal.timeout() (using AbortController)": {
"status": "PASS"
},
"AbortSignal.any() works with intermediate signals (using AbortController)": {
"status": "PASS"
},
"Abort events for AbortSignal.any() signals fire in the right order (using AbortController)": {
"status": "PASS"
},
"Dependent signals for AbortSignal.any() are marked aborted before abort events fire (using AbortController)": {
"status": "PASS"
},
"Dependent signals for AbortSignal.any() are aborted correctly for reentrant aborts (using AbortController)": {
"status": "PASS"
},
"Dependent signals for AbortSignal.any() should use the same DOMException instance from the already aborted source signal (using AbortController)": {
"status": "PASS"
},
"Dependent signals for AbortSignal.any() should use the same DOMException instance from the source signal being aborted later (using AbortController)": {
"status": "PASS"
}
}
50 changes: 50 additions & 0 deletions tests/wpt-harness/expectations/dom/abort/event.any.js.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"AbortController abort() should fire event synchronously": {
"status": "PASS"
},
"controller.signal should always return the same object": {
"status": "PASS"
},
"controller.abort() should do nothing the second time it is called": {
"status": "PASS"
},
"event handler should not be called if added after controller.abort()": {
"status": "PASS"
},
"the abort event should have the right properties": {
"status": "PASS"
},
"AbortController abort(reason) should set signal.reason": {
"status": "PASS"
},
"aborting AbortController without reason creates an \"AbortError\" DOMException": {
"status": "PASS"
},
"AbortController abort(undefined) creates an \"AbortError\" DOMException": {
"status": "PASS"
},
"AbortController abort(null) should set signal.reason": {
"status": "PASS"
},
"static aborting signal should have right properties": {
"status": "PASS"
},
"static aborting signal with reason should set signal.reason": {
"status": "PASS"
},
"throwIfAborted() should throw abort.reason if signal aborted": {
"status": "PASS"
},
"throwIfAborted() should throw primitive abort.reason if signal aborted": {
"status": "PASS"
},
"throwIfAborted() should not throw if signal not aborted": {
"status": "PASS"
},
"AbortSignal.reason returns the same DOMException": {
"status": "PASS"
},
"AbortController.signal.reason returns the same DOMException": {
"status": "PASS"
}
}
3 changes: 3 additions & 0 deletions tests/wpt-harness/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
"console/console-namespace-object-class-string.any.js",
"console/console-tests-historical.any.js",
"console/idlharness.any.js",
"dom/abort/AbortSignal.any.js",
"dom/abort/abort-signal-any.any.js",
"dom/abort/event.any.js",
"dom/events/AddEventListenerOptions-once.any.js",
"dom/events/AddEventListenerOptions-passive.any.js",
"dom/events/Event-constructors.any.js",
Expand Down
Loading