diff --git a/src/components/main/css/matching.rs b/src/components/main/css/matching.rs index 05043e23f7f..f81b1e86da4 100644 --- a/src/components/main/css/matching.rs +++ b/src/components/main/css/matching.rs @@ -8,19 +8,14 @@ use css::node_style::StyledNode; use layout::incremental; use layout::util::LayoutDataAccess; use layout::wrapper::LayoutNode; -use servo_util::task::spawn_named; -use extra::arc::{Arc, RWArc}; -use std::cast; -use std::libc::uintptr_t; -use std::rt; -use std::vec; +use extra::arc::Arc; use style::{TNode, Stylist, cascade}; use style::{Before, After}; pub trait MatchMethods { fn match_node(&self, stylist: &Stylist); - fn match_subtree(&self, stylist: RWArc); + fn match_subtree(&self, stylist: &Stylist); fn cascade_subtree(&self, parent: Option); } @@ -47,54 +42,13 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { None => fail!("no layout data") } } - fn match_subtree(&self, stylist: RWArc) { - let num_tasks = rt::default_sched_threads() * 2; - let mut node_count = 0; - let mut nodes_per_task = vec::from_elem(num_tasks, ~[]); + fn match_subtree(&self, stylist: &Stylist) { for node in self.traverse_preorder() { if node.is_element() { - nodes_per_task[node_count % num_tasks].push(node); - node_count += 1; + node.match_node(stylist); } } - - let (port, chan) = SharedChan::new(); - let mut num_spawned = 0; - - for nodes in nodes_per_task.move_iter() { - if nodes.len() > 0 { - let chan = chan.clone(); - let stylist = stylist.clone(); - - // FIXME(pcwalton): This transmute is to work around the fact that we have no - // mechanism for safe fork/join parallelism. If we had such a thing, then we could - // close over the lifetime-bounded `LayoutNode`. But we can't, so we force it with - // a transmute. - let evil: uintptr_t = unsafe { - cast::transmute(nodes) - }; - - let evil = Some(evil); - spawn_named("MatchMethods for LayoutNode", proc() { - let mut evil = evil; - let nodes: ~[LayoutNode] = unsafe { - cast::transmute(evil.take_unwrap()) - }; - - stylist.read(|stylist| { - for node in nodes.iter() { - node.match_node(stylist); - } - }); - chan.send(()); - }); - num_spawned += 1; - } - } - for _ in range(0, num_spawned) { - port.recv(); - } } fn cascade_subtree(&self, parent: Option) { diff --git a/src/components/main/layout/context.rs b/src/components/main/layout/context.rs index fb797196e71..0d5b3931a02 100644 --- a/src/components/main/layout/context.rs +++ b/src/components/main/layout/context.rs @@ -18,6 +18,7 @@ use gfx::font_context::{FontContext, FontContextInfo}; use servo_msg::constellation_msg::ConstellationChan; use servo_net::local_image_cache::LocalImageCache; use servo_util::geometry::Au; +use style::Stylist; #[thread_local] static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext; @@ -39,6 +40,11 @@ pub struct LayoutContext { /// Information needed to construct a font context. font_context_info: FontContextInfo, + + /// The CSS selector stylist. + /// + /// FIXME(pcwalton): Make this no longer an unsafe pointer once we have fast `RWArc`s. + stylist: *Stylist, } impl LayoutContext { diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 01bae0b9428..2bbb5d81e36 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -22,7 +22,7 @@ use layout::parallel; use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper}; use layout::wrapper::LayoutNode; -use extra::arc::{Arc, MutexArc, RWArc}; +use extra::arc::{Arc, MutexArc}; use geom::rect::Rect; use geom::size::Size2D; use gfx::display_list::{ClipDisplayItemClass, DisplayItem, DisplayItemIterator, DisplayList}; @@ -91,7 +91,7 @@ pub struct LayoutTask { /// A cached display list. display_list: Option>>, - stylist: RWArc, + stylist: ~Stylist, /// The workers that we use for parallel operation. parallel_traversal: Option>, @@ -274,7 +274,7 @@ impl LayoutTask { leaf_set: MutexArc::new(LeafSet::new()), display_list: None, - stylist: RWArc::new(new_stylist()), + stylist: ~new_stylist(), parallel_traversal: parallel_traversal, profiler_chan: profiler_chan, opts: opts.clone() @@ -302,6 +302,7 @@ impl LayoutTask { constellation_chan: self.constellation_chan.clone(), leaf_set: self.leaf_set.clone(), font_context_info: font_context_info, + stylist: &*self.stylist, } } @@ -379,10 +380,7 @@ impl LayoutTask { } fn handle_add_stylesheet(&mut self, sheet: Stylesheet) { - let mut sheet = Some(sheet); - self.stylist.write(|stylist| { - stylist.add_stylesheet(sheet.take_unwrap(), AuthorOrigin); - }); + self.stylist.add_stylesheet(sheet, AuthorOrigin) } /// Builds the flow tree. @@ -521,7 +519,12 @@ impl LayoutTask { ReflowDocumentDamage => {} _ => { profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || { - node.match_subtree(self.stylist.clone()); + match self.parallel_traversal { + None => node.match_subtree(self.stylist), + Some(ref mut traversal) => { + parallel::match_subtree(node, &mut layout_ctx, traversal) + } + } }); profile(time::LayoutSelectorCascadeCategory, self.profiler_chan.clone(), || { node.cascade_subtree(None); diff --git a/src/components/main/layout/parallel.rs b/src/components/main/layout/parallel.rs index b38e6abc9b5..7c5cd9917e6 100644 --- a/src/components/main/layout/parallel.rs +++ b/src/components/main/layout/parallel.rs @@ -2,19 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -//! Implements parallel traversals over the flow tree. +//! Implements parallel traversals over the DOM and flow trees. +//! +//! This code is highly unsafe. Keep this file small and easy to audit. +use css::matching::MatchMethods; use layout::context::LayoutContext; use layout::flow::{Flow, LeafSet, PostorderFlowTraversal}; use layout::flow; use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, BubbleWidthsTraversal}; +use layout::wrapper::LayoutNode; use extra::arc::MutexArc; use servo_util::time::{ProfilerChan, profile}; use servo_util::time; use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy}; use std::cast; +use std::ptr; use std::sync::atomics::{AtomicInt, Relaxed, SeqCst}; +use style::{Stylist, TNode}; pub enum TraversalKind { BubbleWidthsTraversalKind, @@ -39,6 +45,14 @@ pub fn mut_owned_flow_to_unsafe_flow(flow: *mut ~Flow) -> UnsafeFlow { } } +pub type UnsafeLayoutNode = (uint, uint); + +fn layout_node_to_unsafe_layout_node(node: &LayoutNode) -> UnsafeLayoutNode { + unsafe { + cast::transmute_copy(node) + } +} + /// Information that we need stored in each flow. pub struct FlowParallelInfo { /// The number of children that still need work done. @@ -101,6 +115,30 @@ impl<'a> ParallelPostorderFlowTraversal for BubbleWidthsTraversal<'a> {} impl<'a> ParallelPostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {} +fn match_node(unsafe_layout_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*mut LayoutContext,UnsafeLayoutNode>) { + unsafe { + let layout_context: &mut LayoutContext = cast::transmute(*proxy.user_data()); + + // Get a real layout node. + let node: LayoutNode = cast::transmute(unsafe_layout_node); + + // Enqueue kids. + for kid in node.children() { + if kid.is_element() { + proxy.push(WorkUnit { + fun: match_node, + data: layout_node_to_unsafe_layout_node(&kid), + }); + } + } + + // Perform the CSS selector matching. + let stylist: &Stylist = cast::transmute(layout_context.stylist); + node.match_node(stylist); + } +} + fn bubble_widths(unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*mut LayoutContext,UnsafeFlow>) { let layout_context: &mut LayoutContext = unsafe { cast::transmute(*proxy.user_data()) @@ -122,6 +160,24 @@ fn assign_heights_and_store_overflow(unsafe_flow: UnsafeFlow, assign_heights_traversal.run_parallel(unsafe_flow) } +pub fn match_subtree(root_node: &LayoutNode, + layout_context: &mut LayoutContext, + queue: &mut WorkQueue<*mut LayoutContext,UnsafeLayoutNode>) { + unsafe { + queue.data = cast::transmute(layout_context) + } + + // Enqueue the root node. + queue.push(WorkUnit { + fun: match_node, + data: layout_node_to_unsafe_layout_node(root_node), + }); + + queue.run(); + + queue.data = ptr::mut_null() +} + pub fn traverse_flow_tree(kind: TraversalKind, leaf_set: &MutexArc, profiler_chan: ProfilerChan, @@ -147,6 +203,8 @@ pub fn traverse_flow_tree(kind: TraversalKind, }) }); - queue.run() + queue.run(); + + queue.data = ptr::mut_null() }