mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 09:34:57 +09:00
LibWeb: Use JS::HeapFunction for WebIDL promise reaction steps
Switching away from SafeFunction immediately backfired here, as we're dealing with two layers of captures, not one. Let's do the correct fix, which is to use HeapFunction. This makes the API and its behavior explicit, and keeps captures alive as long as the HeapFunction is alive. Fixes #23819.
This commit is contained in:
parent
f1eb837c3d
commit
ffac32d20e
Notes:
sideshowbarker
2024-07-16 18:26:46 +09:00
Author: https://github.com/awesomekling
Commit: ffac32d20e
Pull-request: https://github.com/SerenityOS/serenity/pull/23815
Reviewed-by: https://github.com/ADKaster
5 changed files with 68 additions and 76 deletions
|
@ -375,7 +375,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> Blob::text()
|
|||
auto promise = TRY(reader->read_all_bytes_deprecated());
|
||||
|
||||
// 4. Return the result of transforming promise by a fulfillment handler that returns the result of running UTF-8 decode on its first argument.
|
||||
return WebIDL::upon_fulfillment(*promise, [&](auto const& first_argument) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
return WebIDL::upon_fulfillment(*promise, JS::create_heap_function(heap(), [&vm](JS::Value first_argument) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
auto const& object = first_argument.as_object();
|
||||
VERIFY(is<JS::ArrayBuffer>(object));
|
||||
auto const& buffer = static_cast<const JS::ArrayBuffer&>(object).buffer();
|
||||
|
@ -383,7 +383,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> Blob::text()
|
|||
auto decoder = TextCodec::decoder_for("UTF-8"sv);
|
||||
auto utf8_text = TRY_OR_THROW_OOM(vm, TextCodec::convert_input_to_utf8_using_given_decoder_unless_there_is_a_byte_order_mark(*decoder, buffer));
|
||||
return JS::PrimitiveString::create(vm, move(utf8_text));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// https://w3c.github.io/FileAPI/#dom-blob-arraybuffer
|
||||
|
@ -404,13 +404,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> Blob::array_buffer()
|
|||
auto promise = TRY(reader->read_all_bytes_deprecated());
|
||||
|
||||
// 4. Return the result of transforming promise by a fulfillment handler that returns a new ArrayBuffer whose contents are its first argument.
|
||||
return WebIDL::upon_fulfillment(*promise, [&](auto const& first_argument) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
return WebIDL::upon_fulfillment(*promise, JS::create_heap_function(heap(), [&realm](JS::Value first_argument) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
auto const& object = first_argument.as_object();
|
||||
VERIFY(is<JS::ArrayBuffer>(object));
|
||||
auto const& buffer = static_cast<const JS::ArrayBuffer&>(object).buffer();
|
||||
|
||||
return JS::ArrayBuffer::create(realm, buffer);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -828,7 +828,7 @@ void fetch_descendants_of_and_link_a_module_script(JS::Realm& realm,
|
|||
auto& loading_promise = record->load_requested_modules(state);
|
||||
|
||||
// 6. Upon fulfillment of loadingPromise, run the following steps:
|
||||
WebIDL::upon_fulfillment(loading_promise, [&realm, record, &module_script, on_complete](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(loading_promise, JS::create_heap_function(realm.heap(), [&realm, record, &module_script, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform record.Link().
|
||||
auto linking_result = record->link(realm.vm());
|
||||
|
||||
|
@ -840,10 +840,10 @@ void fetch_descendants_of_and_link_a_module_script(JS::Realm& realm,
|
|||
on_complete->function()(module_script);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 7. Upon rejection of loadingPromise, run the following steps:
|
||||
WebIDL::upon_rejection(loading_promise, [state, &module_script, on_complete](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(loading_promise, JS::create_heap_function(realm.heap(), [state, &module_script, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. If state.[[ParseError]] is not null, set moduleScript's error to rethrow to state.[[ParseError]] and run
|
||||
// onComplete given moduleScript.
|
||||
if (!state->parse_error.is_null()) {
|
||||
|
@ -857,7 +857,7 @@ void fetch_descendants_of_and_link_a_module_script(JS::Realm& realm,
|
|||
}
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
fetch_client.clean_up_after_running_callback();
|
||||
realm.vm().pop_execution_context();
|
||||
|
|
|
@ -127,7 +127,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> readable_stream_cancel(Re
|
|||
|
||||
// 8. Return the result of reacting to sourceCancelPromise with a fulfillment step that returns undefined.
|
||||
auto react_result = WebIDL::react_to_promise(*source_cancel_promise,
|
||||
[](auto const&) -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); },
|
||||
JS::create_heap_function(stream.heap(), [](JS::Value) -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); }),
|
||||
{});
|
||||
|
||||
return WebIDL::create_resolved_promise(realm, react_result);
|
||||
|
@ -535,7 +535,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_stream_default_tee(JS::Realm& r
|
|||
params->branch2 = MUST(create_readable_stream(realm, start_algorithm, pull_algorithm, cancel2_algorithm));
|
||||
|
||||
// 19. Upon rejection of reader.[[closedPromise]] with reason r,
|
||||
WebIDL::upon_rejection(*reader->closed_promise_capability(), [&realm, params, cancel_promise](auto reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*reader->closed_promise_capability(), JS::create_heap_function(realm.heap(), [&realm, params, cancel_promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
auto controller1 = params->branch1->controller()->get<JS::NonnullGCPtr<ReadableStreamDefaultController>>();
|
||||
auto controller2 = params->branch2->controller()->get<JS::NonnullGCPtr<ReadableStreamDefaultController>>();
|
||||
|
||||
|
@ -551,7 +551,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_stream_default_tee(JS::Realm& r
|
|||
}
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 20. Return « branch1, branch2 ».
|
||||
return ReadableStreamPair { *params->branch1, *params->branch2 };
|
||||
|
@ -964,7 +964,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_byte_stream_tee(JS::Realm& real
|
|||
// 1. Upon rejection of thisReader.[[closedPromise]] with reason r,
|
||||
auto closed_promise = this_reader.visit([](auto const& underlying_reader) { return underlying_reader->closed_promise_capability(); });
|
||||
|
||||
WebIDL::upon_rejection(*closed_promise, [&realm, this_reader, params, cancel_promise](auto reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*closed_promise, JS::create_heap_function(realm.heap(), [&realm, this_reader, params, cancel_promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
auto controller1 = params->branch1->controller()->get<JS::NonnullGCPtr<ReadableByteStreamController>>();
|
||||
auto controller2 = params->branch2->controller()->get<JS::NonnullGCPtr<ReadableByteStreamController>>();
|
||||
|
||||
|
@ -985,7 +985,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_byte_stream_tee(JS::Realm& real
|
|||
}
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
// 15. Let pullWithDefaultReader be the following steps:
|
||||
|
@ -1938,7 +1938,7 @@ WebIDL::ExceptionOr<void> readable_stream_default_controller_can_pull_if_needed(
|
|||
auto pull_promise = TRY(controller.pull_algorithm()->function()());
|
||||
|
||||
// 7. Upon fulfillment of pullPromise,
|
||||
WebIDL::upon_fulfillment(*pull_promise, [&](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(*pull_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Set controller.[[pulling]] to false.
|
||||
controller.set_pulling(false);
|
||||
|
||||
|
@ -1952,15 +1952,15 @@ WebIDL::ExceptionOr<void> readable_stream_default_controller_can_pull_if_needed(
|
|||
}
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 8. Upon rejection of pullPromise with reason e,
|
||||
WebIDL::upon_rejection(*pull_promise, [&](auto const& e) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*pull_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value e) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! ReadableStreamDefaultControllerError(controller, e).
|
||||
readable_stream_default_controller_error(controller, e);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -2345,7 +2345,7 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller(ReadableStre
|
|||
auto start_promise = WebIDL::create_resolved_promise(realm, start_result);
|
||||
|
||||
// 11. Upon fulfillment of startPromise,
|
||||
WebIDL::upon_fulfillment(start_promise, [&](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(start_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Set controller.[[started]] to true.
|
||||
controller.set_started(true);
|
||||
|
||||
|
@ -2359,15 +2359,15 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller(ReadableStre
|
|||
TRY(readable_stream_default_controller_can_pull_if_needed(controller));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 12. Upon rejection of startPromise with reason r,
|
||||
WebIDL::upon_rejection(start_promise, [&](auto const& r) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(start_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value r) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! ReadableStreamDefaultControllerError(controller, r).
|
||||
readable_stream_default_controller_error(controller, r);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -2454,7 +2454,7 @@ WebIDL::ExceptionOr<void> readable_byte_stream_controller_call_pull_if_needed(Re
|
|||
auto pull_promise = TRY(controller.pull_algorithm()->function()());
|
||||
|
||||
// 7. Upon fulfillment of pullPromise,
|
||||
WebIDL::upon_fulfillment(*pull_promise, [&](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(*pull_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Set controller.[[pulling]] to false.
|
||||
controller.set_pulling(false);
|
||||
|
||||
|
@ -2468,15 +2468,15 @@ WebIDL::ExceptionOr<void> readable_byte_stream_controller_call_pull_if_needed(Re
|
|||
}
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 8. Upon rejection of pullPromise with reason e,
|
||||
WebIDL::upon_rejection(*pull_promise, [&](auto const& error) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*pull_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value error) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! ReadableByteStreamControllerError(controller, e).
|
||||
readable_byte_stream_controller_error(controller, error);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -2967,7 +2967,7 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller(ReadableStream&
|
|||
auto start_promise = WebIDL::create_resolved_promise(realm, start_result);
|
||||
|
||||
// 16. Upon fulfillment of startPromise,
|
||||
WebIDL::upon_fulfillment(start_promise, [&](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(start_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Set controller.[[started]] to true.
|
||||
controller.set_started(true);
|
||||
|
||||
|
@ -2981,15 +2981,15 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller(ReadableStream&
|
|||
TRY(readable_byte_stream_controller_call_pull_if_needed(controller));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 17. Upon rejection of startPromise with reason r,
|
||||
WebIDL::upon_rejection(start_promise, [&](auto const& r) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(start_promise, JS::create_heap_function(controller.heap(), [&controller](JS::Value r) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! ReadableByteStreamControllerError(controller, r).
|
||||
readable_byte_stream_controller_error(controller, r);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -3577,7 +3577,7 @@ WebIDL::ExceptionOr<void> writable_stream_finish_erroring(WritableStream& stream
|
|||
auto promise = TRY(stream.controller()->abort_steps(abort_request.reason));
|
||||
|
||||
// 13. Upon fulfillment of promise,
|
||||
WebIDL::upon_fulfillment(*promise, [&, abort_promise = abort_request.promise](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(*promise, JS::create_heap_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Resolve abortRequest’s promise with undefined.
|
||||
WebIDL::resolve_promise(realm, abort_promise, JS::js_undefined());
|
||||
|
||||
|
@ -3585,10 +3585,10 @@ WebIDL::ExceptionOr<void> writable_stream_finish_erroring(WritableStream& stream
|
|||
writable_stream_reject_close_and_closed_promise_if_needed(stream);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 14. Upon rejection of promise with reason reason,
|
||||
WebIDL::upon_rejection(*promise, [&, abort_promise = abort_request.promise](auto const& reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*promise, JS::create_heap_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Reject abortRequest’s promise with reason.
|
||||
WebIDL::reject_promise(realm, abort_promise, reason);
|
||||
|
||||
|
@ -3596,7 +3596,7 @@ WebIDL::ExceptionOr<void> writable_stream_finish_erroring(WritableStream& stream
|
|||
writable_stream_reject_close_and_closed_promise_if_needed(stream);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -4085,7 +4085,7 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller(WritableStre
|
|||
auto start_promise = WebIDL::create_resolved_promise(realm, start_result);
|
||||
|
||||
// 17. Upon fulfillment of startPromise,
|
||||
WebIDL::upon_fulfillment(*start_promise, [&](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(*start_promise, JS::create_heap_function(realm.heap(), [&controller, &stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Assert: stream.[[state]] is "writable" or "erroring".
|
||||
auto state = stream.state();
|
||||
VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring);
|
||||
|
@ -4097,10 +4097,10 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller(WritableStre
|
|||
TRY(writable_stream_default_controller_advance_queue_if_needed(controller));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 18. Upon rejection of startPromise with reason r,
|
||||
WebIDL::upon_rejection(*start_promise, [&](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*start_promise, JS::create_heap_function(realm.heap(), [&stream, &controller](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Assert: stream.[[state]] is "writable" or "erroring".
|
||||
auto state = stream.state();
|
||||
VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring);
|
||||
|
@ -4112,7 +4112,7 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller(WritableStre
|
|||
TRY(writable_stream_deal_with_rejection(stream, reason));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -4342,20 +4342,20 @@ WebIDL::ExceptionOr<void> writable_stream_default_controller_process_close(Writa
|
|||
writable_stream_default_controller_clear_algorithms(controller);
|
||||
|
||||
// 7. Upon fulfillment of sinkClosePromise,
|
||||
WebIDL::upon_fulfillment(*sink_close_promise, [&, stream = stream](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(*sink_close_promise, JS::create_heap_function(controller.heap(), [stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! WritableStreamFinishInFlightClose(stream).
|
||||
writable_stream_finish_in_flight_close(*stream);
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 8. Upon rejection of sinkClosePromise with reason reason,
|
||||
WebIDL::upon_rejection(*sink_close_promise, [&, stream = stream](auto const& reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*sink_close_promise, JS::create_heap_function(controller.heap(), [stream = stream](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! WritableStreamFinishInFlightCloseWithError(stream, reason).
|
||||
TRY(writable_stream_finish_in_flight_close_with_error(*stream, reason));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -4373,7 +4373,7 @@ WebIDL::ExceptionOr<void> writable_stream_default_controller_process_write(Writa
|
|||
auto sink_write_promise = TRY(controller.write_algorithm()->function()(chunk));
|
||||
|
||||
// 4. Upon fulfillment of sinkWritePromise,
|
||||
WebIDL::upon_fulfillment(*sink_write_promise, [&, stream = stream](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_fulfillment(*sink_write_promise, JS::create_heap_function(controller.heap(), [&controller, stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! WritableStreamFinishInFlightWrite(stream).
|
||||
writable_stream_finish_in_flight_write(*stream);
|
||||
|
||||
|
@ -4399,10 +4399,10 @@ WebIDL::ExceptionOr<void> writable_stream_default_controller_process_write(Writa
|
|||
TRY(writable_stream_default_controller_advance_queue_if_needed(controller));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
// 5. Upon rejection of sinkWritePromise with reason,
|
||||
WebIDL::upon_rejection(*sink_write_promise, [&, stream = stream](auto const& reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
WebIDL::upon_rejection(*sink_write_promise, JS::create_heap_function(controller.heap(), [&controller, stream](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. If stream.[[state]] is "writable", perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
|
||||
if (stream->state() == WritableStream::State::Writable)
|
||||
writable_stream_default_controller_clear_algorithms(controller);
|
||||
|
@ -4411,7 +4411,7 @@ WebIDL::ExceptionOr<void> writable_stream_default_controller_process_write(Writa
|
|||
TRY(writable_stream_finish_in_flight_write_with_error(*stream, reason));
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -4700,13 +4700,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> transform_stream_default_
|
|||
// 2. Return the result of reacting to transformPromise with the following rejection steps given the argument r:
|
||||
auto react_result = WebIDL::react_to_promise(*transform_promise,
|
||||
{},
|
||||
[&](auto const& reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
JS::create_heap_function(realm.heap(), [&controller](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! TransformStreamError(controller.[[stream]], r).
|
||||
TRY(transform_stream_error(*controller.stream(), reason));
|
||||
|
||||
// 2. Throw r.
|
||||
return JS::throw_completion(reason);
|
||||
});
|
||||
}));
|
||||
|
||||
return WebIDL::create_resolved_promise(realm, react_result);
|
||||
}
|
||||
|
@ -4744,7 +4744,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> transform_stream_default_
|
|||
auto react_result = WebIDL::react_to_promise(
|
||||
*flush_promise,
|
||||
// 1. If flushPromise was fulfilled, then:
|
||||
[readable](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
JS::create_heap_function(realm.heap(), [readable](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. If readable.[[state]] is "errored", throw readable.[[storedError]].
|
||||
if (readable->state() == ReadableStream::State::Errored)
|
||||
return JS::throw_completion(readable->stored_error());
|
||||
|
@ -4754,15 +4754,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> transform_stream_default_
|
|||
readable_stream_default_controller_close(readable->controller().value().get<JS::NonnullGCPtr<ReadableStreamDefaultController>>());
|
||||
|
||||
return JS::js_undefined();
|
||||
},
|
||||
}),
|
||||
// 2. If flushPromise was rejected with reason r, then:
|
||||
[&stream, readable](auto const& reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
JS::create_heap_function(realm.heap(), [&stream, readable](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Perform ! TransformStreamError(stream, r).
|
||||
TRY(transform_stream_error(stream, reason));
|
||||
|
||||
// 2. Throw readable.[[storedError]].
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, readable->stored_error().as_string().utf8_string() };
|
||||
});
|
||||
}));
|
||||
|
||||
return WebIDL::create_resolved_promise(realm, react_result);
|
||||
}
|
||||
|
@ -4788,7 +4788,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> transform_stream_default_
|
|||
|
||||
// 3. Return the result of reacting to backpressureChangePromise with the following fulfillment steps:
|
||||
auto react_result = WebIDL::react_to_promise(*backpressure_change_promise,
|
||||
[&stream, controller, chunk](auto const&) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
JS::create_heap_function(realm.heap(), [&stream, controller, chunk](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
|
||||
// 1. Let writable be stream.[[writable]].
|
||||
auto writable = stream.writable();
|
||||
|
||||
|
@ -4804,7 +4804,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> transform_stream_default_
|
|||
|
||||
// 5. Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
|
||||
return TRY(transform_stream_default_controller_perform_transform(*controller, chunk))->promise();
|
||||
},
|
||||
}),
|
||||
{});
|
||||
|
||||
return WebIDL::create_resolved_promise(realm, react_result);
|
||||
|
|
|
@ -93,7 +93,7 @@ void reject_promise(JS::Realm& realm, Promise const& promise, JS::Value reason)
|
|||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled
|
||||
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, Optional<ReactionSteps> on_fulfilled_callback, Optional<ReactionSteps> on_rejected_callback)
|
||||
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback)
|
||||
{
|
||||
auto& realm = promise.promise()->shape().realm();
|
||||
auto& vm = realm.vm();
|
||||
|
@ -104,8 +104,8 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, Optional<
|
|||
auto value = vm.argument(0);
|
||||
|
||||
// 2. If there is a set of steps to be run if the promise was fulfilled, then let result be the result of performing them, given value if T is not undefined. Otherwise, let result be value.
|
||||
auto result = on_fulfilled_callback.has_value()
|
||||
? TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return (*on_fulfilled_callback)(value); }))
|
||||
auto result = on_fulfilled_callback
|
||||
? TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return on_fulfilled_callback->function()(value); }))
|
||||
: value;
|
||||
|
||||
// 3. Return result, converted to an ECMAScript value.
|
||||
|
@ -121,8 +121,8 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, Optional<
|
|||
auto reason = vm.argument(0);
|
||||
|
||||
// 2. If there is a set of steps to be run if the promise was rejected, then let result be the result of performing them, given reason. Otherwise, let result be a promise rejected with reason.
|
||||
auto result = on_rejected_callback.has_value()
|
||||
? TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return (*on_rejected_callback)(reason); }))
|
||||
auto result = on_rejected_callback
|
||||
? TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return on_rejected_callback->function()(reason); }))
|
||||
: WebIDL::create_rejected_promise(realm, reason)->promise();
|
||||
|
||||
// 3. Return result, converted to an ECMAScript value.
|
||||
|
@ -146,32 +146,24 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, Optional<
|
|||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#upon-fulfillment
|
||||
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const& promise, ReactionSteps steps)
|
||||
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
|
||||
{
|
||||
// 1. Return the result of reacting to promise:
|
||||
return react_to_promise(promise,
|
||||
// - If promise was fulfilled with value v, then:
|
||||
[steps = move(steps)](auto value) {
|
||||
// 1. Perform steps with v.
|
||||
// NOTE: The `return` is not immediately obvious, but `steps` may be something like
|
||||
// "Return the result of ...", which we also need to do _here_.
|
||||
return steps(value);
|
||||
},
|
||||
// 1. Perform steps with v.
|
||||
steps,
|
||||
{});
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#upon-rejection
|
||||
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const& promise, ReactionSteps steps)
|
||||
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
|
||||
{
|
||||
// 1. Return the result of reacting to promise:
|
||||
return react_to_promise(promise, {},
|
||||
// - If promise was rejected with reason r, then:
|
||||
[steps = move(steps)](auto reason) {
|
||||
// 1. Perform steps with r.
|
||||
// NOTE: The `return` is not immediately obvious, but `steps` may be something like
|
||||
// "Return the result of ...", which we also need to do _here_.
|
||||
return steps(reason);
|
||||
});
|
||||
// 1. Perform steps with r.
|
||||
steps);
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#mark-a-promise-as-handled
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
namespace Web::WebIDL {
|
||||
|
||||
// NOTE: This is Function, not SafeFunction, because they get stored in a NativeFunction anyway, which will protect captures.
|
||||
using ReactionSteps = Function<WebIDL::ExceptionOr<JS::Value>(JS::Value)>;
|
||||
using ReactionSteps = JS::HeapFunction<WebIDL::ExceptionOr<JS::Value>(JS::Value)>;
|
||||
|
||||
// https://webidl.spec.whatwg.org/#es-promise
|
||||
using Promise = JS::PromiseCapability;
|
||||
|
@ -27,9 +27,9 @@ JS::NonnullGCPtr<Promise> create_resolved_promise(JS::Realm&, JS::Value);
|
|||
JS::NonnullGCPtr<Promise> create_rejected_promise(JS::Realm&, JS::Value);
|
||||
void resolve_promise(JS::Realm&, Promise const&, JS::Value = JS::js_undefined());
|
||||
void reject_promise(JS::Realm&, Promise const&, JS::Value);
|
||||
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const&, Optional<ReactionSteps> on_fulfilled_callback, Optional<ReactionSteps> on_rejected_callback);
|
||||
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const&, ReactionSteps);
|
||||
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const&, ReactionSteps);
|
||||
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const&, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback);
|
||||
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
|
||||
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
|
||||
void mark_promise_as_handled(Promise const&);
|
||||
void wait_for_all(JS::Realm&, Vector<JS::NonnullGCPtr<Promise>> const& promises, Function<void(Vector<JS::Value> const&)> success_steps, Function<void(JS::Value)> failure_steps);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue