From 8feb9e80477376a529b8c5ce9951e78f6048f054 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 11 Feb 2017 22:36:31 +0100 Subject: [PATCH 01/17] Add SharedRwLock and Locked --- components/style/lib.rs | 3 + components/style/shared_lock.rs | 162 ++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 components/style/shared_lock.rs diff --git a/components/style/lib.rs b/components/style/lib.rs index b5bc9f74440..58dcafe9ceb 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -106,6 +106,7 @@ pub mod restyle_hints; pub mod rule_tree; pub mod scoped_tls; pub mod selector_parser; +pub mod shared_lock; pub mod stylist; #[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo; pub mod sequential; @@ -168,6 +169,8 @@ macro_rules! reexport_computed_values { longhand_properties_idents!(reexport_computed_values); /// Returns whether the two arguments point to the same value. +/// +/// FIXME: Remove this and use Arc::ptr_eq once we require Rust 1.17 #[inline] pub fn arc_ptr_eq(a: &Arc, b: &Arc) -> bool { let a: &T = &**a; diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs new file mode 100644 index 00000000000..4565e6e5f69 --- /dev/null +++ b/components/style/shared_lock.rs @@ -0,0 +1,162 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +//! Different objects protected by the same lock + +use parking_lot::RwLock; +use std::cell::UnsafeCell; +use std::fmt; +use std::sync::Arc; + +/// A shared read/write lock that can protect multiple objects. +#[derive(Clone)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct SharedRwLock { + #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] + arc: Arc>, +} + +impl fmt::Debug for SharedRwLock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("SharedRwLock") + } +} + +impl SharedRwLock { + /// Create a new shared lock + pub fn new() -> Self { + SharedRwLock { + arc: Arc::new(RwLock::new(())) + } + } + + /// Wrap the given data to make its access protected by this lock. + pub fn wrap(&self, data: T) -> Locked { + Locked { + shared_lock: self.clone(), + data: UnsafeCell::new(data), + } + } + + /// Obtain the lock for reading + pub fn read(&self) -> SharedRwLockReadGuard { + self.arc.raw_read(); + SharedRwLockReadGuard { + shared_lock: self + } + } + + /// Obtain the lock for writing + pub fn write(&self) -> SharedRwLockWriteGuard { + self.arc.raw_write(); + SharedRwLockWriteGuard { + shared_lock: self + } + } +} + +/// Data protect by a shared lock. +pub struct Locked { + shared_lock: SharedRwLock, + data: UnsafeCell, +} + +// Unsafe: the data inside `UnsafeCell` is only accessed in `read_with` and `write_with`, +// where guards ensure synchronization. +unsafe impl Send for Locked {} +unsafe impl Sync for Locked {} + +impl fmt::Debug for Locked { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let guard = self.shared_lock.read(); + self.read_with(&guard).fmt(f) + } +} + +impl Locked { + fn same_lock_as(&self, lock: &SharedRwLock) -> bool { + ::arc_ptr_eq(&self.shared_lock.arc, &lock.arc) + } + + /// Access the data for reading. + pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T { + assert!(self.same_lock_as(&guard.shared_lock), + "Locked::read_with called with a guard from an unrelated SharedRwLock"); + let ptr = self.data.get(); + + // Unsafe: + // + // * The guard guarantees that the lock is taken for reading, + // and we’ve checked that it’s the correct lock. + // * The returned reference borrows *both* the data and the guard, + // so that it can outlive neither. + unsafe { + &*ptr + } + } + + /// Access the data for writing. + pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T { + assert!(self.same_lock_as(&guard.shared_lock), + "Locked::write_with called with a guard from an unrelated SharedRwLock"); + let ptr = self.data.get(); + + // Unsafe: + // + // * The guard guarantees that the lock is taken for writing, + // and we’ve checked that it’s the correct lock. + // * The returned reference borrows *both* the data and the guard, + // so that it can outlive neither. + // * We require a mutable borrow of the guard, + // so that one write guard can only be used once at a time. + unsafe { + &mut *ptr + } + } +} + +/// Proof that a shared lock was obtained for reading. +pub struct SharedRwLockReadGuard<'a> { + shared_lock: &'a SharedRwLock, +} + +/// Proof that a shared lock was obtained for writing. +pub struct SharedRwLockWriteGuard<'a> { + shared_lock: &'a SharedRwLock, +} + +impl<'a> Drop for SharedRwLockReadGuard<'a> { + fn drop(&mut self) { + // Unsafe: self.lock is private to this module, only ever set after `raw_read()`, + // and never copied or cloned (see `compile_time_assert` below). + unsafe { + self.shared_lock.arc.raw_unlock_read() + } + } +} + +impl<'a> Drop for SharedRwLockWriteGuard<'a> { + fn drop(&mut self) { + // Unsafe: self.lock is private to this module, only ever set after `raw_write()`, + // and never copied or cloned (see `compile_time_assert` below). + unsafe { + self.shared_lock.arc.raw_unlock_write() + } + } +} + +#[allow(dead_code)] +mod compile_time_assert { + use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard}; + + trait Marker1 {} + impl Marker1 for T {} + impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone + impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone + + trait Marker2 {} + impl Marker2 for T {} + impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy + impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy +} From c5a7294e05a3b370981170ea273acb60b6116bc0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 14 Mar 2017 16:09:41 +0100 Subject: [PATCH 02/17] Replace RwLock with shared_lock::Locked --- components/layout_thread/lib.rs | 17 ++++++--- components/script/dom/bindings/trace.rs | 2 + components/script/dom/document.rs | 16 ++++++++ components/script/dom/htmlmetaelement.rs | 5 ++- components/script/dom/htmlstyleelement.rs | 3 +- components/script/layout_wrapper.rs | 5 +++ components/script/stylesheet_loader.rs | 2 + components/style/encoding_support.rs | 3 ++ components/style/stylesheets.rs | 37 +++++++++++++------ components/style/stylist.rs | 15 +++++--- ports/geckolib/glue.rs | 17 ++++++--- ports/geckolib/stylesheet_loader.rs | 5 ++- tests/unit/style/media_queries.rs | 14 ++++--- tests/unit/style/rule_tree/bench.rs | 2 + tests/unit/style/stylesheets.rs | 8 ++-- tests/unit/style/viewport.rs | 2 + tests/unit/stylo/lib.rs | 3 -- tests/unit/stylo/servo_function_signatures.rs | 3 ++ 18 files changed, 117 insertions(+), 42 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 566d6e437cd..ee374d18fc8 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -115,6 +115,7 @@ use style::logical_geometry::LogicalPoint; use style::media_queries::{Device, MediaType}; use style::parser::ParserContextExtraData; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW}; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; use style::stylist::Stylist; use style::thread_state; @@ -934,6 +935,7 @@ impl LayoutThread { possibly_locked_rw_data: &mut RwData<'a, 'b>) { let document = unsafe { ServoLayoutNode::new(&data.document) }; let document = document.as_document().unwrap(); + let style_guard = document.style_shared_lock().read(); self.quirks_mode = Some(document.quirks_mode()); // FIXME(pcwalton): Combine `ReflowGoal` and `ReflowQueryType`. Then remove this assert. @@ -1010,7 +1012,8 @@ impl LayoutThread { // Calculate the actual viewport as per DEVICE-ADAPT § 6 let device = Device::new(MediaType::Screen, initial_viewport); - Arc::get_mut(&mut rw_data.stylist).unwrap().set_device(device, &data.document_stylesheets); + Arc::get_mut(&mut rw_data.stylist).unwrap() + .set_device(device, &style_guard, &data.document_stylesheets); self.viewport_size = rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| { @@ -1528,7 +1531,8 @@ fn get_root_flow_background_color(flow: &mut Flow) -> webrender_traits::ColorF { } fn get_ua_stylesheets() -> Result { - fn parse_ua_stylesheet(filename: &'static str) -> Result { + fn parse_ua_stylesheet(shared_lock: &SharedRwLock, filename: &'static str) + -> Result { let res = try!(read_resource_file(filename).map_err(|_| filename)); Ok(Stylesheet::from_bytes( &res, @@ -1537,26 +1541,29 @@ fn get_ua_stylesheets() -> Result { None, Origin::UserAgent, Default::default(), + shared_lock.clone(), None, &StdoutErrorReporter, ParserContextExtraData::default())) } + let shared_lock = SharedRwLock::new(); let mut user_or_user_agent_stylesheets = vec!(); // FIXME: presentational-hints.css should be at author origin with zero specificity. // (Does it make a difference?) for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] { - user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(filename))); + user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(&shared_lock, filename))); } for &(ref contents, ref url) in &opts::get().user_stylesheets { user_or_user_agent_stylesheets.push(Stylesheet::from_bytes( &contents, url.clone(), None, None, Origin::User, Default::default(), - None, &StdoutErrorReporter, ParserContextExtraData::default())); + shared_lock.clone(), None, &StdoutErrorReporter, ParserContextExtraData::default())); } - let quirks_mode_stylesheet = try!(parse_ua_stylesheet("quirks-mode.css")); + let quirks_mode_stylesheet = try!(parse_ua_stylesheet(&shared_lock, "quirks-mode.css")); Ok(UserAgentStylesheets { + shared_lock: shared_lock, user_or_user_agent_stylesheets: user_or_user_agent_stylesheets, quirks_mode_stylesheet: quirks_mode_stylesheet, }) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 4d38b39d333..b0828ab6d56 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -99,6 +99,7 @@ use style::keyframes::Keyframe; use style::media_queries::MediaList; use style::properties::PropertyDeclarationBlock; use style::selector_parser::{PseudoElement, Snapshot}; +use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule}; use style::stylesheets::SupportsRule; use style::values::specified::Length; @@ -360,6 +361,7 @@ unsafe_no_jsmanaged_fields!(HttpsState); unsafe_no_jsmanaged_fields!(Request); unsafe_no_jsmanaged_fields!(RequestInit); unsafe_no_jsmanaged_fields!(SharedRt); +unsafe_no_jsmanaged_fields!(StyleSharedRwLock); unsafe_no_jsmanaged_fields!(TouchpadPressurePhase); unsafe_no_jsmanaged_fields!(USVString); unsafe_no_jsmanaged_fields!(ReferrerPolicy); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index b85366a27d2..7a50fe5cf6c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -134,6 +134,7 @@ 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::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; @@ -220,6 +221,9 @@ pub struct Document { scripts: MutNullableJS, anchors: MutNullableJS, applets: MutNullableJS, + /// Lock use for style attributes and author-origin stylesheet objects in this document. + /// Can be acquired once for accessing many objects. + style_shared_lock: StyleSharedRwLock, /// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed. stylesheets: DOMRefCell>>, /// Whether the list of stylesheets has changed since the last reflow was triggered. @@ -1964,6 +1968,7 @@ pub trait LayoutDocumentHelpers { unsafe fn needs_paint_from_layout(&self); unsafe fn will_paint(&self); unsafe fn quirks_mode(&self) -> QuirksMode; + unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock; } #[allow(unsafe_code)] @@ -2000,6 +2005,11 @@ impl LayoutDocumentHelpers for LayoutJS { unsafe fn quirks_mode(&self) -> QuirksMode { (*self.unsafe_get()).quirks_mode() } + + #[inline] + unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock { + (*self.unsafe_get()).style_shared_lock() + } } // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to @@ -2121,6 +2131,7 @@ impl Document { scripts: Default::default(), anchors: Default::default(), applets: Default::default(), + style_shared_lock: StyleSharedRwLock::new(), stylesheets: DOMRefCell::new(None), stylesheets_changed_since_reflow: Cell::new(false), stylesheet_list: MutNullableJS::new(None), @@ -2250,6 +2261,11 @@ impl Document { }; } + /// Return a reference to the per-document shared lock used in stylesheets. + pub fn style_shared_lock(&self) -> &StyleSharedRwLock { + &self.style_shared_lock + } + /// Returns the list of stylesheets associated with nodes in the document. pub fn stylesheets(&self) -> Vec> { self.ensure_stylesheets(); diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index a751486de7d..2f78e74d3b4 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -99,12 +99,15 @@ impl HTMLMetaElement { let content = content.value(); if !content.is_empty() { if let Some(translated_rule) = ViewportRule::from_meta(&**content) { + let document = self.upcast::().owner_doc(); + let shared_lock = document.style_shared_lock(); *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet { rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]), origin: Origin::Author, + shared_lock: shared_lock.clone(), base_url: window_from_node(self).get_url(), namespaces: Default::default(), - media: Default::default(), + media: Arc::new(shared_lock.wrap(Default::default())), // Viewport constraints are always recomputed on resize; they don't need to // force all styles to be recomputed. dirty_on_viewport_size_change: AtomicBool::new(false), diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index f9c6412f854..13721feba58 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -84,9 +84,10 @@ impl HTMLStyleElement { let data = node.GetTextContent().expect("Element.textContent must be a string"); let mq = parse_media_query_list(&mut CssParser::new(&mq_str)); + let shared_lock = node.owner_doc().style_shared_lock().clone(); let loader = StylesheetLoader::for_element(self.upcast()); let sheet = Stylesheet::from_str(&data, url, Origin::Author, mq, - Some(&loader), + shared_lock, Some(&loader), win.css_error_reporter(), ParserContextExtraData::default()); diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 98ce86745f2..5a9a834667b 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -69,6 +69,7 @@ use style::dom::UnsafeNode; use style::element_state::*; use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; +use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::sink::Push; use style::str::is_whitespace; use style::stylist::ApplicableDeclarationBlock; @@ -330,6 +331,10 @@ impl<'ld> ServoLayoutDocument<'ld> { unsafe { self.document.quirks_mode() } } + pub fn style_shared_lock(&self) -> &StyleSharedRwLock { + unsafe { self.document.style_shared_lock() } + } + pub fn from_layout_js(doc: LayoutJS) -> ServoLayoutDocument<'ld> { ServoLayoutDocument { document: doc, diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index cdc93c9808b..26dffa5fe56 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -152,12 +152,14 @@ impl FetchResponseListener for StylesheetContext { let is_stylesheet_load_applicable = self.request_generation_id.map_or(true, |gen| gen == link.get_request_generation_id()); if is_stylesheet_load_applicable { + let shared_lock = document.style_shared_lock().clone(); let sheet = Arc::new(Stylesheet::from_bytes(&data, final_url, protocol_encoding_label, Some(environment_encoding), Origin::Author, media.take().unwrap(), + shared_lock, Some(&loader), win.css_error_reporter(), ParserContextExtraData::default())); diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index 62323ec2314..141291c896e 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -12,6 +12,7 @@ use media_queries::MediaList; use parser::ParserContextExtraData; use self::encoding::{EncodingRef, DecoderTrap}; use servo_url::ServoUrl; +use shared_lock::SharedRwLock; use std::str; use stylesheets::{Stylesheet, StylesheetLoader, Origin}; @@ -54,6 +55,7 @@ impl Stylesheet { environment_encoding: Option, origin: Origin, media: MediaList, + shared_lock: SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) @@ -64,6 +66,7 @@ impl Stylesheet { base_url, origin, media, + shared_lock, stylesheet_loader, error_reporter, extra_data) diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 5b5c47e152f..3d487ec8db1 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -21,6 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser}; use selectors::parser::SelectorList; use servo_config::prefs::PREFS; use servo_url::ServoUrl; +use shared_lock::{SharedRwLock, Locked, SharedRwLockReadGuard}; use std::cell::Cell; use std::fmt; use std::sync::Arc; @@ -175,11 +176,13 @@ pub struct Stylesheet { /// cascading order) pub rules: Arc>, /// List of media associated with the Stylesheet. - pub media: Arc>, + pub media: Arc>, /// The origin of this stylesheet. pub origin: Origin, /// The base url this stylesheet should use. pub base_url: ServoUrl, + /// The lock used for objects inside this stylesheet + pub shared_lock: SharedRwLock, /// The namespaces that apply to this stylesheet. pub namespaces: RwLock, /// Whether this stylesheet would be dirty when the viewport size changes. @@ -191,6 +194,8 @@ pub struct Stylesheet { /// This structure holds the user-agent and user stylesheets. pub struct UserAgentStylesheets { + /// The lock used for user-agent stylesheets. + pub shared_lock: SharedRwLock, /// The user or user agent stylesheets. pub user_or_user_agent_stylesheets: Vec, /// The quirks mode stylesheet. @@ -291,12 +296,12 @@ impl CssRule { /// used for others. /// /// This will not recurse down unsupported @supports rules - pub fn with_nested_rules_and_mq(&self, mut f: F) -> R + pub fn with_nested_rules_and_mq(&self, guard: &SharedRwLockReadGuard, mut f: F) -> R where F: FnMut(&[CssRule], Option<&MediaList>) -> R { match *self { CssRule::Import(ref lock) => { let rule = lock.read(); - let media = rule.stylesheet.media.read(); + let media = rule.stylesheet.media.read_with(guard); let rules = rule.stylesheet.rules.read(); // FIXME(emilio): Include the nested rules if the stylesheet is // loaded. @@ -349,6 +354,7 @@ impl CssRule { let mut rule_parser = TopLevelRuleParser { stylesheet_origin: parent_stylesheet.origin, context: context, + shared_lock: &parent_stylesheet.shared_lock, loader: None, state: Cell::new(state), namespaces: &mut namespaces, @@ -424,7 +430,8 @@ impl ToCss for ImportRule { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { try!(dest.write_str("@import ")); try!(self.url.to_css(dest)); - let media = self.stylesheet.media.read(); + let guard = self.stylesheet.shared_lock.read(); // FIXME: have the caller pass this? + let media = self.stylesheet.media.read_with(&guard); if !media.is_empty() { try!(dest.write_str(" ")); try!(media.to_css(dest)); @@ -554,6 +561,7 @@ impl Stylesheet { let rule_parser = TopLevelRuleParser { stylesheet_origin: existing.origin, namespaces: &mut namespaces, + shared_lock: &existing.shared_lock, loader: stylesheet_loader, context: ParserContext::new_with_extra_data(existing.origin, &existing.base_url, @@ -591,6 +599,7 @@ impl Stylesheet { base_url: ServoUrl, origin: Origin, media: MediaList, + shared_lock: SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) -> Stylesheet { @@ -599,7 +608,8 @@ impl Stylesheet { base_url: base_url, namespaces: RwLock::new(Namespaces::default()), rules: CssRules::new(vec![]), - media: Arc::new(RwLock::new(media)), + media: Arc::new(shared_lock.wrap(media)), + shared_lock: shared_lock.clone(), dirty_on_viewport_size_change: AtomicBool::new(false), disabled: AtomicBool::new(false), }; @@ -638,7 +648,8 @@ impl Stylesheet { /// /// Always true if no associated MediaList exists. pub fn is_effective_for_device(&self, device: &Device) -> bool { - self.media.read().evaluate(device) + let guard = self.shared_lock.read(); // FIXME: have the caller pass this? + self.media.read_with(&guard).evaluate(device) } /// Return an iterator over the effective rules within the style-sheet, as @@ -649,7 +660,8 @@ impl Stylesheet { /// examined. #[inline] pub fn effective_rules(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) { - effective_rules(&self.rules.read().0, device, &mut f); + let guard = self.shared_lock.read(); // FIXME: have the caller pass this? + effective_rules(&self.rules.read().0, device, &guard, &mut f); } /// Returns whether the stylesheet has been explicitly disabled through the @@ -670,16 +682,17 @@ impl Stylesheet { } } -fn effective_rules(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) { +fn effective_rules(rules: &[CssRule], device: &Device, guard: &SharedRwLockReadGuard, f: &mut F) +where F: FnMut(&CssRule) { for rule in rules { f(rule); - rule.with_nested_rules_and_mq(|rules, mq| { + rule.with_nested_rules_and_mq(guard, |rules, mq| { if let Some(media_queries) = mq { if !media_queries.evaluate(device) { return } } - effective_rules(rules, device, f) + effective_rules(rules, device, guard, f) }) } } @@ -724,6 +737,7 @@ pub trait StylesheetLoader { struct TopLevelRuleParser<'a> { stylesheet_origin: Origin, namespaces: &'a mut Namespaces, + shared_lock: &'a SharedRwLock, loader: Option<&'a StylesheetLoader>, context: ParserContext<'a>, state: Cell, @@ -780,7 +794,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { &self.context)); let media = - Arc::new(RwLock::new(parse_media_query_list(input))); + Arc::new(self.shared_lock.wrap(parse_media_query_list(input))); let is_valid_url = url.url().is_some(); @@ -790,6 +804,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { stylesheet: Arc::new(Stylesheet { rules: Arc::new(RwLock::new(CssRules(vec![]))), media: media, + shared_lock: self.shared_lock.clone(), origin: self.context.stylesheet_origin, base_url: self.context.base_url.clone(), namespaces: RwLock::new(Namespaces::default()), diff --git a/components/style/stylist.rs b/components/style/stylist.rs index f7dd149e7d3..e28bb641cd0 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -28,6 +28,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use selectors::parser::SelectorMethods; +#[cfg(feature = "servo")] use shared_lock::SharedRwLockReadGuard; use sink::Push; use smallvec::VecLike; use std::borrow::Borrow; @@ -461,7 +462,8 @@ impl Stylist { /// FIXME(emilio): The semantics of the device for Servo and Gecko are /// different enough we may want to unify them. #[cfg(feature = "servo")] - pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc]) { + pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard, + stylesheets: &[Arc]) { let cascaded_rule = ViewportRule { declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(), }; @@ -473,15 +475,16 @@ impl Stylist { device.account_for_viewport_rule(constraints); } - fn mq_eval_changed(rules: &[CssRule], before: &Device, after: &Device) -> bool { + fn mq_eval_changed(guard: &SharedRwLockReadGuard, rules: &[CssRule], + before: &Device, after: &Device) -> bool { for rule in rules { - let changed = rule.with_nested_rules_and_mq(|rules, mq| { + let changed = rule.with_nested_rules_and_mq(guard, |rules, mq| { if let Some(mq) = mq { if mq.evaluate(before) != mq.evaluate(after) { return true } } - mq_eval_changed(rules, before, after) + mq_eval_changed(guard, rules, before, after) }); if changed { return true @@ -490,12 +493,12 @@ impl Stylist { false } self.is_device_dirty |= stylesheets.iter().any(|stylesheet| { - let mq = stylesheet.media.read(); + let mq = stylesheet.media.read_with(guard); if mq.evaluate(&self.device) != mq.evaluate(&device) { return true } - mq_eval_changed(&stylesheet.rules.read().0, &self.device, &device) + mq_eval_changed(guard, &stylesheet.rules.read().0, &self.device, &device) }); self.device = Arc::new(device); diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 16d8b0c9f36..7330d8f63de 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -76,6 +76,7 @@ use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::selector_parser::PseudoElementCascadeType; use style::sequential; +use style::shared_lock::SharedRwLock; use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; @@ -85,7 +86,7 @@ use style::thread_state; use style::timer::Timer; use style::traversal::{resolve_style, DomTraversal, TraversalDriver}; use style_traits::ToCss; -use stylesheet_loader::StylesheetLoader; +use super::stylesheet_loader::StylesheetLoader; /* * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in @@ -95,12 +96,15 @@ use stylesheet_loader::StylesheetLoader; * depend on but good enough for our purposes. */ -struct GlobalStyleData { +pub struct GlobalStyleData { // How many threads parallel styling can use. pub num_threads: usize, // The parallel styling thread pool. pub style_thread_pool: Option, + + // Shared RWLock for CSSOM objects + pub shared_lock: SharedRwLock, } impl GlobalStyleData { @@ -124,12 +128,13 @@ impl GlobalStyleData { GlobalStyleData { num_threads: num_threads, style_thread_pool: pool, + shared_lock: SharedRwLock::new(), } } } lazy_static! { - static ref GLOBAL_STYLE_DATA: GlobalStyleData = { + pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = { GlobalStyleData::new() }; } @@ -335,8 +340,9 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl SheetParsingMode::eUserSheetFeatures => Origin::User, SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, }; + let shared_lock = GLOBAL_STYLE_DATA.shared_lock.clone(); Arc::new(Stylesheet::from_str( - "", url, origin, Default::default(), None, + "", url, origin, Default::default(), shared_lock, None, &StdoutErrorReporter, extra_data) ).into_strong() } @@ -378,8 +384,9 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, Some(ref s) => Some(s), }; + let shared_lock = GLOBAL_STYLE_DATA.shared_lock.clone(); Arc::new(Stylesheet::from_str( - input, url, origin, Default::default(), loader, + input, url, origin, Default::default(), shared_lock, loader, &StdoutErrorReporter, extra_data) ).into_strong() } diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index 3e6fb421c86..bcd55cce2fd 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -9,6 +9,7 @@ use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; use style::gecko_bindings::sugar::ownership::HasArcFFI; use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader}; use style_traits::ToCss; +use super::glue::GLOBAL_STYLE_DATA; pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet); @@ -20,6 +21,8 @@ impl StylesheetLoader { impl StyleStylesheetLoader for StylesheetLoader { fn request_stylesheet(&self, import_rule: &Arc>) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let import = import_rule.read(); let (spec_bytes, spec_len) = import.url.as_slice_components() .expect("Import only loads valid URLs"); @@ -32,7 +35,7 @@ impl StyleStylesheetLoader for StylesheetLoader { // evaluate them on the main thread. // // Meanwhile, this works. - let media = import.stylesheet.media.read().to_css_string(); + let media = import.stylesheet.media.read_with(&guard).to_css_string(); unsafe { Gecko_LoadStyleSheet(self.0, diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs index 95182676e3c..485ccd1d486 100644 --- a/tests/unit/style/media_queries.rs +++ b/tests/unit/style/media_queries.rs @@ -11,6 +11,7 @@ use style::error_reporting::ParseErrorReporter; use style::media_queries::*; use style::parser::ParserContextExtraData; use style::servo::media_queries::*; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard}; use style::stylesheets::{Stylesheet, Origin, CssRule}; use style::values::specified; use style_traits::ToCss; @@ -29,26 +30,27 @@ fn test_media_rule(css: &str, callback: F) let url = ServoUrl::parse("http://localhost").unwrap(); let css_str = css.to_owned(); let stylesheet = Stylesheet::from_str( - css, url, Origin::Author, Default::default(), + css, url, Origin::Author, Default::default(), SharedRwLock::new(), None, &CSSErrorReporterTest, ParserContextExtraData::default()); let mut rule_count = 0; - media_queries(&stylesheet.rules.read().0, &mut |mq| { + let guard = stylesheet.shared_lock.read(); + media_queries(&guard, &stylesheet.rules.read().0, &mut |mq| { rule_count += 1; callback(mq, css); }); assert!(rule_count > 0, css_str); } -fn media_queries(rules: &[CssRule], f: &mut F) +fn media_queries(guard: &SharedRwLockReadGuard, rules: &[CssRule], f: &mut F) where F: FnMut(&MediaList), { for rule in rules { - rule.with_nested_rules_and_mq(|rules, mq| { + rule.with_nested_rules_and_mq(guard, |rules, mq| { if let Some(mq) = mq { f(mq) } - media_queries(rules, f) + media_queries(guard, rules, f) }) } } @@ -56,7 +58,7 @@ fn media_queries(rules: &[CssRule], f: &mut F) fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) { let url = ServoUrl::parse("http://localhost").unwrap(); let ss = Stylesheet::from_str( - css, url, Origin::Author, Default::default(), + css, url, Origin::Author, Default::default(), SharedRwLock::new(), None, &CSSErrorReporterTest, ParserContextExtraData::default()); let mut rule_count = 0; diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs index 37bef590a64..623a534159a 100644 --- a/tests/unit/style/rule_tree/bench.rs +++ b/tests/unit/style/rule_tree/bench.rs @@ -12,6 +12,7 @@ use style::media_queries::MediaList; use style::parser::ParserContextExtraData; use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock}; use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Origin, Stylesheet, CssRule}; use test::{self, Bencher}; @@ -44,6 +45,7 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> { MediaList { media_queries: vec![], }, + SharedRwLock::new(), None, &ErrorringErrorReporter, ParserContextExtraData {}); diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index a1d649c099c..590e93185f4 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -20,6 +20,7 @@ use style::properties::Importance; use style::properties::{CSSWideKeyword, DeclaredValueOwned, PropertyDeclaration, PropertyDeclarationBlock}; use style::properties::longhands; use style::properties::longhands::animation_play_state; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Origin, Namespaces}; use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule}; use style::values::specified::{LengthOrPercentageOrAuto, Percentage}; @@ -62,14 +63,15 @@ fn test_parse_stylesheet() { }"; let url = ServoUrl::parse("about::test").unwrap(); let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(), - None, + SharedRwLock::new(), None, &CSSErrorReporterTest, ParserContextExtraData::default()); let mut namespaces = Namespaces::default(); namespaces.default = Some(ns!(html)); let expected = Stylesheet { origin: Origin::UserAgent, - media: Default::default(), + media: Arc::new(stylesheet.shared_lock.wrap(Default::default())), + shared_lock: stylesheet.shared_lock.clone(), namespaces: RwLock::new(namespaces), base_url: url, dirty_on_viewport_size_change: AtomicBool::new(false), @@ -324,7 +326,7 @@ fn test_report_error_stylesheet() { let errors = error_reporter.errors.clone(); Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(), - None, + SharedRwLock::new(), None, &error_reporter, ParserContextExtraData::default()); diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index 166094ebdc1..9fe53ebb40c 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -9,6 +9,7 @@ use servo_config::prefs::{PREFS, PrefValue}; use servo_url::ServoUrl; use style::media_queries::{Device, MediaType}; use style::parser::{ParserContext, ParserContextExtraData}; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Stylesheet, Origin}; use style::values::specified::LengthOrPercentageOrAuto::{self, Auto}; use style::values::specified::NoCalcLength::{self, ViewportPercentage}; @@ -24,6 +25,7 @@ macro_rules! stylesheet { ServoUrl::parse("http://localhost").unwrap(), Origin::$origin, Default::default(), + SharedRwLock::new(), None, &$error_reporter, ParserContextExtraData::default() diff --git a/tests/unit/stylo/lib.rs b/tests/unit/stylo/lib.rs index c89687918ef..c0d04ffcbec 100644 --- a/tests/unit/stylo/lib.rs +++ b/tests/unit/stylo/lib.rs @@ -21,8 +21,5 @@ extern crate style_traits; mod sanity_checks; mod size_of; -#[path = "../../../ports/geckolib/stylesheet_loader.rs"] -mod stylesheet_loader; - mod servo_function_signatures; diff --git a/tests/unit/stylo/servo_function_signatures.rs b/tests/unit/stylo/servo_function_signatures.rs index 6bdeb6d5af7..30d6d02439b 100644 --- a/tests/unit/stylo/servo_function_signatures.rs +++ b/tests/unit/stylo/servo_function_signatures.rs @@ -10,6 +10,9 @@ use style::gecko_properties::*; include!(concat!(env!("OUT_DIR"), "/check_bindings.rs")); +#[path = "../../../ports/geckolib/stylesheet_loader.rs"] +mod stylesheet_loader; + #[allow(non_snake_case, unused_unsafe, private_no_mangle_fns)] mod glue { // this module pretends to be glue.rs, with the safe functions swapped for unsafe ones. This is From d18b1280f2a5f660fa8e40dbcb3c0923a7703d58 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 16 Mar 2017 23:08:10 +0100 Subject: [PATCH 03/17] Move shared lock acquires up the call stack. (Or is it down?) --- components/layout_thread/lib.rs | 11 +++++++---- components/style/gecko/data.rs | 9 +++++---- components/style/stylesheets.rs | 5 ++--- components/style/stylist.rs | 16 +++++++++------- ports/geckolib/glue.rs | 32 +++++++++++++++++++++++--------- 5 files changed, 46 insertions(+), 27 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index ee374d18fc8..c86c0221603 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -731,7 +731,8 @@ impl LayoutThread { // GWTODO: Need to handle unloading web fonts. let rw_data = possibly_locked_rw_data.lock(); - if stylesheet.is_effective_for_device(&rw_data.stylist.device) { + let guard = stylesheet.shared_lock.read(); + if stylesheet.is_effective_for_device(&rw_data.stylist.device, &guard) { add_font_face_rules(&*stylesheet, &rw_data.stylist.device, &self.font_cache_thread, @@ -1057,9 +1058,11 @@ impl LayoutThread { } // If the entire flow tree is invalid, then it will be reflowed anyhow. - let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets, - Some(&*UA_STYLESHEETS), - data.stylesheets_changed); + let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update( + &data.document_stylesheets, + &style_guard, + Some(&*UA_STYLESHEETS), + data.stylesheets_changed); let needs_reflow = viewport_size_changed && !needs_dirtying; if needs_dirtying { if let Some(mut d) = element.mutate_data() { diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 627b3845051..e0f7df023e2 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -13,6 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use media_queries::Device; use parking_lot::RwLock; use properties::ComputedValues; +use shared_lock::SharedRwLockReadGuard; use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; @@ -83,20 +84,20 @@ impl PerDocumentStyleDataImpl { /// Reset the device state because it may have changed. /// /// Implies also a stylesheet flush. - pub fn reset_device(&mut self) { + pub fn reset_device(&mut self, guard: &SharedRwLockReadGuard) { { let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); Arc::get_mut(&mut stylist.device).unwrap().reset(); } self.stylesheets_changed = true; - self.flush_stylesheets(); + self.flush_stylesheets(guard); } /// Recreate the style data if the stylesheets have changed. - pub fn flush_stylesheets(&mut self) { + pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) { if self.stylesheets_changed { let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); - stylist.update(&self.stylesheets, None, true); + stylist.update(&self.stylesheets, guard, None, true); self.stylesheets_changed = false; } } diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 3d487ec8db1..092bbdf8a93 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -647,9 +647,8 @@ impl Stylesheet { /// on the associated MediaList. /// /// Always true if no associated MediaList exists. - pub fn is_effective_for_device(&self, device: &Device) -> bool { - let guard = self.shared_lock.read(); // FIXME: have the caller pass this? - self.media.read_with(&guard).evaluate(device) + pub fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool { + self.media.read_with(guard).evaluate(device) } /// Return an iterator over the effective rules within the style-sheet, as diff --git a/components/style/stylist.rs b/components/style/stylist.rs index e28bb641cd0..27adfdd451a 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -28,7 +28,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use selectors::parser::SelectorMethods; -#[cfg(feature = "servo")] use shared_lock::SharedRwLockReadGuard; +use shared_lock::SharedRwLockReadGuard; use sink::Push; use smallvec::VecLike; use std::borrow::Borrow; @@ -159,6 +159,7 @@ impl Stylist { /// device is dirty, which means we need to re-evaluate media queries. pub fn update(&mut self, doc_stylesheets: &[Arc], + doc_guard: &SharedRwLockReadGuard, ua_stylesheets: Option<&UserAgentStylesheets>, stylesheets_changed: bool) -> bool { if !(self.is_device_dirty || stylesheets_changed) { @@ -193,17 +194,18 @@ impl Stylist { self.non_common_style_affecting_attributes_selectors.clear(); if let Some(ua_stylesheets) = ua_stylesheets { + let ua_guard = ua_stylesheets.shared_lock.read(); for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets { - self.add_stylesheet(&stylesheet); + self.add_stylesheet(&stylesheet, &ua_guard); } if self.quirks_mode { - self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet); + self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, &ua_guard); } } for ref stylesheet in doc_stylesheets.iter() { - self.add_stylesheet(stylesheet); + self.add_stylesheet(stylesheet, doc_guard); } debug!("Stylist stats:"); @@ -227,8 +229,8 @@ impl Stylist { true } - fn add_stylesheet(&mut self, stylesheet: &Stylesheet) { - if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device) { + fn add_stylesheet(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) { + if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device, guard) { return; } @@ -271,7 +273,7 @@ impl Stylist { } CssRule::Import(ref import) => { let import = import.read(); - self.add_stylesheet(&import.stylesheet) + self.add_stylesheet(&import.stylesheet, guard) } CssRule::Keyframes(ref keyframes_rule) => { let keyframes_rule = keyframes_rule.read(); diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 7330d8f63de..b8c6e4ebbab 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -204,7 +204,7 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed, debug!("{:?}", ShowSubtreeData(element.as_node())); let shared_style_context = create_shared_context(&per_doc_data); - let ref global_style_data = *GLOBAL_STYLE_DATA; + let global_style_data = &*GLOBAL_STYLE_DATA; let traversal_driver = if global_style_data.style_thread_pool.is_none() { TraversalDriver::Sequential @@ -333,6 +333,7 @@ pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) { #[no_mangle] pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; let url = ServoUrl::parse("about:blank").unwrap(); let extra_data = ParserContextExtraData::default(); let origin = match mode { @@ -340,7 +341,7 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl SheetParsingMode::eUserSheetFeatures => Origin::User, SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, }; - let shared_lock = GLOBAL_STYLE_DATA.shared_lock.clone(); + let shared_lock = global_style_data.shared_lock.clone(); Arc::new(Stylesheet::from_str( "", url, origin, Default::default(), shared_lock, None, &StdoutErrorReporter, extra_data) @@ -357,6 +358,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) -> RawServoStyleSheetStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let origin = match mode { @@ -384,7 +386,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, Some(ref s) => Some(s), }; - let shared_lock = GLOBAL_STYLE_DATA.shared_lock.clone(); + let shared_lock = global_style_data.shared_lock.clone(); Arc::new(Stylesheet::from_str( input, url, origin, Default::default(), shared_lock, loader, &StdoutErrorReporter, extra_data) @@ -430,13 +432,15 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, flush: bool) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.push(sheet.clone()); data.stylesheets_changed = true; if flush { - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } } @@ -444,13 +448,15 @@ pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorr pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, flush: bool) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.insert(0, sheet.clone()); data.stylesheets_changed = true; if flush { - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } } @@ -459,6 +465,8 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS raw_sheet: RawServoStyleSheetBorrowed, raw_reference: RawServoStyleSheetBorrowed, flush: bool) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); let reference = HasArcFFI::as_arc(&raw_reference); @@ -467,7 +475,7 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS data.stylesheets.insert(index, sheet.clone()); data.stylesheets_changed = true; if flush { - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } } @@ -475,19 +483,23 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, flush: bool) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets_changed = true; if flush { - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } } #[no_mangle] pub extern "C" fn Servo_StyleSet_FlushStyleSheets(raw_data: RawServoStyleSetBorrowed) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } #[no_mangle] @@ -732,8 +744,10 @@ pub extern "C" fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned) #[no_mangle] pub extern "C" fn Servo_StyleSet_RebuildData(raw_data: RawServoStyleSetBorrowed) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - data.reset_device(); + data.reset_device(&guard); } #[no_mangle] From 3ae2ecbec2f2a22734e078555614ce7ac3e761a3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 16 Mar 2017 23:42:39 +0100 Subject: [PATCH 04/17] More lock acquire in callers --- components/layout_thread/lib.rs | 13 +++++++++---- components/style/stylesheets.rs | 11 ++++++----- components/style/stylist.rs | 8 +++++--- components/style/viewport.rs | 6 ++++-- tests/unit/style/media_queries.rs | 2 +- tests/unit/style/viewport.rs | 30 ++++++++++++++++++++---------- 6 files changed, 45 insertions(+), 25 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index c86c0221603..566d6c7ca33 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -115,7 +115,7 @@ use style::logical_geometry::LogicalPoint; use style::media_queries::{Device, MediaType}; use style::parser::ParserContextExtraData; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW}; -use style::shared_lock::SharedRwLock; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard}; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; use style::stylist::Stylist; use style::thread_state; @@ -345,13 +345,14 @@ impl<'a, 'b: 'a> RwData<'a, 'b> { } fn add_font_face_rules(stylesheet: &Stylesheet, + guard: &SharedRwLockReadGuard, device: &Device, font_cache_thread: &FontCacheThread, font_cache_sender: &IpcSender<()>, outstanding_web_fonts_counter: &Arc) { if opts::get().load_webfonts_synchronously { let (sender, receiver) = ipc::channel().unwrap(); - stylesheet.effective_font_face_rules(&device, |font_face| { + stylesheet.effective_font_face_rules(&device, guard, |font_face| { let effective_sources = font_face.effective_sources(); font_cache_thread.add_web_font(font_face.family.clone(), effective_sources, @@ -359,7 +360,7 @@ fn add_font_face_rules(stylesheet: &Stylesheet, receiver.recv().unwrap(); }) } else { - stylesheet.effective_font_face_rules(&device, |font_face| { + stylesheet.effective_font_face_rules(&device, guard, |font_face| { let effective_sources = font_face.effective_sources(); outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); font_cache_thread.add_web_font(font_face.family.clone(), @@ -407,8 +408,11 @@ impl LayoutThread { let stylist = Arc::new(Stylist::new(device)); let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0)); - for stylesheet in &*UA_STYLESHEETS.user_or_user_agent_stylesheets { + let ua_stylesheets = &*UA_STYLESHEETS; + let guard = ua_stylesheets.shared_lock.read(); + for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets { add_font_face_rules(stylesheet, + &guard, &stylist.device, &font_cache_thread, &ipc_font_cache_sender, @@ -734,6 +738,7 @@ impl LayoutThread { let guard = stylesheet.shared_lock.read(); if stylesheet.is_effective_for_device(&rw_data.stylist.device, &guard) { add_font_face_rules(&*stylesheet, + &guard, &rw_data.stylist.device, &self.font_cache_thread, &self.font_cache_sender, diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 092bbdf8a93..6c6862fef5e 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -658,9 +658,9 @@ impl Stylesheet { /// nested rules will be skipped. Use `rules` if all rules need to be /// examined. #[inline] - pub fn effective_rules(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) { - let guard = self.shared_lock.read(); // FIXME: have the caller pass this? - effective_rules(&self.rules.read().0, device, &guard, &mut f); + pub fn effective_rules(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F) + where F: FnMut(&CssRule) { + effective_rules(&self.rules.read().0, device, guard, &mut f); } /// Returns whether the stylesheet has been explicitly disabled through the @@ -701,8 +701,9 @@ macro_rules! rule_filter { impl Stylesheet { $( #[allow(missing_docs)] - pub fn $method(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) { - self.effective_rules(device, |rule| { + pub fn $method(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F) + where F: FnMut(&$rule_type) { + self.effective_rules(device, guard, |rule| { if let CssRule::$variant(ref lock) = *rule { let rule = lock.read(); f(&rule) diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 27adfdd451a..0ff9d20d883 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -167,7 +167,9 @@ impl Stylist { } let cascaded_rule = ViewportRule { - declarations: viewport::Cascade::from_stylesheets(doc_stylesheets, &self.device).finish(), + declarations: viewport::Cascade::from_stylesheets( + doc_stylesheets, doc_guard, &self.device + ).finish(), }; self.viewport_constraints = @@ -237,7 +239,7 @@ impl Stylist { // Cheap `Arc` clone so that the closure below can borrow `&mut Stylist`. let device = self.device.clone(); - stylesheet.effective_rules(&device, |rule| { + stylesheet.effective_rules(&device, guard, |rule| { match *rule { CssRule::Style(ref style_rule) => { let guard = style_rule.read(); @@ -467,7 +469,7 @@ impl Stylist { pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard, stylesheets: &[Arc]) { let cascaded_rule = ViewportRule { - declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(), + declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(), }; self.viewport_constraints = diff --git a/components/style/viewport.rs b/components/style/viewport.rs index 9c364dc7249..196216423f0 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -15,6 +15,7 @@ use cssparser::ToCss as ParserToCss; use euclid::size::TypedSize2D; use media_queries::Device; use parser::{ParserContext, log_css_error}; +use shared_lock::SharedRwLockReadGuard; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt; @@ -555,13 +556,14 @@ impl Cascade { } } - pub fn from_stylesheets<'a, I>(stylesheets: I, device: &Device) -> Self + pub fn from_stylesheets<'a, I>(stylesheets: I, guard: &SharedRwLockReadGuard, + device: &Device) -> Self where I: IntoIterator, I::Item: AsRef, { let mut cascade = Self::new(); for stylesheet in stylesheets { - stylesheet.as_ref().effective_viewport_rules(device, |rule| { + stylesheet.as_ref().effective_viewport_rules(device, guard, |rule| { for declaration in &rule.declarations { cascade.add(Cow::Borrowed(declaration)) } diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs index 485ccd1d486..652d68ce953 100644 --- a/tests/unit/style/media_queries.rs +++ b/tests/unit/style/media_queries.rs @@ -62,7 +62,7 @@ fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) { None, &CSSErrorReporterTest, ParserContextExtraData::default()); let mut rule_count = 0; - ss.effective_style_rules(device, |_| rule_count += 1); + ss.effective_style_rules(device, &ss.shared_lock.read(), |_| rule_count += 1); assert!(rule_count == expected_rule_count, css.to_owned()); } diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index 9fe53ebb40c..7423286227d 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -20,12 +20,15 @@ use style_traits::viewport::*; macro_rules! stylesheet { ($css:expr, $origin:ident, $error_reporter:expr) => { + stylesheet!($css, $origin, $error_reporter, SharedRwLock::new()) + }; + ($css:expr, $origin:ident, $error_reporter:expr, $shared_lock:expr) => { Box::new(Stylesheet::from_str( $css, ServoUrl::parse("http://localhost").unwrap(), Origin::$origin, Default::default(), - SharedRwLock::new(), + $shared_lock, None, &$error_reporter, ParserContextExtraData::default() @@ -41,7 +44,7 @@ fn test_viewport_rule(css: &str, PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest); let mut rule_count = 0; - stylesheet.effective_viewport_rules(&device, |rule| { + stylesheet.effective_viewport_rules(&device, &stylesheet.shared_lock.read(), |rule| { rule_count += 1; callback(&rule.declarations, css); }); @@ -253,24 +256,31 @@ fn multiple_stylesheets_cascading() { PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); let error_reporter = CSSErrorReporterTest; + let shared_lock = SharedRwLock::new(); let stylesheets = vec![ - stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", UserAgent, error_reporter), - stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", User, error_reporter), - stylesheet!("@viewport { min-width: 300px; }", Author, error_reporter)]; + stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", + UserAgent, error_reporter, shared_lock.clone()), + stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", + User, error_reporter, shared_lock.clone()), + stylesheet!("@viewport { min-width: 300px; }", + Author, error_reporter, shared_lock.clone()) + ]; - let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish(); + let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish(); assert_decl_len!(declarations == 3); assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.)); assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px)); assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px)); let stylesheets = vec![ - stylesheet!("@viewport { min-width: 100px !important; }", UserAgent, error_reporter), + stylesheet!("@viewport { min-width: 100px !important; }", + UserAgent, error_reporter, shared_lock.clone()), stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }", - User, error_reporter), + User, error_reporter, shared_lock.clone()), stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }", - Author, error_reporter)]; - let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish(); + Author, error_reporter, shared_lock.clone()) + ]; + let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish(); assert_decl_len!(declarations == 3); assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important); assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important); From fe4e70c5f8b05778c09aed0b1d8a727cc1066df3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Mar 2017 00:19:09 +0100 Subject: [PATCH 05/17] Introduce a ToCssWithGuard trait --- components/script/dom/cssconditionrule.rs | 4 ++ components/script/dom/cssfontfacerule.rs | 5 +- components/script/dom/cssgroupingrule.rs | 5 ++ components/script/dom/cssimportrule.rs | 5 +- components/script/dom/csskeyframesrule.rs | 5 +- components/script/dom/cssmediarule.rs | 8 +-- components/script/dom/cssnamespacerule.rs | 5 +- components/script/dom/cssrule.rs | 5 ++ components/script/dom/cssstylerule.rs | 5 +- components/script/dom/csssupportsrule.rs | 8 +-- components/script/dom/cssviewportrule.rs | 5 +- components/style/font_face.rs | 8 +-- components/style/shared_lock.rs | 17 +++++++ components/style/stylesheets.rs | 60 +++++++++++++---------- components/style/viewport.rs | 7 +-- ports/geckolib/glue.rs | 6 ++- 16 files changed, 104 insertions(+), 54 deletions(-) diff --git a/components/script/dom/cssconditionrule.rs b/components/script/dom/cssconditionrule.rs index 02c52bcf28f..42fca721759 100644 --- a/components/script/dom/cssconditionrule.rs +++ b/components/script/dom/cssconditionrule.rs @@ -12,6 +12,7 @@ use dom::csssupportsrule::CSSSupportsRule; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::SharedRwLock; use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] @@ -27,6 +28,9 @@ impl CSSConditionRule { } } + pub fn shared_lock(&self) -> &SharedRwLock { + self.cssgroupingrule.shared_lock() + } } impl CSSConditionRuleMethods for CSSConditionRule { diff --git a/components/script/dom/cssfontfacerule.rs b/components/script/dom/cssfontfacerule.rs index b9ef949c1b7..4556f90a56c 100644 --- a/components/script/dom/cssfontfacerule.rs +++ b/components/script/dom/cssfontfacerule.rs @@ -12,8 +12,8 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::ToCssWithGuard; use style::font_face::FontFaceRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSFontFaceRule { @@ -47,6 +47,7 @@ impl SpecificCSSRule for CSSFontFaceRule { } fn get_css(&self) -> DOMString { - self.fontfacerule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.fontfacerule.read().to_css_string(&guard).into() } } diff --git a/components/script/dom/cssgroupingrule.rs b/components/script/dom/cssgroupingrule.rs index ec608b2bc77..29f6bc361a2 100644 --- a/components/script/dom/cssgroupingrule.rs +++ b/components/script/dom/cssgroupingrule.rs @@ -14,6 +14,7 @@ use dom::cssstylesheet::CSSStyleSheet; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::SharedRwLock; use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] @@ -40,6 +41,10 @@ impl CSSGroupingRule { parent_stylesheet, RulesSource::Rules(self.rules.clone()))) } + + pub fn shared_lock(&self) -> &SharedRwLock { + self.cssrule.shared_lock() + } } impl CSSGroupingRuleMethods for CSSGroupingRule { diff --git a/components/script/dom/cssimportrule.rs b/components/script/dom/cssimportrule.rs index 6ef354ec43e..bb01fdfcc84 100644 --- a/components/script/dom/cssimportrule.rs +++ b/components/script/dom/cssimportrule.rs @@ -12,8 +12,8 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::ToCssWithGuard; use style::stylesheets::ImportRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSImportRule { @@ -49,6 +49,7 @@ impl SpecificCSSRule for CSSImportRule { } fn get_css(&self) -> DOMString { - self.import_rule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.import_rule.read().to_css_string(&guard).into() } } diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index db0240bf9a2..330b1be3627 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -21,8 +21,8 @@ use servo_atoms::Atom; use std::sync::Arc; use style::keyframes::{Keyframe, KeyframeSelector}; use style::parser::ParserContextExtraData; +use style::shared_lock::ToCssWithGuard; use style::stylesheets::KeyframesRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSKeyframesRule { @@ -134,7 +134,8 @@ impl SpecificCSSRule for CSSKeyframesRule { } fn get_css(&self) -> DOMString { - self.keyframesrule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.keyframesrule.read().to_css_string(&guard).into() } fn deparent_children(&self) { diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 31923cb29dd..9242ee01bb7 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -17,12 +17,13 @@ use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; use style::media_queries::parse_media_query_list; +use style::shared_lock::ToCssWithGuard; use style::stylesheets::MediaRule; use style_traits::ToCss; #[dom_struct] pub struct CSSMediaRule { - cssrule: CSSConditionRule, + cssconditionrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] mediarule: Arc>, medialist: MutNullableJS, @@ -33,7 +34,7 @@ impl CSSMediaRule { -> CSSMediaRule { let list = mediarule.read().rules.clone(); CSSMediaRule { - cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), + cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list), mediarule: mediarule, medialist: MutNullableJS::new(None), } @@ -76,7 +77,8 @@ impl SpecificCSSRule for CSSMediaRule { } fn get_css(&self) -> DOMString { - self.mediarule.read().to_css_string().into() + let guard = self.cssconditionrule.shared_lock().read(); + self.mediarule.read().to_css_string(&guard).into() } } diff --git a/components/script/dom/cssnamespacerule.rs b/components/script/dom/cssnamespacerule.rs index 51f60fafd08..46702c275ba 100644 --- a/components/script/dom/cssnamespacerule.rs +++ b/components/script/dom/cssnamespacerule.rs @@ -13,8 +13,8 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::ToCssWithGuard; use style::stylesheets::NamespaceRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSNamespaceRule { @@ -62,6 +62,7 @@ impl SpecificCSSRule for CSSNamespaceRule { } fn get_css(&self) -> DOMString { - self.namespacerule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.namespacerule.read().to_css_string(&guard).into() } } diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs index 277d7323a21..54bb8c175a5 100644 --- a/components/script/dom/cssrule.rs +++ b/components/script/dom/cssrule.rs @@ -20,6 +20,7 @@ use dom::cssviewportrule::CSSViewportRule; use dom::window::Window; use dom_struct::dom_struct; use std::cell::Cell; +use style::shared_lock::SharedRwLock; use style::stylesheets::CssRule as StyleCssRule; @@ -103,6 +104,10 @@ impl CSSRule { pub fn parent_stylesheet(&self) -> &CSSStyleSheet { &self.parent_stylesheet } + + pub fn shared_lock(&self) -> &SharedRwLock { + &self.parent_stylesheet.style_stylesheet().shared_lock + } } impl CSSRuleMethods for CSSRule { diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index 3c4c8c815d1..2423861e446 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -14,8 +14,8 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::ToCssWithGuard; use style::stylesheets::StyleRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSStyleRule { @@ -51,7 +51,8 @@ impl SpecificCSSRule for CSSStyleRule { } fn get_css(&self) -> DOMString { - self.stylerule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.stylerule.read().to_css_string(&guard).into() } } diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs index 0cc113bef1c..d5e844e52aa 100644 --- a/components/script/dom/csssupportsrule.rs +++ b/components/script/dom/csssupportsrule.rs @@ -16,13 +16,14 @@ use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; use style::parser::ParserContext; +use style::shared_lock::ToCssWithGuard; use style::stylesheets::SupportsRule; use style::supports::SupportsCondition; use style_traits::ToCss; #[dom_struct] pub struct CSSSupportsRule { - cssrule: CSSConditionRule, + cssconditionrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] supportsrule: Arc>, } @@ -32,7 +33,7 @@ impl CSSSupportsRule { -> CSSSupportsRule { let list = supportsrule.read().rules.clone(); CSSSupportsRule { - cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), + cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list), supportsrule: supportsrule, } } @@ -75,6 +76,7 @@ impl SpecificCSSRule for CSSSupportsRule { } fn get_css(&self) -> DOMString { - self.supportsrule.read().to_css_string().into() + let guard = self.cssconditionrule.shared_lock().read(); + self.supportsrule.read().to_css_string(&guard).into() } } diff --git a/components/script/dom/cssviewportrule.rs b/components/script/dom/cssviewportrule.rs index c784a26f442..855c8bdda57 100644 --- a/components/script/dom/cssviewportrule.rs +++ b/components/script/dom/cssviewportrule.rs @@ -12,8 +12,8 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::ToCssWithGuard; use style::viewport::ViewportRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSViewportRule { @@ -46,6 +46,7 @@ impl SpecificCSSRule for CSSViewportRule { } fn get_css(&self) -> DOMString { - self.viewportrule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.viewportrule.read().to_css_string(&guard).into() } } diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 0d4bc4f8a09..8bad3a93aee 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -14,6 +14,7 @@ use computed_values::font_family::FamilyName; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; #[cfg(feature = "gecko")] use cssparser::UnicodeRange; use parser::{ParserContext, log_css_error, Parse}; +use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use std::iter; use style_traits::{ToCss, OneOrMoreCommaSeparated}; @@ -230,11 +231,10 @@ macro_rules! font_face_descriptors { } } - impl ToCss for FontFaceRule { + impl ToCssWithGuard for FontFaceRule { // Serialization of FontFaceRule is not specced. - fn to_css(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { dest.write_str("@font-face {\n")?; $( dest.write_str(concat!(" ", $m_name, ": "))?; diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs index 4565e6e5f69..d4d66b8fc5d 100644 --- a/components/style/shared_lock.rs +++ b/components/style/shared_lock.rs @@ -160,3 +160,20 @@ mod compile_time_assert { impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy } + +/// Like ToCss, but with a lock guard given by the caller. +pub trait ToCssWithGuard { + /// Serialize `self` in CSS syntax, writing to `dest`, using the given lock guard. + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write; + + /// Serialize `self` in CSS syntax using the given lock guard and return a string. + /// + /// (This is a convenience wrapper for `to_css` and probably should not be overridden.) + #[inline] + fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> String { + let mut s = String::new(); + self.to_css(guard, &mut s).unwrap(); + s + } +} diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 6c6862fef5e..df6a9641f0d 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -21,7 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser}; use selectors::parser::SelectorList; use servo_config::prefs::PREFS; use servo_url::ServoUrl; -use shared_lock::{SharedRwLock, Locked, SharedRwLockReadGuard}; +use shared_lock::{SharedRwLock, Locked, SharedRwLockReadGuard, ToCssWithGuard}; use std::cell::Cell; use std::fmt; use std::sync::Arc; @@ -372,18 +372,19 @@ impl CssRule { } } -impl ToCss for CssRule { +impl ToCssWithGuard for CssRule { // https://drafts.csswg.org/cssom/#serialize-a-css-rule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { match *self { - CssRule::Namespace(ref lock) => lock.read().to_css(dest), - CssRule::Import(ref lock) => lock.read().to_css(dest), - CssRule::Style(ref lock) => lock.read().to_css(dest), - CssRule::FontFace(ref lock) => lock.read().to_css(dest), - CssRule::Viewport(ref lock) => lock.read().to_css(dest), - CssRule::Keyframes(ref lock) => lock.read().to_css(dest), - CssRule::Media(ref lock) => lock.read().to_css(dest), - CssRule::Supports(ref lock) => lock.read().to_css(dest), + CssRule::Namespace(ref lock) => lock.read().to_css(guard, dest), + CssRule::Import(ref lock) => lock.read().to_css(guard, dest), + CssRule::Style(ref lock) => lock.read().to_css(guard, dest), + CssRule::FontFace(ref lock) => lock.read().to_css(guard, dest), + CssRule::Viewport(ref lock) => lock.read().to_css(guard, dest), + CssRule::Keyframes(ref lock) => lock.read().to_css(guard, dest), + CssRule::Media(ref lock) => lock.read().to_css(guard, dest), + CssRule::Supports(ref lock) => lock.read().to_css(guard, dest), } } } @@ -396,9 +397,10 @@ pub struct NamespaceRule { pub url: Namespace, } -impl ToCss for NamespaceRule { +impl ToCssWithGuard for NamespaceRule { // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@namespace ")); if let Some(ref prefix) = self.prefix { try!(dest.write_str(&*prefix.to_string())); @@ -426,12 +428,12 @@ pub struct ImportRule { pub stylesheet: Arc, } -impl ToCss for ImportRule { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl ToCssWithGuard for ImportRule { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@import ")); try!(self.url.to_css(dest)); - let guard = self.stylesheet.shared_lock.read(); // FIXME: have the caller pass this? - let media = self.stylesheet.media.read_with(&guard); + let media = self.stylesheet.media.read_with(guard); if !media.is_empty() { try!(dest.write_str(" ")); try!(media.to_css(dest)); @@ -451,9 +453,10 @@ pub struct KeyframesRule { pub keyframes: Vec>>, } -impl ToCss for KeyframesRule { +impl ToCssWithGuard for KeyframesRule { // Serialization of KeyframesRule is not specced. - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@keyframes ")); try!(dest.write_str(&*self.name.to_string())); try!(dest.write_str(" { ")); @@ -478,16 +481,17 @@ pub struct MediaRule { pub rules: Arc>, } -impl ToCss for MediaRule { +impl ToCssWithGuard for MediaRule { // Serialization of MediaRule is not specced. // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@media ")); try!(self.media_queries.read().to_css(dest)); try!(dest.write_str(" {")); for rule in self.rules.read().0.iter() { try!(dest.write_str(" ")); - try!(rule.to_css(dest)); + try!(rule.to_css(guard, dest)); } dest.write_str(" }") } @@ -505,14 +509,15 @@ pub struct SupportsRule { pub enabled: bool, } -impl ToCss for SupportsRule { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl ToCssWithGuard for SupportsRule { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@supports ")); try!(self.condition.to_css(dest)); try!(dest.write_str(" {")); for rule in self.rules.read().0.iter() { try!(dest.write_str(" ")); - try!(rule.to_css(dest)); + try!(rule.to_css(guard, dest)); } dest.write_str(" }") } @@ -525,9 +530,10 @@ pub struct StyleRule { pub block: Arc>, } -impl ToCss for StyleRule { +impl ToCssWithGuard for StyleRule { // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { // Step 1 try!(self.selectors.to_css(dest)); // Step 2 diff --git a/components/style/viewport.rs b/components/style/viewport.rs index 196216423f0..690c06fd377 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -15,7 +15,7 @@ use cssparser::ToCss as ParserToCss; use euclid::size::TypedSize2D; use media_queries::Device; use parser::{ParserContext, log_css_error}; -use shared_lock::SharedRwLockReadGuard; +use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt; @@ -505,9 +505,10 @@ impl ViewportRule { } } -impl ToCss for ViewportRule { +impl ToCssWithGuard for ViewportRule { // Serialization of ViewportRule is not specced. - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@viewport { ")); let mut iter = self.declarations.iter(); try!(iter.next().unwrap().to_css(dest)); diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index b8c6e4ebbab..cdc0a530f09 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -76,7 +76,7 @@ use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::selector_parser::PseudoElementCascadeType; use style::sequential; -use style::shared_lock::SharedRwLock; +use style::shared_lock::{SharedRwLock, ToCssWithGuard}; use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; @@ -581,8 +581,10 @@ macro_rules! impl_basic_rule_funcs { #[no_mangle] pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let rule = RwLock::<$rule_type>::as_arc(&rule); - rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + rule.read().to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap(); } } } From 600152bd0049035d3c41dfe4aa381d0713d0127a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Mar 2017 01:02:55 +0100 Subject: [PATCH 06/17] Replace more RwLock with shared_lock::Locked --- components/script/dom/bindings/trace.rs | 4 +-- components/script/dom/cssconditionrule.rs | 4 +++ components/script/dom/cssgroupingrule.rs | 4 +++ components/script/dom/cssmediarule.rs | 7 ++-- components/script/dom/medialist.rs | 44 +++++++++++++++-------- components/style/gecko/arc_types.rs | 3 +- components/style/stylesheets.rs | 13 ++++--- ports/geckolib/glue.rs | 38 +++++++++++++------- 8 files changed, 79 insertions(+), 38 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index b0828ab6d56..b0fabb5fd45 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -99,7 +99,7 @@ use style::keyframes::Keyframe; use style::media_queries::MediaList; use style::properties::PropertyDeclarationBlock; use style::selector_parser::{PseudoElement, Snapshot}; -use style::shared_lock::SharedRwLock as StyleSharedRwLock; +use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked}; use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule}; use style::stylesheets::SupportsRule; use style::values::specified::Length; @@ -574,7 +574,7 @@ unsafe impl JSTraceable for RwLock { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/cssconditionrule.rs b/components/script/dom/cssconditionrule.rs index 42fca721759..44d10c21dd3 100644 --- a/components/script/dom/cssconditionrule.rs +++ b/components/script/dom/cssconditionrule.rs @@ -28,6 +28,10 @@ impl CSSConditionRule { } } + pub fn parent_stylesheet(&self) -> &CSSStyleSheet { + self.cssgroupingrule.parent_stylesheet() + } + pub fn shared_lock(&self) -> &SharedRwLock { self.cssgroupingrule.shared_lock() } diff --git a/components/script/dom/cssgroupingrule.rs b/components/script/dom/cssgroupingrule.rs index 29f6bc361a2..7204b8447f9 100644 --- a/components/script/dom/cssgroupingrule.rs +++ b/components/script/dom/cssgroupingrule.rs @@ -42,6 +42,10 @@ impl CSSGroupingRule { RulesSource::Rules(self.rules.clone()))) } + pub fn parent_stylesheet(&self) -> &CSSStyleSheet { + self.cssrule.parent_stylesheet() + } + pub fn shared_lock(&self) -> &SharedRwLock { self.cssrule.shared_lock() } diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 9242ee01bb7..1d1f0846a51 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -50,22 +50,25 @@ impl CSSMediaRule { fn medialist(&self) -> Root { self.medialist.or_init(|| MediaList::new(self.global().as_window(), + self.cssconditionrule.parent_stylesheet(), self.mediarule.read().media_queries.clone())) } /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface pub fn get_condition_text(&self) -> DOMString { + let guard = self.cssconditionrule.shared_lock().read(); let rule = self.mediarule.read(); - let list = rule.media_queries.read(); + let list = rule.media_queries.read_with(&guard); list.to_css_string().into() } /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface pub fn set_condition_text(&self, text: DOMString) { + let mut guard = self.cssconditionrule.shared_lock().write(); let mut input = Parser::new(&text); let new_medialist = parse_media_query_list(&mut input); let rule = self.mediarule.read(); - let mut list = rule.media_queries.write(); + let mut list = rule.media_queries.write_with(&mut guard); *list = new_medialist; } } diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs index 806946f6356..0020f7f3a08 100644 --- a/components/script/dom/medialist.rs +++ b/components/script/dom/medialist.rs @@ -6,13 +6,14 @@ use core::default::Default; use cssparser::Parser; use dom::bindings::codegen::Bindings::MediaListBinding; use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods; -use dom::bindings::js::Root; +use dom::bindings::js::{JS, Root}; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; +use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{SharedRwLock, Locked}; use style::media_queries::{MediaQuery, parse_media_query_list}; use style::media_queries::MediaList as StyleMediaList; use style_traits::ToCss; @@ -20,38 +21,47 @@ use style_traits::ToCss; #[dom_struct] pub struct MediaList { reflector_: Reflector, + parent_stylesheet: JS, #[ignore_heap_size_of = "Arc"] - media_queries: Arc>, + media_queries: Arc>, } impl MediaList { #[allow(unrooted_must_root)] - pub fn new_inherited(media_queries: Arc>) -> MediaList { + pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, + media_queries: Arc>) -> MediaList { MediaList { + parent_stylesheet: JS::from_ref(parent_stylesheet), reflector_: Reflector::new(), media_queries: media_queries, } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, media_queries: Arc>) + pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, + media_queries: Arc>) -> Root { - reflect_dom_object(box MediaList::new_inherited(media_queries), + reflect_dom_object(box MediaList::new_inherited(parent_stylesheet, media_queries), window, MediaListBinding::Wrap) } + fn shared_lock(&self) -> &SharedRwLock { + &self.parent_stylesheet.style_stylesheet().shared_lock + } } impl MediaListMethods for MediaList { // https://drafts.csswg.org/cssom/#dom-medialist-mediatext fn MediaText(&self) -> DOMString { - DOMString::from(self.media_queries.read().to_css_string()) + let guard = self.shared_lock().read(); + DOMString::from(self.media_queries.read_with(&guard).to_css_string()) } // https://drafts.csswg.org/cssom/#dom-medialist-mediatext fn SetMediaText(&self, value: DOMString) { - let mut media_queries = self.media_queries.write(); + let mut guard = self.shared_lock().write(); + let mut media_queries = self.media_queries.write_with(&mut guard); // Step 2 if value.is_empty() { // Step 1 @@ -65,13 +75,15 @@ impl MediaListMethods for MediaList { // https://drafts.csswg.org/cssom/#dom-medialist-length fn Length(&self) -> u32 { - self.media_queries.read().media_queries.len() as u32 + let guard = self.shared_lock().read(); + self.media_queries.read_with(&guard).media_queries.len() as u32 } // https://drafts.csswg.org/cssom/#dom-medialist-item fn Item(&self, index: u32) -> Option { - self.media_queries.read().media_queries.get(index as usize) - .and_then(|query| { + let guard = self.shared_lock().read(); + self.media_queries.read_with(&guard).media_queries + .get(index as usize).and_then(|query| { let mut s = String::new(); query.to_css(&mut s).unwrap(); Some(DOMString::from_string(s)) @@ -94,13 +106,14 @@ impl MediaListMethods for MediaList { } // Step 3 let m_serialized = m.clone().unwrap().to_css_string(); - let any = self.media_queries.read().media_queries.iter() - .any(|q| m_serialized == q.to_css_string()); + let mut guard = self.shared_lock().write(); + let mq = self.media_queries.write_with(&mut guard); + let any = mq.media_queries.iter().any(|q| m_serialized == q.to_css_string()); if any { return; } // Step 4 - self.media_queries.write().media_queries.push(m.unwrap()); + mq.media_queries.push(m.unwrap()); } // https://drafts.csswg.org/cssom/#dom-medialist-deletemedium @@ -114,7 +127,8 @@ impl MediaListMethods for MediaList { } // Step 3 let m_serialized = m.unwrap().to_css_string(); - let mut media_list = self.media_queries.write(); + let mut guard = self.shared_lock().write(); + let mut media_list = self.media_queries.write_with(&mut guard); let new_vec = media_list.media_queries.drain(..) .filter(|q| m_serialized != q.to_css_string()) .collect(); diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index d822857a9e6..daf0454c81e 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -17,6 +17,7 @@ use media_queries::MediaList; use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::animated_properties::{AnimationValue, AnimationValueMap}; +use shared_lock::Locked; use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule, NamespaceRule}; macro_rules! impl_arc_ffi { @@ -62,7 +63,7 @@ impl_arc_ffi!(AnimationValue => RawServoAnimationValue impl_arc_ffi!(RwLock => RawServoAnimationValueMap [Servo_AnimationValueMap_AddRef, Servo_AnimationValueMap_Release]); -impl_arc_ffi!(RwLock => RawServoMediaList +impl_arc_ffi!(Locked => RawServoMediaList [Servo_MediaList_AddRef, Servo_MediaList_Release]); impl_arc_ffi!(RwLock => RawServoMediaRule diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index df6a9641f0d..3f3d78c1e16 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -316,7 +316,7 @@ impl CssRule { } CssRule::Media(ref lock) => { let media_rule = lock.read(); - let mq = media_rule.media_queries.read(); + let mq = media_rule.media_queries.read_with(guard); let rules = &media_rule.rules.read().0; f(rules, Some(&mq)) } @@ -477,7 +477,7 @@ impl ToCssWithGuard for KeyframesRule { #[allow(missing_docs)] #[derive(Debug)] pub struct MediaRule { - pub media_queries: Arc>, + pub media_queries: Arc>, pub rules: Arc>, } @@ -487,7 +487,7 @@ impl ToCssWithGuard for MediaRule { fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result where W: fmt::Write { try!(dest.write_str("@media ")); - try!(self.media_queries.read().to_css(dest)); + try!(self.media_queries.read_with(guard).to_css(dest)); try!(dest.write_str(" {")); for rule in self.rules.read().0.iter() { try!(dest.write_str(" ")); @@ -753,6 +753,7 @@ impl<'b> TopLevelRuleParser<'b> { fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> { NestedRuleParser { stylesheet_origin: self.stylesheet_origin, + shared_lock: self.shared_lock, context: &self.context, namespaces: self.namespaces, } @@ -774,7 +775,7 @@ enum AtRulePrelude { /// A @font-face rule prelude. FontFace, /// A @media rule prelude, with its media queries. - Media(Arc>), + Media(Arc>), /// An @supports rule, with its conditional Supports(SupportsCondition), /// A @viewport rule prelude. @@ -900,6 +901,7 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> { #[derive(Clone)] // shallow, relatively cheap .clone struct NestedRuleParser<'a, 'b: 'a> { stylesheet_origin: Origin, + shared_lock: &'a SharedRwLock, context: &'a ParserContext<'b>, namespaces: &'b Namespaces, } @@ -931,7 +933,8 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { match_ignore_ascii_case! { name, "media" => { let media_queries = parse_media_query_list(input); - Ok(AtRuleType::WithBlock(AtRulePrelude::Media(Arc::new(RwLock::new(media_queries))))) + let arc = Arc::new(self.shared_lock.wrap(media_queries)); + Ok(AtRuleType::WithBlock(AtRulePrelude::Media(arc))) }, "supports" => { let cond = SupportsCondition::parse(input)?; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index cdc0a530f09..e0335ee0005 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -76,7 +76,7 @@ use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::selector_parser::PseudoElementCascadeType; use style::sequential; -use style::shared_lock::{SharedRwLock, ToCssWithGuard}; +use style::shared_lock::{SharedRwLock, ToCssWithGuard, Locked}; use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; @@ -964,29 +964,37 @@ pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawSer #[no_mangle] pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) { - let list = RwLock::::as_arc(&list); - list.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let list = Locked::::as_arc(&list); + list.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } #[no_mangle] pub extern "C" fn Servo_MediaList_SetText(list: RawServoMediaListBorrowed, text: *const nsACString) { - let list = RwLock::::as_arc(&list); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let list = Locked::::as_arc(&list); let text = unsafe { text.as_ref().unwrap().as_str_unchecked() }; let mut parser = Parser::new(&text); - *list.write() = parse_media_query_list(&mut parser); + *list.write_with(&mut guard) = parse_media_query_list(&mut parser); } #[no_mangle] pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 { - let list = RwLock::::as_arc(&list); - list.read().media_queries.len() as u32 + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let list = Locked::::as_arc(&list); + list.read_with(&guard).media_queries.len() as u32 } #[no_mangle] pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, index: u32, result: *mut nsAString) -> bool { - let list = RwLock::::as_arc(&list); - if let Some(media_query) = list.read().media_queries.get(index as usize) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let list = Locked::::as_arc(&list); + if let Some(media_query) = list.read_with(&guard).media_queries.get(index as usize) { media_query.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); true } else { @@ -997,17 +1005,21 @@ pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, i #[no_mangle] pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed, new_medium: *const nsACString) { - let list = RwLock::::as_arc(&list); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let list = Locked::::as_arc(&list); let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() }; - list.write().append_medium(new_medium); + list.write_with(&mut guard).append_medium(new_medium); } #[no_mangle] pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed, old_medium: *const nsACString) -> bool { - let list = RwLock::::as_arc(&list); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let list = Locked::::as_arc(&list); let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() }; - list.write().delete_medium(old_medium) + list.write_with(&mut guard).delete_medium(old_medium) } macro_rules! get_longhand_from_id { From b213daaa8818ff59557973c01c7d2612e9389abc Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Mar 2017 01:16:49 +0100 Subject: [PATCH 07/17] Tidy --- components/script/dom/cssfontfacerule.rs | 2 +- components/script/dom/medialist.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/script/dom/cssfontfacerule.rs b/components/script/dom/cssfontfacerule.rs index 4556f90a56c..05b665a9975 100644 --- a/components/script/dom/cssfontfacerule.rs +++ b/components/script/dom/cssfontfacerule.rs @@ -12,8 +12,8 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::ToCssWithGuard; use style::font_face::FontFaceRule; +use style::shared_lock::ToCssWithGuard; #[dom_struct] pub struct CSSFontFaceRule { diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs index 0020f7f3a08..b403200983e 100644 --- a/components/script/dom/medialist.rs +++ b/components/script/dom/medialist.rs @@ -13,9 +13,9 @@ use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; use std::sync::Arc; -use style::shared_lock::{SharedRwLock, Locked}; use style::media_queries::{MediaQuery, parse_media_query_list}; use style::media_queries::MediaList as StyleMediaList; +use style::shared_lock::{SharedRwLock, Locked}; use style_traits::ToCss; #[dom_struct] From f35b4e27b3e0b748e10662cfb6f18873258483b7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Mar 2017 11:01:13 +0100 Subject: [PATCH 08/17] Replace RwLock with Locked --- components/script/dom/bindings/trace.rs | 2 +- components/script/dom/cssconditionrule.rs | 5 +-- components/script/dom/cssgroupingrule.rs | 7 ++- components/script/dom/cssrulelist.rs | 16 ++++--- components/script/dom/cssstylesheet.rs | 5 +++ components/script/dom/htmlmetaelement.rs | 3 +- components/script/stylesheet_loader.rs | 2 + components/style/encoding_support.rs | 4 +- components/style/gecko/arc_types.rs | 2 +- components/style/stylesheets.rs | 52 +++++++++++++---------- components/style/stylist.rs | 2 +- ports/geckolib/glue.rs | 30 +++++++++---- tests/unit/style/media_queries.rs | 2 +- tests/unit/style/rule_tree/bench.rs | 3 +- tests/unit/style/stylesheets.rs | 2 +- 15 files changed, 85 insertions(+), 52 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index b0fabb5fd45..122823f6f0d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -508,7 +508,7 @@ unsafe impl JSTraceable for RwLock { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/cssconditionrule.rs b/components/script/dom/cssconditionrule.rs index 44d10c21dd3..8bf5dad6c93 100644 --- a/components/script/dom/cssconditionrule.rs +++ b/components/script/dom/cssconditionrule.rs @@ -10,9 +10,8 @@ use dom::cssmediarule::CSSMediaRule; use dom::cssstylesheet::CSSStyleSheet; use dom::csssupportsrule::CSSSupportsRule; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::SharedRwLock; +use style::shared_lock::{SharedRwLock, Locked}; use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] @@ -22,7 +21,7 @@ pub struct CSSConditionRule { impl CSSConditionRule { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, - rules: Arc>) -> CSSConditionRule { + rules: Arc>) -> CSSConditionRule { CSSConditionRule { cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules), } diff --git a/components/script/dom/cssgroupingrule.rs b/components/script/dom/cssgroupingrule.rs index 7204b8447f9..249aaccd42e 100644 --- a/components/script/dom/cssgroupingrule.rs +++ b/components/script/dom/cssgroupingrule.rs @@ -12,22 +12,21 @@ use dom::cssrule::CSSRule; use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssstylesheet::CSSStyleSheet; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::SharedRwLock; +use style::shared_lock::{SharedRwLock, Locked}; use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] pub struct CSSGroupingRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - rules: Arc>, + rules: Arc>, rulelist: MutNullableJS, } impl CSSGroupingRule { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, - rules: Arc>) -> CSSGroupingRule { + rules: Arc>) -> CSSGroupingRule { CSSGroupingRule { cssrule: CSSRule::new_inherited(parent_stylesheet), rules: rules, diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 0b6351d237c..6321296c785 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -15,6 +15,7 @@ use dom::window::Window; use dom_struct::dom_struct; use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::Locked; use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError}; #[allow(unsafe_code)] @@ -43,7 +44,7 @@ pub struct CSSRuleList { } pub enum RulesSource { - Rules(Arc>), + Rules(Arc>), Keyframes(Arc>), } @@ -52,7 +53,8 @@ impl CSSRuleList { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList { let dom_rules = match rules { RulesSource::Rules(ref rules) => { - rules.read().0.iter().map(|_| MutNullableJS::new(None)).collect() + let guard = parent_stylesheet.shared_lock().read(); + rules.read_with(&guard).0.iter().map(|_| MutNullableJS::new(None)).collect() } RulesSource::Keyframes(ref rules) => { rules.read().keyframes.iter().map(|_| MutNullableJS::new(None)).collect() @@ -89,7 +91,9 @@ impl CSSRuleList { let index = idx as usize; let parent_stylesheet = self.parent_stylesheet.style_stylesheet(); - let new_rule = css_rules.write().insert_rule(rule, parent_stylesheet, index, nested)?; + let mut guard = parent_stylesheet.shared_lock.write(); + let new_rule = css_rules.write_with(&mut guard) + .insert_rule(rule, parent_stylesheet, index, nested)?; let parent_stylesheet = &*self.parent_stylesheet; let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule); @@ -103,7 +107,8 @@ impl CSSRuleList { match self.rules { RulesSource::Rules(ref css_rules) => { - css_rules.write().remove_rule(index)?; + let mut guard = self.parent_stylesheet.shared_lock().write(); + css_rules.write_with(&mut guard).remove_rule(index)?; let mut dom_rules = self.dom_rules.borrow_mut(); dom_rules[index].get().map(|r| r.detach()); dom_rules.remove(index); @@ -133,9 +138,10 @@ impl CSSRuleList { let parent_stylesheet = &self.parent_stylesheet; match self.rules { RulesSource::Rules(ref rules) => { + let guard = parent_stylesheet.shared_lock().read(); CSSRule::new_specific(self.global().as_window(), parent_stylesheet, - rules.read().0[idx as usize].clone()) + rules.read_with(&guard).0[idx as usize].clone()) } RulesSource::Keyframes(ref rules) => { Root::upcast(CSSKeyframeRule::new(self.global().as_window(), diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index f8397a732c2..ee097313c2e 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -16,6 +16,7 @@ use dom::window::Window; use dom_struct::dom_struct; use std::cell::Cell; use std::sync::Arc; +use style::shared_lock::SharedRwLock; use style::stylesheets::Stylesheet as StyleStyleSheet; #[dom_struct] @@ -72,6 +73,10 @@ impl CSSStyleSheet { } } + pub fn shared_lock(&self) -> &SharedRwLock { + &self.style_stylesheet.shared_lock + } + pub fn style_stylesheet(&self) -> &StyleStyleSheet { &self.style_stylesheet } diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index 2f78e74d3b4..a564c6b2661 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -101,8 +101,9 @@ impl HTMLMetaElement { if let Some(translated_rule) = ViewportRule::from_meta(&**content) { let document = self.upcast::().owner_doc(); let shared_lock = document.style_shared_lock(); + let rule = CssRule::Viewport(Arc::new(RwLock::new(translated_rule))); *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet { - rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]), + rules: CssRules::new(vec![rule], shared_lock), origin: Origin::Author, shared_lock: shared_lock.clone(), base_url: window_from_node(self).get_url(), diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 26dffa5fe56..79b90be7426 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -175,10 +175,12 @@ impl FetchResponseListener for StylesheetContext { } StylesheetContextSource::Import(ref import) => { let import = import.read(); + let mut guard = document.style_shared_lock().write(); Stylesheet::update_from_bytes(&import.stylesheet, &data, protocol_encoding_label, Some(environment_encoding), + &mut guard, Some(&loader), win.css_error_reporter(), ParserContextExtraData::default()); diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index 141291c896e..e485dc13cf0 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -12,7 +12,7 @@ use media_queries::MediaList; use parser::ParserContextExtraData; use self::encoding::{EncodingRef, DecoderTrap}; use servo_url::ServoUrl; -use shared_lock::SharedRwLock; +use shared_lock::{SharedRwLock, SharedRwLockWriteGuard}; use std::str; use stylesheets::{Stylesheet, StylesheetLoader, Origin}; @@ -78,6 +78,7 @@ impl Stylesheet { bytes: &[u8], protocol_encoding_label: Option<&str>, environment_encoding: Option, + guard: &mut SharedRwLockWriteGuard, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) { @@ -85,6 +86,7 @@ impl Stylesheet { bytes, protocol_encoding_label, environment_encoding); Self::update_from_str(existing, &string, + guard, stylesheet_loader, error_reporter, extra_data) diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index daf0454c81e..798af00906e 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -39,7 +39,7 @@ macro_rules! impl_arc_ffi { } } -impl_arc_ffi!(RwLock => ServoCssRules +impl_arc_ffi!(Locked => ServoCssRules [Servo_CssRules_AddRef, Servo_CssRules_Release]); impl_arc_ffi!(Stylesheet => RawServoStyleSheet diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 3f3d78c1e16..07dc2632b2d 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -21,7 +21,8 @@ use selector_parser::{SelectorImpl, SelectorParser}; use selectors::parser::SelectorList; use servo_config::prefs::PREFS; use servo_url::ServoUrl; -use shared_lock::{SharedRwLock, Locked, SharedRwLockReadGuard, ToCssWithGuard}; +use shared_lock::{SharedRwLock, Locked, ToCssWithGuard}; +use shared_lock::{SharedRwLockReadGuard, SharedRwLockWriteGuard}; use std::cell::Cell; use std::fmt; use std::sync::Arc; @@ -87,8 +88,8 @@ impl From for RulesMutateError { impl CssRules { #[allow(missing_docs)] - pub fn new(rules: Vec) -> Arc> { - Arc::new(RwLock::new(CssRules(rules))) + pub fn new(rules: Vec, shared_lock: &SharedRwLock) -> Arc> { + Arc::new(shared_lock.wrap(CssRules(rules))) } fn only_ns_or_import(&self) -> bool { @@ -174,7 +175,7 @@ impl CssRules { pub struct Stylesheet { /// List of rules in the order they were found (important for /// cascading order) - pub rules: Arc>, + pub rules: Arc>, /// List of media associated with the Stylesheet. pub media: Arc>, /// The origin of this stylesheet. @@ -302,7 +303,7 @@ impl CssRule { CssRule::Import(ref lock) => { let rule = lock.read(); let media = rule.stylesheet.media.read_with(guard); - let rules = rule.stylesheet.rules.read(); + let rules = rule.stylesheet.rules.read_with(guard); // FIXME(emilio): Include the nested rules if the stylesheet is // loaded. f(&rules.0, Some(&media)) @@ -317,14 +318,14 @@ impl CssRule { CssRule::Media(ref lock) => { let media_rule = lock.read(); let mq = media_rule.media_queries.read_with(guard); - let rules = &media_rule.rules.read().0; + let rules = &media_rule.rules.read_with(guard).0; f(rules, Some(&mq)) } CssRule::Supports(ref lock) => { let supports_rule = lock.read(); let enabled = supports_rule.enabled; if enabled { - let rules = &supports_rule.rules.read().0; + let rules = &supports_rule.rules.read_with(guard).0; f(rules, None) } else { f(&[], None) @@ -478,7 +479,7 @@ impl ToCssWithGuard for KeyframesRule { #[derive(Debug)] pub struct MediaRule { pub media_queries: Arc>, - pub rules: Arc>, + pub rules: Arc>, } impl ToCssWithGuard for MediaRule { @@ -489,7 +490,7 @@ impl ToCssWithGuard for MediaRule { try!(dest.write_str("@media ")); try!(self.media_queries.read_with(guard).to_css(dest)); try!(dest.write_str(" {")); - for rule in self.rules.read().0.iter() { + for rule in self.rules.read_with(guard).0.iter() { try!(dest.write_str(" ")); try!(rule.to_css(guard, dest)); } @@ -504,7 +505,7 @@ pub struct SupportsRule { /// The parsed condition pub condition: SupportsCondition, /// Child rules - pub rules: Arc>, + pub rules: Arc>, /// The result of evaluating the condition pub enabled: bool, } @@ -515,7 +516,7 @@ impl ToCssWithGuard for SupportsRule { try!(dest.write_str("@supports ")); try!(self.condition.to_css(dest)); try!(dest.write_str(" {")); - for rule in self.rules.read().0.iter() { + for rule in self.rules.read_with(guard).0.iter() { try!(dest.write_str(" ")); try!(rule.to_css(guard, dest)); } @@ -555,10 +556,11 @@ impl Stylesheet { /// Updates an empty stylesheet from a given string of text. pub fn update_from_str(existing: &Stylesheet, css: &str, + guard: &mut SharedRwLockWriteGuard, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) { - let mut rules = existing.rules.write(); + let mut rules = existing.rules.write_with(guard); let mut namespaces = existing.namespaces.write(); assert!(rules.is_empty()); @@ -613,18 +615,22 @@ impl Stylesheet { origin: origin, base_url: base_url, namespaces: RwLock::new(Namespaces::default()), - rules: CssRules::new(vec![]), + rules: CssRules::new(Vec::new(), &shared_lock), media: Arc::new(shared_lock.wrap(media)), - shared_lock: shared_lock.clone(), + shared_lock: shared_lock, dirty_on_viewport_size_change: AtomicBool::new(false), disabled: AtomicBool::new(false), }; - Self::update_from_str(&s, - css, - stylesheet_loader, - error_reporter, - extra_data); + { + let mut guard = s.shared_lock.write(); + Self::update_from_str(&s, + css, + &mut guard, + stylesheet_loader, + error_reporter, + extra_data); + } s } @@ -666,7 +672,7 @@ impl Stylesheet { #[inline] pub fn effective_rules(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F) where F: FnMut(&CssRule) { - effective_rules(&self.rules.read().0, device, guard, &mut f); + effective_rules(&self.rules.read_with(guard).0, device, guard, &mut f); } /// Returns whether the stylesheet has been explicitly disabled through the @@ -809,7 +815,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { ImportRule { url: url, stylesheet: Arc::new(Stylesheet { - rules: Arc::new(RwLock::new(CssRules(vec![]))), + rules: CssRules::new(Vec::new(), self.shared_lock), media: media, shared_lock: self.shared_lock.clone(), origin: self.context.stylesheet_origin, @@ -907,7 +913,7 @@ struct NestedRuleParser<'a, 'b: 'a> { } impl<'a, 'b> NestedRuleParser<'a, 'b> { - fn parse_nested_rules(&self, input: &mut Parser) -> Arc> { + fn parse_nested_rules(&self, input: &mut Parser) -> Arc> { let mut iter = RuleListParser::new_for_nested_rule(input, self.clone()); let mut rules = Vec::new(); while let Some(result) = iter.next() { @@ -920,7 +926,7 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> { } } } - CssRules::new(rules) + CssRules::new(rules, self.shared_lock) } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 0ff9d20d883..73684a4b8fd 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -502,7 +502,7 @@ impl Stylist { return true } - mq_eval_changed(guard, &stylesheet.rules.read().0, &self.device, &device) + mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device) }); self.device = Arc::new(device); diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index e0335ee0005..e260f365fa5 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -402,6 +402,8 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let extra_data = unsafe { ParserContextExtraData { base: Some(GeckoArcURI::new(base)), @@ -422,9 +424,9 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet }; let sheet = Stylesheet::as_arc(&stylesheet); - sheet.rules.write().0.clear(); + sheet.rules.write_with(&mut guard).0.clear(); - Stylesheet::update_from_str(&sheet, input, loader, + Stylesheet::update_from_str(&sheet, input, &mut guard, loader, &StdoutErrorReporter, extra_data); } @@ -510,7 +512,9 @@ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleS #[no_mangle] pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool { - !Stylesheet::as_arc(&raw_sheet).rules.read().0.is_empty() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + !Stylesheet::as_arc(&raw_sheet).rules.read_with(&guard).0.is_empty() } #[no_mangle] @@ -521,7 +525,9 @@ pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) - #[no_mangle] pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed, result: nsTArrayBorrowed_uintptr_t) { - let rules = RwLock::::as_arc(&rules).read(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rules = Locked::::as_arc(&rules).read_with(&guard); let iter = rules.0.iter().map(|rule| rule.rule_type() as usize); let (size, upper) = iter.size_hint(); debug_assert_eq!(size, upper.unwrap()); @@ -533,10 +539,12 @@ pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed, pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet: RawServoStyleSheetBorrowed, rule: *const nsACString, index: u32, nested: bool, rule_type: *mut u16) -> nsresult { - let rules = RwLock::::as_arc(&rules); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let rules = Locked::::as_arc(&rules); let sheet = Stylesheet::as_arc(&sheet); let rule = unsafe { rule.as_ref().unwrap().as_str_unchecked() }; - match rules.write().insert_rule(rule, sheet, index as usize, nested) { + match rules.write_with(&mut guard).insert_rule(rule, sheet, index as usize, nested) { Ok(new_rule) => { *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16; nsresult::NS_OK @@ -547,8 +555,10 @@ pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet: #[no_mangle] pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult { - let rules = RwLock::::as_arc(&rules); - match rules.write().remove_rule(index as usize) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let rules = Locked::::as_arc(&rules); + match rules.write_with(&mut guard).remove_rule(index as usize) { Ok(_) => nsresult::NS_OK, Err(err) => err.into() } @@ -562,7 +572,9 @@ macro_rules! impl_basic_rule_funcs { } => { #[no_mangle] pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> { - let rules = RwLock::::as_arc(&rules).read(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rules = Locked::::as_arc(&rules).read_with(&guard); match rules.0[index as usize] { CssRule::$name(ref rule) => rule.clone().into_strong(), _ => { diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs index 652d68ce953..3d2f2809a63 100644 --- a/tests/unit/style/media_queries.rs +++ b/tests/unit/style/media_queries.rs @@ -35,7 +35,7 @@ fn test_media_rule(css: &str, callback: F) ParserContextExtraData::default()); let mut rule_count = 0; let guard = stylesheet.shared_lock.read(); - media_queries(&guard, &stylesheet.rules.read().0, &mut |mq| { + media_queries(&guard, &stylesheet.rules.read_with(&guard).0, &mut |mq| { rule_count += 1; callback(mq, css); }); diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs index 623a534159a..aeac93912aa 100644 --- a/tests/unit/style/rule_tree/bench.rs +++ b/tests/unit/style/rule_tree/bench.rs @@ -49,7 +49,8 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> { None, &ErrorringErrorReporter, ParserContextExtraData {}); - let rules = s.rules.read(); + let guard = s.shared_lock.read(); + let rules = s.rules.read_with(&guard); rules.0.iter().filter_map(|rule| { match *rule { CssRule::Style(ref style_rule) => Some(style_rule), diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 590e93185f4..00cefe23ce9 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -263,7 +263,7 @@ fn test_parse_stylesheet() { ] }))) - ]), + ], &stylesheet.shared_lock), }; assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected)); From adb97d4cbefde92b3645619d826ce175a787a069 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Mar 2017 16:46:22 +0100 Subject: [PATCH 09/17] Wrap most CSS rules in Locked<_> instead of RwLock<_> --- components/script/dom/bindings/trace.rs | 14 ++--- components/script/dom/cssfontfacerule.rs | 11 ++-- components/script/dom/cssimportrule.rs | 11 ++-- components/script/dom/csskeyframesrule.rs | 23 ++++---- components/script/dom/cssmediarule.rs | 39 ++++++++----- components/script/dom/cssnamespacerule.rs | 17 +++--- components/script/dom/cssrulelist.rs | 15 +++-- components/script/dom/csssupportsrule.rs | 20 ++++--- components/script/dom/cssviewportrule.rs | 11 ++-- components/script/dom/htmlmetaelement.rs | 3 +- components/script/stylesheet_loader.rs | 26 ++++++--- components/style/gecko/arc_types.rs | 17 +++++- components/style/stylesheets.rs | 70 +++++++++++++---------- components/style/stylist.rs | 4 +- ports/geckolib/glue.rs | 42 +++++++++----- ports/geckolib/stylesheet_loader.rs | 6 +- tests/unit/style/stylesheets.rs | 4 +- 17 files changed, 194 insertions(+), 139 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 122823f6f0d..efa1a5646f2 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -502,7 +502,7 @@ unsafe impl JSTraceable for Mutex> { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } @@ -520,31 +520,31 @@ unsafe impl JSTraceable for RwLock { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } @@ -556,7 +556,7 @@ unsafe impl JSTraceable for RwLock { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/cssfontfacerule.rs b/components/script/dom/cssfontfacerule.rs index 05b665a9975..184f6784afa 100644 --- a/components/script/dom/cssfontfacerule.rs +++ b/components/script/dom/cssfontfacerule.rs @@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::font_face::FontFaceRule; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; #[dom_struct] pub struct CSSFontFaceRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - fontfacerule: Arc>, + fontfacerule: Arc>, } impl CSSFontFaceRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc>) -> CSSFontFaceRule { CSSFontFaceRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -33,7 +32,7 @@ impl CSSFontFaceRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - fontfacerule: Arc>) -> Root { + fontfacerule: Arc>) -> Root { reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule), window, CSSFontFaceRuleBinding::Wrap) @@ -48,6 +47,6 @@ impl SpecificCSSRule for CSSFontFaceRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.fontfacerule.read().to_css_string(&guard).into() + self.fontfacerule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssimportrule.rs b/components/script/dom/cssimportrule.rs index bb01fdfcc84..3c0eb7eb4aa 100644 --- a/components/script/dom/cssimportrule.rs +++ b/components/script/dom/cssimportrule.rs @@ -10,21 +10,20 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::ImportRule; #[dom_struct] pub struct CSSImportRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - import_rule: Arc>, + import_rule: Arc>, } impl CSSImportRule { fn new_inherited(parent_stylesheet: &CSSStyleSheet, - import_rule: Arc>) + import_rule: Arc>) -> Self { CSSImportRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -35,7 +34,7 @@ impl CSSImportRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - import_rule: Arc>) -> Root { + import_rule: Arc>) -> Root { reflect_dom_object(box Self::new_inherited(parent_stylesheet, import_rule), window, CSSImportRuleBinding::Wrap) @@ -50,6 +49,6 @@ impl SpecificCSSRule for CSSImportRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.import_rule.read().to_css_string(&guard).into() + self.import_rule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index 330b1be3627..d17eeeb51b5 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -16,24 +16,23 @@ use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use servo_atoms::Atom; use std::sync::Arc; use style::keyframes::{Keyframe, KeyframeSelector}; use style::parser::ParserContextExtraData; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::KeyframesRule; #[dom_struct] pub struct CSSKeyframesRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - keyframesrule: Arc>, + keyframesrule: Arc>, rulelist: MutNullableJS, } impl CSSKeyframesRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc>) -> CSSKeyframesRule { CSSKeyframesRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -44,7 +43,7 @@ impl CSSKeyframesRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - keyframesrule: Arc>) -> Root { + keyframesrule: Arc>) -> Root { reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule), window, CSSKeyframesRuleBinding::Wrap) @@ -63,9 +62,10 @@ impl CSSKeyframesRule { fn find_rule(&self, selector: &str) -> Option { let mut input = Parser::new(selector); if let Ok(sel) = KeyframeSelector::parse(&mut input) { + let guard = self.cssrule.shared_lock().read(); // This finds the *last* element matching a selector // because that's the rule that applies. Thus, rposition - self.keyframesrule.read() + self.keyframesrule.read_with(&guard) .keyframes.iter().rposition(|frame| { frame.read().selector == sel }) @@ -86,7 +86,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule { let rule = Keyframe::parse(&rule, self.cssrule.parent_stylesheet().style_stylesheet(), ParserContextExtraData::default()); if let Ok(rule) = rule { - self.keyframesrule.write().keyframes.push(rule); + let mut guard = self.cssrule.shared_lock().write(); + self.keyframesrule.write_with(&mut guard).keyframes.push(rule); self.rulelist().append_lazy_dom_rule(); } } @@ -107,7 +108,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule { // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name fn Name(&self) -> DOMString { - DOMString::from(&*self.keyframesrule.read().name) + let guard = self.cssrule.shared_lock().read(); + DOMString::from(&*self.keyframesrule.read_with(&guard).name) } // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name @@ -122,7 +124,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule { "none" => return Err(Error::Syntax), _ => () } - self.keyframesrule.write().name = Atom::from(value); + let mut guard = self.cssrule.shared_lock().write(); + self.keyframesrule.write_with(&mut guard).name = Atom::from(value); Ok(()) } } @@ -135,7 +138,7 @@ impl SpecificCSSRule for CSSKeyframesRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.keyframesrule.read().to_css_string(&guard).into() + self.keyframesrule.read_with(&guard).to_css_string(&guard).into() } fn deparent_children(&self) { diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 1d1f0846a51..2a07471679e 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -14,10 +14,9 @@ use dom::cssstylesheet::CSSStyleSheet; use dom::medialist::MediaList; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::media_queries::parse_media_query_list; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::MediaRule; use style_traits::ToCss; @@ -25,14 +24,15 @@ use style_traits::ToCss; pub struct CSSMediaRule { cssconditionrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] - mediarule: Arc>, + mediarule: Arc>, medialist: MutNullableJS, } impl CSSMediaRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc>) -> CSSMediaRule { - let list = mediarule.read().rules.clone(); + let guard = parent_stylesheet.shared_lock().read(); + let list = mediarule.read_with(&guard).rules.clone(); CSSMediaRule { cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list), mediarule: mediarule, @@ -42,34 +42,43 @@ impl CSSMediaRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - mediarule: Arc>) -> Root { + mediarule: Arc>) -> Root { reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule), window, CSSMediaRuleBinding::Wrap) } fn medialist(&self) -> Root { - self.medialist.or_init(|| MediaList::new(self.global().as_window(), - self.cssconditionrule.parent_stylesheet(), - self.mediarule.read().media_queries.clone())) + self.medialist.or_init(|| { + let guard = self.cssconditionrule.shared_lock().read(); + MediaList::new(self.global().as_window(), + self.cssconditionrule.parent_stylesheet(), + self.mediarule.read_with(&guard).media_queries.clone()) + }) } /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface pub fn get_condition_text(&self) -> DOMString { let guard = self.cssconditionrule.shared_lock().read(); - let rule = self.mediarule.read(); + let rule = self.mediarule.read_with(&guard); let list = rule.media_queries.read_with(&guard); list.to_css_string().into() } /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface pub fn set_condition_text(&self, text: DOMString) { - let mut guard = self.cssconditionrule.shared_lock().write(); let mut input = Parser::new(&text); let new_medialist = parse_media_query_list(&mut input); - let rule = self.mediarule.read(); - let mut list = rule.media_queries.write_with(&mut guard); - *list = new_medialist; + let mut guard = self.cssconditionrule.shared_lock().write(); + + // Clone an Arc because we can’t borrow `guard` twice at the same time. + + // FIXME(SimonSapin): allow access to multiple objects with one write guard? + // Would need a set of usize pointer addresses or something, + // the same object is not accessed more than once. + let mqs = Arc::clone(&self.mediarule.write_with(&mut guard).media_queries); + + *mqs.write_with(&mut guard) = new_medialist; } } @@ -81,7 +90,7 @@ impl SpecificCSSRule for CSSMediaRule { fn get_css(&self) -> DOMString { let guard = self.cssconditionrule.shared_lock().read(); - self.mediarule.read().to_css_string(&guard).into() + self.mediarule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssnamespacerule.rs b/components/script/dom/cssnamespacerule.rs index 46702c275ba..744a8020667 100644 --- a/components/script/dom/cssnamespacerule.rs +++ b/components/script/dom/cssnamespacerule.rs @@ -11,20 +11,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::NamespaceRule; #[dom_struct] pub struct CSSNamespaceRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - namespacerule: Arc>, + namespacerule: Arc>, } impl CSSNamespaceRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc>) -> CSSNamespaceRule { CSSNamespaceRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -34,7 +33,7 @@ impl CSSNamespaceRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - namespacerule: Arc>) -> Root { + namespacerule: Arc>) -> Root { reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule), window, CSSNamespaceRuleBinding::Wrap) @@ -44,14 +43,16 @@ impl CSSNamespaceRule { impl CSSNamespaceRuleMethods for CSSNamespaceRule { // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix fn Prefix(&self) -> DOMString { - self.namespacerule.read().prefix + let guard = self.cssrule.shared_lock().read(); + self.namespacerule.read_with(&guard).prefix .as_ref().map(|s| s.to_string().into()) .unwrap_or(DOMString::new()) } // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-namespaceuri fn NamespaceURI(&self) -> DOMString { - (*self.namespacerule.read().url).into() + let guard = self.cssrule.shared_lock().read(); + (*self.namespacerule.read_with(&guard).url).into() } } @@ -63,6 +64,6 @@ impl SpecificCSSRule for CSSNamespaceRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.namespacerule.read().to_css_string(&guard).into() + self.namespacerule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 6321296c785..bc77361b5ae 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -13,7 +13,6 @@ use dom::cssrule::CSSRule; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::shared_lock::Locked; use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError}; @@ -45,19 +44,19 @@ pub struct CSSRuleList { pub enum RulesSource { Rules(Arc>), - Keyframes(Arc>), + Keyframes(Arc>), } impl CSSRuleList { #[allow(unrooted_must_root)] pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList { + let guard = parent_stylesheet.shared_lock().read(); let dom_rules = match rules { RulesSource::Rules(ref rules) => { - let guard = parent_stylesheet.shared_lock().read(); rules.read_with(&guard).0.iter().map(|_| MutNullableJS::new(None)).collect() } RulesSource::Keyframes(ref rules) => { - rules.read().keyframes.iter().map(|_| MutNullableJS::new(None)).collect() + rules.read_with(&guard).keyframes.iter().map(|_| MutNullableJS::new(None)).collect() } }; @@ -104,10 +103,10 @@ impl CSSRuleList { // In case of a keyframe rule, index must be valid. pub fn remove_rule(&self, index: u32) -> ErrorResult { let index = index as usize; + let mut guard = self.parent_stylesheet.shared_lock().write(); match self.rules { RulesSource::Rules(ref css_rules) => { - let mut guard = self.parent_stylesheet.shared_lock().write(); css_rules.write_with(&mut guard).remove_rule(index)?; let mut dom_rules = self.dom_rules.borrow_mut(); dom_rules[index].get().map(|r| r.detach()); @@ -119,7 +118,7 @@ impl CSSRuleList { let mut dom_rules = self.dom_rules.borrow_mut(); dom_rules[index].get().map(|r| r.detach()); dom_rules.remove(index); - kf.write().keyframes.remove(index); + kf.write_with(&mut guard).keyframes.remove(index); Ok(()) } } @@ -136,9 +135,9 @@ impl CSSRuleList { self.dom_rules.borrow().get(idx as usize).map(|rule| { rule.or_init(|| { let parent_stylesheet = &self.parent_stylesheet; + let guard = parent_stylesheet.shared_lock().read(); match self.rules { RulesSource::Rules(ref rules) => { - let guard = parent_stylesheet.shared_lock().read(); CSSRule::new_specific(self.global().as_window(), parent_stylesheet, rules.read_with(&guard).0[idx as usize].clone()) @@ -146,7 +145,7 @@ impl CSSRuleList { RulesSource::Keyframes(ref rules) => { Root::upcast(CSSKeyframeRule::new(self.global().as_window(), parent_stylesheet, - rules.read() + rules.read_with(&guard) .keyframes[idx as usize] .clone())) } diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs index d5e844e52aa..7ba3a24d038 100644 --- a/components/script/dom/csssupportsrule.rs +++ b/components/script/dom/csssupportsrule.rs @@ -13,10 +13,9 @@ use dom::cssrule::SpecificCSSRule; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::parser::ParserContext; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::SupportsRule; use style::supports::SupportsCondition; use style_traits::ToCss; @@ -25,13 +24,14 @@ use style_traits::ToCss; pub struct CSSSupportsRule { cssconditionrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] - supportsrule: Arc>, + supportsrule: Arc>, } impl CSSSupportsRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc>) -> CSSSupportsRule { - let list = supportsrule.read().rules.clone(); + let guard = parent_stylesheet.shared_lock().read(); + let list = supportsrule.read_with(&guard).rules.clone(); CSSSupportsRule { cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list), supportsrule: supportsrule, @@ -40,7 +40,7 @@ impl CSSSupportsRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - supportsrule: Arc>) -> Root { + supportsrule: Arc>) -> Root { reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule), window, CSSSupportsRuleBinding::Wrap) @@ -48,7 +48,8 @@ impl CSSSupportsRule { /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface pub fn get_condition_text(&self) -> DOMString { - let rule = self.supportsrule.read(); + let guard = self.cssconditionrule.shared_lock().read(); + let rule = self.supportsrule.read_with(&guard); rule.condition.to_css_string().into() } @@ -62,7 +63,8 @@ impl CSSSupportsRule { let url = win.Document().url(); let context = ParserContext::new_for_cssom(&url, win.css_error_reporter()); let enabled = cond.eval(&context); - let mut rule = self.supportsrule.write(); + let mut guard = self.cssconditionrule.shared_lock().write(); + let rule = self.supportsrule.write_with(&mut guard); rule.condition = cond; rule.enabled = enabled; } @@ -77,6 +79,6 @@ impl SpecificCSSRule for CSSSupportsRule { fn get_css(&self) -> DOMString { let guard = self.cssconditionrule.shared_lock().read(); - self.supportsrule.read().to_css_string(&guard).into() + self.supportsrule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssviewportrule.rs b/components/script/dom/cssviewportrule.rs index 855c8bdda57..38abf909ff0 100644 --- a/components/script/dom/cssviewportrule.rs +++ b/components/script/dom/cssviewportrule.rs @@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::viewport::ViewportRule; #[dom_struct] pub struct CSSViewportRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - viewportrule: Arc>, + viewportrule: Arc>, } impl CSSViewportRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc>) -> CSSViewportRule { + fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc>) -> CSSViewportRule { CSSViewportRule { cssrule: CSSRule::new_inherited(parent_stylesheet), viewportrule: viewportrule, @@ -32,7 +31,7 @@ impl CSSViewportRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - viewportrule: Arc>) -> Root { + viewportrule: Arc>) -> Root { reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule), window, CSSViewportRuleBinding::Wrap) @@ -47,6 +46,6 @@ impl SpecificCSSRule for CSSViewportRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.viewportrule.read().to_css_string(&guard).into() + self.viewportrule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index a564c6b2661..bc6f37561d8 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -19,7 +19,6 @@ use dom::node::{Node, UnbindContext, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever_atoms::LocalName; -use parking_lot::RwLock; use servo_config::prefs::PREFS; use std::ascii::AsciiExt; use std::sync::Arc; @@ -101,7 +100,7 @@ impl HTMLMetaElement { if let Some(translated_rule) = ViewportRule::from_meta(&**content) { let document = self.upcast::().owner_doc(); let shared_lock = document.style_shared_lock(); - let rule = CssRule::Viewport(Arc::new(RwLock::new(translated_rule))); + let rule = CssRule::Viewport(Arc::new(shared_lock.wrap(translated_rule))); *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet { rules: CssRules::new(vec![rule], shared_lock), origin: Origin::Author, diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 79b90be7426..db21ee795fd 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -22,13 +22,13 @@ use ipc_channel::router::ROUTER; use net_traits::{FetchResponseListener, FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy}; use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType}; use network_listener::{NetworkListener, PreInvoke}; -use parking_lot::RwLock; use script_layout_interface::message::Msg; use servo_url::ServoUrl; use std::mem; use std::sync::{Arc, Mutex}; use style::media_queries::MediaList; use style::parser::ParserContextExtraData; +use style::shared_lock::Locked as StyleLocked; use style::stylesheets::{ImportRule, Stylesheet, Origin}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; @@ -55,15 +55,16 @@ pub trait StylesheetOwner { pub enum StylesheetContextSource { // NB: `media` is just an option so we avoid cloning it. LinkElement { media: Option, url: ServoUrl }, - Import(Arc>), + Import(Arc>), } impl StylesheetContextSource { - fn url(&self) -> ServoUrl { + fn url(&self, document: &Document) -> ServoUrl { match *self { StylesheetContextSource::LinkElement { ref url, .. } => url.clone(), StylesheetContextSource::Import(ref import) => { - let import = import.read(); + let guard = document.style_shared_lock().read(); + let import = import.read_with(&guard); // Look at the parser in style::stylesheets, where we don't // trigger a load if the url is invalid. import.url.url() @@ -174,9 +175,16 @@ impl FetchResponseListener for StylesheetContext { } } StylesheetContextSource::Import(ref import) => { - let import = import.read(); let mut guard = document.style_shared_lock().write(); - Stylesheet::update_from_bytes(&import.stylesheet, + + // Clone an Arc because we can’t borrow `guard` twice at the same time. + + // FIXME(SimonSapin): allow access to multiple objects with one write guard? + // Would need a set of usize pointer addresses or something, + // the same object is not accessed more than once. + let stylesheet = Arc::clone(&import.write_with(&mut guard).stylesheet); + + Stylesheet::update_from_bytes(&stylesheet, &data, protocol_encoding_label, Some(environment_encoding), @@ -201,7 +209,7 @@ impl FetchResponseListener for StylesheetContext { document.decrement_script_blocking_stylesheet_count(); } - let url = self.source.url(); + let url = self.source.url(&document); document.finish_load(LoadType::Stylesheet(url)); if let Some(any_failed) = owner.load_finished(successful) { @@ -226,8 +234,8 @@ impl<'a> StylesheetLoader<'a> { impl<'a> StylesheetLoader<'a> { pub fn load(&self, source: StylesheetContextSource, cors_setting: Option, integrity_metadata: String) { - let url = source.url(); let document = document_from_node(self.elem); + let url = source.url(&document); let gen = self.elem.downcast::() .map(HTMLLinkElement::get_request_generation_id); let context = Arc::new(Mutex::new(StylesheetContext { @@ -289,7 +297,7 @@ impl<'a> StylesheetLoader<'a> { } impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> { - fn request_stylesheet(&self, import: &Arc>) { + fn request_stylesheet(&self, import: &Arc>) { //TODO (mrnayak) : Whether we should use the original loader's CORS setting? //Fix this when spec has more details. self.load(StylesheetContextSource::Import(import.clone()), None, "".to_owned()) diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index 798af00906e..58ec43cf387 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -51,10 +51,21 @@ impl_arc_ffi!(ComputedValues => ServoComputedValues impl_arc_ffi!(RwLock => RawServoDeclarationBlock [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]); +/// FIXME: Remove once StyleRule is actually in Locked<_> +pub trait HackHackHack { + fn as_arc<'a>(ptr: &'a &RawServoStyleRule) -> &'a ::std::sync::Arc>; +} + +impl HackHackHack for Locked { + fn as_arc<'a>(ptr: &'a &RawServoStyleRule) -> &'a ::std::sync::Arc> { + RwLock::::as_arc(ptr) + } +} + impl_arc_ffi!(RwLock => RawServoStyleRule [Servo_StyleRule_AddRef, Servo_StyleRule_Release]); -impl_arc_ffi!(RwLock => RawServoImportRule +impl_arc_ffi!(Locked => RawServoImportRule [Servo_ImportRule_AddRef, Servo_ImportRule_Release]); impl_arc_ffi!(AnimationValue => RawServoAnimationValue @@ -66,8 +77,8 @@ impl_arc_ffi!(RwLock => RawServoAnimationValueMap impl_arc_ffi!(Locked => RawServoMediaList [Servo_MediaList_AddRef, Servo_MediaList_Release]); -impl_arc_ffi!(RwLock => RawServoMediaRule +impl_arc_ffi!(Locked => RawServoMediaRule [Servo_MediaRule_AddRef, Servo_MediaRule_Release]); -impl_arc_ffi!(RwLock => RawServoNamespaceRule +impl_arc_ffi!(Locked => RawServoNamespaceRule [Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]); diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 07dc2632b2d..a0f0baa3840 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -213,14 +213,14 @@ pub enum CssRule { // No Charset here, CSSCharsetRule has been removed from CSSOM // https://drafts.csswg.org/cssom/#changes-from-5-december-2013 - Namespace(Arc>), - Import(Arc>), + Namespace(Arc>), + Import(Arc>), Style(Arc>), - Media(Arc>), - FontFace(Arc>), - Viewport(Arc>), - Keyframes(Arc>), - Supports(Arc>), + Media(Arc>), + FontFace(Arc>), + Viewport(Arc>), + Keyframes(Arc>), + Supports(Arc>), } #[allow(missing_docs)] @@ -301,7 +301,7 @@ impl CssRule { where F: FnMut(&[CssRule], Option<&MediaList>) -> R { match *self { CssRule::Import(ref lock) => { - let rule = lock.read(); + let rule = lock.read_with(guard); let media = rule.stylesheet.media.read_with(guard); let rules = rule.stylesheet.rules.read_with(guard); // FIXME(emilio): Include the nested rules if the stylesheet is @@ -316,13 +316,13 @@ impl CssRule { f(&[], None) } CssRule::Media(ref lock) => { - let media_rule = lock.read(); + let media_rule = lock.read_with(guard); let mq = media_rule.media_queries.read_with(guard); let rules = &media_rule.rules.read_with(guard).0; f(rules, Some(&mq)) } CssRule::Supports(ref lock) => { - let supports_rule = lock.read(); + let supports_rule = lock.read_with(guard); let enabled = supports_rule.enabled; if enabled { let rules = &supports_rule.rules.read_with(guard).0; @@ -378,14 +378,14 @@ impl ToCssWithGuard for CssRule { fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - CssRule::Namespace(ref lock) => lock.read().to_css(guard, dest), - CssRule::Import(ref lock) => lock.read().to_css(guard, dest), + CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Style(ref lock) => lock.read().to_css(guard, dest), - CssRule::FontFace(ref lock) => lock.read().to_css(guard, dest), - CssRule::Viewport(ref lock) => lock.read().to_css(guard, dest), - CssRule::Keyframes(ref lock) => lock.read().to_css(guard, dest), - CssRule::Media(ref lock) => lock.read().to_css(guard, dest), - CssRule::Supports(ref lock) => lock.read().to_css(guard, dest), + CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest), } } } @@ -717,7 +717,7 @@ macro_rules! rule_filter { where F: FnMut(&$rule_type) { self.effective_rules(device, guard, |rule| { if let CssRule::$variant(ref lock) = *rule { - let rule = lock.read(); + let rule = lock.read_with(guard); f(&rule) } }) @@ -736,6 +736,18 @@ rule_filter! { effective_supports_rules(Supports => SupportsRule), } +/// FIXME: Remove once StyleRule is actually in Locked<_> +pub trait RwLockStyleRulePretendLockedStyleRule { + /// Pretend we’re Locked<_> + fn read_with(&self, guard: &SharedRwLockReadGuard) -> ::parking_lot::RwLockReadGuard; +} + +impl RwLockStyleRulePretendLockedStyleRule for RwLock { + fn read_with(&self, _: &SharedRwLockReadGuard) -> ::parking_lot::RwLockReadGuard { + self.read() + } +} + /// The stylesheet loader is the abstraction used to trigger network requests /// for `@import` rules. pub trait StylesheetLoader { @@ -743,7 +755,7 @@ pub trait StylesheetLoader { /// /// The called code is responsible to update the `stylesheet` rules field /// when the sheet is done loading. - fn request_stylesheet(&self, import: &Arc>); + fn request_stylesheet(&self, import: &Arc>); } struct TopLevelRuleParser<'a> { @@ -811,7 +823,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { let is_valid_url = url.url().is_some(); - let import_rule = Arc::new(RwLock::new( + let import_rule = Arc::new(self.shared_lock.wrap( ImportRule { url: url, stylesheet: Arc::new(Stylesheet { @@ -855,12 +867,12 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { None }; - return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(RwLock::new( - NamespaceRule { + return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new( + self.shared_lock.wrap(NamespaceRule { prefix: opt_prefix, url: url, - } - ))))) + }) + )))) } else { self.state.set(State::Invalid); return Err(()) // "@namespace must be before any rule but @charset and @import" @@ -973,29 +985,29 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result { match prelude { AtRulePrelude::FontFace => { - Ok(CssRule::FontFace(Arc::new(RwLock::new( + Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap( try!(parse_font_face_block(self.context, input)))))) } AtRulePrelude::Media(media_queries) => { - Ok(CssRule::Media(Arc::new(RwLock::new(MediaRule { + Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule { media_queries: media_queries, rules: self.parse_nested_rules(input), })))) } AtRulePrelude::Supports(cond) => { let enabled = cond.eval(self.context); - Ok(CssRule::Supports(Arc::new(RwLock::new(SupportsRule { + Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(SupportsRule { condition: cond, rules: self.parse_nested_rules(input), enabled: enabled, })))) } AtRulePrelude::Viewport => { - Ok(CssRule::Viewport(Arc::new(RwLock::new( + Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap( try!(ViewportRule::parse(input, self.context)))))) } AtRulePrelude::Keyframes(name) => { - Ok(CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule { + Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule { name: name, keyframes: parse_keyframe_list(&self.context, input), })))) diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 73684a4b8fd..4e6b6350beb 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -274,11 +274,11 @@ impl Stylist { } } CssRule::Import(ref import) => { - let import = import.read(); + let import = import.read_with(guard); self.add_stylesheet(&import.stylesheet, guard) } CssRule::Keyframes(ref keyframes_rule) => { - let keyframes_rule = keyframes_rule.read(); + let keyframes_rule = keyframes_rule.read_with(guard); debug!("Found valid keyframes rule: {:?}", *keyframes_rule); let animation = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes); debug!("Found valid keyframe animation: {:?}", animation); diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index e260f365fa5..24380439062 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -23,6 +23,7 @@ use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInf use style::data::{ElementData, ElementStyles, RestyleData}; use style::dom::{ShowSubtreeData, TElement, TNode}; use style::error_reporting::StdoutErrorReporter; +use style::gecko::arc_types::HackHackHack; use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl}; use style::gecko::restyle_damage::GeckoRestyleDamage; use style::gecko::selector_parser::{SelectorImpl, PseudoElement}; @@ -81,6 +82,7 @@ use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; +use style::stylesheets::RwLockStyleRulePretendLockedStyleRule; use style::supports::parse_condition_or_declaration; use style::thread_state; use style::timer::Timer; @@ -586,17 +588,19 @@ macro_rules! impl_basic_rule_funcs { #[no_mangle] pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) { - let rule = RwLock::<$rule_type>::as_arc(&rule); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::<$rule_type>::as_arc(&rule); let result = unsafe { result.as_mut().unwrap() }; - write!(result, "{:?}", *rule.read()).unwrap(); + write!(result, "{:?}", *rule.read_with(&guard)).unwrap(); } #[no_mangle] pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { let global_style_data = &*GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read(); - let rule = RwLock::<$rule_type>::as_arc(&rule); - rule.read().to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap(); + let rule = Locked::<$rule_type>::as_arc(&rule); + rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap(); } } } @@ -641,26 +645,34 @@ pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowe #[no_mangle] pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong { - let rule = RwLock::::as_arc(&rule); - rule.read().media_queries.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).media_queries.clone().into_strong() } #[no_mangle] pub extern "C" fn Servo_MediaRule_GetRules(rule: RawServoMediaRuleBorrowed) -> ServoCssRulesStrong { - let rule = RwLock::::as_arc(&rule); - rule.read().rules.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).rules.clone().into_strong() } #[no_mangle] pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom { - let rule = RwLock::::as_arc(&rule); - rule.read().prefix.as_ref().unwrap_or(&atom!("")).as_ptr() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).prefix.as_ref().unwrap_or(&atom!("")).as_ptr() } #[no_mangle] pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom { - let rule = RwLock::::as_arc(&rule); - rule.read().url.0.as_ptr() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).url.0.as_ptr() } #[no_mangle] @@ -1404,8 +1416,10 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed, pub extern "C" fn Servo_ImportRule_GetSheet(import_rule: RawServoImportRuleBorrowed) -> RawServoStyleSheetStrong { - let import_rule = RwLock::::as_arc(&import_rule); - import_rule.read().stylesheet.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let import_rule = Locked::::as_arc(&import_rule); + import_rule.read_with(&guard).stylesheet.clone().into_strong() } #[no_mangle] diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index bcd55cce2fd..2e81de1a57e 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -2,11 +2,11 @@ * 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/. */ -use parking_lot::RwLock; use std::sync::Arc; use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; use style::gecko_bindings::sugar::ownership::HasArcFFI; +use style::shared_lock::Locked; use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader}; use style_traits::ToCss; use super::glue::GLOBAL_STYLE_DATA; @@ -20,10 +20,10 @@ impl StylesheetLoader { } impl StyleStylesheetLoader for StylesheetLoader { - fn request_stylesheet(&self, import_rule: &Arc>) { + fn request_stylesheet(&self, import_rule: &Arc>) { let global_style_data = &*GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read(); - let import = import_rule.read(); + let import = import_rule.read_with(&guard); let (spec_bytes, spec_len) = import.url.as_slice_components() .expect("Import only loads valid URLs"); diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 00cefe23ce9..a1c67932b53 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -77,7 +77,7 @@ fn test_parse_stylesheet() { dirty_on_viewport_size_change: AtomicBool::new(false), disabled: AtomicBool::new(false), rules: CssRules::new(vec![ - CssRule::Namespace(Arc::new(RwLock::new(NamespaceRule { + CssRule::Namespace(Arc::new(stylesheet.shared_lock.wrap(NamespaceRule { prefix: None, url: NsAtom::from("http://www.w3.org/1999/xhtml") }))), @@ -235,7 +235,7 @@ fn test_parse_stylesheet() { Importance::Normal), ]))), }))), - CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule { + CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule { name: "foo".into(), keyframes: vec![ Arc::new(RwLock::new(Keyframe { From 57724e5a3755a757e502658094dfda171c78ba78 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Mar 2017 19:48:37 +0100 Subject: [PATCH 10/17] Replace RwLock with Locked --- components/script/dom/bindings/trace.rs | 2 +- components/script/dom/csskeyframerule.rs | 26 +++++++++++------- components/script/dom/csskeyframesrule.rs | 2 +- components/style/keyframes.rs | 33 ++++++++++++++--------- components/style/stylesheets.rs | 8 +++--- components/style/stylist.rs | 3 ++- tests/unit/style/keyframes.rs | 30 ++++++++++++--------- tests/unit/style/stylesheets.rs | 4 +-- 8 files changed, 64 insertions(+), 44 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index efa1a5646f2..387709d7332 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -514,7 +514,7 @@ unsafe impl JSTraceable for StyleLocked { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/csskeyframerule.rs b/components/script/dom/csskeyframerule.rs index 0f620bdc764..617546d6a76 100644 --- a/components/script/dom/csskeyframerule.rs +++ b/components/script/dom/csskeyframerule.rs @@ -12,21 +12,21 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::keyframes::Keyframe; +use style::shared_lock::Locked; use style_traits::ToCss; #[dom_struct] pub struct CSSKeyframeRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - keyframerule: Arc>, + keyframerule: Arc>, style_decl: MutNullableJS, } impl CSSKeyframeRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc>) -> CSSKeyframeRule { CSSKeyframeRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -37,7 +37,7 @@ impl CSSKeyframeRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - keyframerule: Arc>) -> Root { + keyframerule: Arc>) -> Root { reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule), window, CSSKeyframeRuleBinding::Wrap) @@ -48,11 +48,16 @@ impl CSSKeyframeRuleMethods for CSSKeyframeRule { // https://drafts.csswg.org/css-animations/#dom-csskeyframerule-style fn Style(&self) -> Root { self.style_decl.or_init(|| { - CSSStyleDeclaration::new(self.global().as_window(), - CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()), - self.keyframerule.read().block.clone()), - None, - CSSModificationAccess::ReadWrite) + let guard = self.cssrule.shared_lock().read(); + CSSStyleDeclaration::new( + self.global().as_window(), + CSSStyleOwner::CSSRule( + JS::from_ref(self.upcast()), + self.keyframerule.read_with(&guard).block.clone(), + ), + None, + CSSModificationAccess::ReadWrite, + ) }) } } @@ -64,6 +69,7 @@ impl SpecificCSSRule for CSSKeyframeRule { } fn get_css(&self) -> DOMString { - self.keyframerule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.keyframerule.read_with(&guard).to_css_string().into() } } diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index d17eeeb51b5..288ae486d1d 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -67,7 +67,7 @@ impl CSSKeyframesRule { // because that's the rule that applies. Thus, rposition self.keyframesrule.read_with(&guard) .keyframes.iter().rposition(|frame| { - frame.read().selector == sel + frame.read_with(&guard).selector == sel }) } else { None diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index 69aeb669dcc..44ca0921706 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -15,6 +15,7 @@ use properties::{PropertyDeclarationId, LonghandId, ParsedDeclaration}; use properties::LonghandIdSet; use properties::animated_properties::TransitionProperty; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; +use shared_lock::{SharedRwLock, SharedRwLockReadGuard, Locked}; use std::fmt; use std::sync::Arc; use style_traits::ToCss; @@ -125,7 +126,7 @@ impl Keyframe { pub fn parse(css: &str, parent_stylesheet: &Stylesheet, extra_data: ParserContextExtraData) - -> Result>, ()> { + -> Result>, ()> { let error_reporter = MemoryHoleReporter; let context = ParserContext::new_with_extra_data(parent_stylesheet.origin, &parent_stylesheet.base_url, @@ -135,6 +136,7 @@ impl Keyframe { let mut rule_parser = KeyframeListParser { context: &context, + shared_lock: &parent_stylesheet.shared_lock, }; parse_one_rule(&mut input, &mut rule_parser) } @@ -239,13 +241,14 @@ pub struct KeyframesAnimation { } /// Get all the animated properties in a keyframes animation. -fn get_animated_properties(keyframes: &[Arc>]) -> Vec { +fn get_animated_properties(keyframes: &[Arc>], guard: &SharedRwLockReadGuard) + -> Vec { let mut ret = vec![]; let mut seen = LonghandIdSet::new(); // NB: declarations are already deduplicated, so we don't have to check for // it here. for keyframe in keyframes { - let keyframe = keyframe.read(); + let keyframe = keyframe.read_with(&guard); for &(ref declaration, importance) in keyframe.block.read().declarations().iter() { assert!(!importance.important()); @@ -270,7 +273,8 @@ impl KeyframesAnimation { /// /// Otherwise, this will compute and sort the steps used for the animation, /// and return the animation object. - pub fn from_keyframes(keyframes: &[Arc>]) -> Self { + pub fn from_keyframes(keyframes: &[Arc>], guard: &SharedRwLockReadGuard) + -> Self { let mut result = KeyframesAnimation { steps: vec![], properties_changed: vec![], @@ -280,13 +284,13 @@ impl KeyframesAnimation { return result; } - result.properties_changed = get_animated_properties(keyframes); + result.properties_changed = get_animated_properties(keyframes, guard); if result.properties_changed.is_empty() { return result; } for keyframe in keyframes { - let keyframe = keyframe.read(); + let keyframe = keyframe.read_with(&guard); for percentage in keyframe.selector.0.iter() { result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations { block: keyframe.block.clone(), @@ -322,24 +326,27 @@ impl KeyframesAnimation { /// } struct KeyframeListParser<'a> { context: &'a ParserContext<'a>, + shared_lock: &'a SharedRwLock, } /// Parses a keyframe list from CSS input. -pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec>> { - RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context }) - .filter_map(Result::ok) - .collect() +pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser, shared_lock: &SharedRwLock) + -> Vec>> { + RuleListParser::new_for_nested_rule(input, KeyframeListParser { + context: context, + shared_lock: shared_lock, + }).filter_map(Result::ok).collect() } enum Void {} impl<'a> AtRuleParser for KeyframeListParser<'a> { type Prelude = Void; - type AtRule = Arc>; + type AtRule = Arc>; } impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { type Prelude = KeyframeSelector; - type QualifiedRule = Arc>; + type QualifiedRule = Arc>; fn parse_prelude(&mut self, input: &mut Parser) -> Result { let start = input.position(); @@ -372,7 +379,7 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { } // `parse_important` is not called here, `!important` is not allowed in keyframe blocks. } - Ok(Arc::new(RwLock::new(Keyframe { + Ok(Arc::new(self.shared_lock.wrap(Keyframe { selector: prelude, block: Arc::new(RwLock::new(block)), }))) diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index a0f0baa3840..d132c64bbb9 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -451,12 +451,12 @@ pub struct KeyframesRule { /// The name of the current animation. pub name: Atom, /// The keyframes specified for this CSS rule. - pub keyframes: Vec>>, + pub keyframes: Vec>>, } impl ToCssWithGuard for KeyframesRule { // Serialization of KeyframesRule is not specced. - fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result where W: fmt::Write { try!(dest.write_str("@keyframes ")); try!(dest.write_str(&*self.name.to_string())); @@ -468,7 +468,7 @@ impl ToCssWithGuard for KeyframesRule { try!(dest.write_str(" ")); } first = false; - let keyframe = lock.read(); + let keyframe = lock.read_with(&guard); try!(keyframe.to_css(dest)); } dest.write_str(" }") @@ -1009,7 +1009,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { AtRulePrelude::Keyframes(name) => { Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule { name: name, - keyframes: parse_keyframe_list(&self.context, input), + keyframes: parse_keyframe_list(&self.context, input, self.shared_lock), })))) } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 4e6b6350beb..a110e4f7abb 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -280,7 +280,8 @@ impl Stylist { CssRule::Keyframes(ref keyframes_rule) => { let keyframes_rule = keyframes_rule.read_with(guard); debug!("Found valid keyframes rule: {:?}", *keyframes_rule); - let animation = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes); + let animation = KeyframesAnimation::from_keyframes( + &keyframes_rule.keyframes, guard); debug!("Found valid keyframe animation: {:?}", animation); self.animations.insert(keyframes_rule.name.clone(), animation); } diff --git a/tests/unit/style/keyframes.rs b/tests/unit/style/keyframes.rs index 051ff9ca792..a916f18da01 100644 --- a/tests/unit/style/keyframes.rs +++ b/tests/unit/style/keyframes.rs @@ -8,12 +8,14 @@ use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, Keyfra use style::keyframes::{KeyframesStep, KeyframesStepValue}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance}; use style::properties::animated_properties::TransitionProperty; +use style::shared_lock::SharedRwLock; use style::values::specified::{LengthOrPercentageOrAuto, NoCalcLength}; #[test] fn test_empty_keyframe() { + let shared_lock = SharedRwLock::new(); let keyframes = vec![]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![], properties_changed: vec![], @@ -24,13 +26,14 @@ fn test_empty_keyframe() { #[test] fn test_no_property_in_keyframe() { + let shared_lock = SharedRwLock::new(); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), block: Arc::new(RwLock::new(PropertyDeclarationBlock::new())) })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![], properties_changed: vec![], @@ -41,6 +44,7 @@ fn test_no_property_in_keyframe() { #[test] fn test_missing_property_in_initial_keyframe() { + let shared_lock = SharedRwLock::new(); let declarations_on_initial_keyframe = Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( PropertyDeclaration::Width( @@ -65,17 +69,17 @@ fn test_missing_property_in_initial_keyframe() { })); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), block: declarations_on_initial_keyframe.clone(), })), - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), block: declarations_on_final_keyframe.clone(), })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![ KeyframesStep { @@ -97,6 +101,7 @@ fn test_missing_property_in_initial_keyframe() { #[test] fn test_missing_property_in_final_keyframe() { + let shared_lock = SharedRwLock::new(); let declarations_on_initial_keyframe = Arc::new(RwLock::new({ let mut block = PropertyDeclarationBlock::new(); @@ -121,17 +126,17 @@ fn test_missing_property_in_final_keyframe() { ))); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), block: declarations_on_initial_keyframe.clone(), })), - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), block: declarations_on_final_keyframe.clone(), })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![ KeyframesStep { @@ -153,6 +158,7 @@ fn test_missing_property_in_final_keyframe() { #[test] fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { + let shared_lock = SharedRwLock::new(); let declarations = Arc::new(RwLock::new({ let mut block = PropertyDeclarationBlock::new(); @@ -170,16 +176,16 @@ fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { })); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), block: Arc::new(RwLock::new(PropertyDeclarationBlock::new())) })), - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.5)]), block: declarations.clone(), })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![ KeyframesStep { diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index a1c67932b53..99ec3676236 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -238,7 +238,7 @@ fn test_parse_stylesheet() { CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule { name: "foo".into(), keyframes: vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(stylesheet.shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing( vec![KeyframePercentage::new(0.)]), block: Arc::new(RwLock::new(block_from(vec![ @@ -247,7 +247,7 @@ fn test_parse_stylesheet() { Importance::Normal), ]))) })), - Arc::new(RwLock::new(Keyframe { + Arc::new(stylesheet.shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing( vec![KeyframePercentage::new(1.)]), block: Arc::new(RwLock::new(block_from(vec![ From aeffca2a5900ebcf91063e9c7771b642817cb6bd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 00:47:08 +0100 Subject: [PATCH 11/17] Replace RwLock with Locked --- Cargo.lock | 2 - components/layout/block.rs | 2 +- components/layout/construct.rs | 27 +++--- components/layout/context.rs | 8 +- components/layout/display_list_builder.rs | 2 +- components/layout/generated_content.rs | 2 +- components/layout/traversal.rs | 24 ++--- components/layout_thread/lib.rs | 42 ++++++--- components/script/dom/bindings/trace.rs | 2 +- components/script/dom/cssstylerule.rs | 26 +++--- components/script/dom/document.rs | 3 +- .../script_layout_interface/wrapper_traits.rs | 2 + components/style/Cargo.toml | 1 - components/style/context.rs | 10 ++- components/style/gecko/arc_types.rs | 13 +-- components/style/gecko/data.rs | 4 +- components/style/gecko/traversal.rs | 13 +-- components/style/lib.rs | 2 - components/style/matching.rs | 3 + components/style/owning_handle.rs | 89 ------------------- .../style/properties/properties.mako.rs | 9 +- components/style/rule_tree/mod.rs | 81 ++++++++--------- components/style/servo/mod.rs | 10 +++ components/style/shared_lock.rs | 20 +++++ components/style/stylesheets.rs | 18 +--- components/style/stylist.rs | 62 ++++++++----- components/style/traversal.rs | 3 +- ports/geckolib/glue.rs | 50 +++++++---- tests/unit/style/Cargo.toml | 1 - tests/unit/style/lib.rs | 2 - tests/unit/style/owning_handle.rs | 34 ------- tests/unit/style/stylesheets.rs | 6 +- tests/unit/style/stylist.rs | 40 +++++---- 33 files changed, 279 insertions(+), 334 deletions(-) delete mode 100644 components/style/owning_handle.rs delete mode 100644 tests/unit/style/owning_handle.rs diff --git a/Cargo.lock b/Cargo.lock index d8bf220c648..076924c397c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2757,7 +2757,6 @@ dependencies = [ "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2783,7 +2782,6 @@ dependencies = [ "cssparser 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/layout/block.rs b/components/layout/block.rs index 4bfef78cb3d..31f44f0ec0e 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -446,7 +446,7 @@ fn translate_including_floats(cur_b: &mut Au, delta: Au, floats: &mut Floats) { /// /// Note that flows with position 'fixed' just form a flat list as they all /// have the Root flow as their CB. -pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext); +pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext<'a>); impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> { #[inline] diff --git a/components/layout/construct.rs b/components/layout/construct.rs index a6571d0e093..00cd46a079a 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -311,7 +311,7 @@ impl InlineFragmentsAccumulator { /// An object that knows how to create flows. pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> { /// The layout context. - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, /// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of /// the ensuing impl {} by removing the need to parameterize all the methods individually. phantom2: PhantomData, @@ -320,7 +320,7 @@ pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> { impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> FlowConstructor<'a, ConcreteThreadSafeLayoutNode> { /// Creates a new flow constructor. - pub fn new(layout_context: &'a LayoutContext) -> Self { + pub fn new(layout_context: &'a LayoutContext<'a>) -> Self { FlowConstructor { layout_context: layout_context, phantom2: PhantomData, @@ -660,10 +660,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let mut style = node.style(self.style_context()); if node_is_input_or_text_area { - style = self.style_context() - .stylist - .style_for_anonymous_box(&PseudoElement::ServoInputText, - &style) + let context = self.style_context(); + style = context.stylist.style_for_anonymous_box( + &context.guards, &PseudoElement::ServoInputText, &style) } self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style) @@ -1096,11 +1095,14 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> -> ConstructionResult { let mut legalizer = Legalizer::new(); - let table_style = node.style(self.style_context()); - let wrapper_style = self.style_context() - .stylist - .style_for_anonymous_box(&PseudoElement::ServoTableWrapper, - &table_style); + let table_style; + let wrapper_style; + { + let context = self.style_context(); + table_style = node.style(context); + wrapper_style = context.stylist.style_for_anonymous_box( + &context.guards, &PseudoElement::ServoTableWrapper, &table_style); + } let wrapper_fragment = Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, @@ -2080,8 +2082,7 @@ impl Legalizer { let reference_block = reference.as_block(); let mut new_style = reference_block.fragment.style.clone(); for pseudo in pseudos { - new_style = context.stylist.style_for_anonymous_box(pseudo, - &new_style) + new_style = context.stylist.style_for_anonymous_box(&context.guards, pseudo, &new_style) } let fragment = reference_block.fragment .create_similar_anonymous_fragment(new_style, diff --git a/components/layout/context.rs b/components/layout/context.rs index 1dff9f6ea5e..e2ffeb1cbd9 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -75,9 +75,9 @@ pub fn heap_size_of_persistent_local_context() -> usize { } /// Layout information shared among all workers. This must be thread-safe. -pub struct LayoutContext { +pub struct LayoutContext<'a> { /// Bits shared by the layout and style system. - pub style_context: SharedStyleContext, + pub style_context: SharedStyleContext<'a>, /// The shared image cache thread. pub image_cache_thread: Mutex, @@ -95,7 +95,7 @@ pub struct LayoutContext { pub pending_images: Option>> } -impl Drop for LayoutContext { +impl<'a> Drop for LayoutContext<'a> { fn drop(&mut self) { if !thread::panicking() { if let Some(ref pending_images) = self.pending_images { @@ -105,7 +105,7 @@ impl Drop for LayoutContext { } } -impl LayoutContext { +impl<'a> LayoutContext<'a> { #[inline(always)] pub fn shared_context(&self) -> &SharedStyleContext { &self.style_context diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index ab3636fdbc5..2ee9985cf0e 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -121,7 +121,7 @@ fn get_cyclic(arr: &[T], index: usize) -> &T { } pub struct DisplayListBuildState<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, pub root_stacking_context: StackingContext, pub items: HashMap>, pub stacking_context_children: HashMap>, diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index ef2e270c064..887562e89fb 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -97,7 +97,7 @@ static KATAKANA_IROHA: [char; 47] = [ /// The generated content resolution traversal. pub struct ResolveGeneratedContent<'a> { /// The layout context. - layout_context: &'a LayoutContext, + layout_context: &'a LayoutContext<'a>, /// The counter representing an ordered list item. list_item: Counter, /// Named CSS counters. diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 0088ef208f3..3c0c1763d0c 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -22,20 +22,20 @@ use style::traversal::PerLevelTraversalData; use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData}; use wrapper::ThreadSafeLayoutNodeHelpers; -pub struct RecalcStyleAndConstructFlows { - context: LayoutContext, +pub struct RecalcStyleAndConstructFlows<'a> { + context: LayoutContext<'a>, driver: TraversalDriver, } -impl RecalcStyleAndConstructFlows { - pub fn layout_context(&self) -> &LayoutContext { +impl<'a> RecalcStyleAndConstructFlows<'a> { + pub fn layout_context(&self) -> &LayoutContext<'a> { &self.context } } -impl RecalcStyleAndConstructFlows { +impl<'a> RecalcStyleAndConstructFlows<'a> { /// Creates a traversal context, taking ownership of the shared layout context. - pub fn new(context: LayoutContext, driver: TraversalDriver) -> Self { + pub fn new(context: LayoutContext<'a>, driver: TraversalDriver) -> Self { RecalcStyleAndConstructFlows { context: context, driver: driver, @@ -44,13 +44,13 @@ impl RecalcStyleAndConstructFlows { /// Consumes this traversal context, returning ownership of the shared layout /// context to the caller. - pub fn destroy(self) -> LayoutContext { + pub fn destroy(self) -> LayoutContext<'a> { self.context } } #[allow(unsafe_code)] -impl DomTraversal for RecalcStyleAndConstructFlows +impl<'a, E> DomTraversal for RecalcStyleAndConstructFlows<'a> where E: TElement, E::ConcreteNode: LayoutNode, { @@ -152,7 +152,7 @@ fn construct_flows_at(context: &LayoutContext, /// The bubble-inline-sizes traversal, the first part of layout computation. This computes /// preferred and intrinsic inline-sizes and bubbles them up the tree. pub struct BubbleISizes<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PostorderFlowTraversal for BubbleISizes<'a> { @@ -171,7 +171,7 @@ impl<'a> PostorderFlowTraversal for BubbleISizes<'a> { /// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`. #[derive(Copy, Clone)] pub struct AssignISizes<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PreorderFlowTraversal for AssignISizes<'a> { @@ -191,7 +191,7 @@ impl<'a> PreorderFlowTraversal for AssignISizes<'a> { /// positions. In Gecko this corresponds to `Reflow`. #[derive(Copy, Clone)] pub struct AssignBSizes<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PostorderFlowTraversal for AssignBSizes<'a> { @@ -220,7 +220,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizes<'a> { #[derive(Copy, Clone)] pub struct ComputeAbsolutePositions<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> { diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 566d6c7ca33..32708911484 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -114,8 +114,9 @@ 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}; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ReadGuards}; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; use style::stylist::Stylist; use style::thread_state; @@ -215,7 +216,7 @@ pub struct LayoutThread { WebRenderImageInfo, BuildHasherDefault>>>, - // Webrender interface. + /// Webrender interface. webrender_api: webrender_traits::RenderApi, /// The timer object to control the timing of the animations. This should @@ -498,16 +499,18 @@ impl LayoutThread { } // Create a layout context for use in building display lists, hit testing, &c. - fn build_layout_context(&self, - rw_data: &LayoutThreadData, - request_images: bool) - -> LayoutContext { + fn build_layout_context<'a>(&self, + guards: ReadGuards<'a>, + rw_data: &LayoutThreadData, + request_images: bool) + -> LayoutContext<'a> { let thread_local_style_context_creation_data = ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone()); LayoutContext { style_context: SharedStyleContext { stylist: rw_data.stylist.clone(), + guards: guards, running_animations: self.running_animations.clone(), expired_animations: self.expired_animations.clone(), error_reporter: Box::new(self.error_reporter.clone()), @@ -941,7 +944,6 @@ impl LayoutThread { possibly_locked_rw_data: &mut RwData<'a, 'b>) { let document = unsafe { ServoLayoutNode::new(&data.document) }; let document = document.as_document().unwrap(); - let style_guard = document.style_shared_lock().read(); self.quirks_mode = Some(document.quirks_mode()); // FIXME(pcwalton): Combine `ReflowGoal` and `ReflowQueryType`. Then remove this assert. @@ -1017,9 +1019,11 @@ impl LayoutThread { 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 device = Device::new(MediaType::Screen, initial_viewport); Arc::get_mut(&mut rw_data.stylist).unwrap() - .set_device(device, &style_guard, &data.document_stylesheets); + .set_device(device, &author_guard, &data.document_stylesheets); self.viewport_size = rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| { @@ -1063,10 +1067,16 @@ impl LayoutThread { } // If the entire flow tree is invalid, then it will be reflowed anyhow. + let ua_stylesheets = &*UA_STYLESHEETS; + let ua_or_user_guard = ua_stylesheets.shared_lock.read(); + let guards = ReadGuards { + author: &author_guard, + ua_or_user: &ua_or_user_guard, + }; let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update( &data.document_stylesheets, - &style_guard, - Some(&*UA_STYLESHEETS), + &guards, + Some(ua_stylesheets), data.stylesheets_changed); let needs_reflow = viewport_size_changed && !needs_dirtying; if needs_dirtying { @@ -1113,7 +1123,7 @@ impl LayoutThread { } // Create a layout context for use throughout the following passes. - let mut layout_context = self.build_layout_context(&*rw_data, true); + let mut layout_context = self.build_layout_context(guards.clone(), &*rw_data, true); // NB: Type inference falls apart here for some reason, so we need to be very verbose. :-( let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() { @@ -1172,7 +1182,7 @@ impl LayoutThread { } if opts::get().dump_rule_tree { - layout_context.style_context.stylist.rule_tree.dump_stdout(); + layout_context.style_context.stylist.rule_tree.dump_stdout(&guards); } // GC the rule tree if some heuristics are met. @@ -1341,7 +1351,13 @@ impl LayoutThread { page_clip_rect: max_rect(), }; - let mut layout_context = self.build_layout_context(&*rw_data, false); + let author_guard = AUTHOR_SHARED_LOCK.read(); + let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read(); + let guards = ReadGuards { + 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. diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 387709d7332..7cad9f98523 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -550,7 +550,7 @@ unsafe impl JSTraceable for StyleLocked { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index 2423861e446..fed2b947f90 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; -use style::shared_lock::ToCssWithGuard; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::StyleRule; #[dom_struct] pub struct CSSStyleRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - stylerule: Arc>, + stylerule: Arc>, style_decl: MutNullableJS, } impl CSSStyleRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc>) -> CSSStyleRule { CSSStyleRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -37,7 +36,7 @@ impl CSSStyleRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - stylerule: Arc>) -> Root { + stylerule: Arc>) -> Root { reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule), window, CSSStyleRuleBinding::Wrap) @@ -52,7 +51,7 @@ impl SpecificCSSRule for CSSStyleRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.stylerule.read().to_css_string(&guard).into() + self.stylerule.read_with(&guard).to_css_string(&guard).into() } } @@ -60,11 +59,16 @@ impl CSSStyleRuleMethods for CSSStyleRule { // https://drafts.csswg.org/cssom/#dom-cssstylerule-style fn Style(&self) -> Root { self.style_decl.or_init(|| { - CSSStyleDeclaration::new(self.global().as_window(), - CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()), - self.stylerule.read().block.clone()), - None, - CSSModificationAccess::ReadWrite) + let guard = self.cssrule.shared_lock().read(); + CSSStyleDeclaration::new( + self.global().as_window(), + CSSStyleOwner::CSSRule( + JS::from_ref(self.upcast()), + self.stylerule.read_with(&guard).block.clone() + ), + None, + CSSModificationAccess::ReadWrite + ) }) } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 7a50fe5cf6c..b875c75d837 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -134,6 +134,7 @@ 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; @@ -2131,7 +2132,7 @@ impl Document { scripts: Default::default(), anchors: Default::default(), applets: Default::default(), - style_shared_lock: StyleSharedRwLock::new(), + style_shared_lock: AUTHOR_SHARED_LOCK.clone(), stylesheets: DOMRefCell::new(None), stylesheets_changed_since_reflow: Cell::new(false), stylesheet_list: MutNullableJS::new(None), diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 0e7cb160334..86e293d4a05 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -405,6 +405,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + let mut data = self.get_style_data().unwrap().borrow_mut(); let new_style = context.stylist.precomputed_values_for_pseudo( + &context.guards, &style_pseudo, Some(data.styles().primary.values()), CascadeFlags::empty()); @@ -421,6 +422,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + let new_style = context.stylist .lazily_compute_pseudo_element_style( + &context.guards, unsafe { &self.unsafe_get() }, &style_pseudo, data.styles().primary.values()); diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index a4a6e5ac823..c1c234c994a 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -40,7 +40,6 @@ nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true} num-integer = "0.1.32" num-traits = "0.1.32" ordered-float = "0.4" -owning_ref = "0.2.2" parking_lot = "0.3.3" pdqsort = "0.1.0" rayon = "0.6" diff --git a/components/style/context.rs b/components/style/context.rs index 44485915c2c..93dfde0932b 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -17,6 +17,7 @@ use parking_lot::RwLock; use selector_parser::PseudoElement; use selectors::matching::ElementSelectorFlags; use servo_config::opts; +use shared_lock::ReadGuards; use std::collections::HashMap; use std::env; use std::fmt; @@ -61,10 +62,13 @@ pub enum QuirksMode { /// /// There's exactly one of these during a given restyle traversal, and it's /// shared among the worker threads. -pub struct SharedStyleContext { +pub struct SharedStyleContext<'a> { /// The CSS selector stylist. pub stylist: Arc, + /// Guards for pre-acquired locks + pub guards: ReadGuards<'a>, + /// The animations that are currently running. pub running_animations: Arc>>>, @@ -85,7 +89,7 @@ pub struct SharedStyleContext { pub quirks_mode: QuirksMode, } -impl SharedStyleContext { +impl<'a> SharedStyleContext<'a> { /// Return a suitable viewport size in order to be used for viewport units. pub fn viewport_size(&self) -> Size2D { self.stylist.device.au_viewport_size() @@ -306,7 +310,7 @@ impl Drop for ThreadLocalStyleContext { /// shared style context, and a mutable reference to a local one. pub struct StyleContext<'a, E: TElement + 'a> { /// The shared style context reference. - pub shared: &'a SharedStyleContext, + pub shared: &'a SharedStyleContext<'a>, /// The thread-local style context (mutable) reference. pub thread_local: &'a mut ThreadLocalStyleContext, } diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index 58ec43cf387..d400c01c568 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -51,18 +51,7 @@ impl_arc_ffi!(ComputedValues => ServoComputedValues impl_arc_ffi!(RwLock => RawServoDeclarationBlock [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]); -/// FIXME: Remove once StyleRule is actually in Locked<_> -pub trait HackHackHack { - fn as_arc<'a>(ptr: &'a &RawServoStyleRule) -> &'a ::std::sync::Arc>; -} - -impl HackHackHack for Locked { - fn as_arc<'a>(ptr: &'a &RawServoStyleRule) -> &'a ::std::sync::Arc> { - RwLock::::as_arc(ptr) - } -} - -impl_arc_ffi!(RwLock => RawServoStyleRule +impl_arc_ffi!(Locked => RawServoStyleRule [Servo_StyleRule_AddRef, Servo_StyleRule_Release]); impl_arc_ffi!(Locked => RawServoImportRule diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index e0f7df023e2..ad6a1d1629c 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -13,7 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use media_queries::Device; use parking_lot::RwLock; use properties::ComputedValues; -use shared_lock::SharedRwLockReadGuard; +use shared_lock::{ReadGuards, SharedRwLockReadGuard}; use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; @@ -97,7 +97,7 @@ impl PerDocumentStyleDataImpl { pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) { if self.stylesheets_changed { let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); - stylist.update(&self.stylesheets, guard, None, true); + stylist.update(&self.stylesheets, &ReadGuards::same(guard), None, true); self.stylesheets_changed = false; } } diff --git a/components/style/gecko/traversal.rs b/components/style/gecko/traversal.rs index 3cb7f30cb1b..7a68f66c75f 100644 --- a/components/style/gecko/traversal.rs +++ b/components/style/gecko/traversal.rs @@ -13,14 +13,14 @@ use traversal::{DomTraversal, PerLevelTraversalData, TraversalDriver, recalc_sty /// This is the simple struct that Gecko uses to encapsulate a DOM traversal for /// styling. -pub struct RecalcStyleOnly { - shared: SharedStyleContext, +pub struct RecalcStyleOnly<'a> { + shared: SharedStyleContext<'a>, driver: TraversalDriver, } -impl RecalcStyleOnly { +impl<'a> RecalcStyleOnly<'a> { /// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`. - pub fn new(shared: SharedStyleContext, driver: TraversalDriver) -> Self { + pub fn new(shared: SharedStyleContext<'a>, driver: TraversalDriver) -> Self { RecalcStyleOnly { shared: shared, driver: driver, @@ -28,10 +28,11 @@ impl RecalcStyleOnly { } } -impl<'le> DomTraversal> for RecalcStyleOnly { +impl<'recalc, 'le> DomTraversal> for RecalcStyleOnly<'recalc> { type ThreadLocalContext = ThreadLocalStyleContext>; - fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData, + fn process_preorder(&self, + traversal_data: &mut PerLevelTraversalData, thread_local: &mut Self::ThreadLocalContext, node: GeckoNode<'le>) { diff --git a/components/style/lib.rs b/components/style/lib.rs index 58dcafe9ceb..eabb8d20c51 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -60,7 +60,6 @@ extern crate matches; extern crate num_integer; extern crate num_traits; extern crate ordered_float; -extern crate owning_ref; extern crate parking_lot; extern crate pdqsort; extern crate rayon; @@ -99,7 +98,6 @@ pub mod keyframes; pub mod logical_geometry; pub mod matching; pub mod media_queries; -pub mod owning_handle; pub mod parallel; pub mod parser; pub mod restyle_hints; diff --git a/components/style/matching.rs b/components/style/matching.rs index 296862cfe20..f58d429beb0 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -541,6 +541,7 @@ trait PrivateMatchMethods: TElement { let values = Arc::new(cascade(&shared_context.stylist.device, rule_node, + &shared_context.guards, inherited_values, layout_parent_style, Some(&mut cascade_info), @@ -784,6 +785,7 @@ pub trait MatchMethods : TElement { style_attribute, animation_rules, None, + &context.shared.guards, &mut applicable_declarations, &mut flags); let primary_rule_node = compute_rule_node(context, &mut applicable_declarations); @@ -809,6 +811,7 @@ pub trait MatchMethods : TElement { Some(context.thread_local.bloom_filter.filter()), None, pseudo_animation_rules, Some(&pseudo), + &context.shared.guards, &mut applicable_declarations, &mut flags); diff --git a/components/style/owning_handle.rs b/components/style/owning_handle.rs deleted file mode 100644 index 1294bf7e59f..00000000000 --- a/components/style/owning_handle.rs +++ /dev/null @@ -1,89 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -#![allow(unsafe_code)] -#![deny(missing_docs)] - -//! A handle that encapsulate a reference to a given data along with its owner. - -use owning_ref::StableAddress; -use std::ops::{Deref, DerefMut}; - -/// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows -/// consumers to pass around an owned object and a dependent reference, -/// `OwningHandle` contains an owned object and a dependent _object_. -/// -/// `OwningHandle` can encapsulate a `RefMut` along with its associated -/// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`. -/// However, the API is completely generic and there are no restrictions on -/// what types of owning and dependent objects may be used. -/// -/// `OwningHandle` is created by passing an owner object (which dereferences -/// to a stable address) along with a callback which receives a pointer to -/// that stable location. The callback may then dereference the pointer and -/// mint a dependent object, with the guarantee that the returned object will -/// not outlive the referent of the pointer. -/// -/// This does foist some unsafety onto the callback, which needs an `unsafe` -/// block to dereference the pointer. It would be almost good enough for -/// OwningHandle to pass a transmuted &'static reference to the callback -/// since the lifetime is infinite as far as the minted handle is concerned. -/// However, even an `Fn` callback can still allow the reference to escape -/// via a `StaticMutex` or similar, which technically violates the safety -/// contract. Some sort of language support in the lifetime system could -/// make this API a bit nicer. -pub struct OwningHandle - where O: StableAddress, - H: Deref, -{ - handle: H, - _owner: O, -} - -impl Deref for OwningHandle - where O: StableAddress, - H: Deref, -{ - type Target = H::Target; - fn deref(&self) -> &H::Target { - self.handle.deref() - } -} - -unsafe impl StableAddress for OwningHandle - where O: StableAddress, - H: StableAddress, -{} - -impl DerefMut for OwningHandle - where O: StableAddress, - H: DerefMut, -{ - fn deref_mut(&mut self) -> &mut H::Target { - self.handle.deref_mut() - } -} - -impl OwningHandle - where O: StableAddress, - H: Deref, -{ - /// Create a new OwningHandle. The provided callback will be invoked with - /// a pointer to the object owned by `o`, and the returned value is stored - /// as the object to which this `OwningHandle` will forward `Deref` and - /// `DerefMut`. - pub fn new(o: O, f: F) -> Self - where F: Fn(*const O::Target) -> H, - { - let h: H; - { - h = f(o.deref() as *const O::Target); - } - - OwningHandle { - handle: h, - _owner: o, - } - } -} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 7b81b9ae594..1ae30358efa 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -31,6 +31,7 @@ use parser::{Parse, ParserContext, ParserContextExtraData}; use properties::animated_properties::TransitionProperty; #[cfg(feature = "servo")] use servo_config::prefs::PREFS; use servo_url::ServoUrl; +use shared_lock::ReadGuards; use style_traits::ToCss; use stylesheets::Origin; #[cfg(feature = "servo")] use values::Either; @@ -1860,6 +1861,7 @@ bitflags! { /// pub fn cascade(device: &Device, rule_node: &StrongRuleNode, + guards: &ReadGuards, parent_style: Option<<&ComputedValues>, layout_parent_style: Option<<&ComputedValues>, cascade_info: Option<<&mut CascadeInfo>, @@ -1882,11 +1884,12 @@ pub fn cascade(device: &Device, // Hold locks until after the apply_declarations() call returns. // Use filter_map because the root node has no style source. - let lock_guards = rule_node.self_and_ancestors().filter_map(|node| { - node.style_source().map(|source| (source.read(), node.importance())) + let declaration_blocks = rule_node.self_and_ancestors().filter_map(|node| { + let guard = node.cascade_level().guard(guards); + node.style_source().map(|source| (source.read(guard), node.importance())) }).collect::>(); let iter_declarations = || { - lock_guards.iter().flat_map(|&(ref source, source_importance)| { + declaration_blocks.iter().flat_map(|&(ref source, source_importance)| { source.declarations().iter() // Yield declarations later in source order (with more precedence) first. .rev() diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 9a725a19286..c1d4b27edf5 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -10,9 +10,9 @@ use arc_ptr_eq; #[cfg(feature = "servo")] use heapsize::HeapSizeOf; -use owning_handle::OwningHandle; use parking_lot::{RwLock, RwLockReadGuard}; use properties::{Importance, PropertyDeclarationBlock}; +use shared_lock::{Locked, ReadGuards, SharedRwLockReadGuard}; use std::io::{self, Write}; use std::ptr; use std::sync::Arc; @@ -52,35 +52,11 @@ pub struct RuleTree { #[derive(Debug, Clone)] pub enum StyleSource { /// A style rule stable pointer. - Style(Arc>), + Style(Arc>), /// A declaration block stable pointer. Declarations(Arc>), } -type StyleSourceGuardHandle<'a> = - OwningHandle< - RwLockReadGuard<'a, StyleRule>, - RwLockReadGuard<'a, PropertyDeclarationBlock>>; - -/// A guard for a given style source. -pub enum StyleSourceGuard<'a> { - /// A guard for a style rule. - Style(StyleSourceGuardHandle<'a>), - /// A guard for a declaration block. - Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>), -} - -impl<'a> ::std::ops::Deref for StyleSourceGuard<'a> { - type Target = PropertyDeclarationBlock; - - fn deref(&self) -> &Self::Target { - match *self { - StyleSourceGuard::Declarations(ref block) => &*block, - StyleSourceGuard::Style(ref handle) => &*handle, - } - } -} - impl StyleSource { #[inline] fn ptr_equals(&self, other: &Self) -> bool { @@ -92,28 +68,27 @@ impl StyleSource { } } - fn dump(&self, writer: &mut W) { + fn dump(&self, guard: &SharedRwLockReadGuard, writer: &mut W) { use self::StyleSource::*; if let Style(ref rule) = *self { - let _ = write!(writer, "{:?}", rule.read().selectors); + let rule = rule.read_with(guard); + let _ = write!(writer, "{:?}", rule.selectors); } - let _ = write!(writer, " -> {:?}", self.read().declarations()); + let _ = write!(writer, " -> {:?}", self.read(guard).declarations()); } /// Read the style source guard, and obtain thus read access to the /// underlying property declaration block. #[inline] - pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> { - use self::StyleSource::*; - match *self { - Style(ref rule) => { - let owning_ref = OwningHandle::new(rule.read(), |r| unsafe { &*r }.block.read()); - StyleSourceGuard::Style(owning_ref) - } - Declarations(ref block) => StyleSourceGuard::Declarations(block.read()), - } + pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) + -> RwLockReadGuard<'a, PropertyDeclarationBlock> { + let block = match *self { + StyleSource::Style(ref rule) => &rule.read_with(guard).block, + StyleSource::Declarations(ref block) => block, + }; + block.read() } } @@ -137,15 +112,15 @@ impl RuleTree { self.root.clone() } - fn dump(&self, writer: &mut W) { + fn dump(&self, guards: &ReadGuards, writer: &mut W) { let _ = writeln!(writer, " + RuleTree"); - self.root.get().dump(writer, 0); + self.root.get().dump(guards, writer, 0); } /// Dump the rule tree to stdout. - pub fn dump_stdout(&self) { + pub fn dump_stdout(&self, guards: &ReadGuards) { let mut stdout = io::stdout(); - self.dump(&mut stdout); + self.dump(guards, &mut stdout); } /// Insert the given rules, that must be in proper order by specifity, and @@ -307,6 +282,17 @@ pub enum CascadeLevel { } impl CascadeLevel { + /// Select a lock guard for this level + pub fn guard<'a>(&self, guards: &'a ReadGuards<'a>) -> &'a SharedRwLockReadGuard<'a> { + match *self { + CascadeLevel::UANormal | + CascadeLevel::UserNormal | + CascadeLevel::UserImportant | + CascadeLevel::UAImportant => guards.ua_or_user, + _ => guards.author, + } + } + /// Returns whether this cascade level is unique per element, in which case /// we can replace the path in the cascade without fear. pub fn is_unique_per_element(&self) -> bool { @@ -450,7 +436,7 @@ impl RuleNode { } } - fn dump(&self, writer: &mut W, indent: usize) { + fn dump(&self, guards: &ReadGuards, writer: &mut W, indent: usize) { const INDENT_INCREMENT: usize = 4; for _ in 0..indent { @@ -467,7 +453,7 @@ impl RuleNode { match self.source { Some(ref source) => { - source.dump(writer); + source.dump(self.level.guard(guards), writer); } None => { if indent != 0 { @@ -479,7 +465,7 @@ impl RuleNode { let _ = write!(writer, "\n"); for child in self.iter_children() { - child.get().dump(writer, indent + INDENT_INCREMENT); + child.get().dump(guards, writer, indent + INDENT_INCREMENT); } } @@ -627,6 +613,11 @@ impl StrongRuleNode { self.get().source.as_ref() } + /// The cascade level for this node + pub fn cascade_level(&self) -> CascadeLevel { + self.get().level + } + /// Get the importance that this rule node represents. pub fn importance(&self) -> Importance { self.get().level.importance() diff --git a/components/style/servo/mod.rs b/components/style/servo/mod.rs index ad741616eeb..ff6890658d3 100644 --- a/components/style/servo/mod.rs +++ b/components/style/servo/mod.rs @@ -9,3 +9,13 @@ 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(); +} diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs index d4d66b8fc5d..c92ab9efccf 100644 --- a/components/style/shared_lock.rs +++ b/components/style/shared_lock.rs @@ -177,3 +177,23 @@ pub trait ToCssWithGuard { s } } + +/// Guards for a document +#[derive(Clone)] +pub struct ReadGuards<'a> { + /// For author-origin stylesheets + pub author: &'a SharedRwLockReadGuard<'a>, + + /// For user-agent-origin and user-origin stylesheets + pub ua_or_user: &'a SharedRwLockReadGuard<'a>, +} + +impl<'a> ReadGuards<'a> { + /// Same guard for all origins + pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self { + ReadGuards { + author: guard, + ua_or_user: guard, + } + } +} diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index d132c64bbb9..96c553c4a49 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -215,7 +215,7 @@ pub enum CssRule { Namespace(Arc>), Import(Arc>), - Style(Arc>), + Style(Arc>), Media(Arc>), FontFace(Arc>), Viewport(Arc>), @@ -380,7 +380,7 @@ impl ToCssWithGuard for CssRule { match *self { CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest), - CssRule::Style(ref lock) => lock.read().to_css(guard, dest), + CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest), @@ -736,18 +736,6 @@ rule_filter! { effective_supports_rules(Supports => SupportsRule), } -/// FIXME: Remove once StyleRule is actually in Locked<_> -pub trait RwLockStyleRulePretendLockedStyleRule { - /// Pretend we’re Locked<_> - fn read_with(&self, guard: &SharedRwLockReadGuard) -> ::parking_lot::RwLockReadGuard; -} - -impl RwLockStyleRulePretendLockedStyleRule for RwLock { - fn read_with(&self, _: &SharedRwLockReadGuard) -> ::parking_lot::RwLockReadGuard { - self.read() - } -} - /// The stylesheet loader is the abstraction used to trigger network requests /// for `@import` rules. pub trait StylesheetLoader { @@ -1030,7 +1018,7 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { fn parse_block(&mut self, prelude: SelectorList, input: &mut Parser) -> Result { - Ok(CssRule::Style(Arc::new(RwLock::new(StyleRule { + Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule { selectors: prelude, block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input))) })))) diff --git a/components/style/stylist.rs b/components/style/stylist.rs index a110e4f7abb..2166e81946a 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -28,7 +28,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use selectors::parser::SelectorMethods; -use shared_lock::SharedRwLockReadGuard; +use shared_lock::{Locked, SharedRwLockReadGuard, ReadGuards}; use sink::Push; use smallvec::VecLike; use std::borrow::Borrow; @@ -159,7 +159,7 @@ impl Stylist { /// device is dirty, which means we need to re-evaluate media queries. pub fn update(&mut self, doc_stylesheets: &[Arc], - doc_guard: &SharedRwLockReadGuard, + guards: &ReadGuards, ua_stylesheets: Option<&UserAgentStylesheets>, stylesheets_changed: bool) -> bool { if !(self.is_device_dirty || stylesheets_changed) { @@ -168,7 +168,7 @@ impl Stylist { let cascaded_rule = ViewportRule { declarations: viewport::Cascade::from_stylesheets( - doc_stylesheets, doc_guard, &self.device + doc_stylesheets, guards.author, &self.device ).finish(), }; @@ -196,18 +196,17 @@ impl Stylist { self.non_common_style_affecting_attributes_selectors.clear(); if let Some(ua_stylesheets) = ua_stylesheets { - let ua_guard = ua_stylesheets.shared_lock.read(); for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets { - self.add_stylesheet(&stylesheet, &ua_guard); + self.add_stylesheet(&stylesheet, guards.ua_or_user); } if self.quirks_mode { - self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, &ua_guard); + self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user); } } for ref stylesheet in doc_stylesheets.iter() { - self.add_stylesheet(stylesheet, doc_guard); + self.add_stylesheet(stylesheet, guards.author); } debug!("Stylist stats:"); @@ -221,8 +220,9 @@ impl Stylist { SelectorImpl::each_precomputed_pseudo_element(|pseudo| { if let Some(map) = self.pseudos_map.remove(&pseudo) { let declarations = - map.user_agent.get_universal_rules(CascadeLevel::UANormal, - CascadeLevel::UAImportant); + map.user_agent.get_universal_rules( + guards.ua_or_user, CascadeLevel::UANormal, CascadeLevel::UAImportant + ); self.precomputed_pseudo_element_decls.insert(pseudo, declarations); } }); @@ -241,9 +241,9 @@ impl Stylist { stylesheet.effective_rules(&device, guard, |rule| { match *rule { - CssRule::Style(ref style_rule) => { - let guard = style_rule.read(); - for selector in &guard.selectors.0 { + CssRule::Style(ref locked) => { + let style_rule = locked.read_with(&guard); + for selector in &style_rule.selectors.0 { let map = if let Some(ref pseudo) = selector.pseudo_element { self.pseudos_map .entry(pseudo.clone()) @@ -255,14 +255,14 @@ impl Stylist { map.insert(Rule { selector: selector.complex_selector.clone(), - style_rule: style_rule.clone(), + style_rule: locked.clone(), specificity: selector.specificity, source_order: self.rules_source_order, }); } self.rules_source_order += 1; - for selector in &guard.selectors.0 { + for selector in &style_rule.selectors.0 { self.state_deps.note_selector(&selector.complex_selector); if selector.affects_siblings() { self.sibling_affecting_selectors.push(selector.clone()); @@ -300,6 +300,7 @@ impl Stylist { /// values. The flow constructor uses this flag when constructing anonymous /// flows. pub fn precomputed_values_for_pseudo(&self, + guards: &ReadGuards, pseudo: &PseudoElement, parent: Option<&Arc>, cascade_flags: CascadeFlags) @@ -333,6 +334,7 @@ impl Stylist { let computed = properties::cascade(&self.device, &rule_node, + guards, parent.map(|p| &**p), parent.map(|p| &**p), None, @@ -344,6 +346,7 @@ impl Stylist { /// Returns the style for an anonymous box of the given type. #[cfg(feature = "servo")] pub fn style_for_anonymous_box(&self, + guards: &ReadGuards, pseudo: &PseudoElement, parent_style: &Arc) -> Arc { @@ -368,7 +371,7 @@ impl Stylist { if inherit_all { cascade_flags.insert(INHERIT_ALL); } - self.precomputed_values_for_pseudo(&pseudo, Some(parent_style), cascade_flags) + self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags) .values.unwrap() } @@ -380,6 +383,7 @@ impl Stylist { /// Check the documentation on lazy pseudo-elements in /// docs/components/style.md pub fn lazily_compute_pseudo_element_style(&self, + guards: &ReadGuards, element: &E, pseudo: &PseudoElement, parent: &Arc) @@ -401,6 +405,7 @@ impl Stylist { None, AnimationRules(None, None), Some(pseudo), + guards, &mut declarations, &mut flags); @@ -415,6 +420,7 @@ impl Stylist { let computed = properties::cascade(&self.device, &rule_node, + guards, Some(&**parent), Some(&**parent), None, @@ -539,6 +545,7 @@ impl Stylist { style_attribute: Option<&Arc>>, animation_rules: AnimationRules, pseudo_element: Option<&PseudoElement>, + guards: &ReadGuards, applicable_declarations: &mut V, flags: &mut ElementSelectorFlags) -> StyleRelations where E: TElement + @@ -564,6 +571,7 @@ impl Stylist { // Step 1: Normal user-agent rules. map.user_agent.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -588,6 +596,7 @@ impl Stylist { // Step 3: User and author normal rules. map.user.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -595,6 +604,7 @@ impl Stylist { debug!("user normal: {:?}", relations); map.author.get_all_matching_rules(element, parent_bf, + guards.author, applicable_declarations, &mut relations, flags, @@ -629,6 +639,7 @@ impl Stylist { // Step 6: Author-supplied `!important` rules. map.author.get_all_matching_rules(element, parent_bf, + guards.author, applicable_declarations, &mut relations, flags, @@ -652,6 +663,7 @@ impl Stylist { // Step 8: User `!important` rules. map.user.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -665,6 +677,7 @@ impl Stylist { // Step 9: UA `!important` rules. map.user_agent.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -903,6 +916,7 @@ impl SelectorMap { pub fn get_all_matching_rules(&self, element: &E, parent_bf: Option<&BloomFilter>, + guard: &SharedRwLockReadGuard, matching_rules_list: &mut V, relations: &mut StyleRelations, flags: &mut ElementSelectorFlags, @@ -921,6 +935,7 @@ impl SelectorMap { parent_bf, &self.id_hash, &id, + guard, matching_rules_list, relations, flags, @@ -932,6 +947,7 @@ impl SelectorMap { parent_bf, &self.class_hash, class, + guard, matching_rules_list, relations, flags, @@ -947,6 +963,7 @@ impl SelectorMap { parent_bf, local_name_hash, element.get_local_name(), + guard, matching_rules_list, relations, flags, @@ -955,6 +972,7 @@ impl SelectorMap { SelectorMap::get_matching_rules(element, parent_bf, &self.other_rules, + guard, matching_rules_list, relations, flags, @@ -968,6 +986,7 @@ impl SelectorMap { /// Append to `rule_list` all universal Rules (rules with selector `*|*`) in /// `self` sorted by specificity and source order. pub fn get_universal_rules(&self, + guard: &SharedRwLockReadGuard, cascade_level: CascadeLevel, important_cascade_level: CascadeLevel) -> Vec { @@ -985,8 +1004,8 @@ impl SelectorMap { for rule in self.other_rules.iter() { if rule.selector.compound_selector.is_empty() && rule.selector.next.is_none() { - let guard = rule.style_rule.read(); - let block = guard.block.read(); + let style_rule = rule.style_rule.read_with(guard); + let block = style_rule.block.read(); if block.any_normal() { matching_rules_list.push( rule.to_applicable_declaration_block(cascade_level)); @@ -1014,6 +1033,7 @@ impl SelectorMap { parent_bf: Option<&BloomFilter>, hash: &FnvHashMap>, key: &BorrowedStr, + guard: &SharedRwLockReadGuard, matching_rules: &mut Vector, relations: &mut StyleRelations, flags: &mut ElementSelectorFlags, @@ -1027,6 +1047,7 @@ impl SelectorMap { SelectorMap::get_matching_rules(element, parent_bf, rules, + guard, matching_rules, relations, flags, @@ -1038,6 +1059,7 @@ impl SelectorMap { fn get_matching_rules(element: &E, parent_bf: Option<&BloomFilter>, rules: &[Rule], + guard: &SharedRwLockReadGuard, matching_rules: &mut V, relations: &mut StyleRelations, flags: &mut ElementSelectorFlags, @@ -1046,8 +1068,8 @@ impl SelectorMap { V: VecLike { for rule in rules.iter() { - let guard = rule.style_rule.read(); - let block = guard.block.read(); + let style_rule = rule.style_rule.read_with(guard); + let block = style_rule.block.read(); let any_declaration_for_importance = if cascade_level.is_important() { block.any_important() } else { @@ -1145,7 +1167,7 @@ pub struct Rule { pub selector: Arc>, /// The actual style rule. #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] - pub style_rule: Arc>, + pub style_rule: Arc>, /// The source order this style rule appears in. pub source_order: usize, /// The specificity of the rule this selector represents. diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 5c413b9c6bb..1b7c8042bae 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -312,7 +312,8 @@ pub trait DomTraversal : Sync { } /// Helper for the function below. -fn resolve_style_internal(context: &mut StyleContext, element: E, ensure_data: &F) +fn resolve_style_internal(context: &mut StyleContext, + element: E, ensure_data: &F) -> Option where E: TElement, F: Fn(E), diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 24380439062..bbe8bc6907d 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -23,7 +23,6 @@ use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInf use style::data::{ElementData, ElementStyles, RestyleData}; use style::dom::{ShowSubtreeData, TElement, TNode}; use style::error_reporting::StdoutErrorReporter; -use style::gecko::arc_types::HackHackHack; use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl}; use style::gecko::restyle_damage::GeckoRestyleDamage; use style::gecko::selector_parser::{SelectorImpl, PseudoElement}; @@ -77,12 +76,11 @@ use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::selector_parser::PseudoElementCascadeType; use style::sequential; -use style::shared_lock::{SharedRwLock, ToCssWithGuard, Locked}; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ReadGuards, ToCssWithGuard, Locked}; use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; -use style::stylesheets::RwLockStyleRulePretendLockedStyleRule; use style::supports::parse_condition_or_declaration; use style::thread_state; use style::timer::Timer; @@ -167,12 +165,14 @@ pub extern "C" fn Servo_Shutdown() { gecko_properties::shutdown(); } -fn create_shared_context(per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext { +fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard, + per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext<'a> { let local_context_data = ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone()); SharedStyleContext { stylist: per_doc_data.stylist.clone(), + guards: ReadGuards::same(guard), running_animations: per_doc_data.running_animations.clone(), expired_animations: per_doc_data.expired_animations.clone(), // FIXME(emilio): Stop boxing here. @@ -205,8 +205,9 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed, debug!("Traversing subtree:"); debug!("{:?}", ShowSubtreeData(element.as_node())); - let shared_style_context = create_shared_context(&per_doc_data); let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let shared_style_context = create_shared_context(&guard, &per_doc_data); let traversal_driver = if global_style_data.style_thread_pool.is_none() { TraversalDriver::Sequential @@ -625,22 +626,28 @@ impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule), #[no_mangle] pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong { - let rule = RwLock::::as_arc(&rule); - rule.read().block.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).block.clone().into_strong() } #[no_mangle] pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed, declarations: RawServoDeclarationBlockBorrowed) { - let rule = RwLock::::as_arc(&rule); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let rule = Locked::::as_arc(&rule); let declarations = RwLock::::as_arc(&declarations); - rule.write().block = declarations.clone(); + rule.write_with(&mut guard).block = declarations.clone(); } #[no_mangle] pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) { - let rule = RwLock::::as_arc(&rule); - rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } #[no_mangle] @@ -681,6 +688,9 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: skip_display_fixup: bool, raw_data: RawServoStyleSetBorrowed) -> ServoComputedValuesStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let guards = ReadGuards::same(&guard); let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let atom = Atom::from(pseudo_tag); let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true); @@ -691,7 +701,7 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: if skip_display_fixup { cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP); } - data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent, + data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, maybe_parent, cascade_flags) .values.unwrap() .into_strong() @@ -717,14 +727,16 @@ pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed, }; } - match get_pseudo_style(element, pseudo_tag, data.styles(), doc_data) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + match get_pseudo_style(&guard, element, pseudo_tag, data.styles(), doc_data) { Some(values) => values.into_strong(), None if !is_probe => data.styles().primary.values().clone().into_strong(), None => Strong::null(), } } -fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom, +fn get_pseudo_style(guard: &SharedRwLockReadGuard, element: GeckoElement, pseudo_tag: *mut nsIAtom, styles: &ElementStyles, doc_data: &PerDocumentStyleData) -> Option> { @@ -735,7 +747,9 @@ fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom, PseudoElementCascadeType::Lazy => { let d = doc_data.borrow_mut(); let base = styles.primary.values(); - d.stylist.lazily_compute_pseudo_element_style(&element, + let guards = ReadGuards::same(guard); + d.stylist.lazily_compute_pseudo_element_style(&guards, + &element, &pseudo, base) .map(|s| s.values().clone()) @@ -1463,11 +1477,13 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed, raw_data: RawServoStyleSetBorrowed) -> ServoComputedValuesStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let element = GeckoElement(element); let doc_data = PerDocumentStyleData::from_ffi(raw_data); let finish = |styles: &ElementStyles| -> Arc { let maybe_pseudo = if !pseudo_tag.is_null() { - get_pseudo_style(element, pseudo_tag, styles, doc_data) + get_pseudo_style(&guard, element, pseudo_tag, styles, doc_data) } else { None }; @@ -1483,7 +1499,7 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed, } // We don't have the style ready. Go ahead and compute it as necessary. - let shared = create_shared_context(&mut doc_data.borrow_mut()); + let shared = create_shared_context(&guard, &mut doc_data.borrow_mut()); let mut tlc = ThreadLocalStyleContext::new(&shared); let mut context = StyleContext { shared: &shared, diff --git a/tests/unit/style/Cargo.toml b/tests/unit/style/Cargo.toml index 98838676937..7939e617342 100644 --- a/tests/unit/style/Cargo.toml +++ b/tests/unit/style/Cargo.toml @@ -17,7 +17,6 @@ app_units = "0.4" cssparser = "0.12" euclid = "0.11" html5ever-atoms = "0.2" -owning_ref = "0.2.2" parking_lot = "0.3" rayon = "0.6" rustc-serialize = "0.3" diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index 9d7cdcae651..887de470ffa 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -9,7 +9,6 @@ extern crate app_units; extern crate cssparser; extern crate euclid; #[macro_use] extern crate html5ever_atoms; -extern crate owning_ref; extern crate parking_lot; extern crate rayon; extern crate rustc_serialize; @@ -26,7 +25,6 @@ mod attr; mod keyframes; mod logical_geometry; mod media_queries; -mod owning_handle; mod parsing; mod properties; mod rule_tree; diff --git a/tests/unit/style/owning_handle.rs b/tests/unit/style/owning_handle.rs deleted file mode 100644 index cf792ef9605..00000000000 --- a/tests/unit/style/owning_handle.rs +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -use owning_ref::RcRef; -use std::cell::RefCell; -use std::rc::Rc; -use std::sync::{Arc, RwLock}; -use style::owning_handle::OwningHandle; - -#[test] -fn owning_handle() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::new(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); -} - -#[test] -fn nested() { - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = OwningHandle::new(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); -} diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 99ec3676236..2bcb9b58a77 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -81,7 +81,7 @@ fn test_parse_stylesheet() { prefix: None, url: NsAtom::from("http://www.w3.org/1999/xhtml") }))), - CssRule::Style(Arc::new(RwLock::new(StyleRule { + CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { selectors: SelectorList(vec![ Selector { complex_selector: Arc::new(ComplexSelector { @@ -117,7 +117,7 @@ fn test_parse_stylesheet() { Importance::Important), ]))), }))), - CssRule::Style(Arc::new(RwLock::new(StyleRule { + CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { selectors: SelectorList(vec![ Selector { complex_selector: Arc::new(ComplexSelector { @@ -159,7 +159,7 @@ fn test_parse_stylesheet() { Importance::Normal), ]))), }))), - CssRule::Style(Arc::new(RwLock::new(StyleRule { + CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { selectors: SelectorList(vec![ Selector { complex_selector: Arc::new(ComplexSelector { diff --git a/tests/unit/style/stylist.rs b/tests/unit/style/stylist.rs index ab04f2e5dd5..34a7feff965 100644 --- a/tests/unit/style/stylist.rs +++ b/tests/unit/style/stylist.rs @@ -11,17 +11,19 @@ use style::properties::{PropertyDeclarationBlock, PropertyDeclaration}; use style::properties::{longhands, Importance}; use style::rule_tree::CascadeLevel; use style::selector_parser::SelectorParser; +use style::shared_lock::SharedRwLock; use style::stylesheets::StyleRule; use style::stylist::{Rule, SelectorMap}; use style::thread_state; /// Helper method to get some Rules from selector strings. /// Each sublist of the result contains the Rules for one StyleRule. -fn get_mock_rules(css_selectors: &[&str]) -> Vec> { - css_selectors.iter().enumerate().map(|(i, selectors)| { +fn get_mock_rules(css_selectors: &[&str]) -> (Vec>, SharedRwLock) { + let shared_lock = SharedRwLock::new(); + (css_selectors.iter().enumerate().map(|(i, selectors)| { let selectors = SelectorParser::parse_author_origin_no_namespace(selectors).unwrap(); - let rule = Arc::new(RwLock::new(StyleRule { + let locked = Arc::new(shared_lock.wrap(StyleRule { selectors: selectors, block: Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( PropertyDeclaration::Display( @@ -30,21 +32,22 @@ fn get_mock_rules(css_selectors: &[&str]) -> Vec> { ))), })); - let guard = rule.read(); - guard.selectors.0.iter().map(|s| { + let guard = shared_lock.read(); + let rule = locked.read_with(&guard); + rule.selectors.0.iter().map(|s| { Rule { selector: s.complex_selector.clone(), - style_rule: rule.clone(), + style_rule: locked.clone(), specificity: s.specificity, source_order: i, } }).collect() - }).collect() + }).collect(), shared_lock) } -fn get_mock_map(selectors: &[&str]) -> SelectorMap { +fn get_mock_map(selectors: &[&str]) -> (SelectorMap, SharedRwLock) { let mut map = SelectorMap::new(); - let selector_rules = get_mock_rules(selectors); + let (selector_rules, shared_lock) = get_mock_rules(selectors); for rules in selector_rules.into_iter() { for rule in rules.into_iter() { @@ -52,12 +55,12 @@ fn get_mock_map(selectors: &[&str]) -> SelectorMap { } } - map + (map, shared_lock) } #[test] fn test_rule_ordering_same_specificity() { - let rules_list = get_mock_rules(&["a.intro", "img.sidebar"]); + let (rules_list, _) = get_mock_rules(&["a.intro", "img.sidebar"]); let a = &rules_list[0][0]; let b = &rules_list[1][0]; assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)), @@ -67,21 +70,21 @@ fn test_rule_ordering_same_specificity() { #[test] fn test_get_id_name() { - let rules_list = get_mock_rules(&[".intro", "#top"]); + let (rules_list, _) = get_mock_rules(&[".intro", "#top"]); assert_eq!(SelectorMap::get_id_name(&rules_list[0][0]), None); assert_eq!(SelectorMap::get_id_name(&rules_list[1][0]), Some(Atom::from("top"))); } #[test] fn test_get_class_name() { - let rules_list = get_mock_rules(&[".intro.foo", "#top"]); + let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]); assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro"))); assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None); } #[test] fn test_get_local_name() { - let rules_list = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]); + let (rules_list, _) = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]); let check = |i: usize, names: Option<(&str, &str)>| { assert!(SelectorMap::get_local_name(&rules_list[i][0]) == names.map(|(name, lower_name)| LocalNameSelector { @@ -96,7 +99,7 @@ fn test_get_local_name() { #[test] fn test_insert() { - let rules_list = get_mock_rules(&[".intro.foo", "#top"]); + let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]); let mut selector_map = SelectorMap::new(); selector_map.insert(rules_list[1][0].clone()); assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order); @@ -108,10 +111,11 @@ fn test_insert() { #[test] fn test_get_universal_rules() { thread_state::initialize(thread_state::LAYOUT); - let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]); + let (map, shared_lock) = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]); - let decls = map.get_universal_rules(CascadeLevel::UserNormal, - CascadeLevel::UserImportant); + let guard = shared_lock.read(); + let decls = map.get_universal_rules( + &guard, CascadeLevel::UserNormal, CascadeLevel::UserImportant); assert_eq!(decls.len(), 1); } From 1bacd0eb1582f609ad9a9c9a8a33a737bf4bc6f3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 02:10:00 +0100 Subject: [PATCH 12/17] Move all PropertyDeclarationBlock from RwLock<_> to Locked<_> --- Cargo.lock | 3 +- components/script/dom/bindings/trace.rs | 2 +- components/script/dom/csskeyframerule.rs | 5 +- components/script/dom/cssstyledeclaration.rs | 32 ++- components/script/dom/element.rs | 37 +++- components/script/layout_wrapper.rs | 5 +- components/style/Cargo.toml | 3 +- components/style/animation.rs | 2 +- components/style/attr.rs | 4 +- components/style/dom.rs | 12 +- components/style/gecko/arc_types.rs | 2 +- components/style/gecko/global_style_data.rs | 50 +++++ components/style/gecko/mod.rs | 1 + components/style/gecko/wrapper.rs | 14 +- components/style/keyframes.rs | 37 ++-- components/style/lib.rs | 1 + components/style/matching.rs | 6 +- components/style/rule_tree/mod.rs | 17 +- components/style/stylesheets.rs | 11 +- components/style/stylist.rs | 13 +- ports/geckolib/Cargo.toml | 2 - ports/geckolib/glue.rs | 219 ++++++++++--------- ports/geckolib/lib.rs | 2 - ports/geckolib/stylesheet_loader.rs | 2 +- tests/unit/style/keyframes.rs | 17 +- tests/unit/style/rule_tree/bench.rs | 17 +- tests/unit/style/stylesheets.rs | 10 +- tests/unit/style/stylist.rs | 3 +- 28 files changed, 321 insertions(+), 208 deletions(-) create mode 100644 components/style/gecko/global_style_data.rs diff --git a/Cargo.lock b/Cargo.lock index 076924c397c..72065507be0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -928,9 +928,7 @@ dependencies = [ "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.18.0", "servo_url 0.0.1", "style 0.0.1", @@ -2756,6 +2754,7 @@ dependencies = [ "nsstring_vendor 0.1.0", "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 7cad9f98523..ee90766b1e2 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -562,7 +562,7 @@ unsafe impl JSTraceable for StyleLocked { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/csskeyframerule.rs b/components/script/dom/csskeyframerule.rs index 617546d6a76..d36e8988e04 100644 --- a/components/script/dom/csskeyframerule.rs +++ b/components/script/dom/csskeyframerule.rs @@ -14,8 +14,7 @@ use dom::window::Window; use dom_struct::dom_struct; use std::sync::Arc; use style::keyframes::Keyframe; -use style::shared_lock::Locked; -use style_traits::ToCss; +use style::shared_lock::{Locked, ToCssWithGuard}; #[dom_struct] pub struct CSSKeyframeRule { @@ -70,6 +69,6 @@ impl SpecificCSSRule for CSSKeyframeRule { fn get_css(&self) -> DOMString { let guard = self.cssrule.shared_lock().read(); - self.keyframerule.read_with(&guard).to_css_string().into() + self.keyframerule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 8af3b3975d2..d5d248f7880 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -11,10 +11,9 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::cssrule::CSSRule; use dom::element::Element; -use dom::node::{Node, window_from_node}; +use dom::node::{Node, window_from_node, document_from_node}; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use servo_url::ServoUrl; use std::ascii::AsciiExt; use std::sync::Arc; @@ -23,6 +22,7 @@ use style::parser::ParserContextExtraData; use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId}; use style::properties::{parse_one_declaration, parse_style_attribute}; use style::selector_parser::PseudoElement; +use style::shared_lock::Locked; use style_traits::ToCss; // http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface @@ -40,7 +40,7 @@ pub enum CSSStyleOwner { Element(JS), CSSRule(JS, #[ignore_heap_size_of = "Arc"] - Arc>), + Arc>), } impl CSSStyleOwner { @@ -55,10 +55,13 @@ impl CSSStyleOwner { let mut changed = true; match *self { CSSStyleOwner::Element(ref el) => { + let document = document_from_node(&**el); + let shared_lock = document.style_shared_lock(); let mut attr = el.style_attribute().borrow_mut().take(); let result = if attr.is_some() { let lock = attr.as_ref().unwrap(); - let mut pdb = lock.write(); + let mut guard = shared_lock.write(); + let mut pdb = lock.write_with(&mut guard); let result = f(&mut pdb, &mut changed); result } else { @@ -69,7 +72,7 @@ impl CSSStyleOwner { // exact conditions under it changes. changed = !pdb.declarations().is_empty(); if changed { - attr = Some(Arc::new(RwLock::new(pdb))); + attr = Some(Arc::new(shared_lock.wrap(pdb))); } result @@ -83,7 +86,8 @@ impl CSSStyleOwner { // // [1]: https://github.com/whatwg/html/issues/2306 if let Some(pdb) = attr { - let serialization = pdb.read().to_css_string(); + let guard = shared_lock.read(); + let serialization = pdb.read_with(&guard).to_css_string(); el.set_attribute(&local_name!("style"), AttrValue::Declaration(serialization, pdb)); @@ -96,7 +100,10 @@ impl CSSStyleOwner { result } CSSStyleOwner::CSSRule(ref rule, ref pdb) => { - let result = f(&mut *pdb.write(), &mut changed); + let result = { + let mut guard = rule.shared_lock().write(); + f(&mut *pdb.write_with(&mut guard), &mut changed) + }; if changed { rule.global().as_window().Document().invalidate_stylesheets(); } @@ -111,15 +118,20 @@ impl CSSStyleOwner { match *self { CSSStyleOwner::Element(ref el) => { match *el.style_attribute().borrow() { - Some(ref pdb) => f(&pdb.read()), + Some(ref pdb) => { + let document = document_from_node(&**el); + let guard = document.style_shared_lock().read(); + f(pdb.read_with(&guard)) + } None => { let pdb = PropertyDeclarationBlock::new(); f(&pdb) } } } - CSSStyleOwner::CSSRule(_, ref pdb) => { - f(&pdb.read()) + CSSStyleOwner::CSSRule(ref rule, ref pdb) => { + let guard = rule.shared_lock().read(); + f(pdb.read_with(&guard)) } } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 8e13716fa9d..3a73bbce97e 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -82,7 +82,6 @@ use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode}; use html5ever_atoms::{Prefix, LocalName, Namespace, QualName}; use js::jsapi::{HandleValue, JSAutoCompartment}; use net_traits::request::CorsSettings; -use parking_lot::RwLock; use ref_filter_map::ref_filter_map; use script_layout_interface::message::ReflowQueryType; use script_thread::Runnable; @@ -108,6 +107,7 @@ use style::properties::longhands::{self, background_image, border_spacing, font_ use style::restyle_hints::RESTYLE_SELF; use style::rule_tree::CascadeLevel; use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser}; +use style::shared_lock::{SharedRwLock, Locked}; use style::sink::Push; use style::stylist::ApplicableDeclarationBlock; use style::thread_state; @@ -129,7 +129,7 @@ pub struct Element { attrs: DOMRefCell>>, id_attribute: DOMRefCell>, #[ignore_heap_size_of = "Arc"] - style_attribute: DOMRefCell>>>, + style_attribute: DOMRefCell>>>, attr_list: MutNullableJS, class_list: MutNullableJS, state: Cell, @@ -352,7 +352,7 @@ pub trait LayoutElementHelpers { #[allow(unsafe_code)] unsafe fn html_element_in_html_document_for_layout(&self) -> bool; fn id_attribute(&self) -> *const Option; - fn style_attribute(&self) -> *const Option>>; + fn style_attribute(&self) -> *const Option>>; fn local_name(&self) -> &LocalName; fn namespace(&self) -> &Namespace; fn get_lang_for_layout(&self) -> String; @@ -384,14 +384,18 @@ impl LayoutElementHelpers for LayoutJS { where V: Push { #[inline] - fn from_declaration(declaration: PropertyDeclaration) -> ApplicableDeclarationBlock { + fn from_declaration(shared_lock: &SharedRwLock, declaration: PropertyDeclaration) + -> ApplicableDeclarationBlock { ApplicableDeclarationBlock::from_declarations( - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( declaration, Importance::Normal ))), CascadeLevel::PresHints) } + let document = self.upcast::().owner_doc_for_layout(); + let shared_lock = document.style_shared_lock(); + let bgcolor = if let Some(this) = self.downcast::() { this.get_background_color() } else if let Some(this) = self.downcast::() { @@ -408,6 +412,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(color) = bgcolor { hints.push(from_declaration( + shared_lock, PropertyDeclaration::BackgroundColor( CSSColor { parsed: Color::RGBA(color), authored: None }))); } @@ -420,6 +425,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(url) = background { hints.push(from_declaration( + shared_lock, PropertyDeclaration::BackgroundImage( background_image::SpecifiedValue(vec![ background_image::single_value::SpecifiedValue(Some( @@ -442,6 +448,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(color) = color { hints.push(from_declaration( + shared_lock, PropertyDeclaration::Color( longhands::color::SpecifiedValue(CSSColor { parsed: Color::RGBA(color), @@ -459,6 +466,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(font_family) = font_family { hints.push(from_declaration( + shared_lock, PropertyDeclaration::FontFamily( font_family::computed_value::T(vec![ font_family::computed_value::FontFamily::from_atom( @@ -469,6 +477,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(font_size) = font_size { hints.push(from_declaration( + shared_lock, PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into())))) } @@ -481,6 +490,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(cellspacing) = cellspacing { let width_value = specified::Length::from_px(cellspacing as f32); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderSpacing( Box::new(border_spacing::SpecifiedValue { horizontal: width_value.clone(), @@ -514,6 +524,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(size) = size { let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width( specified::LengthOrPercentageOrAuto::Length(value)))); } @@ -539,12 +550,14 @@ impl LayoutElementHelpers for LayoutJS { let width_value = specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width(width_value))); } LengthOrPercentageOrAuto::Length(length) => { let width_value = specified::LengthOrPercentageOrAuto::Length( specified::NoCalcLength::Absolute(length)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width(width_value))); } } @@ -564,12 +577,14 @@ impl LayoutElementHelpers for LayoutJS { let height_value = specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Height(height_value))); } LengthOrPercentageOrAuto::Length(length) => { let height_value = specified::LengthOrPercentageOrAuto::Length( specified::NoCalcLength::Absolute(length)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Height(height_value))); } } @@ -592,6 +607,7 @@ impl LayoutElementHelpers for LayoutJS { // https://html.spec.whatwg.org/multipage/#textarea-effective-width let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width(specified::LengthOrPercentageOrAuto::Length(value)))); } @@ -610,6 +626,7 @@ impl LayoutElementHelpers for LayoutJS { // https://html.spec.whatwg.org/multipage/#textarea-effective-height let value = specified::NoCalcLength::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Height(specified::LengthOrPercentageOrAuto::Length(value)))); } @@ -623,12 +640,16 @@ impl LayoutElementHelpers for LayoutJS { if let Some(border) = border { let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderTopWidth(Box::new(width_value.clone())))); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderLeftWidth(Box::new(width_value.clone())))); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderBottomWidth(Box::new(width_value.clone())))); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderRightWidth(Box::new(width_value)))); } } @@ -672,7 +693,7 @@ impl LayoutElementHelpers for LayoutJS { } #[allow(unsafe_code)] - fn style_attribute(&self) -> *const Option>> { + fn style_attribute(&self) -> *const Option>> { unsafe { (*self.unsafe_get()).style_attribute.borrow_for_layout() } @@ -835,7 +856,7 @@ impl Element { ns!() } - pub fn style_attribute(&self) -> &DOMRefCell>>> { + pub fn style_attribute(&self) -> &DOMRefCell>>> { &self.style_attribute } @@ -2170,7 +2191,7 @@ impl VirtualMethods for Element { block } else { let win = window_from_node(self); - Arc::new(RwLock::new(parse_style_attribute( + Arc::new(doc.style_shared_lock().wrap(parse_style_attribute( &attr.value(), &doc.base_url(), win.css_error_reporter(), diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 5a9a834667b..36aa7601d0b 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -44,7 +44,6 @@ use dom::text::Text; use gfx_traits::ByteIndex; use html5ever_atoms::{LocalName, Namespace}; use msg::constellation_msg::PipelineId; -use parking_lot::RwLock; use range::Range; use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; @@ -69,7 +68,7 @@ use style::dom::UnsafeNode; use style::element_state::*; use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; -use style::shared_lock::SharedRwLock as StyleSharedRwLock; +use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked}; use style::sink::Push; use style::str::is_whitespace; use style::stylist::ApplicableDeclarationBlock; @@ -377,7 +376,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { ServoLayoutNode::from_layout_js(self.element.upcast()) } - fn style_attribute(&self) -> Option<&Arc>> { + fn style_attribute(&self) -> Option<&Arc>> { unsafe { (*self.element.style_attribute()).as_ref() } diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index c1c234c994a..6532efc4e9d 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -13,7 +13,7 @@ path = "lib.rs" doctest = false [features] -gecko = ["nsstring_vendor", "rayon/unstable"] +gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus"] use_bindgen = ["bindgen", "regex"] servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive", "style_traits/servo", "servo_atoms", "html5ever-atoms", @@ -37,6 +37,7 @@ lazy_static = "0.2" log = "0.3" matches = "0.1" nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true} +num_cpus = {version = "1.1.0", optional = true} num-integer = "0.1.32" num-traits = "0.1.32" ordered-float = "0.4" diff --git a/components/style/animation.rs b/components/style/animation.rs index ddf1498d983..9734b67c1fd 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -415,7 +415,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext, match step.value { KeyframesStepValue::ComputedValues => style_from_cascade.clone(), KeyframesStepValue::Declarations { block: ref declarations } => { - let guard = declarations.read(); + let guard = declarations.read_with(context.guards.author); // No !important in keyframes. debug_assert!(guard.declarations().iter() diff --git a/components/style/attr.rs b/components/style/attr.rs index 0d07a35e828..b4cd434635e 100644 --- a/components/style/attr.rs +++ b/components/style/attr.rs @@ -11,9 +11,9 @@ use app_units::Au; use cssparser::{self, Color, RGBA}; use euclid::num::Zero; use num_traits::ToPrimitive; -use parking_lot::RwLock; use properties::PropertyDeclarationBlock; use servo_url::ServoUrl; +use shared_lock::Locked; use std::ascii::AsciiExt; use std::str::FromStr; use std::sync::Arc; @@ -61,7 +61,7 @@ pub enum AttrValue { /// declarationblock for longer than needed. Declaration(String, #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] - Arc>) + Arc>) } /// Shared implementation to parse an integer according to diff --git a/components/style/dom.rs b/components/style/dom.rs index 612105c20e9..ac8ad3bd109 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -11,10 +11,10 @@ use {Atom, Namespace, LocalName}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use data::ElementData; use element_state::ElementState; -use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement}; use selectors::matching::ElementSelectorFlags; +use shared_lock::Locked; use sink::Push; use std::fmt; use std::fmt::Debug; @@ -230,8 +230,8 @@ pub trait PresentationalHintsSynthetizer { /// The animation rules. The first one is for Animation cascade level, and the second one is for /// Transition cascade level. -pub struct AnimationRules(pub Option>>, - pub Option>>); +pub struct AnimationRules(pub Option>>, + pub Option>>); /// The element trait, the main abstraction the style crate acts over. pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { @@ -252,7 +252,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre } /// Get this element's style attribute. - fn style_attribute(&self) -> Option<&Arc>>; + fn style_attribute(&self) -> Option<&Arc>>; /// Get this element's animation rules. fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules { @@ -261,13 +261,13 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// Get this element's animation rule. fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { None } /// Get this element's transition rule. fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { None } diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index d400c01c568..349fca1bbcb 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -48,7 +48,7 @@ impl_arc_ffi!(Stylesheet => RawServoStyleSheet impl_arc_ffi!(ComputedValues => ServoComputedValues [Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]); -impl_arc_ffi!(RwLock => RawServoDeclarationBlock +impl_arc_ffi!(Locked => RawServoDeclarationBlock [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]); impl_arc_ffi!(Locked => RawServoStyleRule diff --git a/components/style/gecko/global_style_data.rs b/components/style/gecko/global_style_data.rs new file mode 100644 index 00000000000..2653ad16b1f --- /dev/null +++ b/components/style/gecko/global_style_data.rs @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +//! Global style data + +use num_cpus; +use rayon; +use shared_lock::SharedRwLock; +use std::cmp; +use std::env; + +/// Global style data +pub struct GlobalStyleData { + /// How many threads parallel styling can use. + pub num_threads: usize, + + /// The parallel styling thread pool. + pub style_thread_pool: Option, + + /// Shared RWLock for CSSOM objects + pub shared_lock: SharedRwLock, +} + +lazy_static! { + /// Global style data + pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = { + let stylo_threads = env::var("STYLO_THREADS") + .map(|s| s.parse::().expect("invalid STYLO_THREADS value")); + let num_threads = match stylo_threads { + Ok(num) => num, + _ => cmp::max(num_cpus::get() * 3 / 4, 1), + }; + + let pool = if num_threads <= 1 { + None + } else { + let configuration = + rayon::Configuration::new().set_num_threads(num_threads); + let pool = rayon::ThreadPool::new(configuration).ok(); + pool + }; + + GlobalStyleData { + num_threads: num_threads, + style_thread_pool: pool, + shared_lock: SharedRwLock::new(), + } + }; +} diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs index 2ee19fc60fc..48d50c5fa80 100644 --- a/components/style/gecko/mod.rs +++ b/components/style/gecko/mod.rs @@ -10,6 +10,7 @@ mod non_ts_pseudo_class_list; pub mod arc_types; pub mod conversions; pub mod data; +pub mod global_style_data; pub mod media_queries; pub mod restyle_damage; pub mod selector_parser; diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index fa057a4ae26..b9cab601f2c 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -20,6 +20,7 @@ use dom::{AnimationRules, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode} use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::StdoutErrorReporter; +use gecko::global_style_data::GLOBAL_STYLE_DATA; use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::snapshot_helpers; use gecko_bindings::bindings; @@ -53,6 +54,7 @@ use selectors::Element; use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{AttrSelector, NamespaceConstraint}; use servo_url::ServoUrl; +use shared_lock::Locked; use sink::Push; use std::fmt; use std::ptr; @@ -407,12 +409,14 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 { fn get_animation_rule(element: &GeckoElement, pseudo: Option<&PseudoElement>, cascade_level: CascadeLevel) - -> Option>> { + -> Option>> { let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo); let animation_values = Arc::new(RwLock::new(AnimationValueMap::new())); if unsafe { Gecko_GetAnimationRule(element.0, atom_ptr, cascade_level, HasArcFFI::arc_as_borrowed(&animation_values)) } { - Some(Arc::new(RwLock::new(PropertyDeclarationBlock::from_animation_value_map(&animation_values.read())))) + let shared_lock = &GLOBAL_STYLE_DATA.shared_lock; + Some(Arc::new(shared_lock.wrap( + PropertyDeclarationBlock::from_animation_value_map(&animation_values.read())))) } else { None } @@ -425,7 +429,7 @@ impl<'le> TElement for GeckoElement<'le> { unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } } - fn style_attribute(&self) -> Option<&Arc>> { + fn style_attribute(&self) -> Option<&Arc>> { let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) }; declarations.map(|s| s.as_arc_opt()).unwrap_or(None) } @@ -436,12 +440,12 @@ impl<'le> TElement for GeckoElement<'le> { } fn get_animation_rule(&self, pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { get_animation_rule(self, pseudo, CascadeLevel::Animations) } fn get_transition_rule(&self, pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { get_animation_rule(self, pseudo, CascadeLevel::Transitions) } diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index 44ca0921706..67f0c848f8d 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -8,14 +8,13 @@ use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser}; use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule}; -use parking_lot::RwLock; use parser::{ParserContext, ParserContextExtraData, log_css_error}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{PropertyDeclarationId, LonghandId, ParsedDeclaration}; use properties::LonghandIdSet; use properties::animated_properties::TransitionProperty; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; -use shared_lock::{SharedRwLock, SharedRwLockReadGuard, Locked}; +use shared_lock::{SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard}; use std::fmt; use std::sync::Arc; use style_traits::ToCss; @@ -102,11 +101,12 @@ pub struct Keyframe { /// /// Note that `!important` rules in keyframes don't apply, but we keep this /// `Arc` just for convenience. - pub block: Arc>, + pub block: Arc>, } -impl ToCss for Keyframe { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl ToCssWithGuard for Keyframe { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { let mut iter = self.selector.percentages().iter(); try!(iter.next().unwrap().to_css(dest)); for percentage in iter { @@ -114,7 +114,7 @@ impl ToCss for Keyframe { try!(percentage.to_css(dest)); } try!(dest.write_str(" { ")); - try!(self.block.read().to_css(dest)); + try!(self.block.read_with(guard).to_css(dest)); try!(dest.write_str(" }")); Ok(()) } @@ -154,7 +154,7 @@ pub enum KeyframesStepValue { Declarations { /// The declaration block per se. #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] - block: Arc> + block: Arc> }, /// A synthetic step computed from the current computed values at the time /// of the animation. @@ -180,10 +180,11 @@ pub struct KeyframesStep { impl KeyframesStep { #[inline] fn new(percentage: KeyframePercentage, - value: KeyframesStepValue) -> Self { + value: KeyframesStepValue, + guard: &SharedRwLockReadGuard) -> Self { let declared_timing_function = match value { KeyframesStepValue::Declarations { ref block } => { - block.read().declarations().iter().any(|&(ref prop_decl, _)| { + block.read_with(guard).declarations().iter().any(|&(ref prop_decl, _)| { match *prop_decl { PropertyDeclaration::AnimationTimingFunction(..) => true, _ => false, @@ -201,13 +202,14 @@ impl KeyframesStep { } /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'. - pub fn get_animation_timing_function(&self) -> Option { + pub fn get_animation_timing_function(&self, guard: &SharedRwLockReadGuard) + -> Option { if !self.declared_timing_function { return None; } match self.value { KeyframesStepValue::Declarations { ref block } => { - let guard = block.read(); + let guard = block.read_with(guard); let &(ref declaration, _) = guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap(); match *declaration { @@ -249,7 +251,8 @@ fn get_animated_properties(keyframes: &[Arc>], guard: &SharedRw // it here. for keyframe in keyframes { let keyframe = keyframe.read_with(&guard); - for &(ref declaration, importance) in keyframe.block.read().declarations().iter() { + let block = keyframe.block.read_with(guard); + for &(ref declaration, importance) in block.declarations().iter() { assert!(!importance.important()); if let Some(property) = TransitionProperty::from_declaration(declaration) { @@ -294,7 +297,7 @@ impl KeyframesAnimation { for percentage in keyframe.selector.0.iter() { result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations { block: keyframe.block.clone(), - })); + }, guard)); } } @@ -304,12 +307,14 @@ impl KeyframesAnimation { // Prepend autogenerated keyframes if appropriate. if result.steps[0].start_percentage.0 != 0. { result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.), - KeyframesStepValue::ComputedValues)); + KeyframesStepValue::ComputedValues, + guard)); } if result.steps.last().unwrap().start_percentage.0 != 1. { result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.), - KeyframesStepValue::ComputedValues)); + KeyframesStepValue::ComputedValues, + guard)); } result @@ -381,7 +386,7 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { } Ok(Arc::new(self.shared_lock.wrap(Keyframe { selector: prelude, - block: Arc::new(RwLock::new(block)), + block: Arc::new(self.shared_lock.wrap(block)), }))) } } diff --git a/components/style/lib.rs b/components/style/lib.rs index eabb8d20c51..ab564c59bd8 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -57,6 +57,7 @@ extern crate log; #[macro_use] extern crate matches; #[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring; +#[cfg(feature = "gecko")] extern crate num_cpus; extern crate num_integer; extern crate num_traits; extern crate ordered_float; diff --git a/components/style/matching.rs b/components/style/matching.rs index f58d429beb0..38552ff46da 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -886,7 +886,8 @@ pub trait MatchMethods : TElement { let new_node = context.shared.stylist.rule_tree .update_rule_at_level(CascadeLevel::StyleAttributeNormal, style_attribute, - primary_rules); + primary_rules, + &context.shared.guards); if let Some(n) = new_node { *primary_rules = n; rule_node_changed = true; @@ -895,7 +896,8 @@ pub trait MatchMethods : TElement { let new_node = context.shared.stylist.rule_tree .update_rule_at_level(CascadeLevel::StyleAttributeImportant, style_attribute, - primary_rules); + primary_rules, + &context.shared.guards); if let Some(n) = new_node { *primary_rules = n; rule_node_changed = true; diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index c1d4b27edf5..80aa88596d6 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -10,7 +10,6 @@ use arc_ptr_eq; #[cfg(feature = "servo")] use heapsize::HeapSizeOf; -use parking_lot::{RwLock, RwLockReadGuard}; use properties::{Importance, PropertyDeclarationBlock}; use shared_lock::{Locked, ReadGuards, SharedRwLockReadGuard}; use std::io::{self, Write}; @@ -54,7 +53,7 @@ pub enum StyleSource { /// A style rule stable pointer. Style(Arc>), /// A declaration block stable pointer. - Declarations(Arc>), + Declarations(Arc>), } impl StyleSource { @@ -82,13 +81,12 @@ impl StyleSource { /// Read the style source guard, and obtain thus read access to the /// underlying property declaration block. #[inline] - pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) - -> RwLockReadGuard<'a, PropertyDeclarationBlock> { + pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock { let block = match *self { StyleSource::Style(ref rule) => &rule.read_with(guard).block, StyleSource::Declarations(ref block) => block, }; - block.read() + block.read_with(guard) } } @@ -162,8 +160,9 @@ impl RuleTree { /// the old path is still valid. pub fn update_rule_at_level(&self, level: CascadeLevel, - pdb: Option<&Arc>>, - path: &StrongRuleNode) + pdb: Option<&Arc>>, + path: &StrongRuleNode, + guards: &ReadGuards) -> Option { debug_assert!(level.is_unique_per_element()); // TODO(emilio): Being smarter with lifetimes we could avoid a bit of @@ -222,13 +221,13 @@ impl RuleTree { // pretty bad styling cases already. if let Some(pdb) = pdb { if level.is_important() { - if pdb.read().any_important() { + if pdb.read_with(level.guard(guards)).any_important() { current = current.ensure_child(self.root.downgrade(), StyleSource::Declarations(pdb.clone()), level); } } else { - if pdb.read().any_normal() { + if pdb.read_with(level.guard(guards)).any_normal() { current = current.ensure_child(self.root.downgrade(), StyleSource::Declarations(pdb.clone()), level); diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 96c553c4a49..95104a4df60 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -469,7 +469,7 @@ impl ToCssWithGuard for KeyframesRule { } first = false; let keyframe = lock.read_with(&guard); - try!(keyframe.to_css(dest)); + try!(keyframe.to_css(guard, dest)); } dest.write_str(" }") } @@ -528,19 +528,19 @@ impl ToCssWithGuard for SupportsRule { #[derive(Debug)] pub struct StyleRule { pub selectors: SelectorList, - pub block: Arc>, + pub block: Arc>, } impl ToCssWithGuard for StyleRule { // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule - fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result where W: fmt::Write { // Step 1 try!(self.selectors.to_css(dest)); // Step 2 try!(dest.write_str(" { ")); // Step 3 - let declaration_block = self.block.read(); + let declaration_block = self.block.read_with(guard); try!(declaration_block.to_css(dest)); // Step 4 if declaration_block.declarations().len() > 0 { @@ -1018,9 +1018,10 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { fn parse_block(&mut self, prelude: SelectorList, input: &mut Parser) -> Result { + let declarations = parse_property_declaration_list(self.context, input); Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule { selectors: prelude, - block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input))) + block: Arc::new(self.shared_lock.wrap(declarations)) })))) } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 2166e81946a..d58e0dd0e85 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -12,7 +12,6 @@ use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement}; use error_reporting::StdoutErrorReporter; use keyframes::KeyframesAnimation; use media_queries::Device; -use parking_lot::RwLock; use pdqsort::sort_by; use properties::{self, CascadeFlags, ComputedValues}; #[cfg(feature = "servo")] @@ -542,7 +541,7 @@ impl Stylist { &self, element: &E, parent_bf: Option<&BloomFilter>, - style_attribute: Option<&Arc>>, + style_attribute: Option<&Arc>>, animation_rules: AnimationRules, pseudo_element: Option<&PseudoElement>, guards: &ReadGuards, @@ -613,7 +612,7 @@ impl Stylist { // Step 4: Normal style attributes. if let Some(sa) = style_attribute { - if sa.read().any_normal() { + if sa.read_with(guards.author).any_normal() { relations |= AFFECTED_BY_STYLE_ATTRIBUTE; Push::push( applicable_declarations, @@ -649,7 +648,7 @@ impl Stylist { // Step 7: `!important` style attributes. if let Some(sa) = style_attribute { - if sa.read().any_important() { + if sa.read_with(guards.author).any_important() { relations |= AFFECTED_BY_STYLE_ATTRIBUTE; Push::push( applicable_declarations, @@ -1005,7 +1004,7 @@ impl SelectorMap { if rule.selector.compound_selector.is_empty() && rule.selector.next.is_none() { let style_rule = rule.style_rule.read_with(guard); - let block = style_rule.block.read(); + let block = style_rule.block.read_with(guard); if block.any_normal() { matching_rules_list.push( rule.to_applicable_declaration_block(cascade_level)); @@ -1069,7 +1068,7 @@ impl SelectorMap { { for rule in rules.iter() { let style_rule = rule.style_rule.read_with(guard); - let block = style_rule.block.read(); + let block = style_rule.block.read_with(guard); let any_declaration_for_importance = if cascade_level.is_important() { block.any_important() } else { @@ -1208,7 +1207,7 @@ impl ApplicableDeclarationBlock { /// Constructs an applicable declaration block from a given property /// declaration block and importance. #[inline] - pub fn from_declarations(declarations: Arc>, + pub fn from_declarations(declarations: Arc>, level: CascadeLevel) -> Self { ApplicableDeclarationBlock { diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 9ed52128eaf..40e9b7e65ad 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -20,9 +20,7 @@ env_logger = {version = "0.4", default-features = false} # disable `regex` to re lazy_static = "0.2" libc = "0.2" log = {version = "0.3.5", features = ["release_max_level_info"]} -num_cpus = "1.1.0" parking_lot = "0.3" -rayon = "0.6" selectors = {path = "../../components/selectors"} servo_url = {path = "../../components/url"} style = {path = "../../components/style", features = ["gecko"]} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index bbe8bc6907d..f39e4a903cc 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -6,13 +6,10 @@ use atomic_refcell::AtomicRefMut; use cssparser::Parser; use cssparser::ToCss as ParserToCss; use env_logger::LogBuilder; -use num_cpus; use parking_lot::RwLock; -use rayon; use selectors::Element; use servo_url::ServoUrl; use std::borrow::Cow; -use std::cmp; use std::env; use std::fmt::Write; use std::ptr; @@ -24,6 +21,7 @@ use style::data::{ElementData, ElementStyles, RestyleData}; use style::dom::{ShowSubtreeData, TElement, TNode}; use style::error_reporting::StdoutErrorReporter; use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl}; +use style::gecko::global_style_data::GLOBAL_STYLE_DATA; use style::gecko::restyle_damage::GeckoRestyleDamage; use style::gecko::selector_parser::{SelectorImpl, PseudoElement}; use style::gecko::traversal::RecalcStyleOnly; @@ -96,48 +94,7 @@ use super::stylesheet_loader::StylesheetLoader; * depend on but good enough for our purposes. */ -pub struct GlobalStyleData { - // How many threads parallel styling can use. - pub num_threads: usize, - // The parallel styling thread pool. - pub style_thread_pool: Option, - - // Shared RWLock for CSSOM objects - pub shared_lock: SharedRwLock, -} - -impl GlobalStyleData { - pub fn new() -> Self { - let stylo_threads = env::var("STYLO_THREADS") - .map(|s| s.parse::().expect("invalid STYLO_THREADS value")); - let num_threads = match stylo_threads { - Ok(num) => num, - _ => cmp::max(num_cpus::get() * 3 / 4, 1), - }; - - let pool = if num_threads <= 1 { - None - } else { - let configuration = - rayon::Configuration::new().set_num_threads(num_threads); - let pool = rayon::ThreadPool::new(configuration).ok(); - pool - }; - - GlobalStyleData { - num_threads: num_threads, - style_thread_pool: pool, - shared_lock: SharedRwLock::new(), - } - } -} - -lazy_static! { - pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = { - GlobalStyleData::new() - }; -} #[no_mangle] pub extern "C" fn Servo_Initialize() { @@ -638,7 +595,7 @@ pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed, let global_style_data = &*GLOBAL_STYLE_DATA; let mut guard = global_style_data.shared_lock.write(); let rule = Locked::::as_arc(&rule); - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); rule.write_with(&mut guard).block = declarations.clone(); } @@ -829,9 +786,10 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) { Ok(parsed) => { + let global_style_data = &*GLOBAL_STYLE_DATA; let mut block = PropertyDeclarationBlock::new(); parsed.expand(|d| block.push(d, Importance::Normal)); - Arc::new(RwLock::new(block)).into_strong() + Arc::new(global_style_data.shared_lock.wrap(block)).into_strong() } Err(_) => RawServoDeclarationBlockStrong::null() } @@ -842,36 +800,47 @@ pub extern "C" fn Servo_ParseStyleAttribute(data: *const nsACString, base: *const nsACString, raw_extra_data: *const structs::GeckoParserExtraData) -> RawServoDeclarationBlockStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; let value = unsafe { data.as_ref().unwrap().as_str_unchecked() }; make_context!((base, raw_extra_data) => (base_url, extra_data)); - Arc::new(RwLock::new(GeckoElement::parse_style_attribute(value, &base_url, extra_data))).into_strong() + Arc::new(global_style_data.shared_lock.wrap( + GeckoElement::parse_style_attribute(value, &base_url, extra_data))).into_strong() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> RawServoDeclarationBlockStrong { - Arc::new(RwLock::new(PropertyDeclarationBlock::new())).into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + Arc::new(global_style_data.shared_lock.wrap(PropertyDeclarationBlock::new())).into_strong() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclarationBlockBorrowed) -> RawServoDeclarationBlockStrong { - let declarations = RwLock::::as_arc(&declarations); - Arc::new(RwLock::new(declarations.read().clone())).into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + Arc::new(global_style_data.shared_lock.wrap( + declarations.read_with(&guard).clone() + )).into_strong() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, b: RawServoDeclarationBlockBorrowed) -> bool { - *RwLock::::as_arc(&a).read().declarations() == - *RwLock::::as_arc(&b).read().declarations() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + *Locked::::as_arc(&a).read_with(&guard).declarations() == + *Locked::::as_arc(&b).read_with(&guard).declarations() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed, result: *mut nsAString) { - let declarations = RwLock::::as_arc(&declarations); - declarations.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } #[no_mangle] @@ -880,9 +849,11 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( property_id: nsCSSPropertyID, buffer: *mut nsAString) { let property_id = get_property_id_from_nscsspropertyid!(property_id, ()); - let declarations = RwLock::::as_arc(&declarations); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); let mut string = String::new(); - let rv = declarations.read().single_value_to_css(&property_id, &mut string); + let rv = declarations.read_with(&guard).single_value_to_css(&property_id, &mut string); debug_assert!(rv.is_ok()); write!(unsafe { &mut *buffer }, "{}", string).expect("Failed to copy string"); @@ -890,15 +861,19 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 { - let declarations = RwLock::::as_arc(&declarations); - declarations.read().declarations().len() as u32 + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard).declarations().len() as u32 } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed, index: u32, result: *mut nsAString) -> bool { - let declarations = RwLock::::as_arc(&declarations); - if let Some(&(ref decl, _)) = declarations.read().declarations().get(index as usize) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + if let Some(&(ref decl, _)) = declarations.read_with(&guard).declarations().get(index as usize) { let result = unsafe { result.as_mut().unwrap() }; decl.id().to_css(result).unwrap(); true @@ -919,8 +894,12 @@ macro_rules! get_property_id_from_property { fn get_property_value(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId, value: *mut nsAString) { - let declarations = RwLock::::as_arc(&declarations); - declarations.read().property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard) + .property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() }) + .unwrap(); } #[no_mangle] @@ -939,8 +918,10 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(declarations: RawS pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed, property: *const nsACString) -> bool { let property_id = get_property_id_from_property!(property, false); - let declarations = RwLock::::as_arc(&declarations); - declarations.read().property_priority(&property_id).important() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard).property_priority(&property_id).important() } fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId, @@ -951,7 +932,10 @@ fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: Pro make_context!((base, data) => (base_url, extra_data)); if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url, &StdoutErrorReporter, extra_data) { - let mut declarations = RwLock::::as_arc(&declarations).write(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let declarations = Locked::::as_arc(&declarations) + .write_with(&mut guard); let importance = if is_important { Importance::Important } else { Importance::Normal }; let mut changed = false; parsed.expand(|decl| { @@ -984,8 +968,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetPropertyById(declarations: RawServoD } fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) { - let declarations = RwLock::::as_arc(&declarations); - declarations.write().remove_property(&property_id); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let declarations = Locked::::as_arc(&declarations); + declarations.write_with(&mut guard).remove_property(&property_id); } #[no_mangle] @@ -1095,9 +1081,11 @@ pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(declarations: property: nsCSSPropertyID) -> bool { use style::properties::PropertyDeclarationId; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property, false); - declarations.read().get(PropertyDeclarationId::Longhand(long)).is_some() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + declarations.read_with(&guard).get(PropertyDeclarationId::Longhand(long)).is_some() } #[no_mangle] @@ -1110,12 +1098,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::longhands::_x_lang::computed_value::T as Lang; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let prop = match_wrap_declared! { long, XLang => Lang(Atom::from(value)), }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1128,7 +1118,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: use style::properties::longhands; use style::values::specified::{BorderStyle, NoCalcLength}; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let value = value as u32; @@ -1152,7 +1142,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: BorderBottomStyle => BorderStyle::from_gecko_keyword(value), BorderLeftStyle => BorderStyle::from_gecko_keyword(value), }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1162,12 +1154,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDecla use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::longhands::_x_span::computed_value::T as Span; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let prop = match_wrap_declared! { long, XSpan => Span(value), }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1180,7 +1174,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations: use style::values::specified::BorderWidth; use style::values::specified::length::NoCalcLength; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let nocalc = NoCalcLength::from_px(value); @@ -1206,7 +1200,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations: } ), }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1217,7 +1213,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::values::specified::length::Percentage; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let pc = Percentage(value); @@ -1229,7 +1225,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations: MarginBottom => pc.into(), MarginLeft => pc.into(), }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1239,7 +1237,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::values::specified::LengthOrPercentageOrAuto; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let auto = LengthOrPercentageOrAuto::Auto; @@ -1251,7 +1249,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations: MarginBottom => auto, MarginLeft => auto, }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1261,7 +1261,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::values::specified::{Color, CSSColor}; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let cc = CSSColor { parsed: Color::CurrentColor, authored: None }; @@ -1271,7 +1271,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations: BorderBottomColor => cc, BorderLeftColor => cc, }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1284,7 +1286,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations: use style::properties::longhands; use style::values::specified::{Color, CSSColor}; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let rgba = convert_nscolor_to_rgba(value); let color = CSSColor { parsed: Color::RGBA(rgba), authored: None }; @@ -1297,7 +1299,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations: Color => longhands::color::SpecifiedValue(color), BackgroundColor => color, }; - declarations.write().push(prop, Importance::Normal); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + declarations.write_with(&mut guard).push(prop, Importance::Normal); } #[no_mangle] @@ -1308,13 +1312,15 @@ pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations: use style::properties::PropertyDeclaration; use style::properties::longhands::font_family::SpecifiedValue as FontFamily; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let string = unsafe { (*value).to_string() }; let mut parser = Parser::new(&string); if let Ok(family) = FontFamily::parse(&mut parser) { if parser.is_exhausted() { + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); let decl = PropertyDeclaration::FontFamily(family); - declarations.write().push(decl, Importance::Normal); + declarations.write_with(&mut guard).push(decl, Importance::Normal); } } } @@ -1325,11 +1331,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarat use style::properties::PropertyDeclaration; use style::properties::longhands::text_decoration_line; - let declarations = RwLock::::as_arc(&declarations); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + + let declarations = Locked::::as_arc(&declarations); let mut decoration = text_decoration_line::computed_value::none; decoration |= text_decoration_line::COLOR_OVERRIDE; let decl = PropertyDeclaration::TextDecorationLine(decoration); - declarations.write().push(decl, Importance::Normal); + declarations.write_with(&mut guard).push(decl, Importance::Normal); } #[no_mangle] @@ -1523,6 +1532,11 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis use style::properties::LonghandIdSet; use style::properties::declaration_block::Importance; use style::values::computed::Context; + + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + + let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let style = ComputedValues::as_arc(&style); @@ -1549,8 +1563,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis .filter(|&property| !property.mServoDeclarationBlock.mRawPtr.is_null()); for property in iter { let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() }; - let declarations = RwLock::::as_arc(&declarations); - let guard = declarations.read(); + let declarations = Locked::::as_arc(&declarations); + let guard = declarations.read_with(&guard); let anim_iter = guard.declarations() .iter() @@ -1614,15 +1628,18 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet use style::gecko_bindings::structs::Keyframe; use style::properties::LonghandIdSet; + let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) }; let style_timing_function = unsafe { timing_function.as_ref().unwrap() }; let style = ComputedValues::as_arc(&style); if let Some(ref animation) = data.stylist.animations().get(&name) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); for step in &animation.steps { // Override timing_function if the keyframe has animation-timing-function. - let timing_function = if let Some(val) = step.get_animation_timing_function() { + let timing_function = if let Some(val) = step.get_animation_timing_function(&guard) { val.into() } else { *style_timing_function @@ -1637,7 +1654,8 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet fn add_computed_property_value(keyframe: *mut Keyframe, index: usize, style: &ComputedValues, - property: &TransitionProperty) { + property: &TransitionProperty, + shared_lock: &SharedRwLock) { let block = style.to_declaration_block(property.clone().into()); unsafe { (*keyframe).mPropertyValues.set_len((index + 1) as u32); @@ -1645,18 +1663,19 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet // FIXME. Do not set computed values once we handles missing keyframes // with additive composition. (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( - Arc::new(RwLock::new(block))); + Arc::new(shared_lock.wrap(block))); } } match step.value { KeyframesStepValue::ComputedValues => { for (index, property) in animation.properties_changed.iter().enumerate() { - add_computed_property_value(keyframe, index, style, property); + add_computed_property_value( + keyframe, index, style, property, &global_style_data.shared_lock); } }, KeyframesStepValue::Declarations { ref block } => { - let guard = block.read(); + let guard = block.read_with(&guard); // Filter out non-animatable properties. let animatable = guard.declarations() @@ -1673,8 +1692,9 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet (*keyframe).mPropertyValues.set_len((index + 1) as u32); (*keyframe).mPropertyValues[index].mProperty = property.into(); (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( - declaration.clone(), Importance::Normal + Arc::new(global_style_data.shared_lock.wrap( + PropertyDeclarationBlock::with_one( + declaration.clone(), Importance::Normal )))); if step.start_percentage.0 == 0. || step.start_percentage.0 == 1. { @@ -1689,7 +1709,8 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet let mut index = unsafe { (*keyframe).mPropertyValues.len() }; for property in animation.properties_changed.iter() { if !seen.has_transition_property_bit(&property) { - add_computed_property_value(keyframe, index, style, property); + add_computed_property_value( + keyframe, index, style, property, &global_style_data.shared_lock); index += 1; } } diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index 0bdbaa12f24..a7dd0561299 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -10,9 +10,7 @@ extern crate env_logger; #[macro_use] extern crate lazy_static; extern crate libc; #[macro_use] extern crate log; -extern crate num_cpus; extern crate parking_lot; -extern crate rayon; extern crate selectors; extern crate servo_url; #[macro_use] extern crate style; diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index 2e81de1a57e..5e226ee54c9 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -3,13 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::sync::Arc; +use style::gecko::global_style_data::GLOBAL_STYLE_DATA; use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; use style::gecko_bindings::sugar::ownership::HasArcFFI; use style::shared_lock::Locked; use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader}; use style_traits::ToCss; -use super::glue::GLOBAL_STYLE_DATA; pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet); diff --git a/tests/unit/style/keyframes.rs b/tests/unit/style/keyframes.rs index a916f18da01..9fe2f0d3f39 100644 --- a/tests/unit/style/keyframes.rs +++ b/tests/unit/style/keyframes.rs @@ -2,7 +2,6 @@ * 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/. */ -use parking_lot::RwLock; use std::sync::Arc; use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector}; use style::keyframes::{KeyframesStep, KeyframesStepValue}; @@ -30,7 +29,7 @@ fn test_no_property_in_keyframe() { let keyframes = vec![ Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), - block: Arc::new(RwLock::new(PropertyDeclarationBlock::new())) + block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new())) })), ]; let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); @@ -46,14 +45,14 @@ fn test_no_property_in_keyframe() { fn test_missing_property_in_initial_keyframe() { let shared_lock = SharedRwLock::new(); let declarations_on_initial_keyframe = - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Width( LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))), Importance::Normal ))); let declarations_on_final_keyframe = - Arc::new(RwLock::new({ + Arc::new(shared_lock.wrap({ let mut block = PropertyDeclarationBlock::new(); block.push( PropertyDeclaration::Width( @@ -103,7 +102,7 @@ fn test_missing_property_in_initial_keyframe() { fn test_missing_property_in_final_keyframe() { let shared_lock = SharedRwLock::new(); let declarations_on_initial_keyframe = - Arc::new(RwLock::new({ + Arc::new(shared_lock.wrap({ let mut block = PropertyDeclarationBlock::new(); block.push( PropertyDeclaration::Width( @@ -119,7 +118,7 @@ fn test_missing_property_in_final_keyframe() { })); let declarations_on_final_keyframe = - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Height( LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))), Importance::Normal, @@ -160,7 +159,7 @@ fn test_missing_property_in_final_keyframe() { fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { let shared_lock = SharedRwLock::new(); let declarations = - Arc::new(RwLock::new({ + Arc::new(shared_lock.wrap({ let mut block = PropertyDeclarationBlock::new(); block.push( PropertyDeclaration::Width( @@ -178,7 +177,7 @@ fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { let keyframes = vec![ Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), - block: Arc::new(RwLock::new(PropertyDeclarationBlock::new())) + block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new())) })), Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.5)]), @@ -191,7 +190,7 @@ fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { KeyframesStep { start_percentage: KeyframePercentage(0.), value: KeyframesStepValue::Declarations { - block: Arc::new(RwLock::new( + block: Arc::new(shared_lock.wrap( // XXX: Should we use ComputedValues in this case? PropertyDeclarationBlock::new() )) diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs index aeac93912aa..4d4012f16c1 100644 --- a/tests/unit/style/rule_tree/bench.rs +++ b/tests/unit/style/rule_tree/bench.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::{Parser, SourcePosition}; -use parking_lot::RwLock; use rayon; use servo_url::ServoUrl; use std::sync::Arc; @@ -65,9 +64,11 @@ fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>) rule_tree.insert_ordered_rules(rules.into_iter()) } -fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)]) -> StrongRuleNode { +fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)], + shared_lock: &SharedRwLock) + -> StrongRuleNode { let mut rules = rules.to_vec(); - rules.push((StyleSource::Declarations(Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + rules.push((StyleSource::Declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Display( longhands::display::SpecifiedValue::block), Importance::Normal @@ -121,11 +122,12 @@ fn bench_expensive_insertion(b: &mut Bencher) { .bar { height: 500px; } \ .baz { display: block; }"); + let shared_lock = SharedRwLock::new(); b.iter(|| { let _gc = AutoGCRuleTree::new(&r); for _ in 0..(4000 + 400) { - test::black_box(test_insertion_style_attribute(&r, &rules_matched)); + test::black_box(test_insertion_style_attribute(&r, &rules_matched, &shared_lock)); } }); } @@ -170,6 +172,7 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) { .bar { height: 500px; } \ .baz { display: block; }"); + let shared_lock = SharedRwLock::new(); b.iter(|| { let _gc = AutoGCRuleTree::new(&r); @@ -178,12 +181,14 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) { s.spawn(|s| { for _ in 0..1000 { test::black_box(test_insertion_style_attribute(&r, - &rules_matched)); + &rules_matched, + &shared_lock)); } s.spawn(|_| { for _ in 0..100 { test::black_box(test_insertion_style_attribute(&r, - &rules_matched)); + &rules_matched, + &shared_lock)); } }) }) diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 2bcb9b58a77..fa6a26963f8 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -109,7 +109,7 @@ fn test_parse_stylesheet() { specificity: (0 << 20) + (1 << 10) + (1 << 0), }, ]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::Display(longhands::display::SpecifiedValue::none), Importance::Important), (PropertyDeclaration::Custom(Atom::from("a"), @@ -154,7 +154,7 @@ fn test_parse_stylesheet() { specificity: (0 << 20) + (0 << 10) + (1 << 0), }, ]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::Display(longhands::display::SpecifiedValue::block), Importance::Normal), ]))), @@ -185,7 +185,7 @@ fn test_parse_stylesheet() { specificity: (1 << 20) + (1 << 10) + (0 << 0), }, ]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::BackgroundColor( longhands::background_color::SpecifiedValue { authored: Some("blue".to_owned().into_boxed_str()), @@ -241,7 +241,7 @@ fn test_parse_stylesheet() { Arc::new(stylesheet.shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing( vec![KeyframePercentage::new(0.)]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::Width( LengthOrPercentageOrAuto::Percentage(Percentage(0.))), Importance::Normal), @@ -250,7 +250,7 @@ fn test_parse_stylesheet() { Arc::new(stylesheet.shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing( vec![KeyframePercentage::new(1.)]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::Width( LengthOrPercentageOrAuto::Percentage(Percentage(1.))), Importance::Normal), diff --git a/tests/unit/style/stylist.rs b/tests/unit/style/stylist.rs index 34a7feff965..8f559703cbe 100644 --- a/tests/unit/style/stylist.rs +++ b/tests/unit/style/stylist.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use html5ever_atoms::LocalName; -use parking_lot::RwLock; use selectors::parser::LocalName as LocalNameSelector; use servo_atoms::Atom; use std::sync::Arc; @@ -25,7 +24,7 @@ fn get_mock_rules(css_selectors: &[&str]) -> (Vec>, SharedRwLock) { let locked = Arc::new(shared_lock.wrap(StyleRule { selectors: selectors, - block: Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Display( longhands::display::SpecifiedValue::block), Importance::Normal From 1e380137831eaf94a1f602c9d8dfae08f10893fa Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 13:49:04 +0100 Subject: [PATCH 13/17] Refactor StylesheetLoader so impls do not need to acquire a shared lock. This fixes a deadlock: https://github.com/servo/servo/pull/16014#issuecomment-287527067 --- components/script/dom/htmllinkelement.rs | 3 +- components/script/stylesheet_loader.rs | 45 ++++++++--------- components/style/stylesheets.rs | 61 ++++++++++++++++-------- ports/geckolib/stylesheet_loader.rs | 34 ++++++++----- 4 files changed, 84 insertions(+), 59 deletions(-) diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index b4f90b89b85..d29a94a11f0 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -291,9 +291,8 @@ impl HTMLLinkElement { // doesn't match. let loader = StylesheetLoader::for_element(self.upcast()); loader.load(StylesheetContextSource::LinkElement { - url: url, media: Some(media), - }, cors_setting, integrity_metadata.to_owned()); + }, url, cors_setting, integrity_metadata.to_owned()); } fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option) { diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index db21ee795fd..7f544e42d08 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -54,32 +54,16 @@ pub trait StylesheetOwner { pub enum StylesheetContextSource { // NB: `media` is just an option so we avoid cloning it. - LinkElement { media: Option, url: ServoUrl }, + LinkElement { media: Option, }, Import(Arc>), } -impl StylesheetContextSource { - fn url(&self, document: &Document) -> ServoUrl { - match *self { - StylesheetContextSource::LinkElement { ref url, .. } => url.clone(), - StylesheetContextSource::Import(ref import) => { - let guard = document.style_shared_lock().read(); - let import = import.read_with(&guard); - // Look at the parser in style::stylesheets, where we don't - // trigger a load if the url is invalid. - import.url.url() - .expect("Invalid urls shouldn't enter the loader") - .clone() - } - } - } -} - /// The context required for asynchronously loading an external stylesheet. pub struct StylesheetContext { /// The element that initiated the request. elem: Trusted, source: StylesheetContextSource, + url: ServoUrl, metadata: Option, /// The response body received to date. data: Vec, @@ -146,7 +130,7 @@ impl FetchResponseListener for StylesheetContext { let loader = StylesheetLoader::for_element(&elem); match self.source { - StylesheetContextSource::LinkElement { ref mut media, .. } => { + StylesheetContextSource::LinkElement { ref mut media } => { let link = elem.downcast::().unwrap(); // We must first check whether the generations of the context and the element match up, // else we risk applying the wrong stylesheet when responses come out-of-order. @@ -209,8 +193,7 @@ impl FetchResponseListener for StylesheetContext { document.decrement_script_blocking_stylesheet_count(); } - let url = self.source.url(&document); - document.finish_load(LoadType::Stylesheet(url)); + document.finish_load(LoadType::Stylesheet(self.url.clone())); if let Some(any_failed) = owner.load_finished(successful) { let event = if any_failed { atom!("error") } else { atom!("load") }; @@ -232,15 +215,16 @@ impl<'a> StylesheetLoader<'a> { } impl<'a> StylesheetLoader<'a> { - pub fn load(&self, source: StylesheetContextSource, cors_setting: Option, + pub fn load(&self, source: StylesheetContextSource, url: ServoUrl, + cors_setting: Option, integrity_metadata: String) { let document = document_from_node(self.elem); - let url = source.url(&document); let gen = self.elem.downcast::() .map(HTMLLinkElement::get_request_generation_id); let context = Arc::new(Mutex::new(StylesheetContext { elem: Trusted::new(&*self.elem), source: source, + url: url.clone(), metadata: None, data: vec![], document: Trusted::new(&*document), @@ -297,9 +281,20 @@ impl<'a> StylesheetLoader<'a> { } impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> { - fn request_stylesheet(&self, import: &Arc>) { + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc> { + let import = make_import(media); + let url = import.url.url().expect("Invalid urls shouldn't enter the loader").clone(); + let arc = make_arc(import); + //TODO (mrnayak) : Whether we should use the original loader's CORS setting? //Fix this when spec has more details. - self.load(StylesheetContextSource::Import(import.clone()), None, "".to_owned()) + self.load(StylesheetContextSource::Import(arc.clone()), url, None, "".to_owned()); + + arc } } diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 95104a4df60..3d572536d7d 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -743,9 +743,31 @@ pub trait StylesheetLoader { /// /// The called code is responsible to update the `stylesheet` rules field /// when the sheet is done loading. - fn request_stylesheet(&self, import: &Arc>); + /// + /// The convoluted signature allows impls to look at MediaList and ImportRule + /// before they’re locked, while keeping the trait object-safe. + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc>; } +struct NoOpLoader; + +impl StylesheetLoader for NoOpLoader { + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc> { + make_arc(make_import(media)) + } +} + + struct TopLevelRuleParser<'a> { stylesheet_origin: Origin, namespaces: &'a mut Namespaces, @@ -801,22 +823,26 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { "import" => { if self.state.get() <= State::Imports { self.state.set(State::Imports); - let url = try!(input.expect_url_or_string()); - let url = - try!(SpecifiedUrl::parse_from_string(url, - &self.context)); + let url_string = input.expect_url_or_string()?; + let specified_url = SpecifiedUrl::parse_from_string(url_string, &self.context)?; - let media = - Arc::new(self.shared_lock.wrap(parse_media_query_list(input))); + let media = parse_media_query_list(input); - let is_valid_url = url.url().is_some(); + let noop_loader = NoOpLoader; + let is_valid_url = specified_url.url().is_some(); + let loader = if is_valid_url { + self.loader.expect("Expected a stylesheet loader for @import") + } else { + &noop_loader + }; - let import_rule = Arc::new(self.shared_lock.wrap( + let mut specified_url = Some(specified_url); + let arc = loader.request_stylesheet(media, &mut |media| { ImportRule { - url: url, + url: specified_url.take().unwrap(), stylesheet: Arc::new(Stylesheet { rules: CssRules::new(Vec::new(), self.shared_lock), - media: media, + media: Arc::new(self.shared_lock.wrap(media)), shared_lock: self.shared_lock.clone(), origin: self.context.stylesheet_origin, base_url: self.context.base_url.clone(), @@ -825,15 +851,10 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { disabled: AtomicBool::new(false), }) } - )); - - if is_valid_url { - let loader = self.loader - .expect("Expected a stylesheet loader for @import"); - loader.request_stylesheet(&import_rule); - } - - return Ok(AtRuleType::WithoutBlock(CssRule::Import(import_rule))) + }, &mut |import_rule| { + Arc::new(self.shared_lock.wrap(import_rule)) + }); + return Ok(AtRuleType::WithoutBlock(CssRule::Import(arc))) } else { self.state.set(State::Invalid); return Err(()) // "@import must be before any rule but @charset" diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index 5e226ee54c9..d904f1b9870 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -3,10 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::sync::Arc; -use style::gecko::global_style_data::GLOBAL_STYLE_DATA; use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; use style::gecko_bindings::sugar::ownership::HasArcFFI; +use style::media_queries::MediaList; use style::shared_lock::Locked; use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader}; use style_traits::ToCss; @@ -20,13 +20,12 @@ impl StylesheetLoader { } impl StyleStylesheetLoader for StylesheetLoader { - fn request_stylesheet(&self, import_rule: &Arc>) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let import = import_rule.read_with(&guard); - let (spec_bytes, spec_len) = import.url.as_slice_components() - .expect("Import only loads valid URLs"); - + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc> { // TODO(emilio): We probably want to share media representation with // Gecko in Stylo. // @@ -35,16 +34,27 @@ impl StyleStylesheetLoader for StylesheetLoader { // evaluate them on the main thread. // // Meanwhile, this works. - let media = import.stylesheet.media.read_with(&guard).to_css_string(); + let media_string = media.to_css_string(); + let import = make_import(media); + + // After we get this raw pointer ImportRule will be moved into a lock and Arc + // and so the Arc pointer inside will also move, + // but the Url it points to or the allocating backing the String inside that Url won’t, + // so this raw pointer will still be valid. + let (spec_bytes, spec_len): (*const u8, usize) = import.url.as_slice_components() + .expect("Import only loads valid URLs"); + + let arc = make_arc(import); unsafe { Gecko_LoadStyleSheet(self.0, self.1, - HasArcFFI::arc_as_borrowed(import_rule), + HasArcFFI::arc_as_borrowed(&arc), spec_bytes, spec_len as u32, - media.as_bytes().as_ptr(), - media.len() as u32); + media_string.as_bytes().as_ptr(), + media_string.len() as u32); } + arc } } From cc046300f0390eadfcff65dcc6d8cea5bed9513e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 14:00:01 +0100 Subject: [PATCH 14/17] Remove some indirection. --- components/script/stylesheet_loader.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 7f544e42d08..fc838319695 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -55,7 +55,7 @@ pub trait StylesheetOwner { pub enum StylesheetContextSource { // NB: `media` is just an option so we avoid cloning it. LinkElement { media: Option, }, - Import(Arc>), + Import(Arc), } /// The context required for asynchronously loading an external stylesheet. @@ -158,16 +158,9 @@ impl FetchResponseListener for StylesheetContext { win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap(); } } - StylesheetContextSource::Import(ref import) => { + StylesheetContextSource::Import(ref stylesheet) => { let mut guard = document.style_shared_lock().write(); - // Clone an Arc because we can’t borrow `guard` twice at the same time. - - // FIXME(SimonSapin): allow access to multiple objects with one write guard? - // Would need a set of usize pointer addresses or something, - // the same object is not accessed more than once. - let stylesheet = Arc::clone(&import.write_with(&mut guard).stylesheet); - Stylesheet::update_from_bytes(&stylesheet, &data, protocol_encoding_label, @@ -289,12 +282,12 @@ impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> { ) -> Arc> { let import = make_import(media); let url = import.url.url().expect("Invalid urls shouldn't enter the loader").clone(); - let arc = make_arc(import); //TODO (mrnayak) : Whether we should use the original loader's CORS setting? //Fix this when spec has more details. - self.load(StylesheetContextSource::Import(arc.clone()), url, None, "".to_owned()); + let source = StylesheetContextSource::Import(import.stylesheet.clone()); + self.load(source, url, None, "".to_owned()); - arc + make_arc(import) } } From d9491187dc7509b4114bfb3d606986fac28e5ff8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 14:25:25 +0100 Subject: [PATCH 15/17] Parse stylesheets without acquiring a shared lock. --- components/script/stylesheet_loader.rs | 3 -- components/style/encoding_support.rs | 4 +- components/style/stylesheets.rs | 70 +++++++++++++++----------- ports/geckolib/glue.rs | 7 +-- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index fc838319695..4c2f06322a4 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -159,13 +159,10 @@ impl FetchResponseListener for StylesheetContext { } } StylesheetContextSource::Import(ref stylesheet) => { - let mut guard = document.style_shared_lock().write(); - Stylesheet::update_from_bytes(&stylesheet, &data, protocol_encoding_label, Some(environment_encoding), - &mut guard, Some(&loader), win.css_error_reporter(), ParserContextExtraData::default()); diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index e485dc13cf0..141291c896e 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -12,7 +12,7 @@ use media_queries::MediaList; use parser::ParserContextExtraData; use self::encoding::{EncodingRef, DecoderTrap}; use servo_url::ServoUrl; -use shared_lock::{SharedRwLock, SharedRwLockWriteGuard}; +use shared_lock::SharedRwLock; use std::str; use stylesheets::{Stylesheet, StylesheetLoader, Origin}; @@ -78,7 +78,6 @@ impl Stylesheet { bytes: &[u8], protocol_encoding_label: Option<&str>, environment_encoding: Option, - guard: &mut SharedRwLockWriteGuard, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) { @@ -86,7 +85,6 @@ impl Stylesheet { bytes, protocol_encoding_label, environment_encoding); Self::update_from_str(existing, &string, - guard, stylesheet_loader, error_reporter, extra_data) diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 3d572536d7d..202c31f7416 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -21,8 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser}; use selectors::parser::SelectorList; use servo_config::prefs::PREFS; use servo_url::ServoUrl; -use shared_lock::{SharedRwLock, Locked, ToCssWithGuard}; -use shared_lock::{SharedRwLockReadGuard, SharedRwLockWriteGuard}; +use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard}; use std::cell::Cell; use std::fmt; use std::sync::Arc; @@ -556,23 +555,42 @@ impl Stylesheet { /// Updates an empty stylesheet from a given string of text. pub fn update_from_str(existing: &Stylesheet, css: &str, - guard: &mut SharedRwLockWriteGuard, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) { - let mut rules = existing.rules.write_with(guard); - let mut namespaces = existing.namespaces.write(); + let mut namespaces = Namespaces::default(); + let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules( + css, &existing.base_url, existing.origin, &mut namespaces, &existing.shared_lock, + stylesheet_loader, error_reporter, extra_data, + ); - assert!(rules.is_empty()); + *existing.namespaces.write() = namespaces; + existing.dirty_on_viewport_size_change + .store(dirty_on_viewport_size_change, Ordering::Release); + // Acquire the lock *after* parsing, to minimize the exclusive section. + let mut guard = existing.shared_lock.write(); + *existing.rules.write_with(&mut guard) = CssRules(rules); + } + + fn parse_rules(css: &str, + base_url: &ServoUrl, + origin: Origin, + namespaces: &mut Namespaces, + shared_lock: &SharedRwLock, + stylesheet_loader: Option<&StylesheetLoader>, + error_reporter: &ParseErrorReporter, + extra_data: ParserContextExtraData) + -> (Vec, bool) { + let mut rules = Vec::new(); let mut input = Parser::new(css); let rule_parser = TopLevelRuleParser { - stylesheet_origin: existing.origin, - namespaces: &mut namespaces, - shared_lock: &existing.shared_lock, + stylesheet_origin: origin, + namespaces: namespaces, + shared_lock: shared_lock, loader: stylesheet_loader, - context: ParserContext::new_with_extra_data(existing.origin, - &existing.base_url, + context: ParserContext::new_with_extra_data(origin, + base_url, error_reporter, extra_data), state: Cell::new(State::Start), @@ -584,7 +602,7 @@ impl Stylesheet { let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); while let Some(result) = iter.next() { match result { - Ok(rule) => rules.0.push(rule), + Ok(rule) => rules.push(rule), Err(range) => { let pos = range.start; let message = format!("Invalid rule: '{}'", iter.input.slice(range)); @@ -594,8 +612,7 @@ impl Stylesheet { } } - existing.dirty_on_viewport_size_change - .store(input.seen_viewport_percentages(), Ordering::Release); + (rules, input.seen_viewport_percentages()) } /// Creates an empty stylesheet and parses it with a given base url, origin @@ -611,28 +628,21 @@ impl Stylesheet { stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) -> Stylesheet { - let s = Stylesheet { + let mut namespaces = Namespaces::default(); + let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules( + css, &base_url, origin, &mut namespaces, &shared_lock, + stylesheet_loader, error_reporter, extra_data, + ); + Stylesheet { origin: origin, base_url: base_url, - namespaces: RwLock::new(Namespaces::default()), - rules: CssRules::new(Vec::new(), &shared_lock), + namespaces: RwLock::new(namespaces), + rules: CssRules::new(rules, &shared_lock), media: Arc::new(shared_lock.wrap(media)), shared_lock: shared_lock, - dirty_on_viewport_size_change: AtomicBool::new(false), + dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change), disabled: AtomicBool::new(false), - }; - - { - let mut guard = s.shared_lock.write(); - Self::update_from_str(&s, - css, - &mut guard, - stylesheet_loader, - error_reporter, - extra_data); } - - s } /// Whether this stylesheet can be dirty on viewport size change. diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index f39e4a903cc..82cbd7aef74 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -362,8 +362,6 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut guard = global_style_data.shared_lock.write(); let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let extra_data = unsafe { ParserContextExtraData { base: Some(GeckoArcURI::new(base)), @@ -384,10 +382,7 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet }; let sheet = Stylesheet::as_arc(&stylesheet); - sheet.rules.write_with(&mut guard).0.clear(); - - Stylesheet::update_from_str(&sheet, input, &mut guard, loader, - &StdoutErrorReporter, extra_data); + Stylesheet::update_from_str(&sheet, input, loader, &StdoutErrorReporter, extra_data); } #[no_mangle] From 2952ccfae2e4883efc4886988dcf17d07d89f66c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 15:41:50 +0100 Subject: [PATCH 16/17] Fix another deadlock --- components/script/dom/cssrulelist.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index bc77361b5ae..1f1573a05d5 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -90,9 +90,12 @@ impl CSSRuleList { let index = idx as usize; let parent_stylesheet = self.parent_stylesheet.style_stylesheet(); - let mut guard = parent_stylesheet.shared_lock.write(); - let new_rule = css_rules.write_with(&mut guard) - .insert_rule(rule, parent_stylesheet, index, nested)?; + let new_rule = { + let mut guard = parent_stylesheet.shared_lock.write(); + css_rules.write_with(&mut guard).insert_rule(rule, parent_stylesheet, index, nested)? + // Drop `guard` here, + // CSSRule::new_specific re-acquires the lock for @support and @media. + }; let parent_stylesheet = &*self.parent_stylesheet; let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule); From d5074136e303544d108dc5615f96e92b854752ee Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 18 Mar 2017 20:12:23 +0100 Subject: [PATCH 17/17] Rename ReadGuards to StylesheetGuards --- components/layout_thread/lib.rs | 8 ++++---- components/style/context.rs | 4 ++-- components/style/gecko/data.rs | 4 ++-- components/style/properties/properties.mako.rs | 4 ++-- components/style/rule_tree/mod.rs | 12 ++++++------ components/style/shared_lock.rs | 6 +++--- components/style/stylist.rs | 12 ++++++------ ports/geckolib/glue.rs | 8 ++++---- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 32708911484..1ebee7b5ead 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -116,7 +116,7 @@ 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, ReadGuards}; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards}; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; use style::stylist::Stylist; use style::thread_state; @@ -500,7 +500,7 @@ impl LayoutThread { // Create a layout context for use in building display lists, hit testing, &c. fn build_layout_context<'a>(&self, - guards: ReadGuards<'a>, + guards: StylesheetGuards<'a>, rw_data: &LayoutThreadData, request_images: bool) -> LayoutContext<'a> { @@ -1069,7 +1069,7 @@ impl LayoutThread { // If the entire flow tree is invalid, then it will be reflowed anyhow. let ua_stylesheets = &*UA_STYLESHEETS; let ua_or_user_guard = ua_stylesheets.shared_lock.read(); - let guards = ReadGuards { + let guards = StylesheetGuards { author: &author_guard, ua_or_user: &ua_or_user_guard, }; @@ -1353,7 +1353,7 @@ impl LayoutThread { let author_guard = AUTHOR_SHARED_LOCK.read(); let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read(); - let guards = ReadGuards { + let guards = StylesheetGuards { author: &author_guard, ua_or_user: &ua_or_user_guard, }; diff --git a/components/style/context.rs b/components/style/context.rs index 93dfde0932b..3a2926672ac 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -17,7 +17,7 @@ use parking_lot::RwLock; use selector_parser::PseudoElement; use selectors::matching::ElementSelectorFlags; use servo_config::opts; -use shared_lock::ReadGuards; +use shared_lock::StylesheetGuards; use std::collections::HashMap; use std::env; use std::fmt; @@ -67,7 +67,7 @@ pub struct SharedStyleContext<'a> { pub stylist: Arc, /// Guards for pre-acquired locks - pub guards: ReadGuards<'a>, + pub guards: StylesheetGuards<'a>, /// The animations that are currently running. pub running_animations: Arc>>>, diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index ad6a1d1629c..a1ef6db3e2e 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -13,7 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use media_queries::Device; use parking_lot::RwLock; use properties::ComputedValues; -use shared_lock::{ReadGuards, SharedRwLockReadGuard}; +use shared_lock::{StylesheetGuards, SharedRwLockReadGuard}; use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; @@ -97,7 +97,7 @@ impl PerDocumentStyleDataImpl { pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) { if self.stylesheets_changed { let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); - stylist.update(&self.stylesheets, &ReadGuards::same(guard), None, true); + stylist.update(&self.stylesheets, &StylesheetGuards::same(guard), None, true); self.stylesheets_changed = false; } } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 1ae30358efa..f9c2cac07b6 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -31,7 +31,7 @@ use parser::{Parse, ParserContext, ParserContextExtraData}; use properties::animated_properties::TransitionProperty; #[cfg(feature = "servo")] use servo_config::prefs::PREFS; use servo_url::ServoUrl; -use shared_lock::ReadGuards; +use shared_lock::StylesheetGuards; use style_traits::ToCss; use stylesheets::Origin; #[cfg(feature = "servo")] use values::Either; @@ -1861,7 +1861,7 @@ bitflags! { /// pub fn cascade(device: &Device, rule_node: &StrongRuleNode, - guards: &ReadGuards, + guards: &StylesheetGuards, parent_style: Option<<&ComputedValues>, layout_parent_style: Option<<&ComputedValues>, cascade_info: Option<<&mut CascadeInfo>, diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 80aa88596d6..54cf785e458 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -11,7 +11,7 @@ use arc_ptr_eq; #[cfg(feature = "servo")] use heapsize::HeapSizeOf; use properties::{Importance, PropertyDeclarationBlock}; -use shared_lock::{Locked, ReadGuards, SharedRwLockReadGuard}; +use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use std::io::{self, Write}; use std::ptr; use std::sync::Arc; @@ -110,13 +110,13 @@ impl RuleTree { self.root.clone() } - fn dump(&self, guards: &ReadGuards, writer: &mut W) { + fn dump(&self, guards: &StylesheetGuards, writer: &mut W) { let _ = writeln!(writer, " + RuleTree"); self.root.get().dump(guards, writer, 0); } /// Dump the rule tree to stdout. - pub fn dump_stdout(&self, guards: &ReadGuards) { + pub fn dump_stdout(&self, guards: &StylesheetGuards) { let mut stdout = io::stdout(); self.dump(guards, &mut stdout); } @@ -162,7 +162,7 @@ impl RuleTree { level: CascadeLevel, pdb: Option<&Arc>>, path: &StrongRuleNode, - guards: &ReadGuards) + guards: &StylesheetGuards) -> Option { debug_assert!(level.is_unique_per_element()); // TODO(emilio): Being smarter with lifetimes we could avoid a bit of @@ -282,7 +282,7 @@ pub enum CascadeLevel { impl CascadeLevel { /// Select a lock guard for this level - pub fn guard<'a>(&self, guards: &'a ReadGuards<'a>) -> &'a SharedRwLockReadGuard<'a> { + pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> { match *self { CascadeLevel::UANormal | CascadeLevel::UserNormal | @@ -435,7 +435,7 @@ impl RuleNode { } } - fn dump(&self, guards: &ReadGuards, writer: &mut W, indent: usize) { + fn dump(&self, guards: &StylesheetGuards, writer: &mut W, indent: usize) { const INDENT_INCREMENT: usize = 4; for _ in 0..indent { diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs index c92ab9efccf..152e2b6ba82 100644 --- a/components/style/shared_lock.rs +++ b/components/style/shared_lock.rs @@ -180,7 +180,7 @@ pub trait ToCssWithGuard { /// Guards for a document #[derive(Clone)] -pub struct ReadGuards<'a> { +pub struct StylesheetGuards<'a> { /// For author-origin stylesheets pub author: &'a SharedRwLockReadGuard<'a>, @@ -188,10 +188,10 @@ pub struct ReadGuards<'a> { pub ua_or_user: &'a SharedRwLockReadGuard<'a>, } -impl<'a> ReadGuards<'a> { +impl<'a> StylesheetGuards<'a> { /// Same guard for all origins pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self { - ReadGuards { + StylesheetGuards { author: guard, ua_or_user: guard, } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index d58e0dd0e85..27d3dd4b10b 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -27,7 +27,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use selectors::parser::SelectorMethods; -use shared_lock::{Locked, SharedRwLockReadGuard, ReadGuards}; +use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use sink::Push; use smallvec::VecLike; use std::borrow::Borrow; @@ -158,7 +158,7 @@ impl Stylist { /// device is dirty, which means we need to re-evaluate media queries. pub fn update(&mut self, doc_stylesheets: &[Arc], - guards: &ReadGuards, + guards: &StylesheetGuards, ua_stylesheets: Option<&UserAgentStylesheets>, stylesheets_changed: bool) -> bool { if !(self.is_device_dirty || stylesheets_changed) { @@ -299,7 +299,7 @@ impl Stylist { /// values. The flow constructor uses this flag when constructing anonymous /// flows. pub fn precomputed_values_for_pseudo(&self, - guards: &ReadGuards, + guards: &StylesheetGuards, pseudo: &PseudoElement, parent: Option<&Arc>, cascade_flags: CascadeFlags) @@ -345,7 +345,7 @@ impl Stylist { /// Returns the style for an anonymous box of the given type. #[cfg(feature = "servo")] pub fn style_for_anonymous_box(&self, - guards: &ReadGuards, + guards: &StylesheetGuards, pseudo: &PseudoElement, parent_style: &Arc) -> Arc { @@ -382,7 +382,7 @@ impl Stylist { /// Check the documentation on lazy pseudo-elements in /// docs/components/style.md pub fn lazily_compute_pseudo_element_style(&self, - guards: &ReadGuards, + guards: &StylesheetGuards, element: &E, pseudo: &PseudoElement, parent: &Arc) @@ -544,7 +544,7 @@ impl Stylist { style_attribute: Option<&Arc>>, animation_rules: AnimationRules, pseudo_element: Option<&PseudoElement>, - guards: &ReadGuards, + guards: &StylesheetGuards, applicable_declarations: &mut V, flags: &mut ElementSelectorFlags) -> StyleRelations where E: TElement + diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 82cbd7aef74..177a6c076e8 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -74,7 +74,7 @@ use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::selector_parser::PseudoElementCascadeType; use style::sequential; -use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ReadGuards, ToCssWithGuard, Locked}; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; @@ -129,7 +129,7 @@ fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard, SharedStyleContext { stylist: per_doc_data.stylist.clone(), - guards: ReadGuards::same(guard), + guards: StylesheetGuards::same(guard), running_animations: per_doc_data.running_animations.clone(), expired_animations: per_doc_data.expired_animations.clone(), // FIXME(emilio): Stop boxing here. @@ -642,7 +642,7 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: -> ServoComputedValuesStrong { let global_style_data = &*GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read(); - let guards = ReadGuards::same(&guard); + let guards = StylesheetGuards::same(&guard); let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let atom = Atom::from(pseudo_tag); let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true); @@ -699,7 +699,7 @@ fn get_pseudo_style(guard: &SharedRwLockReadGuard, element: GeckoElement, pseudo PseudoElementCascadeType::Lazy => { let d = doc_data.borrow_mut(); let base = styles.primary.values(); - let guards = ReadGuards::same(guard); + let guards = StylesheetGuards::same(guard); d.stylist.lazily_compute_pseudo_element_style(&guards, &element, &pseudo,