mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 21:29:06 +00:00
LibWeb: Do not create a RootVector to invoke IDL callbacks
These callbacks are evaluated synchronously via JS::Call. We do not need to construct an expensive RootVector container just to immediately invoke the callbacks. Stylistically, this also helps indicate where the actual arguments start at the call sites, by wrapping the arguments in braces.
This commit is contained in:
parent
ca2f0141f6
commit
6dd2a4c945
Notes:
github-actions[bot]
2025-04-16 11:32:56 +00:00
Author: https://github.com/trflynn89
Commit: 6dd2a4c945
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4376
20 changed files with 60 additions and 119 deletions
|
@ -713,7 +713,7 @@ void queue_mutation_observer_microtask(DOM::Document const& document)
|
|||
MUST(wrapped_records->create_data_property(property_index, record.ptr()));
|
||||
}
|
||||
|
||||
(void)WebIDL::invoke_callback(callback, mutation_observer, WebIDL::ExceptionBehavior::Report, wrapped_records, mutation_observer);
|
||||
(void)WebIDL::invoke_callback(callback, mutation_observer, WebIDL::ExceptionBehavior::Report, { { wrapped_records, mutation_observer } });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4569,7 +4569,7 @@ void Document::queue_intersection_observer_task()
|
|||
|
||||
// 5. Invoke callback with queue as the first argument, observer as the second argument, and observer as the callback this value. If this throws an exception, report the exception.
|
||||
// NOTE: This does not follow the spec as written precisely, but this is the same thing we do elsewhere and there is a WPT test that relies on this.
|
||||
(void)WebIDL::invoke_callback(callback, observer.ptr(), WebIDL::ExceptionBehavior::Report, wrapped_queue, observer.ptr());
|
||||
(void)WebIDL::invoke_callback(callback, observer.ptr(), WebIDL::ExceptionBehavior::Report, { { wrapped_queue, observer.ptr() } });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -2517,7 +2517,7 @@ JS::ThrowCompletionOr<void> Element::upgrade_element(GC::Ref<HTML::CustomElement
|
|||
set_custom_element_state(CustomElementState::Precustomized);
|
||||
|
||||
// 3. Let constructResult be the result of constructing C, with no arguments.
|
||||
auto construct_result = TRY(WebIDL::construct(constructor));
|
||||
auto construct_result = TRY(WebIDL::construct(constructor, {}));
|
||||
|
||||
// 4. If SameValue(constructResult, element) is false, then throw a TypeError.
|
||||
if (!JS::same_value(construct_result, this))
|
||||
|
|
|
@ -578,7 +578,7 @@ WebIDL::ExceptionOr<GC::Ref<Element>> create_element(Document& document, FlyStri
|
|||
auto& constructor = definition->constructor();
|
||||
|
||||
// 2. Set result to the result of constructing C, with no arguments.
|
||||
auto result = TRY(WebIDL::construct(constructor));
|
||||
auto result = TRY(WebIDL::construct(constructor, {}));
|
||||
|
||||
// NOTE: IDL does not currently convert the object for us, so we will have to do it here.
|
||||
if (!result.is_object() || !is<HTML::HTMLElement>(result.as_object()))
|
||||
|
|
|
@ -91,7 +91,7 @@ bool EventDispatcher::inner_invoke(Event& event, Vector<GC::Root<DOM::DOMEventLi
|
|||
// FIXME: These should be wrapped for us in call_user_object_operation, but it currently doesn't do that.
|
||||
auto* this_value = event.current_target().ptr();
|
||||
auto* wrapped_event = &event;
|
||||
auto result = WebIDL::call_user_object_operation(callback, "handleEvent"_string, this_value, wrapped_event);
|
||||
auto result = WebIDL::call_user_object_operation(callback, "handleEvent"_string, this_value, { { wrapped_event } });
|
||||
|
||||
// If this throws an exception, then:
|
||||
if (result.is_error()) {
|
||||
|
|
|
@ -698,7 +698,7 @@ JS::ThrowCompletionOr<void> EventTarget::process_event_handler_for_event(FlyStri
|
|||
// calls directly into the callback without considering things such as proxies, it is a waste. However, if it observable, then we must reuse the this_value that was given to the callback.
|
||||
auto* this_value = error_event.current_target().ptr();
|
||||
|
||||
return_value_or_error = WebIDL::invoke_callback(*callback, this_value, wrapped_message, wrapped_filename, wrapped_lineno, wrapped_colno, error_event.error());
|
||||
return_value_or_error = WebIDL::invoke_callback(*callback, this_value, { { wrapped_message, wrapped_filename, wrapped_lineno, wrapped_colno, error_event.error() } });
|
||||
} else {
|
||||
// -> Otherwise
|
||||
// Invoke callback with one argument, the value of which is the Event object event, with the callback this value set to event's currentTarget. Let return value be the callback's return value. [WEBIDL]
|
||||
|
@ -709,7 +709,7 @@ JS::ThrowCompletionOr<void> EventTarget::process_event_handler_for_event(FlyStri
|
|||
// FIXME: The comments about this in the special_error_event_handling path also apply here.
|
||||
auto* this_value = event.current_target().ptr();
|
||||
|
||||
return_value_or_error = WebIDL::invoke_callback(*callback, this_value, wrapped_event);
|
||||
return_value_or_error = WebIDL::invoke_callback(*callback, this_value, { { wrapped_event } });
|
||||
}
|
||||
|
||||
// If an exception gets thrown by the callback, end these steps and allow the exception to propagate. (It will propagate to the DOM event dispatch logic, which will then report the exception.)
|
||||
|
|
|
@ -169,7 +169,7 @@ JS::ThrowCompletionOr<NodeFilter::Result> NodeIterator::filter(Node& node)
|
|||
|
||||
// 6. Let result be the return value of call a user object’s operation with traverser’s filter, "acceptNode", and « node ».
|
||||
// If this throws an exception, then unset traverser’s active flag and rethrow the exception.
|
||||
auto result = WebIDL::call_user_object_operation(m_filter->callback(), "acceptNode"_string, {}, &node);
|
||||
auto result = WebIDL::call_user_object_operation(m_filter->callback(), "acceptNode"_string, {}, { { &node } });
|
||||
if (result.is_abrupt()) {
|
||||
m_active = false;
|
||||
return result;
|
||||
|
|
|
@ -274,7 +274,7 @@ JS::ThrowCompletionOr<NodeFilter::Result> TreeWalker::filter(Node& node)
|
|||
|
||||
// 6. Let result be the return value of call a user object’s operation with traverser’s filter, "acceptNode", and « node ».
|
||||
// If this throws an exception, then unset traverser’s active flag and rethrow the exception.
|
||||
auto result = WebIDL::call_user_object_operation(m_filter->callback(), "acceptNode"_string, {}, &node);
|
||||
auto result = WebIDL::call_user_object_operation(m_filter->callback(), "acceptNode"_string, {}, { { &node } });
|
||||
if (result.is_abrupt()) {
|
||||
m_active = false;
|
||||
return result;
|
||||
|
|
|
@ -117,7 +117,7 @@ void DataTransferItem::get_as_string(GC::Ptr<WebIDL::CallbackType> callback) con
|
|||
|
||||
HTML::queue_a_task(HTML::Task::Source::Unspecified, nullptr, nullptr,
|
||||
GC::Function<void()>::create(realm.heap(), [callback, data]() {
|
||||
(void)WebIDL::invoke_callback(*callback, {}, data);
|
||||
(void)WebIDL::invoke_callback(*callback, {}, { { data } });
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@ WebIDL::ExceptionOr<void> HTMLCanvasElement::to_blob(GC::Ref<WebIDL::CallbackTyp
|
|||
blob_result = FileAPI::Blob::create(realm(), file_result->buffer, TRY_OR_THROW_OOM(vm(), String::from_utf8(file_result->mime_type)));
|
||||
|
||||
// 2. Invoke callback with « result » and "report".
|
||||
TRY(WebIDL::invoke_callback(*callback, {}, WebIDL::ExceptionBehavior::Report, move(blob_result)));
|
||||
TRY(WebIDL::invoke_callback(*callback, {}, WebIDL::ExceptionBehavior::Report, { { blob_result } }));
|
||||
return {};
|
||||
});
|
||||
if (maybe_error.is_throw_completion())
|
||||
|
|
|
@ -1141,7 +1141,7 @@ bool Navigation::inner_navigate_event_firing_algorithm(
|
|||
// 2. For each handler of event's navigation handler list:
|
||||
for (auto const& handler : event->navigation_handler_list()) {
|
||||
// 1. Append the result of invoking handler with an empty arguments list to promisesList.
|
||||
auto result = WebIDL::invoke_callback(handler, {});
|
||||
auto result = WebIDL::invoke_callback(handler, {}, {});
|
||||
// This *should* be equivalent to converting a promise to a promise capability
|
||||
promises_list.append(WebIDL::create_resolved_promise(realm, result.value()));
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ void UniversalGlobalScopeMixin::queue_microtask(WebIDL::CallbackType& callback)
|
|||
|
||||
// The queueMicrotask(callback) method must queue a microtask to invoke callback with « » and "report".
|
||||
HTML::queue_a_microtask(document, GC::create_function(realm.heap(), [&callback] {
|
||||
(void)WebIDL::invoke_callback(callback, {}, WebIDL::ExceptionBehavior::Report);
|
||||
(void)WebIDL::invoke_callback(callback, {}, WebIDL::ExceptionBehavior::Report, {});
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -1611,7 +1611,7 @@ WebIDL::UnsignedLong Window::request_animation_frame(GC::Ref<WebIDL::CallbackTyp
|
|||
// FIXME: Make this fully spec compliant. Currently implements a mix of 'requestAnimationFrame()' and 'run the animation frame callbacks'.
|
||||
return animation_frame_callback_driver().add(GC::create_function(heap(), [this, callback](double now) {
|
||||
// 3. Invoke callback, passing now as the only argument, and if an exception is thrown, report the exception.
|
||||
auto result = WebIDL::invoke_callback(*callback, {}, JS::Value(now));
|
||||
auto result = WebIDL::invoke_callback(*callback, {}, { { JS::Value(now) } });
|
||||
if (result.is_error())
|
||||
report_exception(result, realm());
|
||||
}));
|
||||
|
@ -1655,7 +1655,7 @@ u32 Window::request_idle_callback(WebIDL::CallbackType& callback, RequestIdleCal
|
|||
|
||||
// 4. Push callback to the end of window's list of idle request callbacks, associated with handle.
|
||||
auto handler = [callback = GC::make_root(callback)](GC::Ref<RequestIdleCallback::IdleDeadline> deadline) -> JS::Completion {
|
||||
return WebIDL::invoke_callback(*callback, {}, deadline.ptr());
|
||||
return WebIDL::invoke_callback(*callback, {}, { { deadline } });
|
||||
};
|
||||
m_idle_request_callbacks.append(adopt_ref(*new IdleCallback(move(handler), handle)));
|
||||
|
||||
|
|
|
@ -639,7 +639,7 @@ void WindowOrWorkerGlobalScopeMixin::queue_the_performance_observer_task()
|
|||
// 9. Call po’s observer callback with observerEntryList as the first argument, with po as the second
|
||||
// argument and as callback this value, and with callbackOptions as the third argument.
|
||||
// If this throws an exception, report the exception.
|
||||
auto completion = WebIDL::invoke_callback(registered_observer->callback(), registered_observer, observer_entry_list, registered_observer, callback_options);
|
||||
auto completion = WebIDL::invoke_callback(registered_observer->callback(), registered_observer, { { observer_entry_list, registered_observer, callback_options } });
|
||||
if (completion.is_abrupt())
|
||||
HTML::report_exception(completion, realm);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ void ResizeObserver::invoke_callback(ReadonlySpan<GC::Ref<ResizeObserverEntry>>
|
|||
MUST(wrapped_records->create_data_property(property_index, record.ptr()));
|
||||
}
|
||||
|
||||
(void)WebIDL::invoke_callback(callback, JS::js_undefined(), WebIDL::ExceptionBehavior::Report, wrapped_records);
|
||||
(void)WebIDL::invoke_callback(callback, JS::js_undefined(), WebIDL::ExceptionBehavior::Report, { { wrapped_records } });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1762,7 +1762,8 @@ GC::Ref<SizeAlgorithm> extract_size_algorithm(JS::VM& vm, QueuingStrategy const&
|
|||
|
||||
// 2. Return an algorithm that performs the following steps, taking a chunk argument:
|
||||
return GC::create_function(vm.heap(), [size = strategy.size](JS::Value chunk) {
|
||||
return WebIDL::invoke_callback(*size, JS::js_undefined(), chunk);
|
||||
// 1. Return the result of invoking strategy["size"] with argument list « chunk ».
|
||||
return WebIDL::invoke_callback(*size, {}, { { chunk } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3145,7 +3146,7 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller_from_underly
|
|||
// invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource.
|
||||
if (underlying_source.start) {
|
||||
start_algorithm = GC::create_function(realm.heap(), [controller, underlying_source_value, callback = underlying_source.start]() -> WebIDL::ExceptionOr<JS::Value> {
|
||||
return TRY(WebIDL::invoke_callback(*callback, underlying_source_value, controller));
|
||||
return TRY(WebIDL::invoke_callback(*callback, underlying_source_value, { { controller } }));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3153,7 +3154,7 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller_from_underly
|
|||
// invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource.
|
||||
if (underlying_source.pull) {
|
||||
pull_algorithm = GC::create_function(realm.heap(), [controller, underlying_source_value, callback = underlying_source.pull]() {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source_value, controller);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source_value, { { controller } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3162,7 +3163,7 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller_from_underly
|
|||
// callback this value underlyingSource.
|
||||
if (underlying_source.cancel) {
|
||||
cancel_algorithm = GC::create_function(realm.heap(), [underlying_source_value, callback = underlying_source.cancel](JS::Value reason) {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source_value, reason);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source_value, { { reason } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4846,7 +4847,7 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
|
|||
// callback this value underlyingSink.
|
||||
if (underlying_sink.start) {
|
||||
start_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.start]() -> WebIDL::ExceptionOr<JS::Value> {
|
||||
return TRY(WebIDL::invoke_callback(*callback, underlying_sink_value, WebIDL::ExceptionBehavior::Rethrow, controller));
|
||||
return TRY(WebIDL::invoke_callback(*callback, underlying_sink_value, WebIDL::ExceptionBehavior::Rethrow, { { controller } }));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4855,7 +4856,7 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
|
|||
// callback this value underlyingSink.
|
||||
if (underlying_sink.write) {
|
||||
write_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.write](JS::Value chunk) {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, chunk, controller);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, { { chunk, controller } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4863,7 +4864,7 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
|
|||
// invoking underlyingSinkDict["close"] with argument list «» and callback this value underlyingSink.
|
||||
if (underlying_sink.close) {
|
||||
close_algorithm = GC::create_function(realm.heap(), [underlying_sink_value, callback = underlying_sink.close]() {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_sink_value);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, {});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4872,7 +4873,7 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
|
|||
// value underlyingSink.
|
||||
if (underlying_sink.abort) {
|
||||
abort_algorithm = GC::create_function(realm.heap(), [underlying_sink_value, callback = underlying_sink.abort](JS::Value reason) {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, reason);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, { { reason } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5275,7 +5276,7 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
|
|||
// callback this value transformer.
|
||||
if (transformer_dict.transform) {
|
||||
transform_algorithm = GC::create_function(realm.heap(), [controller, transformer, callback = transformer_dict.transform](JS::Value chunk) {
|
||||
return WebIDL::invoke_promise_callback(*callback, transformer, chunk, controller);
|
||||
return WebIDL::invoke_promise_callback(*callback, transformer, { { chunk, controller } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5283,7 +5284,7 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
|
|||
// transformerDict["flush"] with argument list « controller » and callback this value transformer.
|
||||
if (transformer_dict.flush) {
|
||||
flush_algorithm = GC::create_function(realm.heap(), [transformer, callback = transformer_dict.flush, controller]() {
|
||||
return WebIDL::invoke_promise_callback(*callback, transformer, controller);
|
||||
return WebIDL::invoke_promise_callback(*callback, transformer, { { controller } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5291,7 +5292,7 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
|
|||
// the result of invoking transformerDict["cancel"] with argument list « reason » and callback this value transformer.
|
||||
if (transformer_dict.cancel) {
|
||||
cancel_algorithm = GC::create_function(realm.heap(), [transformer, callback = transformer_dict.cancel](JS::Value reason) {
|
||||
return WebIDL::invoke_promise_callback(*callback, transformer, reason);
|
||||
return WebIDL::invoke_promise_callback(*callback, transformer, { { reason } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5816,7 +5817,7 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller_from_underlying
|
|||
// invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource.
|
||||
if (underlying_source_dict.start) {
|
||||
start_algorithm = GC::create_function(realm.heap(), [controller, underlying_source, callback = underlying_source_dict.start]() -> WebIDL::ExceptionOr<JS::Value> {
|
||||
return TRY(WebIDL::invoke_callback(*callback, underlying_source, controller));
|
||||
return TRY(WebIDL::invoke_callback(*callback, underlying_source, { { controller } }));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5824,7 +5825,7 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller_from_underlying
|
|||
// invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource.
|
||||
if (underlying_source_dict.pull) {
|
||||
pull_algorithm = GC::create_function(realm.heap(), [controller, underlying_source, callback = underlying_source_dict.pull]() {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source, controller);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source, { { controller } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5833,7 +5834,7 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller_from_underlying
|
|||
// callback this value underlyingSource.
|
||||
if (underlying_source_dict.cancel) {
|
||||
cancel_algorithm = GC::create_function(realm.heap(), [underlying_source, callback = underlying_source_dict.cancel](JS::Value reason) {
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source, reason);
|
||||
return WebIDL::invoke_promise_callback(*callback, underlying_source, { { reason } });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ WebIDL::ExceptionOr<GC::Ref<TransformStream>> TransformStream::construct_impl(JS
|
|||
// 12. If transformerDict["start"] exists, then resolve startPromise with the result of invoking
|
||||
// transformerDict["start"] with argument list « this.[[controller]] » and callback this value transformer.
|
||||
if (transformer_dict.start) {
|
||||
auto result = TRY(WebIDL::invoke_callback(*transformer_dict.start, transformer, stream->controller()));
|
||||
auto result = TRY(WebIDL::invoke_callback(*transformer_dict.start, transformer, { { stream->controller() } }));
|
||||
WebIDL::resolve_promise(realm, start_promise, result);
|
||||
}
|
||||
// 13. Otherwise, resolve startPromise with undefined.
|
||||
|
|
|
@ -243,7 +243,7 @@ GC::Ref<WebIDL::Promise> BaseAudioContext::decode_audio_data(GC::Root<WebIDL::Bu
|
|||
// 4.3. Queue a media element task to invoke errorCallback with error.
|
||||
if (error_callback) {
|
||||
queue_a_media_element_task(GC::create_function(heap(), [&realm, error_callback, error] {
|
||||
auto completion = WebIDL::invoke_callback(*error_callback, {}, error);
|
||||
auto completion = WebIDL::invoke_callback(*error_callback, {}, { { error } });
|
||||
if (completion.is_abrupt())
|
||||
HTML::report_exception(completion, realm);
|
||||
}));
|
||||
|
@ -293,7 +293,7 @@ void BaseAudioContext::queue_a_decoding_operation(GC::Ref<JS::PromiseCapability>
|
|||
|
||||
// 4.2. If errorCallback is not missing, invoke errorCallback with error.
|
||||
if (error_callback) {
|
||||
auto completion = WebIDL::invoke_callback(*error_callback, {}, error);
|
||||
auto completion = WebIDL::invoke_callback(*error_callback, {}, { { error } });
|
||||
if (completion.is_abrupt())
|
||||
HTML::report_exception(completion, realm);
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ void BaseAudioContext::queue_a_decoding_operation(GC::Ref<JS::PromiseCapability>
|
|||
|
||||
// 5.2.3. If successCallback is not missing, invoke successCallback with buffer.
|
||||
if (success_callback) {
|
||||
auto completion = WebIDL::invoke_callback(*success_callback, {}, buffer);
|
||||
auto completion = WebIDL::invoke_callback(*success_callback, {}, { { buffer } });
|
||||
if (completion.is_abrupt())
|
||||
HTML::report_exception(completion, realm);
|
||||
}
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/Enumerate.h>
|
||||
#include <AK/Math.h>
|
||||
#include <AK/NumericLimits.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/ArrayBuffer.h>
|
||||
#include <LibJS/Runtime/DataView.h>
|
||||
#include <LibJS/Runtime/PropertyKey.h>
|
||||
#include <LibJS/Runtime/FunctionObject.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/CallbackType.h>
|
||||
#include <LibWeb/WebIDL/Promise.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
|
@ -141,7 +141,7 @@ inline JS::Completion clean_up_on_return(JS::Realm& stored_realm, JS::Realm& rel
|
|||
|
||||
// https://webidl.spec.whatwg.org/#call-a-user-objects-operation
|
||||
// https://whatpr.org/webidl/1437.html#call-a-user-objects-operation
|
||||
JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String const& operation_name, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args)
|
||||
JS::Completion call_user_object_operation(CallbackType& callback, String const& operation_name, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args)
|
||||
{
|
||||
// 1. Let completion be an uninitialized variable.
|
||||
JS::Completion completion;
|
||||
|
@ -197,9 +197,7 @@ JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String
|
|||
// For simplicity, we currently make the caller do this. However, this means we can't throw exceptions at this point like the spec wants us to.
|
||||
|
||||
// 11. Let callResult be Call(X, thisArg, esArgs).
|
||||
VERIFY(actual_function_object);
|
||||
auto& vm = object->vm();
|
||||
auto call_result = JS::call(vm, as<JS::FunctionObject>(*actual_function_object), this_argument.value(), args.span());
|
||||
auto call_result = JS::call(object->vm(), as<JS::FunctionObject>(*actual_function_object), this_argument.value(), args);
|
||||
|
||||
// 12. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return.
|
||||
if (call_result.is_throw_completion()) {
|
||||
|
@ -244,7 +242,7 @@ JS::ThrowCompletionOr<String> to_usv_string(JS::VM& vm, JS::Value value)
|
|||
// https://webidl.spec.whatwg.org/#invoke-a-callback-function
|
||||
// https://whatpr.org/webidl/1437.html#invoke-a-callback-function
|
||||
template<typename ReturnSteps>
|
||||
static auto invoke_callback_impl(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args, ReturnSteps&& return_steps)
|
||||
static auto invoke_callback_impl(CallbackType& callback, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args, ReturnSteps&& return_steps)
|
||||
{
|
||||
// 1. Let completion be an uninitialized variable.
|
||||
|
||||
|
@ -279,8 +277,7 @@ static auto invoke_callback_impl(WebIDL::CallbackType& callback, Optional<JS::Va
|
|||
// If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return.
|
||||
|
||||
// 10. Let callResult be Call(F, thisArg, jsArgs).
|
||||
auto& vm = function_object->vm();
|
||||
auto call_result = JS::call(vm, as<JS::FunctionObject>(*function_object), this_argument.value(), args.span());
|
||||
auto call_result = JS::call(function_object->vm(), as<JS::FunctionObject>(*function_object), this_argument.value(), args);
|
||||
|
||||
// 11. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return.
|
||||
// 12. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as callable’s
|
||||
|
@ -298,7 +295,7 @@ static auto invoke_callback_impl(WebIDL::CallbackType& callback, Optional<JS::Va
|
|||
}
|
||||
}
|
||||
|
||||
JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, ExceptionBehavior exception_behavior, GC::RootVector<JS::Value> args)
|
||||
JS::Completion invoke_callback(CallbackType& callback, Optional<JS::Value> this_argument, ExceptionBehavior exception_behavior, ReadonlySpan<JS::Value> args)
|
||||
{
|
||||
// https://webidl.spec.whatwg.org/#js-invoking-callback-functions
|
||||
// The exceptionBehavior argument must be supplied if, and only if, callable’s return type is not a promise type. If callable’s return type is neither undefined nor any, it must be "rethrow".
|
||||
|
@ -308,7 +305,7 @@ JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Valu
|
|||
|
||||
VERIFY(exception_behavior == ExceptionBehavior::NotSpecified || callback.operation_returns_promise == OperationReturnsPromise::No);
|
||||
|
||||
return invoke_callback_impl(callback, move(this_argument), move(args), [&](JS::Realm& relevant_realm, JS::Completion completion) -> JS::Completion {
|
||||
return invoke_callback_impl(callback, move(this_argument), args, [&](JS::Realm& relevant_realm, JS::Completion completion) -> JS::Completion {
|
||||
// 3. If completion is an IDL value, return completion.
|
||||
if (!completion.is_abrupt())
|
||||
return completion;
|
||||
|
@ -344,21 +341,21 @@ JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Valu
|
|||
});
|
||||
}
|
||||
|
||||
JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args)
|
||||
JS::Completion invoke_callback(CallbackType& callback, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args)
|
||||
{
|
||||
return invoke_callback(callback, move(this_argument), ExceptionBehavior::NotSpecified, move(args));
|
||||
return invoke_callback(callback, move(this_argument), ExceptionBehavior::NotSpecified, args);
|
||||
}
|
||||
|
||||
// AD-HOC: This may be used as an alternative to WebIDL::invoke_callback when you know the callback returns a promise,
|
||||
// and the caller needs a WebIDL::Promise rather than a JS::Promise.
|
||||
GC::Ref<WebIDL::Promise> invoke_promise_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args)
|
||||
GC::Ref<Promise> invoke_promise_callback(CallbackType& callback, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args)
|
||||
{
|
||||
VERIFY(callback.operation_returns_promise == OperationReturnsPromise::Yes);
|
||||
|
||||
return invoke_callback_impl(callback, move(this_argument), move(args), [&](JS::Realm& relevant_realm, JS::Completion completion) -> GC::Ref<WebIDL::Promise> {
|
||||
return invoke_callback_impl(callback, move(this_argument), args, [&](JS::Realm& relevant_realm, JS::Completion completion) {
|
||||
// 3. If completion is an IDL value, return completion.
|
||||
if (!completion.is_abrupt())
|
||||
return WebIDL::create_resolved_promise(relevant_realm, completion.release_value());
|
||||
return create_resolved_promise(relevant_realm, completion.release_value());
|
||||
|
||||
// 4. Assert: completion is an abrupt completion.
|
||||
VERIFY(completion.is_abrupt());
|
||||
|
@ -371,7 +368,7 @@ GC::Ref<WebIDL::Promise> invoke_promise_callback(WebIDL::CallbackType& callback,
|
|||
});
|
||||
}
|
||||
|
||||
JS::Completion construct(WebIDL::CallbackType& callback, GC::RootVector<JS::Value> args)
|
||||
JS::Completion construct(CallbackType& callback, ReadonlySpan<JS::Value> args)
|
||||
{
|
||||
// 1. Let completion be an uninitialized variable.
|
||||
JS::Completion completion;
|
||||
|
@ -399,8 +396,7 @@ JS::Completion construct(WebIDL::CallbackType& callback, GC::RootVector<JS::Valu
|
|||
// For simplicity, we currently make the caller do this. However, this means we can't throw exceptions at this point like the spec wants us to.
|
||||
|
||||
// 8. Let callResult be Completion(Construct(F, esArgs)).
|
||||
auto& vm = function_object->vm();
|
||||
auto call_result = JS::construct(vm, as<JS::FunctionObject>(*function_object), args.span());
|
||||
auto call_result = JS::construct(function_object->vm(), as<JS::FunctionObject>(*function_object), args);
|
||||
|
||||
// 9. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return.
|
||||
if (call_result.is_throw_completion()) {
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/FunctionObject.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/WebIDL/CallbackType.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::WebIDL {
|
||||
|
||||
|
@ -21,77 +19,23 @@ bool is_buffer_source_type(JS::Value);
|
|||
GC::Ptr<JS::ArrayBuffer> underlying_buffer_source(JS::Object& buffer_source);
|
||||
ErrorOr<ByteBuffer> get_buffer_source_copy(JS::Object const& buffer_source);
|
||||
|
||||
JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String const& operation_name, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args);
|
||||
JS::Completion call_user_object_operation(CallbackType& callback, String const& operation_name, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args);
|
||||
|
||||
JS::ThrowCompletionOr<String> to_string(JS::VM&, JS::Value);
|
||||
JS::ThrowCompletionOr<String> to_usv_string(JS::VM&, JS::Value);
|
||||
JS::ThrowCompletionOr<String> to_byte_string(JS::VM&, JS::Value);
|
||||
|
||||
// https://webidl.spec.whatwg.org/#call-a-user-objects-operation
|
||||
template<typename... Args>
|
||||
JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String const& operation_name, Optional<JS::Value> this_argument, Args&&... args)
|
||||
{
|
||||
auto& function_object = callback.callback;
|
||||
|
||||
GC::RootVector<JS::Value> arguments_list { function_object->heap() };
|
||||
(arguments_list.append(forward<Args>(args)), ...);
|
||||
|
||||
return call_user_object_operation(callback, operation_name, move(this_argument), move(arguments_list));
|
||||
}
|
||||
|
||||
enum class ExceptionBehavior {
|
||||
NotSpecified,
|
||||
Report,
|
||||
Rethrow,
|
||||
};
|
||||
JS::Completion invoke_callback(CallbackType& callback, Optional<JS::Value> this_argument, ExceptionBehavior exception_behavior, ReadonlySpan<JS::Value> args);
|
||||
JS::Completion invoke_callback(CallbackType& callback, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args);
|
||||
|
||||
JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, ExceptionBehavior exception_behavior, GC::RootVector<JS::Value> args);
|
||||
JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args);
|
||||
GC::Ref<Promise> invoke_promise_callback(CallbackType& callback, Optional<JS::Value> this_argument, ReadonlySpan<JS::Value> args);
|
||||
|
||||
// https://webidl.spec.whatwg.org/#invoke-a-callback-function
|
||||
template<typename... Args>
|
||||
JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, ExceptionBehavior exception_behavior, Args&&... args)
|
||||
{
|
||||
auto& function_object = callback.callback;
|
||||
|
||||
GC::RootVector<JS::Value> arguments_list { function_object->heap() };
|
||||
(arguments_list.append(forward<Args>(args)), ...);
|
||||
|
||||
return invoke_callback(callback, move(this_argument), exception_behavior, move(arguments_list));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, Args&&... args)
|
||||
{
|
||||
return invoke_callback(callback, move(this_argument), ExceptionBehavior::NotSpecified, forward<Args>(args)...);
|
||||
}
|
||||
|
||||
GC::Ref<WebIDL::Promise> invoke_promise_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, GC::RootVector<JS::Value> args);
|
||||
|
||||
template<typename... Args>
|
||||
GC::Ref<WebIDL::Promise> invoke_promise_callback(WebIDL::CallbackType& callback, Optional<JS::Value> this_argument, Args&&... args)
|
||||
{
|
||||
auto& function_object = callback.callback;
|
||||
|
||||
GC::RootVector<JS::Value> arguments_list { function_object->heap() };
|
||||
(arguments_list.append(forward<Args>(args)), ...);
|
||||
|
||||
return invoke_promise_callback(callback, move(this_argument), move(arguments_list));
|
||||
}
|
||||
|
||||
JS::Completion construct(WebIDL::CallbackType& callback, GC::RootVector<JS::Value> args);
|
||||
|
||||
// https://webidl.spec.whatwg.org/#construct-a-callback-function
|
||||
template<typename... Args>
|
||||
JS::Completion construct(WebIDL::CallbackType& callback, Args&&... args)
|
||||
{
|
||||
auto& function_object = callback.callback;
|
||||
|
||||
GC::RootVector<JS::Value> arguments_list { function_object->heap() };
|
||||
(arguments_list.append(forward<Args>(args)), ...);
|
||||
|
||||
return construct(callback, move(arguments_list));
|
||||
}
|
||||
JS::Completion construct(CallbackType& callback, ReadonlySpan<JS::Value> args);
|
||||
|
||||
// https://webidl.spec.whatwg.org/#abstract-opdef-integerpart
|
||||
double integer_part(double n);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue