servo: Merge #16033 - Per-document shared lock for author-origin stylesheets (from servo:per-document-locks); r=emilio
authorSimon Sapin <simon.sapin@exyr.org>
Sun, 19 Mar 2017 18:22:23 -0700
changeset 348389 fc3108b384bb5c90763807642998d43d3ff6d4e9
parent 348388 8b0d4d072cf0f78e8c78b08cbca7f5b082d5a9c1
child 348390 b35cbce500bc6ebf7b4b7dd5019c80099ce9dffd
push id39139
push userservo-vcs-sync@mozilla.com
push dateMon, 20 Mar 2017 02:02:52 +0000
treeherderautoland@fc3108b384bb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs16033, 16027
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #16033 - Per-document shared lock for author-origin stylesheets (from servo:per-document-locks); r=emilio Fix #16027 Source-Repo: https://github.com/servo/servo Source-Revision: 8d25dcb8b5f83728987171fe7a5b4905df741e58
servo/components/layout_thread/lib.rs
servo/components/script/dom/document.rs
servo/components/style/servo/mod.rs
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -109,17 +109,16 @@ use std::thread;
 use style::animation::Animation;
 use style::context::{QuirksMode, ReflowGoal, SharedStyleContext, ThreadLocalStyleContextCreationInfo};
 use style::data::StoredRestyleHint;
 use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
 use style::error_reporting::StdoutErrorReporter;
 use style::logical_geometry::LogicalPoint;
 use style::media_queries::{Device, MediaType};
 use style::parser::ParserContextExtraData;
-use style::servo::AUTHOR_SHARED_LOCK;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
 use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
 use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
 use style::stylist::Stylist;
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::{DomTraversal, TraversalDriver};
 
