From c97ec1b2fb687cdce5f8d839e2d85b3e5d9ff3a4 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sat, 30 Aug 2025 12:51:40 -0400 Subject: [PATCH] script: Reduce ScriptThread TLS usage (#38875) We store a pointer to the ScriptThread singleton for a thread in thread-local storage. While we don't have yet have profiles pointing to this TLS access as a hot spot, we can remove a potential performance footgun without a lot of effort by passing around small pieces of data that we otherwise need to fetch from the ScriptThread. Testing: Existing WPT is sufficient Fixes: part of #37969 --------- Signed-off-by: Josh Matthews --- .../script/dom/abstractworkerglobalscope.rs | 6 +- components/script/dom/bindings/constructor.rs | 9 --- components/script/dom/bindings/utils.rs | 9 ++- .../script/dom/customelementregistry.rs | 4 ++ components/script/dom/document.rs | 18 ++++- components/script/dom/domimplementation.rs | 2 + components/script/dom/domparser.rs | 2 + components/script/dom/node.rs | 3 +- .../script/dom/servoparser/async_html.rs | 25 ++++++- components/script/dom/servoparser/html.rs | 2 + components/script/dom/servoparser/mod.rs | 26 ++++++-- components/script/dom/servoparser/xml.rs | 1 + components/script/dom/xmldocument.rs | 7 ++ components/script/dom/xmlhttprequest.rs | 1 + components/script/messaging.rs | 7 +- components/script/script_thread.rs | 65 +++++++++---------- components/script/task_queue.rs | 10 ++- 17 files changed, 129 insertions(+), 68 deletions(-) diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs index 89676edc9c8..95a29dcbe71 100644 --- a/components/script/dom/abstractworkerglobalscope.rs +++ b/components/script/dom/abstractworkerglobalscope.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::collections::HashSet; + use crossbeam_channel::{Receiver, select}; use devtools_traits::DevtoolScriptControlMsg; @@ -53,7 +55,7 @@ pub(crate) fn run_worker_event_loop( let event = select! { recv(worker_scope.control_receiver()) -> msg => T::from_control_msg(msg.unwrap()), recv(task_queue.select()) -> msg => { - task_queue.take_tasks(msg.unwrap()); + task_queue.take_tasks(msg.unwrap(), &HashSet::new()); T::from_worker_msg(task_queue.recv().unwrap()) }, recv(devtools_receiver) -> msg => T::from_devtools_msg(msg.unwrap()), @@ -72,7 +74,7 @@ pub(crate) fn run_worker_event_loop( while !scope.is_closing() { // Batch all events that are ready. // The task queue will throttle non-priority tasks if necessary. - match task_queue.take_tasks_and_recv() { + match task_queue.take_tasks_and_recv(&HashSet::new()) { Err(_) => match devtools_receiver.try_recv() { Ok(message) => sequential.push(T::from_devtools_msg(message)), Err(_) => break, diff --git a/components/script/dom/bindings/constructor.rs b/components/script/dom/bindings/constructor.rs index 8abf4b78f5a..ab78875b4dc 100644 --- a/components/script/dom/bindings/constructor.rs +++ b/components/script/dom/bindings/constructor.rs @@ -52,7 +52,6 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::window::Window; use crate::script_runtime::{CanGc, JSContext, JSContext as SafeJSContext}; -use crate::script_thread::ScriptThread; /// fn html_constructor( @@ -391,14 +390,6 @@ fn get_constructor_object_from_local_name( true } -pub(crate) fn pop_current_element_queue(can_gc: CanGc) { - ScriptThread::pop_current_element_queue(can_gc); -} - -pub(crate) fn push_new_element_queue() { - ScriptThread::push_new_element_queue(); -} - pub(crate) fn call_html_constructor + DomObject>( cx: JSContext, args: &CallArgs, diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 4ea98f02641..8ee758a700e 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -19,9 +19,7 @@ use script_bindings::settings_stack::StackEntry; use crate::DomTypes; use crate::dom::bindings::codegen::{InterfaceObjectMap, PrototypeList}; -use crate::dom::bindings::constructor::{ - call_html_constructor, pop_current_element_queue, push_new_element_queue, -}; +use crate::dom::bindings::constructor::call_html_constructor; use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::error::{Error, report_pending_exception, throw_dom_exception}; use crate::dom::bindings::principals::PRINCIPALS_CALLBACKS; @@ -33,6 +31,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::windowproxy::WindowProxyHandler; use crate::realms::InRealm; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; +use crate::script_thread::ScriptThread; #[derive(JSTraceable, MallocSizeOf)] /// Static data associated with a global object. @@ -185,10 +184,10 @@ impl DomHelpers for crate::DomTypeHolder { } fn push_new_element_queue() { - push_new_element_queue() + ScriptThread::custom_element_reaction_stack().push_new_element_queue() } fn pop_current_element_queue(can_gc: CanGc) { - pop_current_element_queue(can_gc) + ScriptThread::custom_element_reaction_stack().pop_current_element_queue(can_gc) } fn reflect_dom_object(obj: Box, global: &U, can_gc: CanGc) -> DomRoot diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index 577e8a3f938..a5c957f937e 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -1044,8 +1044,12 @@ enum BackupElementQueueFlag { } /// +/// # Safety +/// This can be shared inside an Rc because one of those Rc copies lives +/// inside ScriptThread, so the GC can always reach this structure. #[derive(JSTraceable, MallocSizeOf)] #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] +#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_in_rc)] pub(crate) struct CustomElementReactionStack { stack: DomRefCell>, backup_queue: ElementQueue, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 8c1f81adb3a..379b2f8329b 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -124,7 +124,7 @@ use crate::dom::cdatasection::CDATASection; use crate::dom::comment::Comment; use crate::dom::compositionevent::CompositionEvent; use crate::dom::cssstylesheet::CSSStyleSheet; -use crate::dom::customelementregistry::CustomElementDefinition; +use crate::dom::customelementregistry::{CustomElementDefinition, CustomElementReactionStack}; use crate::dom::customevent::CustomEvent; use crate::dom::document_event_handler::DocumentEventHandler; use crate::dom::documentfragment::DocumentFragment; @@ -565,6 +565,10 @@ pub(crate) struct Document { /// this `Document` will not perform any more rendering updates. #[no_trace] current_canvas_epoch: RefCell, + + /// The global custom element reaction stack for this script thread. + #[conditional_malloc_size_of] + custom_element_reaction_stack: Rc, } #[allow(non_snake_case)] @@ -3261,6 +3265,7 @@ impl Document { allow_declarative_shadow_roots: bool, inherited_insecure_requests_policy: Option, has_trustworthy_ancestor_origin: bool, + custom_element_reaction_stack: Rc, ) -> Document { let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap()); @@ -3434,6 +3439,7 @@ impl Document { resize_observer_started_observing_target: Cell::new(false), waiting_on_canvas_image_updates: Cell::new(false), current_canvas_epoch: RefCell::new(Epoch(0)), + custom_element_reaction_stack, } } @@ -3536,6 +3542,7 @@ impl Document { allow_declarative_shadow_roots: bool, inherited_insecure_requests_policy: Option, has_trustworthy_ancestor_origin: bool, + custom_element_reaction_stack: Rc, can_gc: CanGc, ) -> DomRoot { Self::new_with_proto( @@ -3557,6 +3564,7 @@ impl Document { allow_declarative_shadow_roots, inherited_insecure_requests_policy, has_trustworthy_ancestor_origin, + custom_element_reaction_stack, can_gc, ) } @@ -3581,6 +3589,7 @@ impl Document { allow_declarative_shadow_roots: bool, inherited_insecure_requests_policy: Option, has_trustworthy_ancestor_origin: bool, + custom_element_reaction_stack: Rc, can_gc: CanGc, ) -> DomRoot { let document = reflect_dom_object_with_proto( @@ -3602,6 +3611,7 @@ impl Document { allow_declarative_shadow_roots, inherited_insecure_requests_policy, has_trustworthy_ancestor_origin, + custom_element_reaction_stack, )), window, proto, @@ -3736,6 +3746,7 @@ impl Document { self.allow_declarative_shadow_roots(), Some(self.insecure_requests_policy()), self.has_trustworthy_ancestor_or_current_origin(), + self.custom_element_reaction_stack.clone(), can_gc, ); new_doc @@ -4413,6 +4424,10 @@ impl Document { pub(crate) fn highlighted_dom_node(&self) -> Option> { self.highlighted_dom_node.get() } + + pub(crate) fn custom_element_reaction_stack(&self) -> Rc { + self.custom_element_reaction_stack.clone() + } } #[allow(non_snake_case)] @@ -4444,6 +4459,7 @@ impl DocumentMethods for Document { doc.allow_declarative_shadow_roots(), Some(doc.insecure_requests_policy()), doc.has_trustworthy_ancestor_or_current_origin(), + doc.custom_element_reaction_stack(), can_gc, )) } diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs index bfd9c9967aa..17b864bc219 100644 --- a/components/script/dom/domimplementation.rs +++ b/components/script/dom/domimplementation.rs @@ -117,6 +117,7 @@ impl DOMImplementationMethods for DOMImplementation { loader, Some(self.document.insecure_requests_policy()), self.document.has_trustworthy_ancestor_or_current_origin(), + self.document.custom_element_reaction_stack(), can_gc, ); @@ -184,6 +185,7 @@ impl DOMImplementationMethods for DOMImplementation { self.document.allow_declarative_shadow_roots(), Some(self.document.insecure_requests_policy()), self.document.has_trustworthy_ancestor_or_current_origin(), + self.document.custom_element_reaction_stack(), can_gc, ); diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs index a201ed8a9e3..1c56d629871 100644 --- a/components/script/dom/domparser.rs +++ b/components/script/dom/domparser.rs @@ -104,6 +104,7 @@ impl DOMParserMethods for DOMParser { false, Some(doc.insecure_requests_policy()), doc.has_trustworthy_ancestor_or_current_origin(), + doc.custom_element_reaction_stack(), can_gc, ); // Step switch-1. Parse HTML from a string given document and compliantString. @@ -131,6 +132,7 @@ impl DOMParserMethods for DOMParser { false, Some(doc.insecure_requests_policy()), doc.has_trustworthy_ancestor_or_current_origin(), + doc.custom_element_reaction_stack(), can_gc, ); // Step switch-1. Create an XML parser parser, associated with document, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a0cbe563780..efa698291b4 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -326,7 +326,7 @@ impl Node { /// Implements the "unsafely set HTML" algorithm as specified in: /// - pub fn unsafely_set_html( + pub(crate) fn unsafely_set_html( target: &Node, context_element: &Element, html: DOMString, @@ -2926,6 +2926,7 @@ impl Node { document.allow_declarative_shadow_roots(), Some(document.insecure_requests_policy()), document.has_trustworthy_ancestor_or_current_origin(), + document.custom_element_reaction_stack(), can_gc, ); DomRoot::upcast::(document) diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs index 9c58e34affa..4da99095a89 100644 --- a/components/script/dom/servoparser/async_html.rs +++ b/components/script/dom/servoparser/async_html.rs @@ -8,6 +8,7 @@ use std::borrow::Cow; use std::cell::{Cell, Ref, RefCell, RefMut}; use std::collections::HashMap; use std::collections::vec_deque::VecDeque; +use std::rc::Rc; use std::thread; use crossbeam_channel::{Receiver, Sender, unbounded}; @@ -29,6 +30,7 @@ use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::comment::Comment; +use crate::dom::customelementregistry::CustomElementReactionStack; use crate::dom::document::Document; use crate::dom::documenttype::DocumentType; use crate::dom::element::{Element, ElementCreator}; @@ -228,6 +230,8 @@ pub(crate) struct Tokenizer { #[no_trace] url: ServoUrl, parsing_algorithm: ParsingAlgorithm, + #[conditional_malloc_size_of] + custom_element_reaction_stack: Rc, } impl Tokenizer { @@ -246,6 +250,7 @@ impl Tokenizer { None => ParsingAlgorithm::Normal, }; + let custom_element_reaction_stack = document.custom_element_reaction_stack(); let tokenizer = Tokenizer { document: Dom::from_ref(document), receiver: tokenizer_receiver, @@ -253,6 +258,7 @@ impl Tokenizer { nodes: RefCell::new(HashMap::new()), url, parsing_algorithm: algorithm, + custom_element_reaction_stack, }; tokenizer.insert_node(0, Dom::from_ref(document.upcast())); @@ -397,7 +403,14 @@ impl Tokenizer { .GetParentNode() .expect("append_before_sibling called on node without parent"); - super::insert(parent, Some(sibling), node, self.parsing_algorithm, can_gc); + super::insert( + parent, + Some(sibling), + node, + self.parsing_algorithm, + &self.custom_element_reaction_stack, + can_gc, + ); } fn append(&self, parent: ParseNodeId, node: NodeOrText, can_gc: CanGc) { @@ -409,7 +422,14 @@ impl Tokenizer { }; let parent = &**self.get_node(&parent); - super::insert(parent, None, node, self.parsing_algorithm, can_gc); + super::insert( + parent, + None, + node, + self.parsing_algorithm, + &self.custom_element_reaction_stack, + can_gc, + ); } fn has_parent_node(&self, node: ParseNodeId) -> bool { @@ -454,6 +474,7 @@ impl Tokenizer { &self.document, ElementCreator::ParserCreated(current_line), ParsingAlgorithm::Normal, + &self.custom_element_reaction_stack, can_gc, ); self.insert_node(node, Dom::from_ref(element.upcast())); diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index d431f065e9d..0d21733e583 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -52,12 +52,14 @@ impl Tokenizer { fragment_context: Option, parsing_algorithm: ParsingAlgorithm, ) -> Self { + let custom_element_reaction_stack = document.custom_element_reaction_stack(); let sink = Sink { base_url: url, document: Dom::from_ref(document), current_line: Cell::new(1), script: Default::default(), parsing_algorithm, + custom_element_reaction_stack, }; let quirks_mode = match document.quirks_mode() { diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 6979f31e367..f1d90e74fe5 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use std::cell::Cell; +use std::rc::Rc; use base::cross_process_instant::CrossProcessInstant; use base::id::PipelineId; @@ -57,6 +58,7 @@ use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::characterdata::CharacterData; use crate::dom::comment::Comment; use crate::dom::csp::{CspReporting, GlobalCspReporting, Violation, parse_csp_list_from_metadata}; +use crate::dom::customelementregistry::CustomElementReactionStack; use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument}; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documenttype::DocumentType; @@ -244,6 +246,7 @@ impl ServoParser { allow_declarative_shadow_roots, Some(context_document.insecure_requests_policy()), context_document.has_trustworthy_ancestor_or_current_origin(), + context_document.custom_element_reaction_stack(), can_gc, ); @@ -1156,6 +1159,7 @@ fn insert( reference_child: Option<&Node>, child: NodeOrText>, parsing_algorithm: ParsingAlgorithm, + custom_element_reaction_stack: &CustomElementReactionStack, can_gc: CanGc, ) { match child { @@ -1166,11 +1170,11 @@ fn insert( let element_in_non_fragment = parsing_algorithm != ParsingAlgorithm::Fragment && n.is::(); if element_in_non_fragment { - ScriptThread::push_new_element_queue(); + custom_element_reaction_stack.push_new_element_queue(); } parent.InsertBefore(&n, reference_child, can_gc).unwrap(); if element_in_non_fragment { - ScriptThread::pop_current_element_queue(can_gc); + custom_element_reaction_stack.pop_current_element_queue(can_gc); } }, NodeOrText::AppendText(t) => { @@ -1201,6 +1205,8 @@ pub(crate) struct Sink { current_line: Cell, script: MutNullableDom, parsing_algorithm: ParsingAlgorithm, + #[conditional_malloc_size_of] + custom_element_reaction_stack: Rc, } impl Sink { @@ -1278,6 +1284,7 @@ impl TreeSink for Sink { &self.document, ElementCreator::ParserCreated(self.current_line.get()), parsing_algorithm, + &self.custom_element_reaction_stack, CanGc::note(), ); Dom::from_ref(element.upcast()) @@ -1347,6 +1354,7 @@ impl TreeSink for Sink { Some(sibling), new_node, self.parsing_algorithm, + &self.custom_element_reaction_stack, CanGc::note(), ); } @@ -1366,7 +1374,14 @@ impl TreeSink for Sink { #[cfg_attr(crown, allow(crown::unrooted_must_root))] fn append(&self, parent: &Dom, child: NodeOrText>) { - insert(parent, None, child, self.parsing_algorithm, CanGc::note()); + insert( + parent, + None, + child, + self.parsing_algorithm, + &self.custom_element_reaction_stack, + CanGc::note(), + ); } #[cfg_attr(crown, allow(crown::unrooted_must_root))] @@ -1479,6 +1494,7 @@ fn create_element_for_token( document: &Document, creator: ElementCreator, parsing_algorithm: ParsingAlgorithm, + custom_element_reaction_stack: &CustomElementReactionStack, can_gc: CanGc, ) -> DomRoot { // Step 3. @@ -1506,7 +1522,7 @@ fn create_element_for_token( .perform_a_microtask_checkpoint(can_gc); } // Step 6.3 - ScriptThread::push_new_element_queue() + custom_element_reaction_stack.push_new_element_queue() } // Step 7. @@ -1544,7 +1560,7 @@ fn create_element_for_token( // Step 9. if will_execute_script { // Steps 9.1 - 9.2. - ScriptThread::pop_current_element_queue(can_gc); + custom_element_reaction_stack.pop_current_element_queue(can_gc); // Step 9.3. document.decrement_throw_on_dynamic_markup_insertion_counter(); } diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs index f132cbcb3fd..c6de96ff70b 100644 --- a/components/script/dom/servoparser/xml.rs +++ b/components/script/dom/servoparser/xml.rs @@ -35,6 +35,7 @@ impl Tokenizer { current_line: Cell::new(1), script: Default::default(), parsing_algorithm: ParsingAlgorithm::Normal, + custom_element_reaction_stack: document.custom_element_reaction_stack(), }; let tb = XmlTreeBuilder::new(sink, Default::default()); diff --git a/components/script/dom/xmldocument.rs b/components/script/dom/xmldocument.rs index 8408f0704b7..2617f2e7687 100644 --- a/components/script/dom/xmldocument.rs +++ b/components/script/dom/xmldocument.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::rc::Rc; + use data_url::mime::Mime; use dom_struct::dom_struct; use net_traits::request::InsecureRequestsPolicy; @@ -17,6 +19,7 @@ use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; +use crate::dom::customelementregistry::CustomElementReactionStack; use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument}; use crate::dom::location::Location; use crate::dom::node::Node; @@ -44,6 +47,7 @@ impl XMLDocument { doc_loader: DocumentLoader, inherited_insecure_requests_policy: Option, has_trustworthy_ancestor_origin: bool, + custom_element_reaction_stack: Rc, ) -> XMLDocument { XMLDocument { document: Document::new_inherited( @@ -64,6 +68,7 @@ impl XMLDocument { false, inherited_insecure_requests_policy, has_trustworthy_ancestor_origin, + custom_element_reaction_stack, ), } } @@ -82,6 +87,7 @@ impl XMLDocument { doc_loader: DocumentLoader, inherited_insecure_requests_policy: Option, has_trustworthy_ancestor_origin: bool, + custom_element_reaction_stack: Rc, can_gc: CanGc, ) -> DomRoot { let doc = reflect_dom_object( @@ -98,6 +104,7 @@ impl XMLDocument { doc_loader, inherited_insecure_requests_policy, has_trustworthy_ancestor_origin, + custom_element_reaction_stack, )), window, can_gc, diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 22f0ba46a1a..3d2d1d6bd8f 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -1535,6 +1535,7 @@ impl XMLHttpRequest { false, Some(doc.insecure_requests_policy()), doc.has_trustworthy_ancestor_origin(), + doc.custom_element_reaction_stack(), can_gc, ) } diff --git a/components/script/messaging.rs b/components/script/messaging.rs index 9ceb79e301b..6b81d8f3c7e 100644 --- a/components/script/messaging.rs +++ b/components/script/messaging.rs @@ -5,6 +5,7 @@ use core::fmt; #[cfg(feature = "webgpu")] use std::cell::RefCell; +use std::collections::HashSet; use std::option::Option; use std::result::Result; @@ -397,10 +398,11 @@ impl ScriptThreadReceivers { &self, task_queue: &TaskQueue, timer_scheduler: &TimerScheduler, + fully_active: &HashSet, ) -> MixedMessage { select! { recv(task_queue.select()) -> msg => { - task_queue.take_tasks(msg.unwrap()); + task_queue.take_tasks(msg.unwrap(), fully_active); let event = task_queue .recv() .expect("Spurious wake-up of the event-loop, task-queue has no tasks available"); @@ -437,6 +439,7 @@ impl ScriptThreadReceivers { pub(crate) fn try_recv( &self, task_queue: &TaskQueue, + fully_active: &HashSet, ) -> Option { if let Ok(message) = self.constellation_receiver.try_recv() { let message = message @@ -449,7 +452,7 @@ impl ScriptThreadReceivers { .ok()?; return MixedMessage::FromConstellation(message).into(); } - if let Ok(message) = task_queue.take_tasks_and_recv() { + if let Ok(message) = task_queue.take_tasks_and_recv(fully_active) { return MixedMessage::FromScript(message).into(); } if let Ok(message) = self.devtools_server_receiver.try_recv() { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 48195fa56fe..2d98acfbea9 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -279,7 +279,7 @@ pub struct ScriptThread { docs_with_no_blocking_loads: DomRefCell>>, /// - custom_element_reaction_stack: CustomElementReactionStack, + custom_element_reaction_stack: Rc, /// Cross-process access to the compositor's API. #[no_trace] @@ -723,24 +723,21 @@ impl ScriptThread { with_script_thread(|script_thread| script_thread.is_user_interacting.get()) } - pub(crate) fn get_fully_active_document_ids() -> HashSet { - with_script_thread(|script_thread| { - script_thread - .documents - .borrow() - .iter() - .filter_map(|(id, document)| { - if document.is_fully_active() { - Some(id) - } else { - None - } - }) - .fold(HashSet::new(), |mut set, id| { - let _ = set.insert(id); - set - }) - }) + pub(crate) fn get_fully_active_document_ids(&self) -> HashSet { + self.documents + .borrow() + .iter() + .filter_map(|(id, document)| { + if document.is_fully_active() { + Some(id) + } else { + None + } + }) + .fold(HashSet::new(), |mut set, id| { + let _ = set.insert(id); + set + }) } pub(crate) fn find_window_proxy(id: BrowsingContextId) -> Option> { @@ -810,19 +807,13 @@ impl ScriptThread { .register_paint_worklet_modules(name, properties, painter); } - pub(crate) fn push_new_element_queue() { - with_script_thread(|script_thread| { + pub(crate) fn custom_element_reaction_stack() -> Rc { + with_optional_script_thread(|script_thread| { script_thread + .as_ref() + .unwrap() .custom_element_reaction_stack - .push_new_element_queue(); - }) - } - - pub(crate) fn pop_current_element_queue(can_gc: CanGc) { - with_script_thread(|script_thread| { - script_thread - .custom_element_reaction_stack - .pop_current_element_queue(can_gc); + .clone() }) } @@ -1006,7 +997,7 @@ impl ScriptThread { webxr_registry: state.webxr_registry, worklet_thread_pool: Default::default(), docs_with_no_blocking_loads: Default::default(), - custom_element_reaction_stack: CustomElementReactionStack::new(), + custom_element_reaction_stack: Rc::new(CustomElementReactionStack::new()), compositor_api: state.compositor_api, profile_script_events: opts.debug.profile_script_events, print_pwm: opts.print_pwm, @@ -1352,9 +1343,12 @@ impl ScriptThread { // Receive at least one message so we don't spinloop. debug!("Waiting for event."); - let mut event = self - .receivers - .recv(&self.task_queue, &self.timer_scheduler.borrow()); + let fully_active = self.get_fully_active_document_ids(); + let mut event = self.receivers.recv( + &self.task_queue, + &self.timer_scheduler.borrow(), + &fully_active, + ); loop { debug!("Handling event: {event:?}"); @@ -1464,7 +1458,7 @@ impl ScriptThread { // If any of our input sources has an event pending, we'll perform another iteration // and check for more resize events. If there are no events pending, we'll move // on and execute the sequential non-resize events we've seen. - match self.receivers.try_recv(&self.task_queue) { + match self.receivers.try_recv(&self.task_queue, &fully_active) { Some(new_event) => event = new_event, None => break, } @@ -3422,6 +3416,7 @@ impl ScriptThread { true, incomplete.load_data.inherited_insecure_requests_policy, incomplete.load_data.has_trustworthy_ancestor_origin, + self.custom_element_reaction_stack.clone(), can_gc, ); diff --git a/components/script/task_queue.rs b/components/script/task_queue.rs index aad78c5dc1c..0becbe33829 100644 --- a/components/script/task_queue.rs +++ b/components/script/task_queue.rs @@ -15,7 +15,6 @@ use strum::VariantArray; use crate::dom::bindings::cell::DomRefCell; use crate::dom::worker::TrustedWorkerAddress; use crate::script_runtime::ScriptThreadEventCategory; -use crate::script_thread::ScriptThread; use crate::task::TaskBox; use crate::task_source::TaskSourceName; @@ -197,19 +196,18 @@ impl TaskQueue { } /// Take all tasks again and then run `recv()`. - pub(crate) fn take_tasks_and_recv(&self) -> Result { - self.take_tasks(T::wake_up_msg()); + pub(crate) fn take_tasks_and_recv(&self, fully_active: &HashSet) -> Result { + self.take_tasks(T::wake_up_msg(), fully_active); self.recv() } /// Drain the queue for the current iteration of the event-loop. /// Holding-back throttles above a given high-water mark. - pub(crate) fn take_tasks(&self, first_msg: T) { + pub(crate) fn take_tasks(&self, first_msg: T, fully_active: &HashSet) { // High-watermark: once reached, throttled tasks will be held-back. const PER_ITERATION_MAX: u64 = 5; - let fully_active = ScriptThread::get_fully_active_document_ids(); // Always first check for new tasks, but don't reset 'taken_task_counter'. - self.process_incoming_tasks(first_msg, &fully_active); + self.process_incoming_tasks(first_msg, fully_active); let mut throttled = self.throttled.borrow_mut(); let mut throttled_length: usize = throttled.values().map(|queue| queue.len()).sum(); let mut task_source_cycler = TaskSourceName::VARIANTS.iter().cycle();