diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 88c62bda636..dda2344b544 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -606,9 +606,9 @@ WebIDL::ExceptionOr Document::open(Optional const&, Optional< // because subsequent steps will modify "initial about:blank" to false, which would cause // initial navigation to fail in case it was "about:blank". if (auto navigable = this->navigable(); navigable && navigable->container() && !navigable->container()->content_navigable_initialized()) { - HTML::main_thread_event_loop().spin_processing_tasks_with_source_until(HTML::Task::Source::NavigationAndTraversal, [navigable_container = navigable->container()] { + HTML::main_thread_event_loop().spin_processing_tasks_with_source_until(HTML::Task::Source::NavigationAndTraversal, JS::create_heap_function(heap(), [navigable_container = navigable->container()] { return navigable_container->content_navigable_initialized(); - }); + })); } // 1. If document is an XML document, then throw an "InvalidStateError" DOMException exception. @@ -3451,9 +3451,9 @@ void Document::destroy_a_document_and_its_descendants(JS::GCPtr new_doc })); } - HTML::main_thread_event_loop().spin_until([&] { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&] { return number_unloaded == unloaded_documents_count; - }); + })); destroy_a_document_and_its_descendants(move(after_all_unloads)); } diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index 4991efa425d..d385980f2e9 100644 --- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -332,15 +332,15 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Inf request->current_url().set_scheme("https"_string); } - JS::SafeFunction>()> get_response = [&realm, &vm, &fetch_params, request]() -> WebIDL::ExceptionOr> { + auto get_response = JS::create_heap_function(vm.heap(), [&realm, &vm, &fetch_params, request]() -> WebIDL::ExceptionOr> { dbgln_if(WEB_FETCH_DEBUG, "Fetch: Running 'main fetch' get_response() function"); // -> fetchParams’s preloaded response candidate is not null if (!fetch_params.preloaded_response_candidate().has()) { // 1. Wait until fetchParams’s preloaded response candidate is not "pending". - HTML::main_thread_event_loop().spin_until([&] { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(vm.heap(), [&] { return !fetch_params.preloaded_response_candidate().has(); - }); + })); // 2. Assert: fetchParams’s preloaded response candidate is a response. VERIFY(fetch_params.preloaded_response_candidate().has>()); @@ -426,13 +426,13 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Inf // 2. Return the result of running HTTP fetch given fetchParams. return http_fetch(realm, fetch_params); } - }; + }); if (recursive == Recursive::Yes) { // 12. If response is null, then set response to the result of running the steps corresponding to the first // matching statement: auto pending_response = !response - ? TRY(get_response()) + ? TRY(get_response->function()()) : PendingResponse::create(vm, request, *response); // 13. If recursive is true, then return response. @@ -440,12 +440,12 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Inf } // 11. If recursive is false, then run the remaining steps in parallel. - Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(realm.heap(), [&realm, &vm, &fetch_params, request, response, get_response = move(get_response)] { + Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(realm.heap(), [&realm, &vm, &fetch_params, request, response, get_response] { // 12. If response is null, then set response to the result of running the steps corresponding to the first // matching statement: auto pending_response = PendingResponse::create(vm, request, Infrastructure::Response::create(vm)); if (!response) { - auto pending_response_or_error = get_response(); + auto pending_response_or_error = get_response->function()(); if (pending_response_or_error.is_error()) return; pending_response = pending_response_or_error.release_value(); diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index f7a91c0c4f4..45f6954f36f 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -69,7 +69,7 @@ EventLoop& main_thread_event_loop() } // https://html.spec.whatwg.org/multipage/webappapis.html#spin-the-event-loop -void EventLoop::spin_until(JS::SafeFunction goal_condition) +void EventLoop::spin_until(JS::NonnullGCPtr> goal_condition) { // FIXME: The spec wants us to do the rest of the enclosing algorithm (i.e. the caller) // in the context of the currently running task on entry. That's not possible with this implementation. @@ -92,15 +92,15 @@ void EventLoop::spin_until(JS::SafeFunction goal_condition) // 2. Perform any steps that appear after this spin the event loop instance in the original algorithm. // NOTE: This is achieved by returning from the function. - Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(heap(), [&] { - if (goal_condition()) + Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(heap(), [this, goal_condition] { + if (goal_condition->function()()) return true; if (m_task_queue->has_runnable_tasks()) { schedule(); // FIXME: Remove the platform event loop plugin so that this doesn't look out of place Core::EventLoop::current().wake(); } - return goal_condition(); + return goal_condition->function()(); })); vm.restore_execution_context_stack(); @@ -109,7 +109,7 @@ void EventLoop::spin_until(JS::SafeFunction goal_condition) // NOTE: This is achieved by returning from the function. } -void EventLoop::spin_processing_tasks_with_source_until(Task::Source source, JS::SafeFunction goal_condition) +void EventLoop::spin_processing_tasks_with_source_until(Task::Source source, JS::NonnullGCPtr> goal_condition) { auto& vm = this->vm(); vm.save_execution_context_stack(); @@ -120,8 +120,8 @@ void EventLoop::spin_processing_tasks_with_source_until(Task::Source source, JS: // NOTE: HTML event loop processing steps could run a task with arbitrary source m_skip_event_loop_processing_steps = true; - Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(heap(), [&] { - if (goal_condition()) + Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(heap(), [this, source, goal_condition] { + if (goal_condition->function()()) return true; if (m_task_queue->has_runnable_tasks()) { auto tasks = m_task_queue->take_tasks_matching([&](auto& task) { @@ -137,7 +137,7 @@ void EventLoop::spin_processing_tasks_with_source_until(Task::Source source, JS: // FIXME: Remove the platform event loop plugin so that this doesn't look out of place Core::EventLoop::current().wake(); - return goal_condition(); + return goal_condition->function()(); })); m_skip_event_loop_processing_steps = false; diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index 9558aa925a9..e197c9b9801 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace Web::HTML { @@ -39,8 +38,8 @@ public: TaskQueue& microtask_queue() { return *m_microtask_queue; } TaskQueue const& microtask_queue() const { return *m_microtask_queue; } - void spin_until(JS::SafeFunction goal_condition); - void spin_processing_tasks_with_source_until(Task::Source, JS::SafeFunction goal_condition); + void spin_until(JS::NonnullGCPtr> goal_condition); + void spin_processing_tasks_with_source_until(Task::Source, JS::NonnullGCPtr> goal_condition); void process(); void queue_task_to_update_the_rendering(); diff --git a/Userland/Libraries/LibWeb/HTML/EventSource.cpp b/Userland/Libraries/LibWeb/HTML/EventSource.cpp index feab1c2f094..089006b1b48 100644 --- a/Userland/Libraries/LibWeb/HTML/EventSource.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventSource.cpp @@ -298,9 +298,9 @@ void EventSource::reestablish_the_connection() })); // 2. Wait a delay equal to the reconnection time of the event source. - HTML::main_thread_event_loop().spin_until([&, delay_start = MonotonicTime::now()]() { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&, delay_start = MonotonicTime::now()]() { return (MonotonicTime::now() - delay_start) >= m_reconnection_time; - }); + })); // 3. Optionally, wait some more. In particular, if the previous attempt failed, then user agents might introduce // an exponential backoff delay to avoid overloading a potentially already overloaded server. Alternatively, if @@ -309,7 +309,7 @@ void EventSource::reestablish_the_connection() // 4. Wait until the aforementioned task has run, if it has not yet run. if (!initial_task_has_run) { - HTML::main_thread_event_loop().spin_until([&]() { return initial_task_has_run; }); + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&]() { return initial_task_has_run; })); } // 5. Queue a task to run the following steps: diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index cdf25b1d17b..b6994bfc056 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -862,7 +862,7 @@ WebIDL::ExceptionOr HTMLMediaElement::select_resource() }); // 7. Wait for the task queued by the previous step to have executed. - HTML::main_thread_event_loop().spin_until([&]() { return ran_media_element_task; }); + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&]() { return ran_media_element_task; })); }; // 1. ⌛ If the src attribute's value is the empty string, then end the synchronous section, and jump down to the failed with attribute step below. @@ -1580,7 +1580,7 @@ void HTMLMediaElement::seek_element(double playback_position, MediaSeekMode seek // available, and, if it is, until it has decoded enough data to play back that position. m_seek_in_progress = true; on_seek(playback_position, seek_mode); - HTML::main_thread_event_loop().spin_until([&]() { return !m_seek_in_progress; }); + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&]() { return !m_seek_in_progress; })); // FIXME: 13. Await a stable state. The synchronous section consists of all the remaining steps of this algorithm. (Steps in the // synchronous section are marked with ⌛.) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index 2428ee2d987..554ebe5d932 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -86,7 +86,7 @@ void HTMLScriptElement::execute_script() // https://html.spec.whatwg.org/multipage/document-lifecycle.html#read-html // Before any script execution occurs, the user agent must wait for scripts may run for the newly-created document to be true for document. if (!m_document->ready_to_run_scripts()) - main_thread_event_loop().spin_until([&] { return m_document->ready_to_run_scripts(); }); + main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&] { return m_document->ready_to_run_scripts(); })); // 1. Let document be el's node document. JS::NonnullGCPtr document = this->document(); diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.cpp b/Userland/Libraries/LibWeb/HTML/Navigable.cpp index 57a5d914109..19ca8fdac50 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigable.cpp @@ -883,7 +883,7 @@ static WebIDL::ExceptionOr create_navigation } // 7. Wait until either response is non-null, or navigable's ongoing navigation changes to no longer equal navigationId. - HTML::main_thread_event_loop().spin_until([&]() { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(vm.heap(), [&]() { if (response_holder->response() != nullptr) return true; @@ -891,7 +891,7 @@ static WebIDL::ExceptionOr create_navigation return true; return false; - }); + })); // If the latter condition occurs, then abort fetchController, and return. Otherwise, proceed onward. if (navigation_id.has_value() && (!navigable->ongoing_navigation().has() || navigable->ongoing_navigation().get() != *navigation_id)) { fetch_controller->abort(realm, {}); diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index 3f7e36e0f53..eddc92cf30e 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -231,6 +231,8 @@ void HTMLParser::run(const URL::URL& url, HTMLTokenizer::StopAtInsertionPoint st // https://html.spec.whatwg.org/multipage/parsing.html#the-end void HTMLParser::the_end(JS::NonnullGCPtr document, JS::GCPtr parser) { + auto& heap = document->heap(); + // Once the user agent stops parsing the document, the user agent must run the following steps: // NOTE: This is a static method because the spec sometimes wants us to "act as if the user agent had stopped @@ -281,10 +283,10 @@ void HTMLParser::the_end(JS::NonnullGCPtr document, JS::GCPtrscripts_to_execute_when_parsing_has_finished().is_empty()) { // 1. Spin the event loop until the first script in the list of scripts that will execute when the document has finished parsing // has its "ready to be parser-executed" flag set and the parser's Document has no style sheet that is blocking scripts. - main_thread_event_loop().spin_until([&] { + main_thread_event_loop().spin_until(JS::create_heap_function(heap, [&] { return document->scripts_to_execute_when_parsing_has_finished().first()->is_ready_to_be_parser_executed() && !document->has_a_style_sheet_that_is_blocking_scripts(); - }); + })); // 2. Execute the first script in the list of scripts that will execute when the document has finished parsing. document->scripts_to_execute_when_parsing_has_finished().first()->execute_script(); @@ -294,7 +296,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr document, JS::GCPtrheap(), [document = document] { + queue_global_task(HTML::Task::Source::DOMManipulation, *document, JS::create_heap_function(heap, [document = document] { // 1. Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object. document->load_timing_info().dom_content_loaded_event_start_time = HighResolutionTime::current_high_resolution_time(relevant_global_object(*document)); @@ -312,14 +314,14 @@ void HTMLParser::the_end(JS::NonnullGCPtr document, JS::GCPtrscripts_to_execute_as_soon_as_possible().is_empty(); - }); + })); // 8. Spin the event loop until there is nothing that delays the load event in the Document. - main_thread_event_loop().spin_until([&] { + main_thread_event_loop().spin_until(JS::create_heap_function(heap, [&] { return !document->anything_is_delaying_the_load_event(); - }); + })); // 9. Queue a global task on the DOM manipulation task source given the Document's relevant global object to run the following steps: queue_global_task(HTML::Task::Source::DOMManipulation, *document, JS::create_heap_function(document->heap(), [document = document] { @@ -2940,9 +2942,9 @@ void HTMLParser::handle_text(HTMLToken& token) if (m_document->has_a_style_sheet_that_is_blocking_scripts() || the_script->is_ready_to_be_parser_executed() == false) { // spin the event loop until the parser's Document has no style sheet that is blocking scripts // and the script's ready to be parser-executed becomes true. - main_thread_event_loop().spin_until([&] { + main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&] { return !m_document->has_a_style_sheet_that_is_blocking_scripts() && the_script->is_ready_to_be_parser_executed(); - }); + })); } // 6. If this parser has been aborted in the meantime, return. diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp index 05179839b95..ea09c7631a1 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp @@ -505,9 +505,9 @@ WebIDL::ExceptionOr> fetch_a_classic_worker_impo // 5. Pause until response is not null. auto& event_loop = settings_object.responsible_event_loop(); - event_loop.spin_until([&]() { + event_loop.spin_until(JS::create_heap_function(vm.heap(), [&]() -> bool { return response; - }); + })); // 6. Set response to response's unsafe response. response = response->unsafe_response(); diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp index a9d4fe26f1b..fcc18f6c2ee 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -659,16 +659,16 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ })); } - auto check_if_document_population_tasks_completed = JS::SafeFunction([&] { + auto check_if_document_population_tasks_completed = JS::create_heap_function(heap(), [&] { return changing_navigable_continuations.size() + completed_change_jobs == total_change_jobs; }); if (synchronous_navigation == SynchronousNavigation::Yes) { // NOTE: Synchronous navigation should never require document population, so it is safe to process only NavigationAndTraversal source. - main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, move(check_if_document_population_tasks_completed)); + main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, check_if_document_population_tasks_completed); } else { // NOTE: Process all task sources while waiting because reloading or back/forward navigation might require fetching to populate a document. - main_thread_event_loop().spin_until(move(check_if_document_population_tasks_completed)); + main_thread_event_loop().spin_until(check_if_document_population_tasks_completed); } // 13. Let navigablesThatMustWaitBeforeHandlingSyncNavigation be an empty set. @@ -788,9 +788,9 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ } } - main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, [&] { + main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, JS::create_heap_function(heap(), [&] { return completed_change_jobs == total_change_jobs; - }); + })); // 15. Let totalNonchangingJobs be the size of nonchangingNavigablesThatStillNeedUpdates. auto total_non_changing_jobs = non_changing_navigables_that_still_need_updates.size(); @@ -836,9 +836,9 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ // AD-HOC: Since currently populate_session_history_entry_document does not run in parallel // we call spin_until to interrupt execution of this function and let document population // to complete. - main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, [&] { + main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, JS::create_heap_function(heap(), [&] { return completed_non_changing_jobs == total_non_changing_jobs; - }); + })); // 20. Set traversable's current session history step to targetStep. m_current_session_history_step = target_step; @@ -941,9 +941,9 @@ TraversableNavigable::CheckIfUnloadingIsCanceledResult TraversableNavigable::che })); // 6. Wait for eventsFired to be true. - main_thread_event_loop().spin_until([&] { + main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&] { return events_fired; - }); + })); // 7. If finalStatus is not "continue", then return finalStatus. if (final_status != CheckIfUnloadingIsCanceledResult::Continue) @@ -977,9 +977,9 @@ TraversableNavigable::CheckIfUnloadingIsCanceledResult TraversableNavigable::che } // 8. Wait for completedTasks to be totalTasks. - main_thread_event_loop().spin_until([&] { + main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&] { return completed_tasks == total_tasks; - }); + })); // 9. Return finalStatus. return final_status; diff --git a/Userland/Libraries/LibWeb/SVG/SVGScriptElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGScriptElement.cpp index 5fba6e28ff7..a85f898eef7 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGScriptElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGScriptElement.cpp @@ -61,7 +61,7 @@ void SVGScriptElement::process_the_script_element() // https://html.spec.whatwg.org/multipage/document-lifecycle.html#read-html // Before any script execution occurs, the user agent must wait for scripts may run for the newly-created document to be true for document. if (!m_document->ready_to_run_scripts()) - HTML::main_thread_event_loop().spin_until([&] { return m_document->ready_to_run_scripts(); }); + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap(), [&] { return m_document->ready_to_run_scripts(); })); // FIXME: Support non-inline scripts. auto& settings_object = document().relevant_settings_object(); diff --git a/Userland/Libraries/LibWeb/ServiceWorker/Job.cpp b/Userland/Libraries/LibWeb/ServiceWorker/Job.cpp index 1892ba6af1a..e2efcf3530b 100644 --- a/Userland/Libraries/LibWeb/ServiceWorker/Job.cpp +++ b/Userland/Libraries/LibWeb/ServiceWorker/Job.cpp @@ -359,7 +359,7 @@ static void update(JS::VM& vm, JS::NonnullGCPtr job) // FIXME: This feels.. uncomfortable but it should work to block the current task until the fetch has progressed past our processResponse hook or aborted auto& event_loop = job->client ? job->client->responsible_event_loop() : HTML::main_thread_event_loop(); - event_loop.spin_until([fetch_controller, &realm, &process_response_completion_result]() -> bool { + event_loop.spin_until(JS::create_heap_function(realm.heap(), [fetch_controller, &realm, &process_response_completion_result]() -> bool { if (process_response_completion_result.has_value()) return true; if (fetch_controller->state() == Fetch::Infrastructure::FetchController::State::Terminated || fetch_controller->state() == Fetch::Infrastructure::FetchController::State::Aborted) { @@ -367,7 +367,7 @@ static void update(JS::VM& vm, JS::NonnullGCPtr job) return true; } return false; - }); + })); return process_response_completion_result.release_value(); }; diff --git a/Userland/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp b/Userland/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp index 5f7b273e7d9..01c4ffbf5c1 100644 --- a/Userland/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp +++ b/Userland/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp @@ -177,9 +177,9 @@ void XMLDocumentBuilder::element_end(const XML::Name& name) // 2. Spin the event loop until the parser's Document has no style sheet that is blocking scripts and the pending parsing-blocking script's "ready to be parser-executed" flag is set. if (m_document->has_a_style_sheet_that_is_blocking_scripts() || !pending_parsing_blocking_script->is_ready_to_be_parser_executed()) { - HTML::main_thread_event_loop().spin_until([&] { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(script_element.heap(), [&] { return !m_document->has_a_style_sheet_that_is_blocking_scripts() && pending_parsing_blocking_script->is_ready_to_be_parser_executed(); - }); + })); } // 3. Unblock this instance of the XML parser, such that tasks that invoke it can again be run. @@ -231,6 +231,8 @@ void XMLDocumentBuilder::comment(StringView data) void XMLDocumentBuilder::document_end() { + auto& heap = m_document->heap(); + // When an XML parser reaches the end of its input, it must stop parsing. // If the active speculative HTML parser is not null, then stop the speculative HTML parser and return. // NOTE: Noop. @@ -248,10 +250,10 @@ void XMLDocumentBuilder::document_end() while (!m_document->scripts_to_execute_when_parsing_has_finished().is_empty()) { // Spin the event loop until the first script in the list of scripts that will execute when the document has finished parsing has its "ready to be parser-executed" flag set // and the parser's Document has no style sheet that is blocking scripts. - HTML::main_thread_event_loop().spin_until([&] { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap, [&] { return m_document->scripts_to_execute_when_parsing_has_finished().first()->is_ready_to_be_parser_executed() && !m_document->has_a_style_sheet_that_is_blocking_scripts(); - }); + })); // Execute the first script in the list of scripts that will execute when the document has finished parsing. m_document->scripts_to_execute_when_parsing_has_finished().first()->execute_script(); @@ -278,14 +280,14 @@ void XMLDocumentBuilder::document_end() })); // Spin the event loop until the set of scripts that will execute as soon as possible and the list of scripts that will execute in order as soon as possible are empty. - HTML::main_thread_event_loop().spin_until([&] { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap, [&] { return m_document->scripts_to_execute_as_soon_as_possible().is_empty(); - }); + })); // Spin the event loop until there is nothing that delays the load event in the Document. - HTML::main_thread_event_loop().spin_until([&] { + HTML::main_thread_event_loop().spin_until(JS::create_heap_function(heap, [&] { return !m_document->anything_is_delaying_the_load_event(); - }); + })); // Queue a global task on the DOM manipulation task source given the Document's relevant global object to run the following steps: queue_global_task(HTML::Task::Source::DOMManipulation, m_document, JS::create_heap_function(m_document->heap(), [document = m_document] {