Explorar o código

LibWeb: Propagate Realm instead of VM more through Fetch

This makes Fetch rely less on using main_thread_vm().current_realm(),
which relies on the dummy execution context if no JavaScript is
currently running.
Luke Wilde %!s(int64=2) %!d(string=hai) anos
pai
achega
9acc542059

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/Body.cpp

@@ -132,7 +132,7 @@ WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm& realm, ByteBuffer bytes,
         }
     case PackageDataType::JSON:
         // Return the result of running parse JSON from bytes on bytes.
-        return Infra::parse_json_bytes_to_javascript_value(vm, bytes);
+        return Infra::parse_json_bytes_to_javascript_value(realm, bytes);
     case PackageDataType::Text:
         // Return the result of running UTF-8 decode on bytes.
         return JS::PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, String::from_utf8(bytes)));

+ 22 - 11
Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp

@@ -8,6 +8,7 @@
 #include <AK/TypeCasts.h>
 #include <LibJS/Runtime/PromiseCapability.h>
 #include <LibWeb/Bindings/ExceptionOrUtils.h>
+#include <LibWeb/Bindings/HostDefined.h>
 #include <LibWeb/DOM/AbortSignal.h>
 #include <LibWeb/Fetch/FetchMethod.h>
 #include <LibWeb/Fetch/Fetching/Fetching.h>
@@ -36,7 +37,7 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
     if (exception_or_request_object.is_exception()) {
         // FIXME: We should probably make this a public API?
         auto throw_completion = Bindings::Detail::dom_exception_to_throw_completion(vm, exception_or_request_object.release_error());
-        WebIDL::reject_promise(vm, promise_capability, *throw_completion.value());
+        WebIDL::reject_promise(realm, promise_capability, *throw_completion.value());
         return verify_cast<JS::Promise>(*promise_capability->promise().ptr());
     }
     auto request_object = exception_or_request_object.release_value();