@@ -185,16 +184,19 @@ pub struct LayoutThread {
     new_animations_receiver: Receiver<Animation>,
 
     /// The number of Web fonts that have been requested but not yet loaded.
     outstanding_web_fonts: Arc<AtomicUsize>,
 
     /// The root of the flow tree.
     root_flow: Option<FlowRef>,
 
+    /// The document-specific shared lock used for author-origin stylesheets
+    document_shared_lock: Option<SharedRwLock>,
+
     /// The list of currently-running animations.
     running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
 
     /// The list of animations that have expired since the last style recalculation.
     expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
 
     /// A counter for epoch messages
     epoch: Epoch,
@@ -437,16 +439,17 @@ impl LayoutThread {
             font_cache_sender: ipc_font_cache_sender,
             parallel_traversal: parallel_traversal,
             parallel_flag: true,
             generation: 0,
             new_animations_sender: new_animations_sender,
             new_animations_receiver: new_animations_receiver,
             outstanding_web_fonts: outstanding_web_fonts_counter,
             root_flow: None,
+            document_shared_lock: None,
             running_animations: Arc::new(RwLock::new(HashMap::new())),
             expired_animations: Arc::new(RwLock::new(HashMap::new())),
             epoch: Epoch(0),
             viewport_size: Size2D::new(Au(0), Au(0)),
             webrender_api: webrender_api_sender.create_api(),
             rw_data: Arc::new(Mutex::new(
                 LayoutThreadData {
                     constellation_chan: constellation_chan,
@@ -1015,17 +1018,19 @@ impl LayoutThread {
 
         let initial_viewport = data.window_size.initial_viewport;
         let old_viewport_size = self.viewport_size;
         let current_screen_size = Size2D::new(Au::from_f32_px(initial_viewport.width),
                                               Au::from_f32_px(initial_viewport.height));
 
         // Calculate the actual viewport as per DEVICE-ADAPT ยง 6
 
-        let author_guard = document.style_shared_lock().read();
+        let document_shared_lock = document.style_shared_lock();
+        self.document_shared_lock = Some(document_shared_lock.clone());
+        let author_guard = document_shared_lock.read();
         let device = Device::new(MediaType::Screen, initial_viewport);
         Arc::get_mut(&mut rw_data.stylist).unwrap()
             .set_device(device, &author_guard, &data.document_stylesheets);
 
         self.viewport_size =
             rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| {
                 debug!("Viewport constraints: {:?}", constraints);
 
@@ -1184,21 +1189,24 @@ impl LayoutThread {
         if opts::get().dump_rule_tree {
             layout_context.style_context.stylist.rule_tree.dump_stdout(&guards);
         }
 
         // GC the rule tree if some heuristics are met.
         unsafe { layout_context.style_context.stylist.rule_tree.maybe_gc(); }
 
         // Perform post-style recalculation layout passes.
-        self.perform_post_style_recalc_layout_passes(&data.reflow_info,
-                                                     Some(&data.query_type),
-                                                     Some(&document),
-                                                     &mut rw_data,
-                                                     &mut layout_context);
+        if let Some(mut root_flow) = self.root_flow.clone() {
+            self.perform_post_style_recalc_layout_passes(&mut root_flow,
+                                                         &data.reflow_info,
+                                                         Some(&data.query_type),
+                                                         Some(&document),
+                                                         &mut rw_data,
+                                                         &mut layout_context);
+        }
 
         self.respond_to_query_if_necessary(&data.query_type,
                                            &mut *rw_data,
                                            &mut layout_context);
     }
 
     fn respond_to_query_if_necessary(&mut self,
                                      query_type: &ReflowQueryType,
@@ -1341,133 +1349,135 @@ impl LayoutThread {
         self.tick_animations(&mut rw_data);
     }
 
     fn tick_animations(&mut self, rw_data: &mut LayoutThreadData) {
         if opts::get().relayout_event {
             println!("**** pipeline={}\tForDisplay\tSpecial\tAnimationTick", self.id);
         }
 
-        let reflow_info = Reflow {
-            goal: ReflowGoal::ForDisplay,
-            page_clip_rect: max_rect(),
-        };
+        if let Some(mut root_flow) = self.root_flow.clone() {
+            let reflow_info = Reflow {
+                goal: ReflowGoal::ForDisplay,
+                page_clip_rect: max_rect(),
+            };
 
-        let author_guard = AUTHOR_SHARED_LOCK.read();
-        let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
-        let guards = StylesheetGuards {
-            author: &author_guard,
-            ua_or_user: &ua_or_user_guard,
-        };
-        let mut layout_context = self.build_layout_context(guards, &*rw_data, false);
+            // Unwrap here should not panic since self.root_flow is only ever set to Some(_)
+            // in handle_reflow() where self.document_shared_lock is as well.
+            let author_shared_lock = self.document_shared_lock.clone().unwrap();
+            let author_guard = author_shared_lock.read();
+            let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
+            let guards = StylesheetGuards {
+                author: &author_guard,
+                ua_or_user: &ua_or_user_guard,
+            };
+            let mut layout_context = self.build_layout_context(guards, &*rw_data, false);
 
-        if let Some(mut root_flow) = self.root_flow.clone() {
-            // Perform an abbreviated style recalc that operates without access to the DOM.
-            let animations = self.running_animations.read();
-            profile(time::ProfilerCategory::LayoutStyleRecalc,
-                    self.profiler_metadata(),
-                    self.time_profiler_chan.clone(),
-                    || {
-                        animation::recalc_style_for_animations(&layout_context,
-                                                               FlowRef::deref_mut(&mut root_flow),
-                                                               &animations)
-                    });
+            {
+                // Perform an abbreviated style recalc that operates without access to the DOM.
+                let animations = self.running_animations.read();
+                profile(time::ProfilerCategory::LayoutStyleRecalc,
+                        self.profiler_metadata(),
+                        self.time_profiler_chan.clone(),
+                        || {
+                            animation::recalc_style_for_animations(
+                                &layout_context, FlowRef::deref_mut(&mut root_flow), &animations)
+                        });
+            }
+            self.perform_post_style_recalc_layout_passes(&mut root_flow,
+                                                         &reflow_info,
+                                                         None,
+                                                         None,
+                                                         &mut *rw_data,
+                                                         &mut layout_context);
+            assert!(layout_context.pending_images.is_none());
         }
-
-        self.perform_post_style_recalc_layout_passes(&reflow_info,
-                                                     None,
-                                                     None,
-                                                     &mut *rw_data,
-                                                     &mut layout_context);
-
-        assert!(layout_context.pending_images.is_none());
     }
 
     fn perform_post_style_recalc_layout_passes(&mut self,
+                                               root_flow: &mut FlowRef,
                                                data: &Reflow,
                                                query_type: Option<&ReflowQueryType>,
                                                document: Option<&ServoLayoutDocument>,
                                                rw_data: &mut LayoutThreadData,
                                                context: &mut LayoutContext) {
-        if let Some(mut root_flow) = self.root_flow.clone() {
-            // Kick off animations if any were triggered, expire completed ones.
-            animation::update_animation_state(&self.constellation_chan,
-                                              &self.script_chan,
-                                              &mut *self.running_animations.write(),
-                                              &mut *self.expired_animations.write(),
-                                              &self.new_animations_receiver,
-                                              self.id,
-                                              &self.timer);
+        // Kick off animations if any were triggered, expire completed ones.
+        animation::update_animation_state(&self.constellation_chan,
+                                          &self.script_chan,
+                                          &mut *self.running_animations.write(),
+                                          &mut *self.expired_animations.write(),
+                                          &self.new_animations_receiver,
+                                          self.id,
+                                          &self.timer);
+
+        profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
+                self.profiler_metadata(),
+                self.time_profiler_chan.clone(),
+                || {
+            // Call `compute_layout_damage` even in non-incremental mode, because it sets flags
+            // that are needed in both incremental and non-incremental traversals.
+            let damage = FlowRef::deref_mut(root_flow).compute_layout_damage();
 
-            profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
+            if opts::get().nonincremental_layout || damage.contains(REFLOW_ENTIRE_DOCUMENT) {
+                FlowRef::deref_mut(root_flow).reflow_entire_document()
+            }
+        });
+
+        if opts::get().trace_layout {
+            layout_debug::begin_trace(root_flow.clone());
+        }
+
+        // Resolve generated content.
+        profile(time::ProfilerCategory::LayoutGeneratedContent,
+                self.profiler_metadata(),
+                self.time_profiler_chan.clone(),
+                || sequential::resolve_generated_content(FlowRef::deref_mut(root_flow), &context));
+
+        // Guess float placement.
+        profile(time::ProfilerCategory::LayoutFloatPlacementSpeculation,
+                self.profiler_metadata(),
+                self.time_profiler_chan.clone(),
+                || sequential::guess_float_placement(FlowRef::deref_mut(root_flow)));
+
+        // Perform the primary layout passes over the flow tree to compute the locations of all
+        // the boxes.
+        if flow::base(&**root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
+            profile(time::ProfilerCategory::LayoutMain,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || {
-                // Call `compute_layout_damage` even in non-incremental mode, because it sets flags
-                // that are needed in both incremental and non-incremental traversals.
-                let damage = FlowRef::deref_mut(&mut root_flow).compute_layout_damage();
+                let profiler_metadata = self.profiler_metadata();
 
-                if opts::get().nonincremental_layout || damage.contains(REFLOW_ENTIRE_DOCUMENT) {
-                    FlowRef::deref_mut(&mut root_flow).reflow_entire_document()
+                if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
+                    // Parallel mode.
+                    LayoutThread::solve_constraints_parallel(traversal,
+                                                             FlowRef::deref_mut(root_flow),
+                                                             profiler_metadata,
+                                                             self.time_profiler_chan.clone(),
+                                                             &*context);
+                } else {
+                    //Sequential mode
+                    LayoutThread::solve_constraints(FlowRef::deref_mut(root_flow), &context)
                 }
             });
-
-            if opts::get().trace_layout {
-                layout_debug::begin_trace(root_flow.clone());
-            }
-
-            // Resolve generated content.
-            profile(time::ProfilerCategory::LayoutGeneratedContent,
-                    self.profiler_metadata(),
-                    self.time_profiler_chan.clone(),
-                    || sequential::resolve_generated_content(FlowRef::deref_mut(&mut root_flow), &context));
-
-            // Guess float placement.
-            profile(time::ProfilerCategory::LayoutFloatPlacementSpeculation,
-                    self.profiler_metadata(),
-                    self.time_profiler_chan.clone(),
-                    || sequential::guess_float_placement(FlowRef::deref_mut(&mut root_flow)));
-
-            // Perform the primary layout passes over the flow tree to compute the locations of all
-            // the boxes.
-            if flow::base(&*root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
-                profile(time::ProfilerCategory::LayoutMain,
-                        self.profiler_metadata(),
-                        self.time_profiler_chan.clone(),
-                        || {
-                    let profiler_metadata = self.profiler_metadata();
+        }
 
-                    if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
-                        // Parallel mode.
-                        LayoutThread::solve_constraints_parallel(traversal,
-                                                                 FlowRef::deref_mut(&mut root_flow),
-                                                                 profiler_metadata,
-                                                                 self.time_profiler_chan.clone(),
-                                                                 &*context);
-                    } else {
-                        //Sequential mode
-                        LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &context)
-                    }
-                });
-            }
+        profile(time::ProfilerCategory::LayoutStoreOverflow,
+                self.profiler_metadata(),
+                self.time_profiler_chan.clone(),
+                || {
+            sequential::store_overflow(context,
+                                       FlowRef::deref_mut(root_flow) as &mut Flow);
+        });
 
-            profile(time::ProfilerCategory::LayoutStoreOverflow,
-                    self.profiler_metadata(),
-                    self.time_profiler_chan.clone(),
-                    || {
-                sequential::store_overflow(context,
-                                           FlowRef::deref_mut(&mut root_flow) as &mut Flow);
-            });
-
-            self.perform_post_main_layout_passes(data,
-                                                 query_type,
-                                                 document,
-                                                 rw_data,
-                                                 context);
-        }
+        self.perform_post_main_layout_passes(data,
+                                             query_type,
+                                             document,
+                                             rw_data,
+                                             context);
     }
 
     fn perform_post_main_layout_passes(&mut self,
                                        data: &Reflow,
                                        query_type: Option<&ReflowQueryType>,
                                        document: Option<&ServoLayoutDocument>,
                                        rw_data: &mut LayoutThreadData,
                                        layout_context: &mut LayoutContext) {
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -129,17 +129,16 @@ use std::iter::once;
 use std::mem;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::time::{Duration, Instant};
 use style::attr::AttrValue;
 use style::context::{QuirksMode, ReflowGoal};
 use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE};
 use style::selector_parser::{RestyleDamage, Snapshot};
-use style::servo::AUTHOR_SHARED_LOCK;
 use style::shared_lock::SharedRwLock as StyleSharedRwLock;
 use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
 use style::stylesheets::Stylesheet;
 use task_source::TaskSource;
 use time;
 use timers::OneshotTimerCallback;
 use url::Host;
 use url::percent_encoding::percent_decode;
@@ -2127,17 +2126,17 @@ impl Document {
             classes_map: DOMRefCell::new(HashMap::new()),
             images: Default::default(),
             embeds: Default::default(),
             links: Default::default(),
             forms: Default::default(),
             scripts: Default::default(),
             anchors: Default::default(),
             applets: Default::default(),
-            style_shared_lock: AUTHOR_SHARED_LOCK.clone(),
+            style_shared_lock: StyleSharedRwLock::new(),
             stylesheets: DOMRefCell::new(None),
             stylesheets_changed_since_reflow: Cell::new(false),
             stylesheet_list: MutNullableJS::new(None),
             ready_state: Cell::new(ready_state),
             domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
             possibly_focused: Default::default(),
             focused: Default::default(),
             current_script: Default::default(),
--- a/servo/components/style/servo/mod.rs
+++ b/servo/components/style/servo/mod.rs
@@ -4,18 +4,8 @@
 
 //! Servo-specific bits of the style system.
 //!
 //! These get compiled out on a Gecko build.
 
 pub mod media_queries;
 pub mod restyle_damage;
 pub mod selector_parser;
-
-use shared_lock::SharedRwLock;
-
-lazy_static! {
-    /// Per-process shared lock for author-origin stylesheets
-    ///
-    /// FIXME: make it per-document or per-pipeline instead:
-    /// https://github.com/servo/servo/issues/16027
-    pub static ref AUTHOR_SHARED_LOCK: SharedRwLock = SharedRwLock::new();
-}