layout: Stop storing intermediate applicable declarations inside layout

data.

9% improvement in style recalc on the rainbow page.
This commit is contained in:
Patrick Walton 2014-02-07 11:00:24 -08:00
parent 758f5ba755
commit cf8203848a
4 changed files with 77 additions and 84 deletions

View file

@ -12,24 +12,48 @@ use layout::wrapper::LayoutNode;
use extra::arc::Arc; use extra::arc::Arc;
use script::layout_interface::LayoutChan; use script::layout_interface::LayoutChan;
use servo_util::smallvec::SmallVec; use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec16};
use style::{TNode, Stylist, cascade}; use style::{After, Before, PropertyDeclaration, Stylist, TNode, cascade};
use style::{Before, After};
pub struct ApplicableDeclarations {
normal: SmallVec16<Arc<~[PropertyDeclaration]>>,
before: SmallVec0<Arc<~[PropertyDeclaration]>>,
after: SmallVec0<Arc<~[PropertyDeclaration]>>,
}
impl ApplicableDeclarations {
pub fn new() -> ApplicableDeclarations {
ApplicableDeclarations {
normal: SmallVec16::new(),
before: SmallVec0::new(),
after: SmallVec0::new(),
}
}
pub fn clear(&mut self) {
self.normal = SmallVec16::new();
self.before = SmallVec0::new();
self.after = SmallVec0::new();
}
}
pub trait MatchMethods { pub trait MatchMethods {
fn match_node(&self, stylist: &Stylist);
/// Performs aux initialization, selector matching, and cascading sequentially. /// Performs aux initialization, selector matching, and cascading sequentially.
fn match_and_cascade_subtree(&self, fn match_and_cascade_subtree(&self,
stylist: &Stylist, stylist: &Stylist,
layout_chan: &LayoutChan, layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations,
parent: Option<LayoutNode>); parent: Option<LayoutNode>);
unsafe fn cascade_node(&self, parent: Option<LayoutNode>); fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations);
unsafe fn cascade_node(&self,
parent: Option<LayoutNode>,
applicable_declarations: &ApplicableDeclarations);
} }
impl<'ln> MatchMethods for LayoutNode<'ln> { impl<'ln> MatchMethods for LayoutNode<'ln> {
fn match_node(&self, stylist: &Stylist) { fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations) {
let style_attribute = self.with_element(|element| { let style_attribute = self.with_element(|element| {
match *element.style_attribute() { match *element.style_attribute() {
None => None, None => None,
@ -37,55 +61,50 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
} }
}); });
let mut layout_data_ref = self.mutate_layout_data(); stylist.push_applicable_declarations(self,
match *layout_data_ref.get() { style_attribute,
Some(ref mut layout_data) => { None,
//FIXME To implement a clear() on SmallVec and use it(init_applicable_declarations). &mut applicable_declarations.normal);
layout_data.data.init_applicable_declarations(); stylist.push_applicable_declarations(self,
None,
stylist.push_applicable_declarations(self, Some(Before),
style_attribute, &mut applicable_declarations.before);
None, stylist.push_applicable_declarations(self,
&mut layout_data.data.applicable_declarations); None,
stylist.push_applicable_declarations(self, Some(After),
None, &mut applicable_declarations.after);
Some(Before),
&mut layout_data
.data
.before_applicable_declarations);
stylist.push_applicable_declarations(self,
None,
Some(After),
&mut layout_data
.data
.after_applicable_declarations);
}
None => fail!("no layout data")
}
} }
fn match_and_cascade_subtree(&self, fn match_and_cascade_subtree(&self,
stylist: &Stylist, stylist: &Stylist,
layout_chan: &LayoutChan, layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations,
parent: Option<LayoutNode>) { parent: Option<LayoutNode>) {
self.initialize_layout_data((*layout_chan).clone()); self.initialize_layout_data((*layout_chan).clone());
if self.is_element() { if self.is_element() {
self.match_node(stylist); self.match_node(stylist, applicable_declarations);
} }
unsafe { unsafe {
self.cascade_node(parent) self.cascade_node(parent, applicable_declarations)
} }
applicable_declarations.clear();
for kid in self.children() { for kid in self.children() {
kid.match_and_cascade_subtree(stylist, layout_chan, Some(*self)) kid.match_and_cascade_subtree(stylist,
layout_chan,
applicable_declarations,
Some(*self))
} }
} }
unsafe fn cascade_node(&self, parent: Option<LayoutNode>) { unsafe fn cascade_node(&self,
parent: Option<LayoutNode>,
applicable_declarations: &ApplicableDeclarations) {
macro_rules! cascade_node( macro_rules! cascade_node(
($applicable_declarations: ident, $style: ident) => {{ ($applicable_declarations: expr, $style: ident) => {{
// Get our parent's style. This must be unsafe so that we don't touch the parent's // Get our parent's style. This must be unsafe so that we don't touch the parent's
// borrow flags. // borrow flags.
// //
@ -100,18 +119,19 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
Some(ref parent_layout_data) => { Some(ref parent_layout_data) => {
match parent_layout_data.data.style { match parent_layout_data.data.style {
None => fail!("parent hasn't been styled yet?!"), None => fail!("parent hasn't been styled yet?!"),
Some(ref style) => Some(style.get()), Some(ref style) => Some(style),
} }
} }
} }
} }
}; };
let computed_values = { let computed_values = match parent_style {
let layout_data_ref = self.borrow_layout_data(); Some(ref style) => {
let layout_data = layout_data_ref.get().as_ref().unwrap(); Arc::new(cascade($applicable_declarations.as_slice(),
Arc::new(cascade(layout_data.data.$applicable_declarations.as_slice(), Some(style.get())))
parent_style)) }
None => Arc::new(cascade($applicable_declarations.as_slice(), None)),
}; };
let mut layout_data_ref = self.mutate_layout_data(); let mut layout_data_ref = self.mutate_layout_data();
@ -132,24 +152,12 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}} }}
); );
{ cascade_node!(applicable_declarations.normal, style);
let before_len = { if applicable_declarations.before.len() > 0 {
let layout_data_ref = self.borrow_layout_data(); cascade_node!(applicable_declarations.before, before_style);
layout_data_ref.get().as_ref().unwrap().data.before_applicable_declarations.len()
};
if before_len > 0 {
cascade_node!(before_applicable_declarations, before_style);
}
} }
cascade_node!(applicable_declarations, style); if applicable_declarations.after.len() > 0 {
{ cascade_node!(applicable_declarations.after, after_style);
let after_len = {
let layout_data_ref = self.borrow_layout_data();
layout_data_ref.get().as_ref().unwrap().data.after_applicable_declarations.len()
};
if after_len > 0 {
cascade_node!(after_applicable_declarations, after_style);
}
} }
} }
} }