@@ -47,7 +48,7 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
     // 4. If requestObject’s signal is aborted, then:
     if (request_object->signal()->aborted()) {
         // 1. Abort the fetch() call with p, request, null, and requestObject’s signal’s abort reason.
-        abort_fetch(vm, promise_capability, request, nullptr, request_object->signal()->reason());
+        abort_fetch(realm, promise_capability, request, nullptr, request_object->signal()->reason());
 
         // 2. Return p.
         return verify_cast<JS::Promise>(*promise_capability->promise().ptr());
@@ -79,11 +80,21 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
 
     // 12. Set controller to the result of calling fetch given request and processResponse given response being these
     //     steps:
-    auto process_response = [&vm, locally_aborted, promise_capability, request, response_object_handle, &relevant_realm](JS::NonnullGCPtr<Infrastructure::Response> response) mutable {
+    auto process_response = [locally_aborted, promise_capability, request, response_object_handle, &relevant_realm](JS::NonnullGCPtr<Infrastructure::Response> response) mutable {
         // 1. If locallyAborted is true, then abort these steps.
         if (locally_aborted->value())
             return;
 
+        // NOTE: Not part of the spec, but we need to have an execution context on the stack to call native functions.
+        //       (In this case, Promise functions)
+        auto& environment_settings_object = Bindings::host_defined_environment_settings_object(relevant_realm);
+        environment_settings_object.prepare_to_run_script();
+
+        ScopeGuard guard = [&]() {
+            // See above NOTE.
+            environment_settings_object.clean_up_after_running_script();
+        };
+
         // 2. If response’s aborted flag is set, then:
         if (response->aborted()) {
             // FIXME: 1. Let deserializedError be the result of deserialize a serialized abort reason given controller’s
@@ -91,7 +102,7 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
             auto deserialized_error = JS::js_undefined();
 
             // 2. Abort the fetch() call with p, request, responseObject, and deserializedError.
-            abort_fetch(vm, promise_capability, request, response_object_handle.cell(), deserialized_error);
+            abort_fetch(relevant_realm, promise_capability, request, response_object_handle.cell(), deserialized_error);
 
             // 3. Abort these steps.
             return;
@@ -100,7 +111,7 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
         // 3. If response is a network error, then reject p with a TypeError and abort these steps.
         if (response->is_network_error()) {
             auto message = response->network_error_message().value_or("Response is a network error"sv);
-            WebIDL::reject_promise(vm, promise_capability, JS::TypeError::create(relevant_realm, message).release_allocated_value_but_fixme_should_propagate_errors());
+            WebIDL::reject_promise(relevant_realm, promise_capability, JS::TypeError::create(relevant_realm, message).release_allocated_value_but_fixme_should_propagate_errors());
             return;
         }
 
@@ -110,7 +121,7 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
         response_object_handle = JS::make_handle(response_object);
 
         // 5. Resolve p with responseObject.
-        WebIDL::resolve_promise(vm, promise_capability, response_object);
+        WebIDL::resolve_promise(relevant_realm, promise_capability, response_object);
     };
     controller = MUST(Fetching::fetch(
         realm,
@@ -126,7 +137,7 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
             })));
 
     // 11. Add the following abort steps to requestObject’s signal:
-    request_object->signal()->add_abort_algorithm([&vm, locally_aborted, request, controller, promise_capability_handle = JS::make_handle(*promise_capability), request_object_handle = JS::make_handle(*request_object), response_object_handle] {
+    request_object->signal()->add_abort_algorithm([locally_aborted, request, controller, promise_capability_handle = JS::make_handle(*promise_capability), request_object_handle = JS::make_handle(*request_object), response_object_handle, &relevant_realm] {
         dbgln_if(WEB_FETCH_DEBUG, "Fetch: Request object signal's abort algorithm called");
 
         auto& promise_capability = *promise_capability_handle;
@@ -140,10 +151,10 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
         VERIFY(controller);
 
         // 3. Abort controller with requestObject’s signal’s abort reason.
-        controller->abort(vm, request_object.signal()->reason());
+        controller->abort(relevant_realm, request_object.signal()->reason());
 
         // 4. Abort the fetch() call with p, request, responseObject, and requestObject’s signal’s abort reason.
-        abort_fetch(vm, promise_capability, request, response_object, request_object.signal()->reason());
+        abort_fetch(relevant_realm, promise_capability, request, response_object, request_object.signal()->reason());
     });
 
     // 13. Return p.
@@ -151,13 +162,13 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
 }
 
 // https://fetch.spec.whatwg.org/#abort-fetch
-void abort_fetch(JS::VM& vm, WebIDL::Promise const& promise, JS::NonnullGCPtr<Infrastructure::Request> request, JS::GCPtr<Response> response_object, JS::Value error)
+void abort_fetch(JS::Realm& realm, WebIDL::Promise const& promise, JS::NonnullGCPtr<Infrastructure::Request> request, JS::GCPtr<Response> response_object, JS::Value error)
 {
     dbgln_if(WEB_FETCH_DEBUG, "Fetch: Aborting fetch with: request @ {}, error = {}", request.ptr(), error);
 
     // 1. Reject promise with error.
     // NOTE: This is a no-op if promise has already fulfilled.
-    WebIDL::reject_promise(vm, promise, error);
+    WebIDL::reject_promise(realm, promise, error);
 
     // 2. If request’s body is non-null and is readable, then cancel request’s body with error.
     if (auto* body = request->body().get_pointer<Infrastructure::Body>(); body != nullptr && body->stream()->is_readable()) {

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/FetchMethod.h

@@ -15,6 +15,6 @@
 namespace Web::Fetch {
 
 JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM&, RequestInfo const& input, RequestInit const& init = {});
-void abort_fetch(JS::VM&, WebIDL::Promise const&, JS::NonnullGCPtr<Infrastructure::Request>, JS::GCPtr<Response>, JS::Value error);
+void abort_fetch(JS::Realm&, WebIDL::Promise const&, JS::NonnullGCPtr<Infrastructure::Request>, JS::GCPtr<Response>, JS::Value error);
 
 }

+ 2 - 2
Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp

@@ -759,7 +759,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm& rea
     // 4. If request’s service-workers mode is "all", then:
     if (request->service_workers_mode() == Infrastructure::Request::ServiceWorkersMode::All) {
         // 1. Let requestForServiceWorker be a clone of request.
-        auto request_for_service_worker = TRY(request->clone(vm));
+        auto request_for_service_worker = TRY(request->clone(realm));
 
         // 2. If requestForServiceWorker’s body is non-null, then:
         if (!request_for_service_worker->body().has<Empty>()) {
@@ -1147,7 +1147,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
             // NOTE: Implementations are encouraged to avoid teeing request’s body’s stream when request’s body’s
             //       source is null as only a single body is needed in that case. E.g., when request’s body’s source
             //       is null, redirects and authentication will end up failing the fetch.
-            http_request = TRY(request->clone(vm));
+            http_request = TRY(request->clone(realm));
 
             // 2. Set httpFetchParams to a copy of fetchParams.
             // 3. Set httpFetchParams’s request to httpRequest.

+ 1 - 3
Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.cpp

@@ -55,10 +55,8 @@ JS::NonnullGCPtr<FetchTimingInfo> FetchController::extract_full_timing_info() co
 }
 
 // https://fetch.spec.whatwg.org/#fetch-controller-abort
-void FetchController::abort(JS::VM& vm, Optional<JS::Value> error)
+void FetchController::abort(JS::Realm& realm, Optional<JS::Value> error)
 {
-    auto& realm = *vm.current_realm();
-
     // 1. Set controller’s state to "aborted".
     m_state = State::Aborted;
 

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.h

@@ -36,7 +36,7 @@ public:
     void report_timing(JS::Object const&) const;
     void process_next_manual_redirect() const;
     [[nodiscard]] JS::NonnullGCPtr<FetchTimingInfo> extract_full_timing_info() const;
-    void abort(JS::VM&, Optional<JS::Value>);
+    void abort(JS::Realm&, Optional<JS::Value>);
     void terminate();
 
 private:

+ 2 - 6
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp

@@ -25,16 +25,12 @@ Body::Body(JS::Handle<Streams::ReadableStream> stream, SourceType source, Option
 }
 
 // https://fetch.spec.whatwg.org/#concept-body-clone
-WebIDL::ExceptionOr<Body> Body::clone() const
+WebIDL::ExceptionOr<Body> Body::clone(JS::Realm& realm) const
 {
     // To clone a body body, run these steps:
-
-    auto& vm = Bindings::main_thread_vm();
-    auto& realm = *vm.current_realm();
-
     // FIXME: 1. Let « out1, out2 » be the result of teeing body’s stream.
     // FIXME: 2. Set body’s stream to out1.
-    auto out2 = MUST_OR_THROW_OOM(vm.heap().allocate<Streams::ReadableStream>(realm, realm));
+    auto out2 = MUST_OR_THROW_OOM(realm.heap().allocate<Streams::ReadableStream>(realm, realm));
 
     // 3. Return a body whose stream is out2 and other members are copied from body.
     return Body { JS::make_handle(out2), m_source, m_length };

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h

@@ -31,7 +31,7 @@ public:
     [[nodiscard]] SourceType const& source() const { return m_source; }
     [[nodiscard]] Optional<u64> const& length() const { return m_length; }
 
-    WebIDL::ExceptionOr<Body> clone() const;
+    WebIDL::ExceptionOr<Body> clone(JS::Realm&) const;
 
     WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> fully_read_as_promise() const;
 

+ 3 - 2
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp

@@ -195,9 +195,10 @@ ErrorOr<ByteBuffer> Request::byte_serialize_origin() const
 }
 
 // https://fetch.spec.whatwg.org/#concept-request-clone
-WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone(JS::VM& vm) const
+WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone(JS::Realm& realm) const
 {
     // To clone a request request, run these steps:
+    auto& vm = realm.vm();
 
     // 1. Let newRequest be a copy of request, except for its body.
     auto new_request = Infrastructure::Request::create(vm);
@@ -242,7 +243,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone(JS::VM& vm) const
 
     // 2. If request’s body is non-null, set newRequest’s body to the result of cloning request’s body.
     if (auto const* body = m_body.get_pointer<Body>())
-        new_request->set_body(TRY(body->clone()));
+        new_request->set_body(TRY(body->clone(realm)));
 
     // 3. Return newRequest.
     return new_request;

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h

@@ -297,7 +297,7 @@ public:
     [[nodiscard]] ErrorOr<String> serialize_origin() const;
     [[nodiscard]] ErrorOr<ByteBuffer> byte_serialize_origin() const;
 
-    [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone(JS::VM&) const;
+    [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone(JS::Realm&) const;
 
     [[nodiscard]] ErrorOr<void> add_range_header(u64 first, Optional<u64> const& last);
     [[nodiscard]] ErrorOr<void> add_origin_header();

+ 4 - 3
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp

@@ -127,13 +127,14 @@ ErrorOr<Optional<AK::URL>> Response::location_url(Optional<String> const& reques
 }
 
 // https://fetch.spec.whatwg.org/#concept-response-clone
-WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone(JS::VM& vm) const
+WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone(JS::Realm& realm) const
 {
     // To clone a response response, run these steps:
+    auto& vm = realm.vm();
 
     // 1. If response is a filtered response, then return a new identical filtered response whose internal response is a clone of response’s internal response.
     if (is<FilteredResponse>(*this)) {
-        auto internal_response = TRY(static_cast<FilteredResponse const&>(*this).internal_response()->clone(vm));
+        auto internal_response = TRY(static_cast<FilteredResponse const&>(*this).internal_response()->clone(realm));
         if (is<BasicFilteredResponse>(*this))
             return TRY_OR_THROW_OOM(vm, BasicFilteredResponse::create(vm, internal_response));
         if (is<CORSFilteredResponse>(*this))
@@ -164,7 +165,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone(JS::VM& vm) cons
 
     // 3. If response’s body is non-null, then set newResponse’s body to the result of cloning response’s body.
     if (m_body.has_value())
-        new_response->set_body(TRY(m_body->clone()));
+        new_response->set_body(TRY(m_body->clone(realm)));
 
     // 4. Return newResponse.
     return new_response;

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h

@@ -106,7 +106,7 @@ public:
     [[nodiscard]] Optional<AK::URL const&> url() const;
     [[nodiscard]] ErrorOr<Optional<AK::URL>> location_url(Optional<String> const& request_fragment) const;
 
-    [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> clone(JS::VM&) const;
+    [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> clone(JS::Realm&) const;
 
     // Non-standard
     [[nodiscard]] Optional<StringView> network_error_message() const;

+ 2 - 2
Userland/Libraries/LibWeb/Fetch/Request.cpp

@@ -634,14 +634,14 @@ Bindings::RequestDuplex Request::duplex() const
 // https://fetch.spec.whatwg.org/#dom-request-clone
 WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone() const
 {
-    auto& vm = this->vm();
+    auto& realm = this->realm();
 
     // 1. If this is unusable, then throw a TypeError.
     if (is_unusable())
         return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request is unusable"sv };
 
     // 2. Let clonedRequest be the result of cloning this’s request.
-    auto cloned_request = TRY(m_request->clone(vm));
+    auto cloned_request = TRY(m_request->clone(realm));
 
     // 3. Let clonedRequestObject be the result of creating a Request object, given clonedRequest, this’s headers’s guard, and this’s relevant Realm.
     auto cloned_request_object = TRY(Request::create(HTML::relevant_realm(*this), cloned_request, m_headers->guard()));

+ 2 - 2
Userland/Libraries/LibWeb/Fetch/Response.cpp

@@ -286,14 +286,14 @@ JS::NonnullGCPtr<Headers> Response::headers() const
 // https://fetch.spec.whatwg.org/#dom-response-clone
 WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone() const
 {
-    auto& vm = this->vm();
+    auto& realm = this->realm();
 
     // 1. If this is unusable, then throw a TypeError.
     if (is_unusable())
         return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Response is unusable"sv };
 
     // 2. Let clonedResponse be the result of cloning this’s response.
-    auto cloned_response = TRY(m_response->clone(vm));
+    auto cloned_response = TRY(m_response->clone(realm));
 
     // 3. Return the result of creating a Response object, given clonedResponse, this’s headers’s guard, and this’s relevant Realm.
     return TRY(Response::create(HTML::relevant_realm(*this), cloned_response, m_headers->guard()));

+ 6 - 4
Userland/Libraries/LibWeb/Infra/JSON.cpp

@@ -15,23 +15,25 @@
 namespace Web::Infra {
 
 // https://infra.spec.whatwg.org/#parse-a-json-string-to-a-javascript-value
-WebIDL::ExceptionOr<JS::Value> parse_json_string_to_javascript_value(JS::VM& vm, StringView string)
+WebIDL::ExceptionOr<JS::Value> parse_json_string_to_javascript_value(JS::Realm& realm, StringView string)
 {
-    auto& realm = *vm.current_realm();
+    auto& vm = realm.vm();
 
     // 1. Return ? Call(%JSON.parse%, undefined, « string »).
     return TRY(JS::call(vm, realm.intrinsics().json_parse_function(), JS::js_undefined(), MUST_OR_THROW_OOM(JS::PrimitiveString::create(vm, string))));
 }
 
 // https://infra.spec.whatwg.org/#parse-json-bytes-to-a-javascript-value
-WebIDL::ExceptionOr<JS::Value> parse_json_bytes_to_javascript_value(JS::VM& vm, ReadonlyBytes bytes)
+WebIDL::ExceptionOr<JS::Value> parse_json_bytes_to_javascript_value(JS::Realm& realm, ReadonlyBytes bytes)
 {
+    auto& vm = realm.vm();
+
     // 1. Let string be the result of running UTF-8 decode on bytes.
     TextCodec::UTF8Decoder decoder;
     auto string = TRY_OR_THROW_OOM(vm, decoder.to_utf8(bytes));
 
     // 2. Return the result of parsing a JSON string to an Infra value given string.
-    return parse_json_string_to_javascript_value(vm, string);
+    return parse_json_string_to_javascript_value(realm, string);
 }
 
 // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string

+ 2 - 2
Userland/Libraries/LibWeb/Infra/JSON.h

@@ -12,8 +12,8 @@
 
 namespace Web::Infra {
 
-WebIDL::ExceptionOr<JS::Value> parse_json_string_to_javascript_value(JS::VM&, StringView);
-WebIDL::ExceptionOr<JS::Value> parse_json_bytes_to_javascript_value(JS::VM&, ReadonlyBytes);
+WebIDL::ExceptionOr<JS::Value> parse_json_string_to_javascript_value(JS::Realm&, StringView);
+WebIDL::ExceptionOr<JS::Value> parse_json_bytes_to_javascript_value(JS::Realm&, ReadonlyBytes);
 WebIDL::ExceptionOr<String> serialize_javascript_value_to_json_string(JS::VM&, JS::Value);
 WebIDL::ExceptionOr<ByteBuffer> serialize_javascript_value_to_json_bytes(JS::VM&, JS::Value);
 

+ 7 - 3
Userland/Libraries/LibWeb/WebIDL/Promise.cpp

@@ -10,6 +10,7 @@
 #include <LibJS/Runtime/PromiseConstructor.h>
 #include <LibJS/Runtime/Realm.h>
 #include <LibWeb/Bindings/ExceptionOrUtils.h>
+#include <LibWeb/Bindings/HostDefined.h>
 #include <LibWeb/WebIDL/ExceptionOr.h>
 #include <LibWeb/WebIDL/Promise.h>
 
@@ -69,20 +70,23 @@ JS::NonnullGCPtr<Promise> create_rejected_promise(JS::Realm& realm, JS::Value re
 }
 
 // https://webidl.spec.whatwg.org/#resolve
-void resolve_promise(JS::VM& vm, Promise const& promise, JS::Value value)
+void resolve_promise(JS::Realm& realm, Promise const& promise, JS::Value value)
 {
+    auto& vm = realm.vm();
+
     // 1. If x is not given, then let it be the undefined value.
     // NOTE: This is done via the default argument.
 
     // 2. Let value be the result of converting x to an ECMAScript value.
-
     // 3. Perform ! Call(p.[[Resolve]], undefined, « value »).
     MUST(JS::call(vm, *promise.resolve(), JS::js_undefined(), value));
 }
 
 // https://webidl.spec.whatwg.org/#reject
-void reject_promise(JS::VM& vm, Promise const& promise, JS::Value reason)
+void reject_promise(JS::Realm& realm, Promise const& promise, JS::Value reason)
 {
+    auto& vm = realm.vm();
+
     // 1. Perform ! Call(p.[[Reject]], undefined, « r »).
     MUST(JS::call(vm, *promise.reject(), JS::js_undefined(), reason));
 }

+ 2 - 2
Userland/Libraries/LibWeb/WebIDL/Promise.h

@@ -22,8 +22,8 @@ using Promise = JS::PromiseCapability;
 JS::NonnullGCPtr<Promise> create_promise(JS::Realm&);
 JS::NonnullGCPtr<Promise> create_resolved_promise(JS::Realm&, JS::Value);
 JS::NonnullGCPtr<Promise> create_rejected_promise(JS::Realm&, JS::Value);
-void resolve_promise(JS::VM&, Promise const&, JS::Value = JS::js_undefined());
-void reject_promise(JS::VM&, Promise const&, 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);

+ 1 - 1
Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp

@@ -182,7 +182,7 @@ WebIDL::ExceptionOr<JS::Value> XMLHttpRequest::response()
             return JS::js_null();
 
         // 3. Let jsonObject be the result of running parse JSON from bytes on this’s received bytes. If that threw an exception, then return null.
-        auto json_object_result = Infra::parse_json_bytes_to_javascript_value(vm, m_received_bytes);
+        auto json_object_result = Infra::parse_json_bytes_to_javascript_value(realm(), m_received_bytes);
         if (json_object_result.is_error())
             return JS::js_null();