mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:07:45 +00:00
LibWeb: Replace GlobalObject with Realm in wrapper functions
Similar to create() in LibJS, wrap() et al. are on a low enough level to warrant passing a Realm directly instead of relying on the current realm from the VM, as a wrapper may need to be allocated while no JS is being executed.
This commit is contained in:
parent
56b2ae5ac0
commit
40a70461a0
60 changed files with 261 additions and 235 deletions
|
@ -19,9 +19,9 @@ AbortSignal::AbortSignal()
|
|||
{
|
||||
}
|
||||
|
||||
JS::Object* AbortSignal::create_wrapper(JS::GlobalObject& global_object)
|
||||
JS::Object* AbortSignal::create_wrapper(JS::Realm& realm)
|
||||
{
|
||||
return wrap(global_object, *this);
|
||||
return wrap(realm, *this);
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#abortsignal-add
|
||||
|
@ -38,6 +38,10 @@ void AbortSignal::add_abort_algorithm(Function<void()> abort_algorithm)
|
|||
// https://dom.spec.whatwg.org/#abortsignal-signal-abort
|
||||
void AbortSignal::signal_abort(JS::Value reason)
|
||||
{
|
||||
VERIFY(wrapper());
|
||||
auto& vm = wrapper()->vm();
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. If signal is aborted, then return.
|
||||
if (aborted())
|
||||
return;
|
||||
|
@ -46,7 +50,7 @@ void AbortSignal::signal_abort(JS::Value reason)
|
|||
if (!reason.is_undefined())
|
||||
m_abort_reason = reason;
|
||||
else
|
||||
m_abort_reason = wrap(wrapper()->global_object(), AbortError::create("Aborted without reason"));
|
||||
m_abort_reason = wrap(realm, AbortError::create("Aborted without reason"));
|
||||
|
||||
// 3. For each algorithm in signal’s abort algorithms: run algorithm.
|
||||
for (auto& algorithm : m_abort_algorithms)
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
// ^EventTarget
|
||||
virtual void ref_event_target() override { ref(); }
|
||||
virtual void unref_event_target() override { unref(); }
|
||||
virtual JS::Object* create_wrapper(JS::GlobalObject&) override;
|
||||
virtual JS::Object* create_wrapper(JS::Realm&) override;
|
||||
|
||||
private:
|
||||
AbortSignal();
|
||||
|
|
|
@ -58,6 +58,6 @@ private:
|
|||
|
||||
namespace Web::Bindings {
|
||||
|
||||
DOMTokenListWrapper* wrap(JS::GlobalObject&, DOM::DOMTokenList&);
|
||||
DOMTokenListWrapper* wrap(JS::Realm&, DOM::DOMTokenList&);
|
||||
|
||||
}
|
||||
|
|
|
@ -88,7 +88,8 @@ bool EventDispatcher::inner_invoke(Event& event, Vector<NonnullRefPtr<DOM::DOMEv
|
|||
|
||||
// 6. Let global be listener callback’s associated Realm’s global object.
|
||||
auto& callback = listener->callback->callback();
|
||||
auto& global = callback.callback.cell()->global_object();
|
||||
auto& realm = callback.callback->shape().realm();
|
||||
auto& global = realm.global_object();
|
||||
|
||||
// 7. Let currentEvent be undefined.
|
||||
RefPtr<Event> current_event;
|
||||
|
@ -112,8 +113,8 @@ bool EventDispatcher::inner_invoke(Event& event, Vector<NonnullRefPtr<DOM::DOMEv
|
|||
|
||||
// 10. Call a user object’s operation with listener’s callback, "handleEvent", « event », and event’s currentTarget attribute value. If this throws an exception, then:
|
||||
// FIXME: These should be wrapped for us in call_user_object_operation, but it currently doesn't do that.
|
||||
auto* this_value = Bindings::wrap(global, *event.current_target());
|
||||
auto* wrapped_event = Bindings::wrap(global, event);
|
||||
auto* this_value = Bindings::wrap(realm, *event.current_target());
|
||||
auto* wrapped_event = Bindings::wrap(realm, event);
|
||||
auto result = Bindings::IDL::call_user_object_operation(callback, "handleEvent", this_value, wrapped_event);
|
||||
|
||||
// If this throws an exception, then:
|
||||
|
|
|
@ -384,10 +384,10 @@ Bindings::CallbackType* EventTarget::get_current_value_of_event_handler(FlyStrin
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto& global_object = settings_object.global_object();
|
||||
auto& vm = Bindings::main_thread_vm();
|
||||
|
||||
// 8. Push settings object's realm execution context onto the JavaScript execution context stack; it is now the running JavaScript execution context.
|
||||
global_object.vm().push_execution_context(settings_object.realm_execution_context());
|
||||
vm.push_execution_context(settings_object.realm_execution_context());
|
||||
|
||||
// 9. Let function be the result of calling OrdinaryFunctionCreate, with arguments:
|
||||
// functionPrototype
|
||||
|
@ -419,19 +419,19 @@ Bindings::CallbackType* EventTarget::get_current_value_of_event_handler(FlyStrin
|
|||
// 3. If eventHandler is an element's event handler, then set scope to NewObjectEnvironment(document, true, scope).
|
||||
// (Otherwise, eventHandler is a Window object's event handler.)
|
||||
if (is<Element>(this)) {
|
||||
auto* wrapped_document = Bindings::wrap(global_object, *document);
|
||||
auto* wrapped_document = Bindings::wrap(realm, *document);
|
||||
scope = JS::new_object_environment(*wrapped_document, true, scope);
|
||||
}
|
||||
|
||||
// 4. If form owner is not null, then set scope to NewObjectEnvironment(form owner, true, scope).
|
||||
if (form_owner) {
|
||||
auto* wrapped_form_owner = Bindings::wrap(global_object, *form_owner);
|
||||
auto* wrapped_form_owner = Bindings::wrap(realm, *form_owner);
|
||||
scope = JS::new_object_environment(*wrapped_form_owner, true, scope);
|
||||
}
|
||||
|
||||
// 5. If element is not null, then set scope to NewObjectEnvironment(element, true, scope).
|
||||
if (element) {
|
||||
auto* wrapped_element = Bindings::wrap(global_object, *element);
|
||||
auto* wrapped_element = Bindings::wrap(realm, *element);
|
||||
scope = JS::new_object_environment(*wrapped_element, true, scope);
|
||||
}
|
||||
|
||||
|
@ -441,8 +441,8 @@ Bindings::CallbackType* EventTarget::get_current_value_of_event_handler(FlyStrin
|
|||
VERIFY(function);
|
||||
|
||||
// 10. Remove settings object's realm execution context from the JavaScript execution context stack.
|
||||
VERIFY(global_object.vm().execution_context_stack().last() == &settings_object.realm_execution_context());
|
||||
global_object.vm().pop_execution_context();
|
||||
VERIFY(vm.execution_context_stack().last() == &settings_object.realm_execution_context());
|
||||
vm.pop_execution_context();
|
||||
|
||||
// 11. Set function.[[ScriptOrModule]] to null.
|
||||
function->set_script_or_module({});
|
||||
|
@ -602,6 +602,7 @@ JS::ThrowCompletionOr<void> EventTarget::process_event_handler_for_event(FlyStri
|
|||
|
||||
// Needed for wrapping.
|
||||
auto* callback_object = callback->callback.cell();
|
||||
auto& realm = callback_object->shape().realm();
|
||||
|
||||
if (special_error_event_handling) {
|
||||
// -> If special error event handling is true
|
||||
|
@ -619,7 +620,7 @@ JS::ThrowCompletionOr<void> EventTarget::process_event_handler_for_event(FlyStri
|
|||
// NOTE: current_target is always non-null here, as the event dispatcher takes care to make sure it's non-null (and uses it as the this value for the callback!)
|
||||
// FIXME: This is rewrapping the this value of the callback defined in activate_event_handler. While I don't think this is observable as the event dispatcher
|
||||
// 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 = Bindings::wrap(callback_object->global_object(), *error_event.current_target());
|
||||
auto* this_value = Bindings::wrap(realm, *error_event.current_target());
|
||||
|
||||
return_value_or_error = Bindings::IDL::invoke_callback(*callback, this_value, wrapped_message, wrapped_filename, wrapped_lineno, wrapped_colno, error_event.error());
|
||||
} else {
|
||||
|
@ -627,10 +628,10 @@ JS::ThrowCompletionOr<void> EventTarget::process_event_handler_for_event(FlyStri
|
|||
// 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]
|
||||
|
||||
// FIXME: This has the same rewrapping issue as this_value.
|
||||
auto* wrapped_event = Bindings::wrap(callback_object->global_object(), event);
|
||||
auto* wrapped_event = Bindings::wrap(realm, event);
|
||||
|
||||
// FIXME: The comments about this in the special_error_event_handling path also apply here.
|
||||
auto* this_value = Bindings::wrap(callback_object->global_object(), *event.current_target());
|
||||
auto* this_value = Bindings::wrap(realm, *event.current_target());
|
||||
|
||||
return_value_or_error = Bindings::IDL::invoke_callback(*callback, this_value, wrapped_event);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual bool dispatch_event(NonnullRefPtr<Event>);
|
||||
ExceptionOr<bool> dispatch_event_binding(NonnullRefPtr<Event>);
|
||||
|
||||
virtual JS::Object* create_wrapper(JS::GlobalObject&) = 0;
|
||||
virtual JS::Object* create_wrapper(JS::Realm&) = 0;
|
||||
|
||||
virtual EventTarget* get_parent(Event const&) { return nullptr; }
|
||||
|
||||
|
|
|
@ -64,6 +64,6 @@ private:
|
|||
|
||||
namespace Web::Bindings {
|
||||
|
||||
HTMLCollectionWrapper* wrap(JS::GlobalObject&, DOM::HTMLCollection&);
|
||||
HTMLCollectionWrapper* wrap(JS::Realm&, DOM::HTMLCollection&);
|
||||
|
||||
}
|
||||
|
|
|
@ -64,6 +64,6 @@ private:
|
|||
|
||||
namespace Web::Bindings {
|
||||
|
||||
NamedNodeMapWrapper* wrap(JS::GlobalObject&, DOM::NamedNodeMap&);
|
||||
NamedNodeMapWrapper* wrap(JS::Realm&, DOM::NamedNodeMap&);
|
||||
|
||||
}
|
||||
|
|
|
@ -806,9 +806,9 @@ bool Node::is_editable() const
|
|||
return parent() && parent()->is_editable();
|
||||
}
|
||||
|
||||
JS::Object* Node::create_wrapper(JS::GlobalObject& global_object)
|
||||
JS::Object* Node::create_wrapper(JS::Realm& realm)
|
||||
{
|
||||
return wrap(global_object, *this);
|
||||
return wrap(realm, *this);
|
||||
}
|
||||
|
||||
void Node::removed_last_ref()
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
// ^EventTarget
|
||||
virtual void ref_event_target() final { ref(); }
|
||||
virtual void unref_event_target() final { unref(); }
|
||||
virtual JS::Object* create_wrapper(JS::GlobalObject&) override;
|
||||
virtual JS::Object* create_wrapper(JS::Realm&) override;
|
||||
|
||||
virtual ~Node();
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ private:
|
|||
Bindings::CallbackType m_callback;
|
||||
};
|
||||
|
||||
inline JS::Object* wrap(JS::GlobalObject&, Web::DOM::NodeFilter& filter)
|
||||
inline JS::Object* wrap(JS::Realm&, Web::DOM::NodeFilter& filter)
|
||||
{
|
||||
return filter.callback().callback.cell();
|
||||
}
|
||||
|
|
|
@ -118,12 +118,12 @@ JS::ThrowCompletionOr<RefPtr<Node>> NodeIterator::traverse(Direction direction)
|
|||
JS::ThrowCompletionOr<NodeFilter::Result> NodeIterator::filter(Node& node)
|
||||
{
|
||||
VERIFY(wrapper());
|
||||
auto& global_object = wrapper()->global_object();
|
||||
auto& vm = wrapper()->vm();
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. If traverser’s active flag is set, then throw an "InvalidStateError" DOMException.
|
||||
if (m_active)
|
||||
return JS::throw_completion(wrap(global_object, InvalidStateError::create("NodeIterator is already active")));
|
||||
return JS::throw_completion(wrap(realm, InvalidStateError::create("NodeIterator is already active")));
|
||||
|
||||
// 2. Let n be node’s nodeType attribute value − 1.
|
||||
auto n = node.node_type() - 1;
|
||||
|
@ -141,7 +141,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 = Bindings::IDL::call_user_object_operation(m_filter->callback(), "acceptNode", {}, wrap(global_object, node));
|
||||
auto result = Bindings::IDL::call_user_object_operation(m_filter->callback(), "acceptNode", {}, wrap(realm, node));
|
||||
if (result.is_abrupt()) {
|
||||
m_active = false;
|
||||
return result;
|
||||
|
|
|
@ -221,12 +221,12 @@ JS::ThrowCompletionOr<RefPtr<Node>> TreeWalker::next_node()
|
|||
JS::ThrowCompletionOr<NodeFilter::Result> TreeWalker::filter(Node& node)
|
||||
{
|
||||
VERIFY(wrapper());
|
||||
auto& global_object = wrapper()->global_object();
|
||||
auto& vm = wrapper()->vm();
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. If traverser’s active flag is set, then throw an "InvalidStateError" DOMException.
|
||||
if (m_active)
|
||||
return JS::throw_completion(wrap(global_object, InvalidStateError::create("NodeIterator is already active")));
|
||||
return JS::throw_completion(wrap(realm, InvalidStateError::create("NodeIterator is already active")));
|
||||
|
||||
// 2. Let n be node’s nodeType attribute value − 1.
|
||||
auto n = node.node_type() - 1;
|
||||
|
@ -244,7 +244,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 = Bindings::IDL::call_user_object_operation(m_filter->callback(), "acceptNode", {}, wrap(global_object, node));
|
||||
auto result = Bindings::IDL::call_user_object_operation(m_filter->callback(), "acceptNode", {}, wrap(realm, node));
|
||||
if (result.is_abrupt()) {
|
||||
m_active = false;
|
||||
return result;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue