LibWeb: Prefer react_to_promise over upon_fulfillment + upon_rejection

While debugging a spec-compliant implementation of ReadableStreamPipeTo,
I spent a lot of time inspecting promise internals. This is much less
noisy if we halve the number of temporary promises.
This commit is contained in:
Timothy Flynn 2025-04-09 17:50:24 -04:00 committed by Tim Flynn
commit e9a7694cdb
Notes: github-actions[bot] 2025-04-11 16:12:13 +00:00
2 changed files with 190 additions and 181 deletions

View file

@ -836,8 +836,9 @@ void fetch_descendants_of_and_link_a_module_script(JS::Realm& realm,
// 5. Let loadingPromise be record.LoadRequestedModules(state).
auto& loading_promise = record->load_requested_modules(state);
WebIDL::react_to_promise(loading_promise,
// 6. Upon fulfillment of loadingPromise, run the following steps:
WebIDL::upon_fulfillment(loading_promise, GC::create_function(realm.heap(), [&realm, record, &module_script, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_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());
@ -849,10 +850,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, GC::create_function(realm.heap(), [state, &module_script, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_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()) {

View file

@ -2199,8 +2199,9 @@ void readable_stream_default_controller_can_pull_if_needed(ReadableStreamDefault
// 6. Let pullPromise be the result of performing controller.[[pullAlgorithm]].
auto pull_promise = controller.pull_algorithm()->function()();
WebIDL::react_to_promise(pull_promise,
// 7. Upon fulfillment of pullPromise,
WebIDL::upon_fulfillment(*pull_promise, GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Set controller.[[pulling]] to false.
controller.set_pulling(false);
@ -2214,10 +2215,10 @@ void readable_stream_default_controller_can_pull_if_needed(ReadableStreamDefault
}
return JS::js_undefined();
}));
}),
// 8. Upon rejection of pullPromise with reason e,
WebIDL::upon_rejection(*pull_promise, GC::create_function(controller.heap(), [&controller](JS::Value e) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value e) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Perform ! ReadableStreamDefaultControllerError(controller, e).
readable_stream_default_controller_error(controller, e);
@ -2626,8 +2627,9 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller(ReadableStre
// 10. Let startPromise be a promise resolved with startResult.
auto start_promise = WebIDL::create_resolved_promise(realm, start_result);
WebIDL::react_to_promise(start_promise,
// 11. Upon fulfillment of startPromise,
WebIDL::upon_fulfillment(start_promise, GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Set controller.[[started]] to true.
controller.set_started(true);
@ -2641,10 +2643,10 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller(ReadableStre
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, GC::create_function(controller.heap(), [&controller](JS::Value r) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value r) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Perform ! ReadableStreamDefaultControllerError(controller, r).
readable_stream_default_controller_error(controller, r);
@ -2735,8 +2737,9 @@ void readable_byte_stream_controller_call_pull_if_needed(ReadableByteStreamContr
// 6. Let pullPromise be the result of performing controller.[[pullAlgorithm]].
auto pull_promise = controller.pull_algorithm()->function()();
WebIDL::react_to_promise(pull_promise,
// 7. Upon fulfillment of pullPromise,
WebIDL::upon_fulfillment(*pull_promise, GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Set controller.[[pulling]] to false.
controller.set_pulling(false);
@ -2750,10 +2753,10 @@ void readable_byte_stream_controller_call_pull_if_needed(ReadableByteStreamContr
}
return JS::js_undefined();
}));
}),
// 8. Upon rejection of pullPromise with reason e,
WebIDL::upon_rejection(*pull_promise, GC::create_function(controller.heap(), [&controller](JS::Value error) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value error) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Perform ! ReadableByteStreamControllerError(controller, e).
readable_byte_stream_controller_error(controller, error);
@ -3242,8 +3245,9 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller(ReadableStream&
// 15. Let startPromise be a promise resolved with startResult.
auto start_promise = WebIDL::create_resolved_promise(realm, start_result);
WebIDL::react_to_promise(start_promise,
// 16. Upon fulfillment of startPromise,
WebIDL::upon_fulfillment(start_promise, GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Set controller.[[started]] to true.
controller.set_started(true);
@ -3257,10 +3261,10 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller(ReadableStream&
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, GC::create_function(controller.heap(), [&controller](JS::Value r) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller](JS::Value r) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Perform ! ReadableByteStreamControllerError(controller, r).
readable_byte_stream_controller_error(controller, r);
@ -3782,8 +3786,9 @@ void writable_stream_finish_erroring(WritableStream& stream)
// 12. Let promise be ! stream.[[controller]].[[AbortSteps]](abortRequests reason).
auto promise = stream.controller()->abort_steps(abort_request.reason);
WebIDL::react_to_promise(promise,
// 13. Upon fulfillment of promise,
WebIDL::upon_fulfillment(*promise, GC::create_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Resolve abortRequests promise with undefined.
WebIDL::resolve_promise(realm, abort_promise, JS::js_undefined());
@ -3791,10 +3796,10 @@ 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, GC::create_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(realm.heap(), [&realm, &stream, abort_promise = abort_request.promise](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Reject abortRequests promise with reason.
WebIDL::reject_promise(realm, abort_promise, reason);
@ -4313,8 +4318,9 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller(WritableStre
// 16. Let startPromise be a promise resolved with startResult.
auto start_promise = WebIDL::create_resolved_promise(realm, start_result);
WebIDL::react_to_promise(start_promise,
// 17. Upon fulfillment of startPromise,
WebIDL::upon_fulfillment(*start_promise, GC::create_function(realm.heap(), [&controller, &stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_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);
@ -4326,10 +4332,10 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller(WritableStre
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, GC::create_function(realm.heap(), [&stream, &controller](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_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);
@ -4575,16 +4581,17 @@ void writable_stream_default_controller_process_close(WritableStreamDefaultContr
// 6. Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
writable_stream_default_controller_clear_algorithms(controller);
WebIDL::react_to_promise(sink_close_promise,
// 7. Upon fulfillment of sinkClosePromise,
WebIDL::upon_fulfillment(*sink_close_promise, GC::create_function(controller.heap(), [stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_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, GC::create_function(controller.heap(), [stream = stream](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [stream = stream](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Perform ! WritableStreamFinishInFlightCloseWithError(stream, reason).
writable_stream_finish_in_flight_close_with_error(*stream, reason);
@ -4604,8 +4611,9 @@ void writable_stream_default_controller_process_write(WritableStreamDefaultContr
// 3. Let sinkWritePromise be the result of performing controller.[[writeAlgorithm]], passing in chunk.
auto sink_write_promise = controller.write_algorithm()->function()(chunk);
WebIDL::react_to_promise(sink_write_promise,
// 4. Upon fulfillment of sinkWritePromise,
WebIDL::upon_fulfillment(*sink_write_promise, GC::create_function(controller.heap(), [&controller, stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_function(controller.heap(), [&controller, stream](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Perform ! WritableStreamFinishInFlightWrite(stream).
writable_stream_finish_in_flight_write(*stream);
@ -4631,10 +4639,10 @@ void writable_stream_default_controller_process_write(WritableStreamDefaultContr
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, GC::create_function(controller.heap(), [&controller, stream](JS::Value reason) -> WebIDL::ExceptionOr<JS::Value> {
GC::create_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);