View file

@ -5,7 +5,7 @@
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be //! The layout task. Performs layout on the DOM, builds display lists and sends them to be
/// rendered. /// rendered.
use css::matching::MatchMethods; use css::matching::{ApplicableDeclarations, MatchMethods};
use css::select::new_stylist; use css::select::new_stylist;
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::construct::{FlowConstructionResult, FlowConstructor, NoConstructionResult}; use layout::construct::{FlowConstructionResult, FlowConstructor, NoConstructionResult};
@ -561,8 +561,10 @@ impl LayoutTask {
profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || { profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || {
match self.parallel_traversal { match self.parallel_traversal {
None => { None => {
let mut applicable_declarations = ApplicableDeclarations::new();
node.match_and_cascade_subtree(self.stylist, node.match_and_cascade_subtree(self.stylist,
&layout_ctx.layout_chan, &layout_ctx.layout_chan,
&mut applicable_declarations,
None) None)
} }
Some(ref mut traversal) => { Some(ref mut traversal) => {

View file

@ -6,7 +6,7 @@
//! //!
//! This code is highly unsafe. Keep this file small and easy to audit. //! This code is highly unsafe. Keep this file small and easy to audit.
use css::matching::MatchMethods; use css::matching::{ApplicableDeclarations, MatchMethods};
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::extra::LayoutAuxMethods; use layout::extra::LayoutAuxMethods;
use layout::flow::{Flow, FlowLeafSet, PostorderFlowTraversal}; use layout::flow::{Flow, FlowLeafSet, PostorderFlowTraversal};
@ -149,10 +149,12 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
// parser. // parser.
node.initialize_layout_data(layout_context.layout_chan.clone()); node.initialize_layout_data(layout_context.layout_chan.clone());
let mut applicable_declarations = ApplicableDeclarations::new();
if node.is_element() { if node.is_element() {
// Perform the CSS selector matching. // Perform the CSS selector matching.
let stylist: &Stylist = cast::transmute(layout_context.stylist); let stylist: &Stylist = cast::transmute(layout_context.stylist);
node.match_node(stylist); node.match_node(stylist, &mut applicable_declarations);
} }
// Perform the CSS cascade. // Perform the CSS cascade.
@ -161,7 +163,7 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
} else { } else {
node.parent_node() node.parent_node()
}; };
node.cascade_node(parent_opt); node.cascade_node(parent_opt, &applicable_declarations);
// Enqueue kids. // Enqueue kids.
let mut child_count = 0; let mut child_count = 0;

View file

@ -12,13 +12,12 @@ use script::dom::bindings::utils::Reflectable;
use script::dom::node::AbstractNode; use script::dom::node::AbstractNode;
use script::layout_interface::{LayoutChan, UntrustedNodeAddress}; use script::layout_interface::{LayoutChan, UntrustedNodeAddress};
use servo_util::range::Range; use servo_util::range::Range;
use servo_util::smallvec::{SmallVec0, SmallVec16};
use std::cast; use std::cast;
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
use std::iter::Enumerate; use std::iter::Enumerate;
use std::libc::uintptr_t; use std::libc::uintptr_t;
use std::vec::VecIterator; use std::vec::VecIterator;
use style::{ComputedValues, PropertyDeclaration}; use style::ComputedValues;
/// A range of nodes. /// A range of nodes.
pub struct NodeRange { pub struct NodeRange {
@ -130,13 +129,6 @@ impl ElementMapping {
/// Data that layout associates with a node. /// Data that layout associates with a node.
pub struct PrivateLayoutData { pub struct PrivateLayoutData {
/// The results of CSS matching for this node.
applicable_declarations: SmallVec16<Arc<~[PropertyDeclaration]>>,
before_applicable_declarations: SmallVec0<Arc<~[PropertyDeclaration]>>,
after_applicable_declarations: SmallVec0<Arc<~[PropertyDeclaration]>>,
/// The results of CSS styling for this node. /// The results of CSS styling for this node.
before_style: Option<Arc<ComputedValues>>, before_style: Option<Arc<ComputedValues>>,
@ -159,9 +151,6 @@ impl PrivateLayoutData {
/// Creates new layout data. /// Creates new layout data.
pub fn new() -> PrivateLayoutData { pub fn new() -> PrivateLayoutData {
PrivateLayoutData { PrivateLayoutData {
applicable_declarations: SmallVec16::new(),
before_applicable_declarations: SmallVec0::new(),
after_applicable_declarations: SmallVec0::new(),
before_style: None, before_style: None,
style: None, style: None,
after_style: None, after_style: None,
@ -170,14 +159,6 @@ impl PrivateLayoutData {
parallel: DomParallelInfo::new(), parallel: DomParallelInfo::new(),
} }
} }
/// Initialize the function for applicable_declarations.
pub fn init_applicable_declarations(&mut self) {
//FIXME To implement a clear() on SmallVec and use it(init_applicable_declarations).
self.applicable_declarations = SmallVec16::new();
self.before_applicable_declarations = SmallVec0::new();
self.after_applicable_declarations = SmallVec0::new();
}
} }
pub struct LayoutDataWrapper { pub struct LayoutDataWrapper {