From de1a3d879fa910d4e77a48b9055cd1cdac3f21a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 24 Nov 2016 00:47:00 +0100 Subject: [PATCH] style: Enable the bloom filter recovering. --- components/layout/traversal.rs | 8 +++----- components/layout_thread/lib.rs | 3 ++- components/style/gecko/traversal.rs | 6 +++--- components/style/parallel.rs | 18 ++++++++++++++---- components/style/sequential.rs | 20 +++++++++++++++----- components/style/traversal.rs | 28 ++++++++++++++++++++-------- ports/geckolib/glue.rs | 12 +++++++++--- 7 files changed, 66 insertions(+), 29 deletions(-) diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index d1701448988..e20d3ab98ef 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -19,6 +19,7 @@ use style::dom::{StylingMode, TElement, TNode}; use style::selector_parser::RestyleDamage; use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT}; use style::traversal::{DomTraversalContext, recalc_style_at, remove_from_bloom_filter}; +use style::traversal::PerLevelTraversalData; use util::opts; use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData}; @@ -72,17 +73,14 @@ impl<'lc, N> DomTraversalContext for RecalcStyleAndConstructFlows<'lc> } } - fn process_preorder(&self, node: N) { + fn process_preorder(&self, node: N, data: &mut PerLevelTraversalData) { // FIXME(pcwalton): Stop allocating here. Ideally this should just be // done by the HTML parser. node.initialize_data(); - // FIXME(emilio): Get it! - let traversal_depth = None; - if !node.is_text_node() { let el = node.as_element().unwrap(); - recalc_style_at::<_, _, Self>(&self.context, traversal_depth, el); + recalc_style_at::<_, _, Self>(&self.context, data, el); } } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 3530cbb24e5..3b435fc64bb 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1131,6 +1131,7 @@ impl LayoutThread { viewport_size_changed, data.reflow_info.goal); + let dom_depth = Some(0); // This is always the root node. if element.styling_mode() != StylingMode::Stop { // Recalculate CSS styles and rebuild flows and fragments. profile(time::ProfilerCategory::LayoutStyleRecalc, @@ -1145,7 +1146,7 @@ impl LayoutThread { } Some(ref mut traversal) => { parallel::traverse_dom::( - element.as_node(), &shared_layout_context, traversal); + element.as_node(), dom_depth, &shared_layout_context, traversal); } } }); diff --git a/components/style/gecko/traversal.rs b/components/style/gecko/traversal.rs index c323f48552a..cc6bed8f79b 100644 --- a/components/style/gecko/traversal.rs +++ b/components/style/gecko/traversal.rs @@ -9,7 +9,7 @@ use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode}; use gecko::context::StandaloneStyleContext; use gecko::wrapper::{GeckoElement, GeckoNode}; use std::mem; -use traversal::{DomTraversalContext, recalc_style_at}; +use traversal::{DomTraversalContext, PerLevelTraversalData, recalc_style_at}; pub struct RecalcStyleOnly<'lc> { context: StandaloneStyleContext<'lc>, @@ -29,10 +29,10 @@ impl<'lc, 'ln> DomTraversalContext> for RecalcStyleOnly<'lc> { } } - fn process_preorder(&self, node: GeckoNode<'ln>) { + fn process_preorder(&self, node: GeckoNode<'ln>, data: &mut PerLevelTraversalData) { if node.is_element() && (!self.context.shared_context().skip_root || node.opaque() != self.root) { let el = node.as_element().unwrap(); - recalc_style_at::<_, _, Self>(&self.context, self.root, el); + recalc_style_at::<_, _, Self>(&self.context, data, el); } } diff --git a/components/style/parallel.rs b/components/style/parallel.rs index 8ef1b42a17d..1b9258e7aca 100644 --- a/components/style/parallel.rs +++ b/components/style/parallel.rs @@ -9,13 +9,14 @@ use dom::{OpaqueNode, TElement, TNode, UnsafeNode}; use rayon; use std::sync::atomic::Ordering; +use traversal::{DomTraversalContext, PerLevelTraversalData}; use traversal::{STYLE_SHARING_CACHE_HITS, STYLE_SHARING_CACHE_MISSES}; -use traversal::DomTraversalContext; use util::opts; pub const CHUNK_SIZE: usize = 64; pub fn traverse_dom(root: N, + known_root_dom_depth: Option, shared_context: &C::SharedContext, queue: &rayon::ThreadPool) where N: TNode, @@ -27,11 +28,14 @@ pub fn traverse_dom(root: N, } let nodes = vec![root.to_unsafe()].into_boxed_slice(); + let data = PerLevelTraversalData { + current_dom_depth: known_root_dom_depth, + }; let root = root.opaque(); queue.install(|| { rayon::scope(|scope| { let nodes = nodes; - top_down_dom::(&nodes, root, scope, shared_context); + top_down_dom::(&nodes, root, data, scope, shared_context); }); }); @@ -50,6 +54,7 @@ pub fn traverse_dom(root: N, #[allow(unsafe_code)] fn top_down_dom<'a, 'scope, N, C>(unsafe_nodes: &'a [UnsafeNode], root: OpaqueNode, + mut data: PerLevelTraversalData, scope: &'a rayon::Scope<'scope>, shared_context: &'scope C::SharedContext) where N: TNode, @@ -64,7 +69,7 @@ fn top_down_dom<'a, 'scope, N, C>(unsafe_nodes: &'a [UnsafeNode], // Perform the appropriate traversal. let mut children_to_process = 0isize; - context.process_preorder(node); + context.process_preorder(node, &mut data); if let Some(el) = node.as_element() { C::traverse_children(el, |kid| { children_to_process += 1; @@ -90,11 +95,16 @@ fn top_down_dom<'a, 'scope, N, C>(unsafe_nodes: &'a [UnsafeNode], // be able to access it without races. context.local_context().style_sharing_candidate_cache.borrow_mut().clear(); + if let Some(ref mut depth) = data.current_dom_depth { + *depth += 1; + } + for chunk in discovered_child_nodes.chunks(CHUNK_SIZE) { let nodes = chunk.iter().cloned().collect::>().into_boxed_slice(); + let data = data.clone(); scope.spawn(move |scope| { let nodes = nodes; - top_down_dom::(&nodes, root, scope, shared_context) + top_down_dom::(&nodes, root, data, scope, shared_context) }) } } diff --git a/components/style/sequential.rs b/components/style/sequential.rs index 8e04b53e57e..4b92c52f80d 100644 --- a/components/style/sequential.rs +++ b/components/style/sequential.rs @@ -5,20 +5,27 @@ //! Implements sequential traversal over the DOM tree. use dom::TNode; -use traversal::DomTraversalContext; +use traversal::{DomTraversalContext, PerLevelTraversalData}; pub fn traverse_dom(root: N, shared: &C::SharedContext) where N: TNode, C: DomTraversalContext { - fn doit<'a, N, C>(context: &'a C, node: N) + fn doit<'a, N, C>(context: &'a C, node: N, data: &mut PerLevelTraversalData) where N: TNode, C: DomTraversalContext { - context.process_preorder(node); + context.process_preorder(node, data); if let Some(el) = node.as_element() { - C::traverse_children(el, |kid| doit::(context, kid)); + if let Some(ref mut depth) = data.current_dom_depth { + *depth += 1; + } + + C::traverse_children(el, |kid| doit::(context, kid, data)); + + // NB: Data is unused now, but we can always decrement the count + // here if we need it for the post-order one :) } if context.needs_postorder_traversal() { @@ -26,8 +33,11 @@ pub fn traverse_dom(root: N, } } + let mut data = PerLevelTraversalData { + current_dom_depth: None, + }; let context = C::new(shared, root.opaque()); - doit::(&context, root); + doit::(&context, root, &mut data); // Clear the local LRU cache since we store stateful elements inside. context.local_context().style_sharing_candidate_cache.borrow_mut().clear(); diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 9d3f15a5895..685c33b265f 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -90,13 +90,19 @@ pub fn remove_from_bloom_filter<'a, E, C>(context: &C, root: OpaqueNode, element } } +// NB: Keep this as small as possible, please! +#[derive(Clone, Debug)] +pub struct PerLevelTraversalData { + pub current_dom_depth: Option, +} + pub trait DomTraversalContext { type SharedContext: Sync + 'static; fn new<'a>(&'a Self::SharedContext, OpaqueNode) -> Self; /// Process `node` on the way down, before its children have been processed. - fn process_preorder(&self, node: N); + fn process_preorder(&self, node: N, data: &mut PerLevelTraversalData); /// Process `node` on the way up, after its children have been processed. /// @@ -200,7 +206,7 @@ pub fn style_element_in_display_none_subtree<'a, E, C, F>(element: E, #[inline] #[allow(unsafe_code)] pub fn recalc_style_at<'a, E, C, D>(context: &'a C, - dom_depth: Option, + data: &mut PerLevelTraversalData, element: E) where E: TElement, C: StyleContext<'a>, @@ -212,7 +218,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, element, should_compute, mode, element.borrow_data()); let (computed_display_none, propagated_hint) = if should_compute { - compute_style::<_, _, D>(context, dom_depth, element) + compute_style::<_, _, D>(context, data, element) } else { (false, StoredRestyleHint::empty()) }; @@ -231,7 +237,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, } fn compute_style<'a, E, C, D>(context: &'a C, - dom_depth: Option, + data: &mut PerLevelTraversalData, element: E) -> (bool, StoredRestyleHint) where E: TElement, C: StyleContext<'a>, @@ -239,11 +245,17 @@ fn compute_style<'a, E, C, D>(context: &'a C, { let shared_context = context.shared_context(); let mut bf = take_thread_local_bloom_filter(shared_context); - // Ensure the bloom filter is up to date. - bf.insert_parents_recovering(element, - dom_depth, - shared_context.generation); + let dom_depth = bf.insert_parents_recovering(element, + data.current_dom_depth, + shared_context.generation); + + // Update the dom depth with the up-to-date dom depth. + // + // Note that this is always the same than the pre-existing depth, but it can + // change from unknown to known at this step. + data.current_dom_depth = Some(dom_depth); + bf.assert_complete(element); let mut data = unsafe { D::ensure_element_data(&element).borrow_mut() }; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 4cfb8a50662..1f813303b21 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -60,7 +60,7 @@ use style::string_cache::Atom; use style::stylesheets::{CssRule, Origin, Stylesheet, StyleRule}; use style::thread_state; use style::timer::Timer; -use style::traversal::recalc_style_at; +use style::traversal::{recalc_style_at, PerLevelTraversalData}; use style_traits::ToCss; /* @@ -148,10 +148,12 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed, let mut per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut shared_style_context = create_shared_context(&mut per_doc_data); shared_style_context.skip_root = skip_root; + let known_depth = None; + if per_doc_data.num_threads == 1 || per_doc_data.work_queue.is_none() { sequential::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), &shared_style_context); } else { - parallel::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), &shared_style_context, + parallel::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), known_depth, &shared_style_context, per_doc_data.work_queue.as_mut().unwrap()); } } @@ -793,7 +795,11 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed, let mut per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let shared_style_context = create_shared_context(&mut per_doc_data); let context = StandaloneStyleContext::new(&shared_style_context); - recalc_style_at::<_, _, RecalcStyleOnly>(&context, element.as_node().opaque(), element); + + let mut data = PerLevelTraversalData { + current_dom_depth: None, + }; + recalc_style_at::<_, _, RecalcStyleOnly>(&context, &mut data, element); // The element was either unstyled or needed restyle. If it was unstyled, it may have // additional unstyled children that subsequent traversals won't find now that the style