servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio
authorSimon Sapin <simon.sapin@exyr.org>
Sun, 19 Mar 2017 14:31:19 -0700
changeset 348381 e3e83e6bf4096e76458b7753afd91d082626b348
parent 348380 c6e919aa3aa9d1e73d3e649a1bae7c8488f05554
child 348382 1f17eeabf363349bd01b0c6c4edfaf58ade60c6e
push id31522
push usercbook@mozilla.com
push dateMon, 20 Mar 2017 12:09:19 +0000
treeherdermozilla-central@cb4e80abb488 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664
servo/Cargo.lock
servo/components/layout/block.rs
servo/components/layout/construct.rs
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/generated_content.rs
servo/components/layout/traversal.rs
servo/components/layout_thread/lib.rs
servo/components/script/dom/bindings/trace.rs
servo/components/script/dom/cssconditionrule.rs
servo/components/script/dom/cssfontfacerule.rs
servo/components/script/dom/cssgroupingrule.rs
servo/components/script/dom/cssimportrule.rs
servo/components/script/dom/csskeyframerule.rs
servo/components/script/dom/csskeyframesrule.rs
servo/components/script/dom/cssmediarule.rs
servo/components/script/dom/cssnamespacerule.rs
servo/components/script/dom/cssrule.rs
servo/components/script/dom/cssrulelist.rs
servo/components/script/dom/cssstyledeclaration.rs
servo/components/script/dom/cssstylerule.rs
servo/components/script/dom/cssstylesheet.rs
servo/components/script/dom/csssupportsrule.rs
servo/components/script/dom/cssviewportrule.rs
servo/components/script/dom/document.rs
servo/components/script/dom/element.rs
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmetaelement.rs
servo/components/script/dom/htmlstyleelement.rs
servo/components/script/dom/medialist.rs
servo/components/script/layout_wrapper.rs
servo/components/script/stylesheet_loader.rs
servo/components/script_layout_interface/wrapper_traits.rs
servo/components/style/Cargo.toml
servo/components/style/animation.rs
servo/components/style/attr.rs
servo/components/style/context.rs
servo/components/style/dom.rs
servo/components/style/encoding_support.rs
servo/components/style/font_face.rs
servo/components/style/gecko/arc_types.rs
servo/components/style/gecko/data.rs
servo/components/style/gecko/global_style_data.rs
servo/components/style/gecko/mod.rs
servo/components/style/gecko/traversal.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/keyframes.rs
servo/components/style/lib.rs
servo/components/style/matching.rs
servo/components/style/owning_handle.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/rule_tree/mod.rs
servo/components/style/servo/mod.rs
servo/components/style/shared_lock.rs
servo/components/style/stylesheets.rs
servo/components/style/stylist.rs
servo/components/style/traversal.rs
servo/components/style/viewport.rs
servo/ports/geckolib/Cargo.toml
servo/ports/geckolib/glue.rs
servo/ports/geckolib/lib.rs
servo/ports/geckolib/stylesheet_loader.rs
servo/tests/unit/style/Cargo.toml
servo/tests/unit/style/keyframes.rs
servo/tests/unit/style/lib.rs
servo/tests/unit/style/media_queries.rs
servo/tests/unit/style/owning_handle.rs
servo/tests/unit/style/rule_tree/bench.rs
servo/tests/unit/style/stylesheets.rs
servo/tests/unit/style/stylist.rs
servo/tests/unit/style/viewport.rs
servo/tests/unit/stylo/lib.rs
servo/tests/unit/stylo/servo_function_signatures.rs
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -923,19 +923,17 @@ name = "geckoservo"
 version = "0.0.1"
 dependencies = [
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "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",
  "style_traits 0.0.1",
  "stylo_tests 0.0.1",
 ]
 
 [[package]]
@@ -2751,18 +2749,18 @@ dependencies = [
  "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "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)",
- "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)",
  "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.18.0",
  "serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
@@ -2778,17 +2776,16 @@ dependencies = [
 [[package]]
 name = "style_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "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)",
  "selectors 0.18.0",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -441,17 +441,17 @@ fn translate_including_floats(cur_b: &mu
 /// absolute Containing Block.
 /// - Thus, leaf nodes and inner non-root nodes are all Absolute Flows.
 ///
 /// A Flow tree can have several Absolute Flow trees (depending on the number
 /// of relatively positioned flows it has).
 ///
 /// 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]
     fn process(&self, flow: &mut Flow) {
         {
             // The root of the absolute flow tree is definitely not absolutely
             // positioned. Nothing to process here.
             let flow: &Flow = flow;
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -306,26 +306,26 @@ impl InlineFragmentsAccumulator {
         }
         fragments
     }
 }
 
 /// 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<N>,
 }
 
 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,
         }
     }
 
     #[inline]
     fn style_context(&self) -> &SharedStyleContext {
@@ -655,20 +655,19 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
             if node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement)) {
                 for kid in node.children() {
                     self.set_flow_construction_result(&kid, ConstructionResult::None)
                 }
             }
 
             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)
         }
 
         self.build_flow_for_block_starting_with_fragments(flow, node, initial_fragments)
     }
 
@@ -1091,21 +1090,24 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
     }
 
     /// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with
     /// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
     fn build_flow_for_table(&mut self, node: &ConcreteThreadSafeLayoutNode, float_value: float::T)
                             -> 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,
                                                  wrapper_style,
                                                  node.selected_style(),
                                                  node.restyle_damage(),
                                                  SpecificFragmentInfo::TableWrapper);
         let wrapper_float_kind = FloatKind::from_property(float_value);
@@ -2075,18 +2077,17 @@ impl Legalizer {
                                 pseudos: &[PseudoElement],
                                 specific_fragment_info: SpecificFragmentInfo,
                                 constructor: extern "Rust" fn(Fragment) -> F)
                                 -> FlowRef
                                 where F: Flow {
         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,
                                                                          specific_fragment_info);
         FlowRef::new(Arc::new(constructor(fragment)))
     }
 }
 
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -70,19 +70,19 @@ pub fn heap_size_of_persistent_local_con
             context.heap_size_of_children()
         } else {
             0
         }
     })
 }
 
 /// 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<ImageCacheThread>,
 
     /// Interface to the font cache thread.
     pub font_cache_thread: Mutex<FontCacheThread>,
 
     /// A cache of WebRender image info.
@@ -90,27 +90,27 @@ pub struct LayoutContext {
                                                   WebRenderImageInfo,
                                                   BuildHasherDefault<FnvHasher>>>>,
 
     /// A list of in-progress image loads to be shared with the script thread.
     /// A None value means that this layout was not initiated by the script thread.
     pub pending_images: Option<Mutex<Vec<PendingImage>>>
 }
 
-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 {
                 assert!(pending_images.lock().unwrap().is_empty());
             }
         }
     }
 }
 
-impl LayoutContext {
+impl<'a> LayoutContext<'a> {
     #[inline(always)]
     pub fn shared_context(&self) -> &SharedStyleContext {
         &self.style_context
     }
 
     pub fn get_or_request_image_or_meta(&self,
                                         node: OpaqueNode,
                                         url: ServoUrl,
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -116,17 +116,17 @@ static THREAD_TINT_COLORS: [ColorF; 8] =
     ColorF { r: 137.0 / 255.0, g: 196.0 / 255.0, b: 78.0 / 255.0, a: 0.7 },
 ];
 
 fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
     &arr[index % arr.len()]
 }
 
 pub struct DisplayListBuildState<'a> {
-    pub layout_context: &'a LayoutContext,
+    pub layout_context: &'a LayoutContext<'a>,
     pub root_stacking_context: StackingContext,
     pub items: HashMap<StackingContextId, Vec<DisplayItem>>,
     pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>,
     pub scroll_roots: HashMap<ScrollRootId, ScrollRoot>,
     pub processing_scroll_root_element: bool,
 
     /// The current stacking context id, used to keep track of state when building.
     /// recursively building and processing the display list.
--- a/servo/components/layout/generated_content.rs
+++ b/servo/components/layout/generated_content.rs
@@ -92,17 +92,17 @@ 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.
     counters: HashMap<String, Counter>,
     /// The level of quote nesting.
     quote: u32,
 }
 
--- a/servo/components/layout/traversal.rs
+++ b/servo/components/layout/traversal.rs
@@ -17,45 +17,45 @@ use style::data::ElementData;
 use style::dom::{NodeInfo, TElement, TNode};
 use style::selector_parser::RestyleDamage;
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
 use style::traversal::{DomTraversal, TraversalDriver, recalc_style_at};
 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,
         }
     }
 
     /// 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<E> DomTraversal<E> for RecalcStyleAndConstructFlows
+impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
     where E: TElement,
           E::ConcreteNode: LayoutNode,
 {
     type ThreadLocalContext = ScopedThreadLocalLayoutContext<E>;
 
     fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData,
                         thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) {
         // FIXME(pcwalton): Stop allocating here. Ideally this should just be
@@ -147,17 +147,17 @@ fn construct_flows_at<N>(context: &Layou
     if let Some(el) = node.as_element() {
         unsafe { el.unset_dirty_descendants(); }
     }
 }
 
 /// 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> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         flow.bubble_inline_sizes();
         flow::mut_base(flow).restyle_damage.remove(BUBBLE_ISIZES);
     }
@@ -166,17 +166,17 @@ impl<'a> PostorderFlowTraversal for Bubb
     fn should_process(&self, flow: &mut Flow) -> bool {
         flow::base(flow).restyle_damage.contains(BUBBLE_ISIZES)
     }
 }
 
 /// 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> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         flow.assign_inline_sizes(self.layout_context);
     }
 
@@ -186,17 +186,17 @@ impl<'a> PreorderFlowTraversal for Assig
     }
 }
 
 /// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of
 /// layout computation. Determines the final block-sizes for all layout objects and computes
 /// 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> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         // Can't do anything with anything that floats might flow through until we reach their
         // inorder parent.
         //
@@ -215,17 +215,17 @@ impl<'a> PostorderFlowTraversal for Assi
         base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) &&
         // The fragmentation countainer is responsible for calling Flow::fragment recursively
         !base.flags.contains(CAN_BE_FRAGMENTED)
     }
 }
 
 #[derive(Copy, Clone)]
 pub struct ComputeAbsolutePositions<'a> {
-    pub layout_context: &'a LayoutContext,
+    pub layout_context: &'a LayoutContext<'a>,
 }
 
 impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         flow.compute_absolute_position(self.layout_context);
     }
 }
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -109,17 +109,19 @@ use std::thread;
 use style::animation::Animation;
 use style::context::{QuirksMode, ReflowGoal, SharedStyleContext, ThreadLocalStyleContextCreationInfo};
 use style::data::StoredRestyleHint;
 use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
 use style::error_reporting::StdoutErrorReporter;
 use style::logical_geometry::LogicalPoint;
 use style::media_queries::{Device, MediaType};
 use style::parser::ParserContextExtraData;
+use style::servo::AUTHOR_SHARED_LOCK;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
+use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
 use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
 use style::stylist::Stylist;
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::{DomTraversal, TraversalDriver};
 
 /// Information needed by the layout thread.
 pub struct LayoutThread {
@@ -209,17 +211,17 @@ pub struct LayoutThread {
 
     /// The CSS error reporter for all CSS loaded in this layout thread
     error_reporter: CSSErrorReporter,
 
     webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder),
                                               WebRenderImageInfo,
                                               BuildHasherDefault<FnvHasher>>>>,
 
-    // Webrender interface.
+    /// Webrender interface.
     webrender_api: webrender_traits::RenderApi,
 
     /// The timer object to control the timing of the animations. This should
     /// only be a test-mode timer during testing for animations.
     timer: Timer,
 
     // Number of layout threads. This is copied from `servo_config::opts`, but we'd
     // rather limit the dependency on that module here.
@@ -339,31 +341,32 @@ impl<'a, 'b: 'a> RwData<'a, 'b> {
         match rw_data {
             RWGuard::Used(x) => drop(x),
             RWGuard::Held(x) => *self.possibly_locked_rw_data = Some(x),
         }
     }
 }
 
 fn add_font_face_rules(stylesheet: &Stylesheet,
+                       guard: &SharedRwLockReadGuard,
                        device: &Device,
                        font_cache_thread: &FontCacheThread,
                        font_cache_sender: &IpcSender<()>,
                        outstanding_web_fonts_counter: &Arc<AtomicUsize>) {
     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,
                                            sender.clone());
             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(),
                                           effective_sources,
                                           (*font_cache_sender).clone());
         })
     }
 }
@@ -401,18 +404,21 @@ impl LayoutThread {
 
         // Ask the router to proxy IPC messages from the font cache thread to the layout thread.
         let (ipc_font_cache_sender, ipc_font_cache_receiver) = ipc::channel().unwrap();
         let font_cache_receiver =
             ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_font_cache_receiver);
 
         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,
                                 &outstanding_web_fonts_counter);
         }
 
         LayoutThread {
             id: id,
@@ -488,26 +494,28 @@ impl LayoutThread {
             possibly_locked_rw_data: &mut possibly_locked_rw_data,
         };
         while self.handle_request(&mut rw_data) {
             // Loop indefinitely.
         }
     }
 
     // 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: StylesheetGuards<'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()),
                 local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
                 timer: self.timer.clone(),
                 quirks_mode: self.quirks_mode.unwrap(),
             },
             image_cache_thread: Mutex::new(self.image_cache_thread.clone()),
@@ -725,18 +733,20 @@ impl LayoutThread {
 
     fn handle_add_stylesheet<'a, 'b>(&self,
                                      stylesheet: Arc<Stylesheet>,
                                      possibly_locked_rw_data: &mut RwData<'a, 'b>) {
         // Find all font-face rules and notify the font cache of them.
         // 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,
+                                &guard,
                                 &rw_data.stylist.device,
                                 &self.font_cache_thread,
                                 &self.font_cache_sender,
                                 &self.outstanding_web_fonts);
         }
 
         possibly_locked_rw_data.block(rw_data);
     }
@@ -1004,18 +1014,21 @@ impl LayoutThread {
         debug!("{:?}", ShowSubtree(element.as_node()));
 
         let initial_viewport = data.window_size.initial_viewport;
         let old_viewport_size = self.viewport_size;
         let current_screen_size = Size2D::new(Au::from_f32_px(initial_viewport.width),
                                               Au::from_f32_px(initial_viewport.height));
 
         // Calculate the actual viewport as per DEVICE-ADAPT § 6
+
+        let author_guard = document.style_shared_lock().read();
         let 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, &author_guard, &data.document_stylesheets);
 
         self.viewport_size =
             rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| {
                 debug!("Viewport constraints: {:?}", constraints);
 
                 // other rules are evaluated against the actual viewport
                 Size2D::new(Au::from_f32_px(constraints.size.width),
                             Au::from_f32_px(constraints.size.height))
@@ -1049,19 +1062,27 @@ impl LayoutThread {
                     } else {
                         next = iter.next();
                     }
                 }
             }
         }
 
         // 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 ua_stylesheets = &*UA_STYLESHEETS;
+        let ua_or_user_guard = ua_stylesheets.shared_lock.read();
+        let guards = StylesheetGuards {
+            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,
+            &guards,
+            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() {
                 if d.has_styles() {
                     d.ensure_restyle().hint.insert(&StoredRestyleHint::subtree());
                 }
             }
         }
@@ -1097,17 +1118,17 @@ impl LayoutThread {
                 if let Some(s) = restyle.snapshot {
                     restyle_data.snapshot.ensure(move || s);
                 }
                 debug!("Noting restyle for {:?}: {:?}", el, restyle_data);
             }
         }
 
         // 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() {
             TraversalDriver::Parallel
         } else {
             TraversalDriver::Sequential
         };
 
@@ -1156,17 +1177,17 @@ impl LayoutThread {
 
         layout_context = traversal.destroy();
 
         if opts::get().dump_style_tree {
             println!("{:?}", ShowSubtreeDataAndPrimaryValues(element.as_node()));
         }
 
         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.
         unsafe { layout_context.style_context.stylist.rule_tree.maybe_gc(); }
 
         // Perform post-style recalculation layout passes.
         self.perform_post_style_recalc_layout_passes(&data.reflow_info,
                                                      Some(&data.query_type),
@@ -1325,17 +1346,23 @@ impl LayoutThread {
             println!("**** pipeline={}\tForDisplay\tSpecial\tAnimationTick", self.id);
         }
 
         let reflow_info = Reflow {
             goal: ReflowGoal::ForDisplay,
             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 = StylesheetGuards {
+            author: &author_guard,
+            ua_or_user: &ua_or_user_guard,
+        };
+        let mut layout_context = self.build_layout_context(guards, &*rw_data, false);
 
         if let Some(mut root_flow) = self.root_flow.clone() {
             // Perform an abbreviated style recalc that operates without access to the DOM.
             let animations = self.running_animations.read();
             profile(time::ProfilerCategory::LayoutStyleRecalc,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || {
@@ -1523,45 +1550,49 @@ fn get_root_flow_background_color(flow: 
     let kid_block_flow = kid.as_block();
     kid_block_flow.fragment
                   .style
                   .resolve_color(kid_block_flow.fragment.style.get_background().background_color)
                   .to_gfx_color()
 }
 
 fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
-    fn parse_ua_stylesheet(filename: &'static str) -> Result<Stylesheet, &'static str> {
+    fn parse_ua_stylesheet(shared_lock: &SharedRwLock, filename: &'static str)
+                           -> Result<Stylesheet, &'static str> {
         let res = try!(read_resource_file(filename).map_err(|_| filename));
         Ok(Stylesheet::from_bytes(
             &res,
             ServoUrl::parse(&format!("chrome://resources/{:?}", filename)).unwrap(),
             None,
             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,
     })
 }
 
 /// Returns true if the given reflow query type needs a full, up-to-date display list to be present
 /// or false if it only needs stacking-relative positions.
 fn reflow_query_type_needs_display_list(query_type: &ReflowQueryType) -> bool {
--- a/servo/components/script/dom/bindings/trace.rs
+++ b/servo/components/script/dom/bindings/trace.rs
@@ -94,16 +94,17 @@ use std::time::{SystemTime, Instant};
 use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
 use style::context::QuirksMode;
 use style::element_state::*;
 use style::font_face::FontFaceRule;
 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, Locked as StyleLocked};
 use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule};
 use style::stylesheets::SupportsRule;
 use style::values::specified::Length;
 use style::viewport::ViewportRule;
 use time::Duration;
 use uuid::Uuid;
 use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
 use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId};
@@ -355,16 +356,17 @@ unsafe_no_jsmanaged_fields!(Mime);
 unsafe_no_jsmanaged_fields!(AttrIdentifier);
 unsafe_no_jsmanaged_fields!(AttrValue);
 unsafe_no_jsmanaged_fields!(Snapshot);
 unsafe_no_jsmanaged_fields!(PendingRestyle);
 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);
 unsafe_no_jsmanaged_fields!(Response);
 unsafe_no_jsmanaged_fields!(ResponseBody);
 unsafe_no_jsmanaged_fields!(ResourceThreads);
 unsafe_no_jsmanaged_fields!(StatusCode);
 unsafe_no_jsmanaged_fields!(SystemTime);
@@ -495,89 +497,89 @@ unsafe impl JSTraceable for Size2D<i32> 
 }
 
 unsafe impl JSTraceable for Mutex<Option<SharedRt>> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<FontFaceRule> {
+unsafe impl JSTraceable for StyleLocked<FontFaceRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<CssRules> {
+unsafe impl JSTraceable for StyleLocked<CssRules> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<Keyframe> {
+unsafe impl JSTraceable for StyleLocked<Keyframe> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<KeyframesRule> {
+unsafe impl JSTraceable for StyleLocked<KeyframesRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<ImportRule> {
+unsafe impl JSTraceable for StyleLocked<ImportRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<SupportsRule> {
+unsafe impl JSTraceable for StyleLocked<SupportsRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<MediaRule> {
+unsafe impl JSTraceable for StyleLocked<MediaRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<NamespaceRule> {
+unsafe impl JSTraceable for StyleLocked<NamespaceRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<StyleRule> {
+unsafe impl JSTraceable for StyleLocked<StyleRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<ViewportRule> {
+unsafe impl JSTraceable for StyleLocked<ViewportRule> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<PropertyDeclarationBlock> {
+unsafe impl JSTraceable for StyleLocked<PropertyDeclarationBlock> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
 unsafe impl JSTraceable for RwLock<SharedRt> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
-unsafe impl JSTraceable for RwLock<MediaList> {
+unsafe impl JSTraceable for StyleLocked<MediaList> {
     unsafe fn trace(&self, _trc: *mut JSTracer) {
         // Do nothing.
     }
 }
 
 /// Holds a set of JSTraceables that need to be rooted
 struct RootedTraceableSet {
     set: Vec<*const JSTraceable>,
--- a/servo/components/script/dom/cssconditionrule.rs
+++ b/servo/components/script/dom/cssconditionrule.rs
@@ -5,33 +5,40 @@
 use dom::bindings::codegen::Bindings::CSSConditionRuleBinding::CSSConditionRuleMethods;
 use dom::bindings::inheritance::Castable;
 use dom::bindings::str::DOMString;
 use dom::cssgroupingrule::CSSGroupingRule;
 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, Locked};
 use style::stylesheets::CssRules as StyleCssRules;
 
 #[dom_struct]
 pub struct CSSConditionRule {
     cssgroupingrule: CSSGroupingRule,
 }
 
 impl CSSConditionRule {
     pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
-                         rules: Arc<RwLock<StyleCssRules>>) -> CSSConditionRule {
+                         rules: Arc<Locked<StyleCssRules>>) -> CSSConditionRule {
         CSSConditionRule {
             cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules),
         }
     }
 
+    pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
+        self.cssgroupingrule.parent_stylesheet()
+    }
+
+    pub fn shared_lock(&self) -> &SharedRwLock {
+        self.cssgroupingrule.shared_lock()
+    }
 }
 
 impl CSSConditionRuleMethods for CSSConditionRule {
     /// https://drafts.csswg.org/css-conditional-3/#dom-cssconditionrule-conditiontext
     fn ConditionText(&self) -> DOMString {
         if let Some(rule) = self.downcast::<CSSMediaRule>() {
             rule.get_condition_text()
         } else if let Some(rule) = self.downcast::<CSSSupportsRule>() {
--- a/servo/components/script/dom/cssfontfacerule.rs
+++ b/servo/components/script/dom/cssfontfacerule.rs
@@ -5,48 +5,48 @@
 use dom::bindings::codegen::Bindings::CSSFontFaceRuleBinding;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 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_traits::ToCss;
+use style::shared_lock::{Locked, ToCssWithGuard};
 
 #[dom_struct]
 pub struct CSSFontFaceRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    fontfacerule: Arc<RwLock<FontFaceRule>>,
+    fontfacerule: Arc<Locked<FontFaceRule>>,
 }
 
 impl CSSFontFaceRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<Locked<FontFaceRule>>)
                      -> CSSFontFaceRule {
         CSSFontFaceRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             fontfacerule: fontfacerule,
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> {
+               fontfacerule: Arc<Locked<FontFaceRule>>) -> Root<CSSFontFaceRule> {
         reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule),
                            window,
                            CSSFontFaceRuleBinding::Wrap)
     }
 }
 
 impl SpecificCSSRule for CSSFontFaceRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::FONT_FACE_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.fontfacerule.read().to_css_string().into()
+        let guard = self.cssrule.shared_lock().read();
+        self.fontfacerule.read_with(&guard).to_css_string(&guard).into()
     }
 }
--- a/servo/components/script/dom/cssgroupingrule.rs
+++ b/servo/components/script/dom/cssgroupingrule.rs
@@ -7,44 +7,52 @@ use dom::bindings::error::{ErrorResult, 
 use dom::bindings::inheritance::Castable;
 use dom::bindings::js::{MutNullableJS, Root};
 use dom::bindings::reflector::DomObject;
 use dom::bindings::str::DOMString;
 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, Locked};
 use style::stylesheets::CssRules as StyleCssRules;
 
 #[dom_struct]
 pub struct CSSGroupingRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    rules: Arc<RwLock<StyleCssRules>>,
+    rules: Arc<Locked<StyleCssRules>>,
     rulelist: MutNullableJS<CSSRuleList>,
 }
 
 impl CSSGroupingRule {
     pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
-                         rules: Arc<RwLock<StyleCssRules>>) -> CSSGroupingRule {
+                         rules: Arc<Locked<StyleCssRules>>) -> CSSGroupingRule {
         CSSGroupingRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             rules: rules,
             rulelist: MutNullableJS::new(None),
         }
     }
 
     fn rulelist(&self) -> Root<CSSRuleList> {
         let parent_stylesheet = self.upcast::<CSSRule>().parent_stylesheet();
         self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(),
                                                   parent_stylesheet,
                                                   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()
+    }
 }
 
 impl CSSGroupingRuleMethods for CSSGroupingRule {
     // https://drafts.csswg.org/cssom/#dom-cssgroupingrule-cssrules
     fn CssRules(&self) -> Root<CSSRuleList> {
         // XXXManishearth check origin clean flag
         self.rulelist()
     }
--- a/servo/components/script/dom/cssimportrule.rs
+++ b/servo/components/script/dom/cssimportrule.rs
@@ -5,50 +5,50 @@
 use dom::bindings::codegen::Bindings::CSSImportRuleBinding;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 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::{Locked, ToCssWithGuard};
 use style::stylesheets::ImportRule;
-use style_traits::ToCss;
 
 #[dom_struct]
 pub struct CSSImportRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    import_rule: Arc<RwLock<ImportRule>>,
+    import_rule: Arc<Locked<ImportRule>>,
 }
 
 impl CSSImportRule {
     fn new_inherited(parent_stylesheet: &CSSStyleSheet,
-                     import_rule: Arc<RwLock<ImportRule>>)
+                     import_rule: Arc<Locked<ImportRule>>)
                      -> Self {
         CSSImportRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             import_rule: import_rule,
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window,
                parent_stylesheet: &CSSStyleSheet,
-               import_rule: Arc<RwLock<ImportRule>>) -> Root<Self> {
+               import_rule: Arc<Locked<ImportRule>>) -> Root<Self> {
         reflect_dom_object(box Self::new_inherited(parent_stylesheet, import_rule),
                            window,
                            CSSImportRuleBinding::Wrap)
     }
 }
 
 impl SpecificCSSRule for CSSImportRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::IMPORT_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.import_rule.read().to_css_string().into()
+        let guard = self.cssrule.shared_lock().read();
+        self.import_rule.read_with(&guard).to_css_string(&guard).into()
     }
 }
--- a/servo/components/script/dom/csskeyframerule.rs
+++ b/servo/components/script/dom/csskeyframerule.rs
@@ -7,63 +7,68 @@ use dom::bindings::inheritance::Castable
 use dom::bindings::js::{JS, MutNullableJS, Root};
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
 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_traits::ToCss;
+use style::shared_lock::{Locked, ToCssWithGuard};
 
 #[dom_struct]
 pub struct CSSKeyframeRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    keyframerule: Arc<RwLock<Keyframe>>,
+    keyframerule: Arc<Locked<Keyframe>>,
     style_decl: MutNullableJS<CSSStyleDeclaration>,
 }
 
 impl CSSKeyframeRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<RwLock<Keyframe>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<Locked<Keyframe>>)
                      -> CSSKeyframeRule {
         CSSKeyframeRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             keyframerule: keyframerule,
             style_decl: Default::default(),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               keyframerule: Arc<RwLock<Keyframe>>) -> Root<CSSKeyframeRule> {
+               keyframerule: Arc<Locked<Keyframe>>) -> Root<CSSKeyframeRule> {
         reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule),
                            window,
                            CSSKeyframeRuleBinding::Wrap)
     }
 }
 
 impl CSSKeyframeRuleMethods for CSSKeyframeRule {
     // https://drafts.csswg.org/css-animations/#dom-csskeyframerule-style
     fn Style(&self) -> Root<CSSStyleDeclaration> {
         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,
+            )
         })
     }
 }
 
 impl SpecificCSSRule for CSSKeyframeRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::KEYFRAME_RULE
     }
 
     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(&guard).into()
     }
 }
--- a/servo/components/script/dom/csskeyframesrule.rs
+++ b/servo/components/script/dom/csskeyframesrule.rs
@@ -11,45 +11,44 @@ use dom::bindings::js::{MutNullableJS, R
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::csskeyframerule::CSSKeyframeRule;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 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::{Locked, ToCssWithGuard};
 use style::stylesheets::KeyframesRule;
-use style_traits::ToCss;
 
 #[dom_struct]
 pub struct CSSKeyframesRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    keyframesrule: Arc<RwLock<KeyframesRule>>,
+    keyframesrule: Arc<Locked<KeyframesRule>>,
     rulelist: MutNullableJS<CSSRuleList>,
 }
 
 impl CSSKeyframesRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<Locked<KeyframesRule>>)
                      -> CSSKeyframesRule {
         CSSKeyframesRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             keyframesrule: keyframesrule,
             rulelist: MutNullableJS::new(None),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> {
+               keyframesrule: Arc<Locked<KeyframesRule>>) -> Root<CSSKeyframesRule> {
         reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule),
                            window,
                            CSSKeyframesRuleBinding::Wrap)
     }
 
     fn rulelist(&self) -> Root<CSSRuleList> {
         self.rulelist.or_init(|| {
             let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet();
@@ -58,21 +57,22 @@ impl CSSKeyframesRule {
                              RulesSource::Keyframes(self.keyframesrule.clone()))
         })
     }
 
     /// Given a keyframe selector, finds the index of the first corresponding rule if any
     fn find_rule(&self, selector: &str) -> Option<usize> {
         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
+                    frame.read_with(&guard).selector == sel
                 })
         } else {
             None
         }
     }
 }
 
 impl CSSKeyframesRuleMethods for CSSKeyframesRule {
@@ -81,17 +81,18 @@ impl CSSKeyframesRuleMethods for CSSKeyf
         self.rulelist()
     }
 
     // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-appendrule
     fn AppendRule(&self, rule: DOMString) {
         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();
         }
     }
 
     // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
     fn DeleteRule(&self, selector: DOMString) {
         if let Some(idx) = self.find_rule(&selector) {
             let _ = self.rulelist().remove_rule(idx as u32);
@@ -102,42 +103,45 @@ impl CSSKeyframesRuleMethods for CSSKeyf
     fn FindRule(&self, selector: DOMString) -> Option<Root<CSSKeyframeRule>> {
         self.find_rule(&selector).and_then(|idx| {
             self.rulelist().item(idx as u32)
         }).and_then(Root::downcast)
     }
 
     // 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
     fn SetName(&self, value: DOMString) -> ErrorResult {
         // https://github.com/w3c/csswg-drafts/issues/801
         // Setting this property to a CSS-wide keyword or `none` will
         // throw a Syntax Error.
         match_ignore_ascii_case! { &value,
             "initial" => return Err(Error::Syntax),
             "inherit" => return Err(Error::Syntax),
             "unset" => return Err(Error::Syntax),
             "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(())
     }
 }
 
 impl SpecificCSSRule for CSSKeyframesRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::KEYFRAMES_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.keyframesrule.read().to_css_string().into()
+        let guard = self.cssrule.shared_lock().read();
+        self.keyframesrule.read_with(&guard).to_css_string(&guard).into()
     }
 
     fn deparent_children(&self) {
         self.rulelist.get().map(|list| list.deparent_all());
     }
 }
--- a/servo/components/script/dom/cssmediarule.rs
+++ b/servo/components/script/dom/cssmediarule.rs
@@ -9,79 +9,93 @@ use dom::bindings::js::{MutNullableJS, R
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssconditionrule::CSSConditionRule;
 use dom::cssrule::SpecificCSSRule;
 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::{Locked, 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<RwLock<MediaRule>>,
+    mediarule: Arc<Locked<MediaRule>>,
     medialist: MutNullableJS<MediaList>,
 }
 
 impl CSSMediaRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<Locked<MediaRule>>)
                      -> CSSMediaRule {
-        let list = mediarule.read().rules.clone();
+        let guard = parent_stylesheet.shared_lock().read();
+        let list = mediarule.read_with(&guard).rules.clone();
         CSSMediaRule {
-            cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
+            cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
             mediarule: mediarule,
             medialist: MutNullableJS::new(None),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> {
+               mediarule: Arc<Locked<MediaRule>>) -> Root<CSSMediaRule> {
         reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule),
                            window,
                            CSSMediaRuleBinding::Wrap)
     }
 
     fn medialist(&self) -> Root<MediaList> {
-        self.medialist.or_init(|| MediaList::new(self.global().as_window(),
-                                                 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 rule = self.mediarule.read();
-        let list = rule.media_queries.read();
+        let guard = self.cssconditionrule.shared_lock().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 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();
-        *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;
     }
 }
 
 impl SpecificCSSRule for CSSMediaRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::MEDIA_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.mediarule.read().to_css_string().into()
+        let guard = self.cssconditionrule.shared_lock().read();
+        self.mediarule.read_with(&guard).to_css_string(&guard).into()
     }
 }
 
 impl CSSMediaRuleMethods for CSSMediaRule {
     // https://drafts.csswg.org/cssom/#dom-cssgroupingrule-media
     fn Media(&self) -> Root<MediaList> {
         self.medialist()
     }
--- a/servo/components/script/dom/cssnamespacerule.rs
+++ b/servo/components/script/dom/cssnamespacerule.rs
@@ -6,62 +6,64 @@ use dom::bindings::codegen::Bindings::CS
 use dom::bindings::codegen::Bindings::CSSNamespaceRuleBinding::CSSNamespaceRuleMethods;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 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::{Locked, ToCssWithGuard};
 use style::stylesheets::NamespaceRule;
-use style_traits::ToCss;
 
 #[dom_struct]
 pub struct CSSNamespaceRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    namespacerule: Arc<RwLock<NamespaceRule>>,
+    namespacerule: Arc<Locked<NamespaceRule>>,
 }
 
 impl CSSNamespaceRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<Locked<NamespaceRule>>)
                      -> CSSNamespaceRule {
         CSSNamespaceRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             namespacerule: namespacerule,
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> {
+               namespacerule: Arc<Locked<NamespaceRule>>) -> Root<CSSNamespaceRule> {
         reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule),
                            window,
                            CSSNamespaceRuleBinding::Wrap)
     }
 }
 
 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()
     }
 }
 
 impl SpecificCSSRule for CSSNamespaceRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::NAMESPACE_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.namespacerule.read().to_css_string().into()
+        let guard = self.cssrule.shared_lock().read();
+        self.namespacerule.read_with(&guard).to_css_string(&guard).into()
     }
 }
--- a/servo/components/script/dom/cssrule.rs
+++ b/servo/components/script/dom/cssrule.rs
@@ -15,16 +15,17 @@ use dom::cssmediarule::CSSMediaRule;
 use dom::cssnamespacerule::CSSNamespaceRule;
 use dom::cssstylerule::CSSStyleRule;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::csssupportsrule::CSSSupportsRule;
 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;
 
 
 #[dom_struct]
 pub struct CSSRule {
     reflector_: Reflector,
     parent_stylesheet: JS<CSSStyleSheet>,
 
@@ -98,16 +99,20 @@ impl CSSRule {
         // Spec doesn't ask us to do this, but it makes sense
         // and browsers implement this behavior
         self.as_specific().deparent_children();
     }
 
     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 {
     // https://drafts.csswg.org/cssom/#dom-cssrule-type
     fn Type(&self) -> u16 {
         self.as_specific().ty()
     }
 
--- a/servo/components/script/dom/cssrulelist.rs
+++ b/servo/components/script/dom/cssrulelist.rs
@@ -8,18 +8,18 @@ use dom::bindings::codegen::Bindings::CS
 use dom::bindings::error::{Error, ErrorResult, Fallible};
 use dom::bindings::js::{JS, MutNullableJS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::csskeyframerule::CSSKeyframeRule;
 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};
 
 #[allow(unsafe_code)]
 unsafe_no_jsmanaged_fields!(RulesSource);
 
 unsafe_no_jsmanaged_fields!(CssRules);
 
 impl From<RulesMutateError> for Error {
@@ -38,29 +38,30 @@ pub struct CSSRuleList {
     reflector_: Reflector,
     parent_stylesheet: JS<CSSStyleSheet>,
     #[ignore_heap_size_of = "Arc"]
     rules: RulesSource,
     dom_rules: DOMRefCell<Vec<MutNullableJS<CSSRule>>>
 }
 
 pub enum RulesSource {
-    Rules(Arc<RwLock<CssRules>>),
-    Keyframes(Arc<RwLock<KeyframesRule>>),
+    Rules(Arc<Locked<CssRules>>),
+    Keyframes(Arc<Locked<KeyframesRule>>),
 }
 
 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) => {
-                rules.read().0.iter().map(|_| MutNullableJS::new(None)).collect()
+                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()
             }
         };
 
         CSSRuleList {
             reflector_: Reflector::new(),
             parent_stylesheet: JS::from_ref(parent_stylesheet),
             rules: rules,
             dom_rules: DOMRefCell::new(dom_rules),
@@ -84,68 +85,75 @@ impl CSSRuleList {
             panic!("Called insert_rule on non-CssRule-backed CSSRuleList");
         };
 
         let global = self.global();
         let window = global.as_window();
         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 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);
         self.dom_rules.borrow_mut().insert(index, MutNullableJS::new(Some(&*dom_rule)));
         Ok((idx))
     }
 
     // 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) => {
-                css_rules.write().remove_rule(index)?;
+                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);
                 Ok(())
             }
             RulesSource::Keyframes(ref kf) => {
                 // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
                 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(())
             }
         }
     }
 
     // Remove parent stylesheets from all children
     pub fn deparent_all(&self) {
         for rule in self.dom_rules.borrow().iter() {
             rule.get().map(|r| Root::upcast(r).deparent());
         }
     }
 
     pub fn item(&self, idx: u32) -> Option<Root<CSSRule>> {
         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) => {
                         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(),
                                                           parent_stylesheet,
-                                                          rules.read()
+                                                          rules.read_with(&guard)
                                                                 .keyframes[idx as usize]
                                                                 .clone()))
                     }
                 }
 
             })
         })
     }
--- a/servo/components/script/dom/cssstyledeclaration.rs
+++ b/servo/components/script/dom/cssstyledeclaration.rs
@@ -6,28 +6,28 @@ use dom::bindings::codegen::Bindings::CS
 use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
 use dom::bindings::error::{Error, ErrorResult, Fallible};
 use dom::bindings::inheritance::Castable;
 use dom::bindings::js::{JS, Root};
 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;
 use style::attr::AttrValue;
 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
 #[dom_struct]
 pub struct CSSStyleDeclaration {
     reflector_: Reflector,
     owner: CSSStyleOwner,
     readonly: bool,
@@ -35,96 +35,108 @@ pub struct CSSStyleDeclaration {
 }
 
 #[derive(HeapSizeOf, JSTraceable)]
 #[must_root]
 pub enum CSSStyleOwner {
     Element(JS<Element>),
     CSSRule(JS<CSSRule>,
             #[ignore_heap_size_of = "Arc"]
-            Arc<RwLock<PropertyDeclarationBlock>>),
+            Arc<Locked<PropertyDeclarationBlock>>),
 }
 
 impl CSSStyleOwner {
     // Mutate the declaration block associated to this style owner, and
     // optionally indicate if it has changed (assumed to be true).
     fn mutate_associated_block<F, R>(&self, f: F) -> R
         where F: FnOnce(&mut PropertyDeclarationBlock, &mut bool) -> R,
     {
         // TODO(emilio): This has some duplication just to avoid dummy clones.
         //
         // This is somewhat complex but the complexity is encapsulated.
         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 {
                     let mut pdb = PropertyDeclarationBlock::new();
                     let result = f(&mut pdb, &mut changed);
 
                     // Here `changed` is somewhat silly, because we know the
                     // 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
                 };
 
                 if changed {
                     // Note that there's no need to remove the attribute here if
                     // the declaration block is empty[1], and if `attr` is
                     // `None` it means that it necessarily didn't change, so no
                     // need to go through all the set_attribute machinery.
                     //
                     // [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));
                     }
                 } else {
                     // Remember to put it back.
                     *el.style_attribute().borrow_mut() = attr;
                 }
 
                 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();
                 }
                 result
             }
         }
     }
 
     fn with_block<F, R>(&self, f: F) -> R
         where F: FnOnce(&PropertyDeclarationBlock) -> R,
     {
         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))
             }
         }
     }
 
     fn window(&self) -> Root<Window> {
         match *self {
             CSSStyleOwner::Element(ref el) => window_from_node(&**el),
             CSSStyleOwner::CSSRule(ref rule, _) => Root::from_ref(rule.global().as_window()),
--- a/servo/components/script/dom/cssstylerule.rs
+++ b/servo/components/script/dom/cssstylerule.rs
@@ -7,63 +7,68 @@ use dom::bindings::inheritance::Castable
 use dom::bindings::js::{JS, MutNullableJS, Root};
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
 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, ToCssWithGuard};
 use style::stylesheets::StyleRule;
-use style_traits::ToCss;
 
 #[dom_struct]
 pub struct CSSStyleRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    stylerule: Arc<RwLock<StyleRule>>,
+    stylerule: Arc<Locked<StyleRule>>,
     style_decl: MutNullableJS<CSSStyleDeclaration>,
 }
 
 impl CSSStyleRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<Locked<StyleRule>>)
                      -> CSSStyleRule {
         CSSStyleRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             stylerule: stylerule,
             style_decl: Default::default(),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> {
+               stylerule: Arc<Locked<StyleRule>>) -> Root<CSSStyleRule> {
         reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule),
                            window,
                            CSSStyleRuleBinding::Wrap)
     }
 }
 
 impl SpecificCSSRule for CSSStyleRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::STYLE_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.stylerule.read().to_css_string().into()
+        let guard = self.cssrule.shared_lock().read();
+        self.stylerule.read_with(&guard).to_css_string(&guard).into()
     }
 }
 
 impl CSSStyleRuleMethods for CSSStyleRule {
     // https://drafts.csswg.org/cssom/#dom-cssstylerule-style
     fn Style(&self) -> Root<CSSStyleDeclaration> {
         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
+            )
         })
     }
 }
--- a/servo/components/script/dom/cssstylesheet.rs
+++ b/servo/components/script/dom/cssstylesheet.rs
@@ -11,16 +11,17 @@ use dom::bindings::reflector::{reflect_d
 use dom::bindings::str::DOMString;
 use dom::cssrulelist::{CSSRuleList, RulesSource};
 use dom::element::Element;
 use dom::stylesheet::StyleSheet;
 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]
 pub struct CSSStyleSheet {
     stylesheet: StyleSheet,
     owner: JS<Element>,
     rulelist: MutNullableJS<CSSRuleList>,
     #[ignore_heap_size_of = "Arc"]
@@ -67,16 +68,20 @@ impl CSSStyleSheet {
     }
 
     pub fn set_disabled(&self, disabled: bool) {
         if self.style_stylesheet.set_disabled(disabled) {
             self.global().as_window().Document().invalidate_stylesheets();
         }
     }
 
+    pub fn shared_lock(&self) -> &SharedRwLock {
+        &self.style_stylesheet.shared_lock
+    }
+
     pub fn style_stylesheet(&self) -> &StyleStyleSheet {
         &self.style_stylesheet
     }
 
     pub fn set_origin_clean(&self, origin_clean: bool) {
         self.origin_clean.set(origin_clean);
     }
 }
--- a/servo/components/script/dom/csssupportsrule.rs
+++ b/servo/components/script/dom/csssupportsrule.rs
@@ -8,73 +8,77 @@ use dom::bindings::codegen::Bindings::Wi
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssconditionrule::CSSConditionRule;
 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::{Locked, 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<RwLock<SupportsRule>>,
+    supportsrule: Arc<Locked<SupportsRule>>,
 }
 
 impl CSSSupportsRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<RwLock<SupportsRule>>)
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<Locked<SupportsRule>>)
                      -> CSSSupportsRule {
-        let list = supportsrule.read().rules.clone();
+        let guard = parent_stylesheet.shared_lock().read();
+        let list = supportsrule.read_with(&guard).rules.clone();
         CSSSupportsRule {
-            cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
+            cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
             supportsrule: supportsrule,
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               supportsrule: Arc<RwLock<SupportsRule>>) -> Root<CSSSupportsRule> {
+               supportsrule: Arc<Locked<SupportsRule>>) -> Root<CSSSupportsRule> {
         reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule),
                            window,
                            CSSSupportsRuleBinding::Wrap)
     }
 
     /// 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()
     }
 
     /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
     pub fn set_condition_text(&self, text: DOMString) {
         let mut input = Parser::new(&text);
         let cond = SupportsCondition::parse(&mut input);
         if let Ok(cond) = cond {
             let global = self.global();
             let win = global.as_window();
             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;
         }
     }
 }
 
 impl SpecificCSSRule for CSSSupportsRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::SUPPORTS_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.supportsrule.read().to_css_string().into()
+        let guard = self.cssconditionrule.shared_lock().read();
+        self.supportsrule.read_with(&guard).to_css_string(&guard).into()
     }
 }
--- a/servo/components/script/dom/cssviewportrule.rs
+++ b/servo/components/script/dom/cssviewportrule.rs
@@ -5,47 +5,47 @@
 use dom::bindings::codegen::Bindings::CSSViewportRuleBinding;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 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::{Locked, ToCssWithGuard};
 use style::viewport::ViewportRule;
-use style_traits::ToCss;
 
 #[dom_struct]
 pub struct CSSViewportRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
-    viewportrule: Arc<RwLock<ViewportRule>>,
+    viewportrule: Arc<Locked<ViewportRule>>,
 }
 
 impl CSSViewportRule {
-    fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule {
+    fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<Locked<ViewportRule>>) -> CSSViewportRule {
         CSSViewportRule {
             cssrule: CSSRule::new_inherited(parent_stylesheet),
             viewportrule: viewportrule,
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
-               viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> {
+               viewportrule: Arc<Locked<ViewportRule>>) -> Root<CSSViewportRule> {
         reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule),
                            window,
                            CSSViewportRuleBinding::Wrap)
     }
 }
 
 impl SpecificCSSRule for CSSViewportRule {
     fn ty(&self) -> u16 {
         use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
         CSSRuleConstants::VIEWPORT_RULE
     }
 
     fn get_css(&self) -> DOMString {
-        self.viewportrule.read().to_css_string().into()
+        let guard = self.cssrule.shared_lock().read();
+        self.viewportrule.read_with(&guard).to_css_string(&guard).into()
     }
 }
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -129,16 +129,18 @@ use std::iter::once;
 use std::mem;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::time::{Duration, Instant};
 use style::attr::AttrValue;
 use style::context::{QuirksMode, ReflowGoal};
 use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE};
 use style::selector_parser::{RestyleDamage, Snapshot};
+use style::servo::AUTHOR_SHARED_LOCK;
+use style::shared_lock::SharedRwLock as StyleSharedRwLock;
 use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
 use style::stylesheets::Stylesheet;
 use task_source::TaskSource;
 use time;
 use timers::OneshotTimerCallback;
 use url::Host;
 use url::percent_encoding::percent_decode;
 
@@ -215,16 +217,19 @@ pub struct Document {
     classes_map: DOMRefCell<HashMap<Vec<Atom>, JS<HTMLCollection>>>,
     images: MutNullableJS<HTMLCollection>,
     embeds: MutNullableJS<HTMLCollection>,
     links: MutNullableJS<HTMLCollection>,
     forms: MutNullableJS<HTMLCollection>,
     scripts: MutNullableJS<HTMLCollection>,
     anchors: MutNullableJS<HTMLCollection>,
     applets: MutNullableJS<HTMLCollection>,
+    /// 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<Option<Vec<StylesheetInDocument>>>,
     /// Whether the list of stylesheets has changed since the last reflow was triggered.
     stylesheets_changed_since_reflow: Cell<bool>,
     stylesheet_list: MutNullableJS<StyleSheetList>,
     ready_state: Cell<DocumentReadyState>,
     /// Whether the DOMContentLoaded event has already been dispatched.
     domcontentloaded_dispatched: Cell<bool>,
@@ -1959,16 +1964,17 @@ pub enum DocumentSource {
 
 #[allow(unsafe_code)]
 pub trait LayoutDocumentHelpers {
     unsafe fn is_html_document_for_layout(&self) -> bool;
     unsafe fn drain_pending_restyles(&self) -> Vec<(LayoutJS<Element>, PendingRestyle)>;
     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)]
 impl LayoutDocumentHelpers for LayoutJS<Document> {
     #[inline]
     unsafe fn is_html_document_for_layout(&self) -> bool {
         (*self.unsafe_get()).is_html_document
     }
@@ -1995,16 +2001,21 @@ impl LayoutDocumentHelpers for LayoutJS<
     unsafe fn will_paint(&self) {
         (*self.unsafe_get()).needs_paint.set(false)
     }
 
     #[inline]
     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
 // The spec says to return a bool, we actually return an Option<Host> containing
 // the parsed host in the successful case, to avoid having to re-parse the host.
 fn get_registrable_domain_suffix_of_or_is_equal_to(host_suffix_string: &str, original_host: Host) -> Option<Host> {
     // Step 1
     if host_suffix_string.is_empty() {
@@ -2116,16 +2127,17 @@ impl Document {
             classes_map: DOMRefCell::new(HashMap::new()),
             images: Default::default(),
             embeds: Default::default(),
             links: Default::default(),
             forms: Default::default(),
             scripts: Default::default(),
             anchors: Default::default(),
             applets: Default::default(),
+            style_shared_lock: AUTHOR_SHARED_LOCK.clone(),
             stylesheets: DOMRefCell::new(None),
             stylesheets_changed_since_reflow: Cell::new(false),
             stylesheet_list: MutNullableJS::new(None),
             ready_state: Cell::new(ready_state),
             domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
             possibly_focused: Default::default(),
             focused: Default::default(),
             current_script: Default::default(),
@@ -2245,16 +2257,21 @@ impl Document {
                         node: JS::from_ref(&*node),
                         stylesheet: stylesheet,
                     })
                 })
                 .collect());
         };
     }
 
+    /// 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<Arc<Stylesheet>> {
         self.ensure_stylesheets();
         self.stylesheets.borrow().as_ref().unwrap().iter()
                         .map(|s| s.stylesheet.clone())
                         .collect()
     }
 
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -77,17 +77,16 @@ use dom::window::ReflowReason;
 use dom_struct::dom_struct;
 use html5ever::serialize;
 use html5ever::serialize::SerializeOpts;
 use html5ever::serialize::TraversalScope;
 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;
 use selectors::matching::{ElementSelectorFlags, StyleRelations, matches};
 use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use servo_atoms::Atom;
 use std::ascii::AsciiExt;
@@ -103,16 +102,17 @@ use style::context::{QuirksMode, ReflowG
 use style::element_state::*;
 use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
 use style::parser::ParserContextExtraData;
 use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
 use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
 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;
 use style::values::CSSFloat;
 use style::values::specified::{self, CSSColor};
 use stylesheet_loader::StylesheetOwner;
 
 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
@@ -124,17 +124,17 @@ pub struct Element {
     node: Node,
     local_name: LocalName,
     tag_name: TagName,
     namespace: Namespace,
     prefix: Option<DOMString>,
     attrs: DOMRefCell<Vec<JS<Attr>>>,
     id_attribute: DOMRefCell<Option<Atom>>,
     #[ignore_heap_size_of = "Arc"]
-    style_attribute: DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>>,
+    style_attribute: DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
     attr_list: MutNullableJS<NamedNodeMap>,
     class_list: MutNullableJS<DOMTokenList>,
     state: Cell<ElementState>,
     /// These flags are set by the style system to indicate the that certain
     /// operations may require restyling this element or its descendants. The
     /// flags are not atomic, so the style system takes care of only set them
     /// when it has exclusive access to the element.
     #[ignore_heap_size_of = "bitflags defined in rust-selectors"]
@@ -347,17 +347,17 @@ pub trait LayoutElementHelpers {
         where V: Push<ApplicableDeclarationBlock>;
     #[allow(unsafe_code)]
     unsafe fn get_colspan(self) -> u32;
     #[allow(unsafe_code)]
     unsafe fn get_rowspan(self) -> u32;
     #[allow(unsafe_code)]
     unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
     fn id_attribute(&self) -> *const Option<Atom>;
-    fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>>;
+    fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
     fn local_name(&self) -> &LocalName;
     fn namespace(&self) -> &Namespace;
     fn get_lang_for_layout(&self) -> String;
     fn get_checked_state_for_layout(&self) -> bool;
     fn get_indeterminate_state_for_layout(&self) -> bool;
     fn get_state_for_layout(&self) -> ElementState;
     fn insert_selector_flags(&self, flags: ElementSelectorFlags);
     fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
@@ -379,52 +379,58 @@ impl LayoutElementHelpers for LayoutJS<E
             .map(|attr| attr.value_tokens_forever().unwrap())
     }
 
     #[allow(unsafe_code)]
     unsafe fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
         where V: Push<ApplicableDeclarationBlock>
     {
         #[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::<Node>().owner_doc_for_layout();
+        let shared_lock = document.style_shared_lock();
+
         let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
             this.get_background_color()
         } else if let Some(this) = self.downcast::<HTMLTableElement>() {
             this.get_background_color()
         } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
             this.get_background_color()
         } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
             this.get_background_color()
         } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
             this.get_background_color()
         } else {
             None
         };
 
         if let Some(color) = bgcolor {
             hints.push(from_declaration(
+                shared_lock,
                 PropertyDeclaration::BackgroundColor(
                     CSSColor { parsed: Color::RGBA(color), authored: None })));
         }
 
         let background = if let Some(this) = self.downcast::<HTMLBodyElement>() {
             this.get_background()
         } else {
             None
         };
 
         if let Some(url) = background {
             hints.push(from_declaration(
+                shared_lock,
                 PropertyDeclaration::BackgroundImage(
                     background_image::SpecifiedValue(vec![
                         background_image::single_value::SpecifiedValue(Some(
                             specified::Image::for_cascade(url.into(), specified::url::UrlExtraData { })
                         ))
                     ]))));
         }
 
@@ -437,16 +443,17 @@ impl LayoutElementHelpers for LayoutJS<E
             // https://html.spec.whatwg.org/multipage/#the-hr-element-2:presentational-hints-5
             this.get_color()
         } else {
             None
         };
 
         if let Some(color) = color {
             hints.push(from_declaration(
+                shared_lock,
                 PropertyDeclaration::Color(
                     longhands::color::SpecifiedValue(CSSColor {
                         parsed: Color::RGBA(color),
                         authored: None,
                     })
                 )
             ));
         }
@@ -454,38 +461,41 @@ impl LayoutElementHelpers for LayoutJS<E
         let font_family = if let Some(this) = self.downcast::<HTMLFontElement>() {
             this.get_face()
         } else {
             None
         };
 
         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(
                                 font_family)]))));
         }
 
         let font_size = self.downcast::<HTMLFontElement>().and_then(|this| this.get_size());
 
         if let Some(font_size) = font_size {
             hints.push(from_declaration(
+                shared_lock,
                 PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into()))))
         }
 
         let cellspacing = if let Some(this) = self.downcast::<HTMLTableElement>() {
             this.get_cellspacing()
         } else {
             None
         };
 
         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(),
                         vertical: width_value,
                     }))));
         }
 
 
@@ -509,16 +519,17 @@ impl LayoutElementHelpers for LayoutJS<E
             }
         } else {
             None
         };
 
         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))));
         }
 
         let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
             this.get_width()
         } else if let Some(this) = self.downcast::<HTMLImageElement>() {
             this.get_width()
@@ -534,22 +545,24 @@ impl LayoutElementHelpers for LayoutJS<E
         };
 
         match width {
             LengthOrPercentageOrAuto::Auto => {}
             LengthOrPercentageOrAuto::Percentage(percentage) => {
                 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)));
             }
         }
 
 
         let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
             this.get_height()
         } else if let Some(this) = self.downcast::<HTMLImageElement>() {
@@ -559,22 +572,24 @@ impl LayoutElementHelpers for LayoutJS<E
         };
 
         match height {
             LengthOrPercentageOrAuto::Auto => {}
             LengthOrPercentageOrAuto::Percentage(percentage) => {
                 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)));
             }
         }
 
 
         let cols = if let Some(this) = self.downcast::<HTMLTextAreaElement>() {
             match this.get_cols() {
                 0 => None,
@@ -587,16 +602,17 @@ impl LayoutElementHelpers for LayoutJS<E
         if let Some(cols) = cols {
             // TODO(mttr) ServoCharacterWidth uses the size math for <input type="text">, but
             // the math for <textarea> is a little different since we need to take
             // scrollbar size into consideration (but we don't have a scrollbar yet!)
             //
             // 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))));
         }
 
         let rows = if let Some(this) = self.downcast::<HTMLTextAreaElement>() {
             match this.get_rows() {
                 0 => None,
                 r => Some(r as i32),
             }
@@ -605,35 +621,40 @@ impl LayoutElementHelpers for LayoutJS<E
         };
 
         if let Some(rows) = rows {
             // TODO(mttr) This should take scrollbar size into consideration.
             //
             // 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))));
         }
 
 
         let border = if let Some(this) = self.downcast::<HTMLTableElement>() {
             this.get_border()
         } else {
             None
         };
 
         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))));
         }
     }
 
     #[allow(unsafe_code)]
     unsafe fn get_colspan(self) -> u32 {
         if let Some(this) = self.downcast::<HTMLTableCellElement>() {
             this.get_colspan().unwrap_or(1)
@@ -667,17 +688,17 @@ impl LayoutElementHelpers for LayoutJS<E
     #[allow(unsafe_code)]
     fn id_attribute(&self) -> *const Option<Atom> {
         unsafe {
             (*self.unsafe_get()).id_attribute.borrow_for_layout()
         }
     }
 
     #[allow(unsafe_code)]
-    fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+    fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>> {
         unsafe {
             (*self.unsafe_get()).style_attribute.borrow_for_layout()
         }
     }
 
     #[allow(unsafe_code)]
     fn local_name(&self) -> &LocalName {
         unsafe {
@@ -830,17 +851,17 @@ impl Element {
             if let Some(attr) = attr {
                 return (**attr.value()).into();
             }
         }
 
         ns!()
     }
 
-    pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>> {
+    pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
         &self.style_attribute
     }
 
     pub fn summarize(&self) -> Vec<AttrInfo> {
         self.attrs.borrow().iter()
                            .map(|attr| attr.summarize())
                            .collect()
     }
@@ -2165,17 +2186,17 @@ impl VirtualMethods for Element {
                                 AttrValue::Declaration(s, b) => (s, b),
                                 _ => unreachable!(),
                             };
                             let mut value = AttrValue::String(serialization);
                             attr.swap_value(&mut value);
                             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(),
                                 ParserContextExtraData::default())))
                         };
 
                         Some(block)
                     }
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -286,19 +286,18 @@ impl HTMLLinkElement {
         };
 
         self.request_generation_id.set(self.request_generation_id.get().increment());
 
         // TODO: #8085 - Don't load external stylesheets if the node's mq
         // 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<String>) {
         let document = document_from_node(self);
         match document.base_url().join(href) {
             Ok(url) => {
                 let event = ConstellationMsg::NewFavicon(url.clone());
                 document.window().upcast::<GlobalScope>().constellation_chan().send(event).unwrap();
--- a/servo/components/script/dom/htmlmetaelement.rs
+++ b/servo/components/script/dom/htmlmetaelement.rs
@@ -14,17 +14,16 @@ use dom::cssstylesheet::CSSStyleSheet;
 use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::htmlelement::HTMLElement;
 use dom::htmlheadelement::HTMLHeadElement;
 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;
 use std::sync::atomic::AtomicBool;
 use style::attr::AttrValue;
 use style::str::HTML_SPACE_CHARACTERS;
 use style::stylesheets::{Stylesheet, CssRule, CssRules, Origin};
 use style::viewport::ViewportRule;
@@ -94,22 +93,26 @@ impl HTMLMetaElement {
         if !PREFS.get("layout.viewport.enabled").as_boolean().unwrap_or(false) {
             return;
         }
         let element = self.upcast::<Element>();
         if let Some(content) = element.get_attribute(&ns!(), &local_name!("content")).r() {
             let content = content.value();
             if !content.is_empty() {
                 if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
+                    let document = self.upcast::<Node>().owner_doc();
+                    let shared_lock = document.style_shared_lock();
+                    let rule = CssRule::Viewport(Arc::new(shared_lock.wrap(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(),
                         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),
                         disabled: AtomicBool::new(false),
                     }));
                     let doc = document_from_node(self);
                     doc.invalidate_stylesheets();
                 }
--- a/servo/components/script/dom/htmlstyleelement.rs
+++ b/servo/components/script/dom/htmlstyleelement.rs
@@ -79,19 +79,20 @@ impl HTMLStyleElement {
         let mq_attribute = element.get_attribute(&ns!(), &local_name!("media"));
         let mq_str = match mq_attribute {
             Some(a) => String::from(&**a.value()),
             None => String::new(),
         };
 
         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());
 
         let sheet = Arc::new(sheet);
 
         // No subresource loads were triggered, just fire the load event now.
         if self.pending_loads.get() == 0 {
             self.upcast::<EventTarget>().fire_event(atom!("load"));
--- a/servo/components/script/dom/medialist.rs
+++ b/servo/components/script/dom/medialist.rs
@@ -1,82 +1,94 @@
 /* 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 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::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]
 pub struct MediaList {
     reflector_: Reflector,
+    parent_stylesheet: JS<CSSStyleSheet>,
     #[ignore_heap_size_of = "Arc"]
-    media_queries: Arc<RwLock<StyleMediaList>>,
+    media_queries: Arc<Locked<StyleMediaList>>,
 }
 
 impl MediaList {
     #[allow(unrooted_must_root)]
-    pub fn new_inherited(media_queries: Arc<RwLock<StyleMediaList>>) -> MediaList {
+    pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
+                         media_queries: Arc<Locked<StyleMediaList>>) -> 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<RwLock<StyleMediaList>>)
+    pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
+               media_queries: Arc<Locked<StyleMediaList>>)
         -> Root<MediaList> {
-        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
             *media_queries = StyleMediaList::default();
             return;
         }
         // Step 3
         let mut parser = Parser::new(&value);
         *media_queries = parse_media_query_list(&mut parser);
     }
 
     // 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<DOMString> {
-        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))
         })
     }
 
     // https://drafts.csswg.org/cssom/#dom-medialist-item
     fn IndexedGetter(&self, index: u32) -> Option<DOMString> {
@@ -89,35 +101,37 @@ impl MediaListMethods for MediaList {
         let mut parser = Parser::new(&medium);
         let m = MediaQuery::parse(&mut parser);
         // Step 2
         if let Err(_) = m {
             return;
         }
         // 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
     fn DeleteMedium(&self, medium: DOMString) {
         // Step 1
         let mut parser = Parser::new(&medium);
         let m = MediaQuery::parse(&mut parser);
         // Step 2
         if let Err(_) = m {
             return;
         }
         // 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();
         media_list.media_queries = new_vec;
     }
 }
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -39,17 +39,16 @@ use dom::characterdata::LayoutCharacterD
 use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle};
 use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
 use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_DIRTY_DESCENDANTS, IS_IN_DOC};
 use dom::node::{LayoutNodeHelpers, Node};
 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};
 use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
 use selectors::matching::{ElementSelectorFlags, StyleRelations};
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use servo_atoms::Atom;
@@ -64,16 +63,17 @@ use style::attr::AttrValue;
 use style::computed_values::display;
 use style::context::{QuirksMode, SharedStyleContext};
 use style::data::ElementData;
 use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TElement, TNode};
 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, Locked as StyleLocked};
 use style::sink::Push;
 use style::str::is_whitespace;
 use style::stylist::ApplicableDeclarationBlock;
 
 #[derive(Copy, Clone)]
 pub struct ServoLayoutNode<'a> {
     /// The wrapped node.
     node: LayoutJS<Node>,
@@ -325,16 +325,20 @@ impl<'ld> ServoLayoutDocument<'ld> {
     pub fn will_paint(&self) {
         unsafe { self.document.will_paint(); }
     }
 
     pub fn quirks_mode(&self) -> QuirksMode {
         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<Document>) -> ServoLayoutDocument<'ld> {
         ServoLayoutDocument {
             document: doc,
             chain: PhantomData,
         }
     }
 }
 
@@ -367,17 +371,17 @@ impl<'le> PresentationalHintsSynthetizer
 
 impl<'le> TElement for ServoLayoutElement<'le> {
     type ConcreteNode = ServoLayoutNode<'le>;
 
     fn as_node(&self) -> ServoLayoutNode<'le> {
         ServoLayoutNode::from_layout_js(self.element.upcast())
     }
 
-    fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
+    fn style_attribute(&self) -> Option<&Arc<StyleLocked<PropertyDeclarationBlock>>> {
         unsafe {
             (*self.element.style_attribute()).as_ref()
         }
     }
 
     fn get_state(&self) -> ElementState {
         self.element.get_state_for_layout()
     }
--- a/servo/components/script/stylesheet_loader.rs
+++ b/servo/components/script/stylesheet_loader.rs
@@ -17,23 +17,23 @@ use encoding::all::UTF_8;
 use hyper::header::ContentType;
 use hyper::mime::{Mime, TopLevel, SubLevel};
 use hyper_serde::Serde;
 use ipc_channel::ipc;
 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;
 
 pub trait StylesheetOwner {
     /// Returns whether this element was inserted by the parser (i.e., it should
     /// trigger a document-load-blocking load).
     fn parser_inserted(&self) -> bool;
 
@@ -49,41 +49,26 @@ pub trait StylesheetOwner {
     fn load_finished(&self, successful: bool) -> Option<bool>;
 
     /// Sets origin_clean flag.
     fn set_origin_clean(&self, origin_clean: bool);
 }
 
 pub enum StylesheetContextSource {
     // NB: `media` is just an option so we avoid cloning it.
-    LinkElement { media: Option<MediaList>, url: ServoUrl },
-    Import(Arc<RwLock<ImportRule>>),
-}
-
-impl StylesheetContextSource {
-    fn url(&self) -> ServoUrl {
-        match *self {
-            StylesheetContextSource::LinkElement { ref url, .. } => url.clone(),
-            StylesheetContextSource::Import(ref import) => {
-                let import = import.read();
-                // 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()
-            }
-        }
-    }
+    LinkElement { media: Option<MediaList>, },
+    Import(Arc<Stylesheet>),
 }
 
 /// The context required for asynchronously loading an external stylesheet.
 pub struct StylesheetContext {
     /// The element that initiated the request.
     elem: Trusted<HTMLElement>,
     source: StylesheetContextSource,
+    url: ServoUrl,
     metadata: Option<Metadata>,
     /// The response body received to date.
     data: Vec<u8>,
     /// The node document for elem when the load was initiated.
     document: Trusted<Document>,
     origin_clean: bool,
     /// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet.
     /// This is ignored for `HTMLStyleElement` and imports.
@@ -140,45 +125,46 @@ impl FetchResponseListener for Styleshee
             let environment_encoding = UTF_8 as EncodingRef;
             let protocol_encoding_label = metadata.charset.as_ref().map(|s| &**s);
             let final_url = metadata.final_url;
 
             let win = window_from_node(&*elem);
 
             let loader = StylesheetLoader::for_element(&elem);
             match self.source {
-                StylesheetContextSource::LinkElement { ref mut media, .. } => {
+                StylesheetContextSource::LinkElement { ref mut media } => {
                     let link = elem.downcast::<HTMLLinkElement>().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.
                     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()));
 
                         if link.is_alternate() {
                             sheet.set_disabled(true);
                         }
 
                         link.set_stylesheet(sheet.clone());
 
                         win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap();
                     }
                 }
-                StylesheetContextSource::Import(ref import) => {
-                    let import = import.read();
-                    Stylesheet::update_from_bytes(&import.stylesheet,
+                StylesheetContextSource::Import(ref stylesheet) => {
+                    Stylesheet::update_from_bytes(&stylesheet,
                                                   &data,
                                                   protocol_encoding_label,
                                                   Some(environment_encoding),
                                                   Some(&loader),
                                                   win.css_error_reporter(),
                                                   ParserContextExtraData::default());
                 }
             }
@@ -192,18 +178,17 @@ impl FetchResponseListener for Styleshee
 
         let owner = elem.upcast::<Element>().as_stylesheet_owner()
             .expect("Stylesheet not loaded by <style> or <link> element!");
         owner.set_origin_clean(self.origin_clean);
         if owner.parser_inserted() {
             document.decrement_script_blocking_stylesheet_count();
         }
 
-        let url = self.source.url();
-        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") };
             elem.upcast::<EventTarget>().fire_event(event);
         }
     }
 }
 
@@ -215,25 +200,26 @@ impl<'a> StylesheetLoader<'a> {
     pub fn for_element(element: &'a HTMLElement) -> Self {
         StylesheetLoader {
             elem: element,
         }
     }
 }
 
 impl<'a> StylesheetLoader<'a> {
-    pub fn load(&self, source: StylesheetContextSource, cors_setting: Option<CorsSettings>,
+    pub fn load(&self, source: StylesheetContextSource, url: ServoUrl,
+                cors_setting: Option<CorsSettings>,
                 integrity_metadata: String) {
-        let url = source.url();
         let document = document_from_node(self.elem);
         let gen = self.elem.downcast::<HTMLLinkElement>()
                            .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),
             origin_clean: true,
             request_generation_id: gen,
         }));
 
         let (action_sender, action_receiver) = ipc::channel().unwrap();
@@ -280,14 +266,25 @@ impl<'a> StylesheetLoader<'a> {
             .. RequestInit::default()
         };
 
         document.fetch_async(LoadType::Stylesheet(url), request, action_sender);
     }
 }
 
 impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> {
-    fn request_stylesheet(&self, import: &Arc<RwLock<ImportRule>>) {
+    fn request_stylesheet(
+        &self,
+        media: MediaList,
+        make_import: &mut FnMut(MediaList) -> ImportRule,
+        make_arc: &mut FnMut(ImportRule) -> Arc<StyleLocked<ImportRule>>,
+    ) -> Arc<StyleLocked<ImportRule>> {
+        let import = make_import(media);
+        let url = import.url.url().expect("Invalid urls shouldn't enter the loader").clone();
+
         //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())
+        let source = StylesheetContextSource::Import(import.stylesheet.clone());
+        self.load(source, url, None, "".to_owned());
+
+        make_arc(import)
     }
 }
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -400,32 +400,34 @@ pub trait ThreadSafeLayoutElement: Clone
                     PseudoElementCascadeType::Precomputed => {
                         if !self.get_style_data()
                                 .unwrap()
                                 .borrow()
                                 .styles().pseudos.contains_key(&style_pseudo) {
                             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());
                             data.styles_mut().pseudos
                                 .insert(style_pseudo.clone(), new_style);
                         }
                     }
                     PseudoElementCascadeType::Lazy => {
                         if !self.get_style_data()
                                 .unwrap()
                                 .borrow()
                                 .styles().pseudos.contains_key(&style_pseudo) {
                             let mut data = self.get_style_data().unwrap().borrow_mut();
                             let new_style =
                                 context.stylist
                                        .lazily_compute_pseudo_element_style(
+                                           &context.guards,
                                            unsafe { &self.unsafe_get() },
                                            &style_pseudo,
                                            data.styles().primary.values());
                             data.styles_mut().pseudos
                                 .insert(style_pseudo.clone(), new_style.unwrap());
                         }
                     }
                 }
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -8,17 +8,17 @@ publish = false
 build = "build.rs"
 
 [lib]
 name = "style"
 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",
          "cssparser/heapsize", "cssparser/serde", "encoding",
          "rayon/unstable", "servo_url/servo"]
 testing = []
 
 [dependencies]
@@ -32,20 +32,20 @@ euclid = "0.11"
 fnv = "1.0"
 heapsize = "0.3.0"
 heapsize_derive = {version = "0.1", optional = true}
 html5ever-atoms = {version = "0.2", optional = true}
 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"
-owning_ref = "0.2.2"
 parking_lot = "0.3.3"
 pdqsort = "0.1.0"
 rayon = "0.6"
 selectors = { path = "../selectors" }
 serde = {version = "0.9", optional = true}
 serde_derive = {version = "0.9", optional = true}
 servo_atoms = {path = "../atoms", optional = true}
 servo_config = {path = "../config"}
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -410,17 +410,17 @@ pub fn start_transitions_if_applicable(n
 fn compute_style_for_animation_step(context: &SharedStyleContext,
                                     step: &KeyframesStep,
                                     previous_style: &ComputedValues,
                                     style_from_cascade: &ComputedValues)
                                     -> ComputedValues {
     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()
                             .all(|&(_, importance)| importance == Importance::Normal));
 
             let iter = || {
                 guard.declarations().iter().rev().map(|&(ref decl, _importance)| decl)
             };
--- a/servo/components/style/attr.rs
+++ b/servo/components/style/attr.rs
@@ -6,19 +6,19 @@
 //!
 //! [attr]: https://dom.spec.whatwg.org/#interface-attr
 
 use {Atom, Prefix, Namespace, LocalName};
 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;
 use str::{HTML_SPACE_CHARACTERS, read_exponent, read_fraction};
 use str::{read_numbers, split_commas, split_html_space_chars};
 #[cfg(not(feature = "gecko"))] use str::str_join;
 use values::specified::Length;
 
@@ -56,17 +56,17 @@ pub enum AttrValue {
     /// `style` element, and is set from its relevant CSSInlineStyleDeclaration,
     /// and then converted to a string in Element::attribute_mutated.
     ///
     /// Note that we don't necessarily need to do that (we could just clone the
     /// declaration block), but that avoids keeping a refcounted
     /// declarationblock for longer than needed.
     Declaration(String,
                 #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-                Arc<RwLock<PropertyDeclarationBlock>>)
+                Arc<Locked<PropertyDeclarationBlock>>)
 }
 
 /// Shared implementation to parse an integer according to
 /// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-integers> or
 /// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-negative-integers>
 fn do_parse_integer<T: Iterator<Item=char>>(input: T) -> Result<i64, ()> {
     let mut input = input.skip_while(|c| {
         HTML_SPACE_CHARACTERS.iter().any(|s| s == c)
--- a/servo/components/style/context.rs
+++ b/servo/components/style/context.rs
@@ -12,16 +12,17 @@ use data::ElementData;
 use dom::{OpaqueNode, TNode, TElement, SendElement};
 use error_reporting::ParseErrorReporter;
 use euclid::Size2D;
 use matching::StyleSharingCandidateCache;
 use parking_lot::RwLock;
 use selector_parser::PseudoElement;
 use selectors::matching::ElementSelectorFlags;
 use servo_config::opts;
+use shared_lock::StylesheetGuards;
 use std::collections::HashMap;
 use std::env;
 use std::fmt;
 use std::ops::Add;
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::Sender;
 use stylist::Stylist;
 use thread_state;
@@ -56,20 +57,23 @@ pub enum QuirksMode {
     /// No quirks mode.
     NoQuirks,
 }
 
 /// A shared style context.
 ///
 /// 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<Stylist>,
 
+    /// Guards for pre-acquired locks
+    pub guards: StylesheetGuards<'a>,
+
     /// The animations that are currently running.
     pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
 
     /// The list of animations that have expired since the last style recalculation.
     pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
 
     ///The CSS error reporter for all CSS loaded in this layout thread
     pub error_reporter: Box<ParseErrorReporter>,
@@ -80,17 +84,17 @@ pub struct SharedStyleContext {
     /// The current timer for transitions and animations. This is needed to test
     /// them.
     pub timer: Timer,
 
     /// The QuirksMode state which the document needs to be rendered with
     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<Au> {
         self.stylist.device.au_viewport_size()
     }
 }
 
 /// Information about the current element being processed. We group this together
 /// into a single struct within ThreadLocalStyleContext so that we can instantiate
@@ -301,17 +305,17 @@ impl<E: TElement> Drop for ThreadLocalSt
         }
     }
 }
 
 /// A `StyleContext` is just a simple container for a immutable reference to a
 /// 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<E>,
 }
 
 /// Why we're doing reflow.
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub enum ReflowGoal {
     /// We're reflowing in order to send a display list to the screen.
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -6,20 +6,20 @@
 
 #![allow(unsafe_code)]
 #![deny(missing_docs)]
 
 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;
 use std::ops::Deref;
 use std::sync::Arc;
 use stylist::ApplicableDeclarationBlock;
 
 pub use style_traits::UnsafeNode;
@@ -225,18 +225,18 @@ pub trait PresentationalHintsSynthetizer
     /// Generate the proper applicable declarations due to presentational hints,
     /// and insert them into `hints`.
     fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
         where V: Push<ApplicableDeclarationBlock>;
 }
 
 /// 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<Arc<RwLock<PropertyDeclarationBlock>>>,
-                          pub Option<Arc<RwLock<PropertyDeclarationBlock>>>);
+pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
+                          pub Option<Arc<Locked<PropertyDeclarationBlock>>>);
 
 /// The element trait, the main abstraction the style crate acts over.
 pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
     /// The concrete node type.
     type ConcreteNode: TNode<ConcreteElement = Self>;
 
     /// Get this element as a node.
     fn as_node(&self) -> Self::ConcreteNode;
@@ -247,32 +247,32 @@ pub trait TElement : PartialEq + Debug +
         if self.as_node().opaque() == reflow_root {
             None
         } else {
             self.parent_element()
         }
     }
 
     /// Get this element's style attribute.
-    fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
+    fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>>;
 
     /// Get this element's animation rules.
     fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules {
         AnimationRules(None, None)
     }
 
     /// Get this element's animation rule.
     fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
-                          -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+                          -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
         None
     }
 
     /// Get this element's transition rule.
     fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>)
-                           -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+                           -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
         None
     }
 
     /// Get this element's state, for non-tree-structural pseudos.
     fn get_state(&self) -> ElementState;
 
     /// Whether this element has an attribute with a given namespace.
     fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool;
--- a/servo/components/style/encoding_support.rs
+++ b/servo/components/style/encoding_support.rs
@@ -7,16 +7,17 @@
 extern crate encoding;
 
 use cssparser::{stylesheet_encoding, EncodingSupport};
 use error_reporting::ParseErrorReporter;
 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};
 
 struct RustEncoding;
 
 impl EncodingSupport for RustEncoding {
     type Encoding = EncodingRef;
 
@@ -49,26 +50,28 @@ impl Stylesheet {
     /// Takes care of decoding the network bytes and forwards the resulting
     /// string to `Stylesheet::from_str`.
     pub fn from_bytes(bytes: &[u8],
                       base_url: ServoUrl,
                       protocol_encoding_label: Option<&str>,
                       environment_encoding: Option<EncodingRef>,
                       origin: Origin,
                       media: MediaList,
+                      shared_lock: SharedRwLock,
                       stylesheet_loader: Option<&StylesheetLoader>,
                       error_reporter: &ParseErrorReporter,
                       extra_data: ParserContextExtraData)
                       -> Stylesheet {
         let (string, _) = decode_stylesheet_bytes(
             bytes, protocol_encoding_label, environment_encoding);
         Stylesheet::from_str(&string,
                              base_url,
                              origin,
                              media,
+                             shared_lock,
                              stylesheet_loader,
                              error_reporter,
                              extra_data)
     }
 
     /// Updates an empty stylesheet with a set of bytes that reached over the
     /// network.
     pub fn update_from_bytes(existing: &Stylesheet,
--- a/servo/components/style/font_face.rs
+++ b/servo/components/style/font_face.rs
@@ -9,16 +9,17 @@
 #![deny(missing_docs)]
 
 #[cfg(feature = "gecko")]
 use computed_values::{font_style, font_weight, font_stretch};
 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};
 use values::specified::url::SpecifiedUrl;
 
 /// A source for a font-face rule.
 #[derive(Clone, Debug, PartialEq, Eq)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
@@ -225,21 +226,20 @@ macro_rules! font_face_descriptors {
                     )*
                     $(
                         $o_ident: $o_initial,
                     )*
                 }
             }
         }
 
-        impl ToCss for FontFaceRule {
+        impl ToCssWithGuard for FontFaceRule {
             // Serialization of FontFaceRule is not specced.
-            fn to_css<W>(&self, dest: &mut W) -> fmt::Result
-                where W: fmt::Write,
-            {
+            fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
+            where W: fmt::Write {
                 dest.write_str("@font-face {\n")?;
                 $(
                     dest.write_str(concat!("  ", $m_name, ": "))?;
                     ToCss::to_css(&self.$m_ident, dest)?;
                     dest.write_str(";\n")?;
                 )*
                 $(
                     // Because of parse_font_face_block,
--- a/servo/components/style/gecko/arc_types.rs
+++ b/servo/components/style/gecko/arc_types.rs
@@ -12,16 +12,17 @@ use gecko_bindings::bindings::{RawServoM
 use gecko_bindings::bindings::{RawServoStyleSheet, RawServoStyleRule, RawServoImportRule};
 use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules};
 use gecko_bindings::structs::{RawServoAnimationValue, RawServoAnimationValueMap, RawServoDeclarationBlock};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 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 {
     ($servo_type:ty => $gecko_type:ty [$addref:ident, $release:ident]) => {
         unsafe impl HasFFI for $servo_type {
             type FFIType = $gecko_type;
         }
         unsafe impl HasArcFFI for $servo_type {}
@@ -33,40 +34,40 @@ macro_rules! impl_arc_ffi {
 
         #[no_mangle]
         pub unsafe extern "C" fn $release(obj: &$gecko_type) {
             <$servo_type>::release(obj);
         }
     }
 }
 
-impl_arc_ffi!(RwLock<CssRules> => ServoCssRules
+impl_arc_ffi!(Locked<CssRules> => ServoCssRules
               [Servo_CssRules_AddRef, Servo_CssRules_Release]);
 
 impl_arc_ffi!(Stylesheet => RawServoStyleSheet
               [Servo_StyleSheet_AddRef, Servo_StyleSheet_Release]);
 
 impl_arc_ffi!(ComputedValues => ServoComputedValues
               [Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]);
 
-impl_arc_ffi!(RwLock<PropertyDeclarationBlock> => RawServoDeclarationBlock
+impl_arc_ffi!(Locked<PropertyDeclarationBlock> => RawServoDeclarationBlock
               [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]);
 
-impl_arc_ffi!(RwLock<StyleRule> => RawServoStyleRule
+impl_arc_ffi!(Locked<StyleRule> => RawServoStyleRule
               [Servo_StyleRule_AddRef, Servo_StyleRule_Release]);
 
-impl_arc_ffi!(RwLock<ImportRule> => RawServoImportRule
+impl_arc_ffi!(Locked<ImportRule> => RawServoImportRule
               [Servo_ImportRule_AddRef, Servo_ImportRule_Release]);
 
 impl_arc_ffi!(AnimationValue => RawServoAnimationValue
               [Servo_AnimationValue_AddRef, Servo_AnimationValue_Release]);
 
 impl_arc_ffi!(RwLock<AnimationValueMap> => RawServoAnimationValueMap
               [Servo_AnimationValueMap_AddRef, Servo_AnimationValueMap_Release]);
 
-impl_arc_ffi!(RwLock<MediaList> => RawServoMediaList
+impl_arc_ffi!(Locked<MediaList> => RawServoMediaList
               [Servo_MediaList_AddRef, Servo_MediaList_Release]);
 
-impl_arc_ffi!(RwLock<MediaRule> => RawServoMediaRule
+impl_arc_ffi!(Locked<MediaRule> => RawServoMediaRule
               [Servo_MediaRule_AddRef, Servo_MediaRule_Release]);
 
-impl_arc_ffi!(RwLock<NamespaceRule> => RawServoNamespaceRule
+impl_arc_ffi!(Locked<NamespaceRule> => RawServoNamespaceRule
               [Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]);
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -8,16 +8,17 @@ use animation::Animation;
 use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
 use dom::OpaqueNode;
 use gecko_bindings::bindings::RawServoStyleSet;
 use gecko_bindings::structs::RawGeckoPresContextOwned;
 use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
 use media_queries::Device;
 use parking_lot::RwLock;
 use properties::ComputedValues;
+use shared_lock::{StylesheetGuards, SharedRwLockReadGuard};
 use std::collections::HashMap;
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use stylesheets::Stylesheet;
 use stylist::Stylist;
 
 /// The container for data that a Servo-backed Gecko document needs to style
 /// itself.
@@ -78,30 +79,30 @@ impl PerDocumentStyleData {
         self.0.borrow_mut()
     }
 }
 
 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, &StylesheetGuards::same(guard), None, true);
             self.stylesheets_changed = false;
         }
     }
 
     /// Get the default computed values for this document.
     pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
         self.stylist.device.default_computed_values_arc()
     }
new file mode 100644
--- /dev/null
+++ b/servo/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<rayon::ThreadPool>,
+
+    /// 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::<usize>().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(),
+        }
+    };
+}
--- a/servo/components/style/gecko/mod.rs
+++ b/servo/components/style/gecko/mod.rs
@@ -5,16 +5,17 @@
 //! Gecko-specific style-system bits.
 
 #[macro_use]
 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;
 pub mod snapshot;
 pub mod snapshot_helpers;
 pub mod traversal;
 pub mod values;
 pub mod wrapper;
--- a/servo/components/style/gecko/traversal.rs
+++ b/servo/components/style/gecko/traversal.rs
@@ -8,35 +8,36 @@ use atomic_refcell::AtomicRefCell;
 use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
 use data::ElementData;
 use dom::{NodeInfo, TNode};
 use gecko::wrapper::{GeckoElement, GeckoNode};
 use traversal::{DomTraversal, PerLevelTraversalData, TraversalDriver, recalc_style_at};
 
 /// 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,
         }
     }
 }
 
-impl<'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly {
+impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
     type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>;
 
-    fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData,
+    fn process_preorder(&self,
+                        traversal_data: &mut PerLevelTraversalData,
                         thread_local: &mut Self::ThreadLocalContext,
                         node: GeckoNode<'le>)
     {
         if node.is_element() {
             let el = node.as_element().unwrap();
             let mut data = unsafe { el.ensure_data() }.borrow_mut();
             let mut context = StyleContext {
                 shared: &self.shared,
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -15,16 +15,17 @@
 //! the separation between the style system implementation and everything else.
 
 use atomic_refcell::AtomicRefCell;
 use data::ElementData;
 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;
 use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
 use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetLastChild, Gecko_GetNextStyleChild};
 use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement, Gecko_MatchesElement};
 use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
 use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
@@ -48,16 +49,17 @@ use properties::{ComputedValues, parse_s
 use properties::PropertyDeclarationBlock;
 use properties::animated_properties::AnimationValueMap;
 use rule_tree::CascadeLevel as ServoCascadeLevel;
 use selector_parser::{ElementExt, Snapshot};
 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;
 use std::sync::Arc;
 use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
 use stylist::ApplicableDeclarationBlock;
 
 /// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
@@ -402,51 +404,53 @@ fn selector_flags_to_node_flags(flags: E
     }
 
     gecko_flags
 }
 
 fn get_animation_rule(element: &GeckoElement,
                       pseudo: Option<&PseudoElement>,
                       cascade_level: CascadeLevel)
-                      -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+                      -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
     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
     }
 }
 
 impl<'le> TElement for GeckoElement<'le> {
     type ConcreteNode = GeckoNode<'le>;
 
     fn as_node(&self) -> Self::ConcreteNode {
         unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
     }
 
-    fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
+    fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
         let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
         declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
     }
 
     fn get_animation_rules(&self, pseudo: Option<&PseudoElement>) -> AnimationRules {
         AnimationRules(self.get_animation_rule(pseudo),
                        self.get_transition_rule(pseudo))
     }
 
     fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
-                          -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+                          -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
         get_animation_rule(self, pseudo, CascadeLevel::Animations)
     }
 
     fn get_transition_rule(&self, pseudo: Option<&PseudoElement>)
-                           -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+                           -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
         get_animation_rule(self, pseudo, CascadeLevel::Transitions)
     }
 
     fn get_state(&self) -> ElementState {
         unsafe {
             ElementState::from_bits_truncate(Gecko_ElementState(self.0) as u32)
         }
     }
--- a/servo/components/style/keyframes.rs
+++ b/servo/components/style/keyframes.rs
@@ -3,23 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Keyframes: https://drafts.csswg.org/css-animations/#keyframes
 
 #![deny(missing_docs)]
 
 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, ToCssWithGuard};
 use std::fmt;
 use std::sync::Arc;
 use style_traits::ToCss;
 use stylesheets::{MemoryHoleReporter, Stylesheet};
 
 /// A number from 0 to 1, indicating the percentage of the animation when this
 /// keyframe should run.
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
@@ -96,50 +96,52 @@ impl KeyframeSelector {
 pub struct Keyframe {
     /// The selector this keyframe was specified from.
     pub selector: KeyframeSelector,
 
     /// The declaration block that was declared inside this keyframe.
     ///
     /// Note that `!important` rules in keyframes don't apply, but we keep this
     /// `Arc` just for convenience.
-    pub block: Arc<RwLock<PropertyDeclarationBlock>>,
+    pub block: Arc<Locked<PropertyDeclarationBlock>>,
 }
 
-impl ToCss for Keyframe {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+impl ToCssWithGuard for Keyframe {
+    fn to_css<W>(&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 {
             try!(write!(dest, ", "));
             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(())
     }
 }
 
 
 impl Keyframe {
     /// Parse a CSS keyframe.
     pub fn parse(css: &str,
                  parent_stylesheet: &Stylesheet,
                  extra_data: ParserContextExtraData)
-                 -> Result<Arc<RwLock<Self>>, ()> {
+                 -> Result<Arc<Locked<Self>>, ()> {
         let error_reporter = MemoryHoleReporter;
         let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                          &parent_stylesheet.base_url,
                                                          &error_reporter,
                                                          extra_data);
         let mut input = Parser::new(css);
 
         let mut rule_parser = KeyframeListParser {
             context: &context,
+            shared_lock: &parent_stylesheet.shared_lock,
         };
         parse_one_rule(&mut input, &mut rule_parser)
     }
 }
 
 /// A keyframes step value. This can be a synthetised keyframes animation, that
 /// is, one autogenerated from the current computed values, or a list of
 /// declarations to apply.
@@ -147,17 +149,17 @@ impl Keyframe {
 /// TODO: Find a better name for this?
 #[derive(Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum KeyframesStepValue {
     /// A step formed by a declaration block specified by the CSS.
     Declarations {
         /// The declaration block per se.
         #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-        block: Arc<RwLock<PropertyDeclarationBlock>>
+        block: Arc<Locked<PropertyDeclarationBlock>>
     },
     /// A synthetic step computed from the current computed values at the time
     /// of the animation.
     ComputedValues,
 }
 
 /// A single step from a keyframe animation.
 #[derive(Debug)]
@@ -173,20 +175,21 @@ pub struct KeyframesStep {
     ///
     /// This is used to know when to override the keyframe animation style.
     pub declared_timing_function: bool,
 }
 
 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,
                     }
                 })
             }
             _ => false,
         };
@@ -194,23 +197,24 @@ impl KeyframesStep {
         KeyframesStep {
             start_percentage: percentage,
             value: value,
             declared_timing_function: declared_timing_function,
         }
     }
 
     /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
-    pub fn get_animation_timing_function(&self) -> Option<SpecifiedTimingFunction> {
+    pub fn get_animation_timing_function(&self, guard: &SharedRwLockReadGuard)
+                                         -> Option<SpecifiedTimingFunction> {
         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 {
                     PropertyDeclaration::AnimationTimingFunction(ref value) => {
                         // Use the first value.
                         Some(value.0[0])
                     },
                     PropertyDeclaration::CSSWideKeyword(..) => None,
@@ -234,24 +238,26 @@ impl KeyframesStep {
 pub struct KeyframesAnimation {
     /// The difference steps of the animation.
     pub steps: Vec<KeyframesStep>,
     /// The properties that change in this animation.
     pub properties_changed: Vec<TransitionProperty>,
 }
 
 /// Get all the animated properties in a keyframes animation.
-fn get_animated_properties(keyframes: &[Arc<RwLock<Keyframe>>]) -> Vec<TransitionProperty> {
+fn get_animated_properties(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRwLockReadGuard)
+                           -> Vec<TransitionProperty> {
     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();
-        for &(ref declaration, importance) in keyframe.block.read().declarations().iter() {
+        let keyframe = keyframe.read_with(&guard);
+        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) {
                 if !seen.has_transition_property_bit(&property) {
                     ret.push(property);
                     seen.set_transition_property_bit(&property);
                 }
             }
@@ -265,86 +271,92 @@ impl KeyframesAnimation {
     /// Create a keyframes animation from a given list of keyframes.
     ///
     /// This will return a keyframe animation with empty steps and
     /// properties_changed if the list of keyframes is empty, or there are no
     //  animated properties obtained from the keyframes.
     ///
     /// Otherwise, this will compute and sort the steps used for the animation,
     /// and return the animation object.
-    pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Self {
+    pub fn from_keyframes(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRwLockReadGuard)
+                          -> Self {
         let mut result = KeyframesAnimation {
             steps: vec![],
             properties_changed: vec![],
         };
 
         if keyframes.is_empty() {
             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(),
-                }));
+                }, guard));
             }
         }
 
         // Sort by the start percentage, so we can easily find a frame.
         result.steps.sort_by_key(|step| step.start_percentage);
 
         // 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
     }
 }
 
 /// Parses a keyframes list, like:
 /// 0%, 50% {
 ///     width: 50%;
 /// }
 ///
 /// 40%, 60%, 100% {
 ///     width: 100%;
 /// }
 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<Arc<RwLock<Keyframe>>> {
-    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<Arc<Locked<Keyframe>>> {
+    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<RwLock<Keyframe>>;
+    type AtRule = Arc<Locked<Keyframe>>;
 }
 
 impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
     type Prelude = KeyframeSelector;
-    type QualifiedRule = Arc<RwLock<Keyframe>>;
+    type QualifiedRule = Arc<Locked<Keyframe>>;
 
     fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
         let start = input.position();
         match KeyframeSelector::parse(input) {
             Ok(sel) => Ok(sel),
             Err(()) => {
                 let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
                 log_css_error(input, start, &message, self.context);
@@ -367,19 +379,19 @@ impl<'a> QualifiedRuleParser for Keyfram
                     let pos = range.start;
                     let message = format!("Unsupported keyframe property declaration: '{}'",
                                           iter.input.slice(range));
                     log_css_error(iter.input, pos, &*message, self.context);
                 }
             }
             // `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)),
+            block: Arc::new(self.shared_lock.wrap(block)),
         })))
     }
 }
 
 struct KeyframeDeclarationParser<'a, 'b: 'a> {
     context: &'a ParserContext<'b>,
 }
 
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -52,20 +52,20 @@ extern crate heapsize;
 #[macro_use]
 extern crate lazy_static;
 #[macro_use]
 extern crate log;
 #[allow(unused_extern_crates)]
 #[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;
-extern crate owning_ref;
 extern crate parking_lot;
 extern crate pdqsort;
 extern crate rayon;
 extern crate selectors;
 #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
 #[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_url;
@@ -94,23 +94,23 @@ pub mod font_face;
 pub mod font_metrics;
 #[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
 #[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
 pub mod keyframes;
 #[allow(missing_docs)] // TODO.
 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;
 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;
 pub mod sink;
 pub mod str;
 pub mod stylesheets;
 pub mod supports;
 pub mod thread_state;
@@ -163,16 +163,18 @@ macro_rules! reexport_computed_values {
             // Don't use a side-specific name needlessly:
             pub use properties::longhands::border_top_style::computed_value as border_style;
         }
     }
 }
 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<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
     let a: &T = &**a;
     let b: &T = &**b;
     (a as *const T) == (b as *const T)
 }
 
 /// Serializes as CSS a comma-separated list of any `T` that supports being
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -536,16 +536,17 @@ trait PrivateMatchMethods: TElement {
                 unsafe { self.as_node().set_can_be_fragmented(can_be_fragmented); }
             }
         }
 
         // Invoke the cascade algorithm.
         let values =
             Arc::new(cascade(&shared_context.stylist.device,
                              rule_node,
+                             &shared_context.guards,
                              inherited_values,
                              layout_parent_style,
                              Some(&mut cascade_info),
                              &*shared_context.error_reporter,
                              cascade_flags));
 
         cascade_info.finish(&self.as_node());
         values
@@ -779,16 +780,17 @@ pub trait MatchMethods : TElement {
 
         // Compute the primary rule node.
         let mut primary_relations =
             stylist.push_applicable_declarations(self,
                                                  Some(context.thread_local.bloom_filter.filter()),
                                                  style_attribute,
                                                  animation_rules,
                                                  None,
+                                                 &context.shared.guards,
                                                  &mut applicable_declarations,
                                                  &mut flags);
         let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
         if !data.has_styles() {
             data.set_styles(ElementStyles::new(ComputedStyle::new_partial(primary_rule_node)));
             rule_nodes_changed = true;
         } else if data.styles().primary.rules != primary_rule_node {
             data.styles_mut().primary.rules = primary_rule_node;
@@ -804,16 +806,17 @@ pub trait MatchMethods : TElement {
                 self.get_animation_rules(Some(&pseudo))
             } else {
                 AnimationRules(None, None)
             };
             stylist.push_applicable_declarations(self,
                                                  Some(context.thread_local.bloom_filter.filter()),
                                                  None, pseudo_animation_rules,
                                                  Some(&pseudo),
+                                                 &context.shared.guards,
                                                  &mut applicable_declarations,
                                                  &mut flags);
 
             if !applicable_declarations.is_empty() {
                 let new_rules = compute_rule_node(context, &mut applicable_declarations);
                 match per_pseudo.entry(pseudo) {
                     Entry::Occupied(mut e) => {
                         if e.get().rules != new_rules {
@@ -878,26 +881,28 @@ pub trait MatchMethods : TElement {
         let mut rule_node_changed = false;
 
         if hint.contains(RESTYLE_STYLE_ATTRIBUTE) {
             let style_attribute = self.style_attribute();
 
             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;
             }
 
             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;
             }
         }
 
         // The per-pseudo rule nodes never change in this path.
         rule_node_changed
deleted file mode 100644
--- a/servo/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<O, H>
-    where O: StableAddress,
-          H: Deref,
-{
-    handle: H,
-    _owner: O,
-}
-
-impl<O, H> Deref for OwningHandle<O, H>
-    where O: StableAddress,
-          H: Deref,
-{
-    type Target = H::Target;
-    fn deref(&self) -> &H::Target {
-        self.handle.deref()
-    }
-}
-
-unsafe impl<O, H> StableAddress for OwningHandle<O, H>
-    where O: StableAddress,
-          H: StableAddress,
-{}
-
-impl<O, H> DerefMut for OwningHandle<O, H>
-    where O: StableAddress,
-          H: DerefMut,
-{
-    fn deref_mut(&mut self) -> &mut H::Target {
-        self.handle.deref_mut()
-    }
-}
-
-impl<O, H> OwningHandle<O, H>
-    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<F>(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,
-        }
-    }
-}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -26,16 +26,17 @@ use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
 #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
 use logical_geometry::WritingMode;
 use media_queries::Device;
 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::StylesheetGuards;
 use style_traits::ToCss;
 use stylesheets::Origin;
 #[cfg(feature = "servo")] use values::Either;
 use values::{HasViewportPercentage, computed};
 use cascade_info::CascadeInfo;
 use rule_tree::StrongRuleNode;
 #[cfg(feature = "servo")] use values::specified::BorderStyle;
 
@@ -1855,16 +1856,17 @@ bitflags! {
 ///
 ///   * `parent_style`: The parent style, if applicable; if `None`, this is the root node.
 ///
 /// Returns the computed values.
 ///   * `flags`: Various flags.
 ///
 pub fn cascade(device: &Device,
                rule_node: &StrongRuleNode,
+               guards: &StylesheetGuards,
                parent_style: Option<<&ComputedValues>,
                layout_parent_style: Option<<&ComputedValues>,
                cascade_info: Option<<&mut CascadeInfo>,
                error_reporter: &ParseErrorReporter,
                flags: CascadeFlags)
                -> ComputedValues {
     debug_assert_eq!(parent_style.is_some(), layout_parent_style.is_some());
     let (is_root_element, inherited_style, layout_parent_style) = match parent_style {
@@ -1877,21 +1879,22 @@ pub fn cascade(device: &Device,
             (true,
              device.default_computed_values(),
              device.default_computed_values())
         }
     };
 
     // 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::<Vec<_>>();
     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()
             .filter_map(move |&(ref declaration, declaration_importance)| {
                 if declaration_importance == source_importance {
                     Some(declaration)
                 } else {
                     None
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -5,19 +5,18 @@
 #![allow(unsafe_code)]
 #![deny(missing_docs)]
 
 //! The rule tree.
 
 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, StylesheetGuards, SharedRwLockReadGuard};
 use std::io::{self, Write};
 use std::ptr;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
 use stylesheets::StyleRule;
 use thread_state;
 
 /// The rule tree, the structure servo uses to preserve the results of selector
@@ -47,78 +46,52 @@ pub struct RuleTree {
 ///
 /// Note that, even though the declaration block from inside the style rule
 /// could be enough to implement the rule tree, keeping the whole rule provides
 /// more debuggability, and also the ability of show those selectors to
 /// devtools.
 #[derive(Debug, Clone)]
 pub enum StyleSource {
     /// A style rule stable pointer.
-    Style(Arc<RwLock<StyleRule>>),
+    Style(Arc<Locked<StyleRule>>),
     /// A declaration block stable pointer.
-    Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
-}
-
-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,
-        }
-    }
+    Declarations(Arc<Locked<PropertyDeclarationBlock>>),
 }
 
 impl StyleSource {
     #[inline]
     fn ptr_equals(&self, other: &Self) -> bool {
         use self::StyleSource::*;
         match (self, other) {
             (&Style(ref one), &Style(ref other)) => arc_ptr_eq(one, other),
             (&Declarations(ref one), &Declarations(ref other)) => arc_ptr_eq(one, other),
             _ => false,
         }
     }
 
-    fn dump<W: Write>(&self, writer: &mut W) {
+    fn dump<W: Write>(&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) -> &'a PropertyDeclarationBlock {
+        let block = match *self {
+            StyleSource::Style(ref rule) => &rule.read_with(guard).block,
+            StyleSource::Declarations(ref block) => block,
+        };
+        block.read_with(guard)
     }
 }
 
 /// This value exists here so a node that pushes itself to the list can know
 /// that is in the free list by looking at is next pointer, and comparing it
 /// with null.
 ///
 /// The root node doesn't have a null pointer in the free list, but this value.
@@ -132,25 +105,25 @@ impl RuleTree {
         }
     }
 
     /// Get the root rule node.
     pub fn root(&self) -> StrongRuleNode {
         self.root.clone()
     }
 
-    fn dump<W: Write>(&self, writer: &mut W) {
+    fn dump<W: Write>(&self, guards: &StylesheetGuards, 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: &StylesheetGuards) {
         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
     /// return the corresponding rule node representing the last inserted one.
     pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
         where I: Iterator<Item=(StyleSource, CascadeLevel)>,
     {
         self.insert_ordered_rules_from(self.root.clone(), iter)
@@ -182,18 +155,19 @@ impl RuleTree {
     }
 
     /// Replaces a rule in a given level (if present) for another rule.
     ///
     /// Returns the resulting node that represents the new path, or None if
     /// the old path is still valid.
     pub fn update_rule_at_level(&self,
                                 level: CascadeLevel,
-                                pdb: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
-                                path: &StrongRuleNode)
+                                pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
+                                path: &StrongRuleNode,
+                                guards: &StylesheetGuards)
                                 -> Option<StrongRuleNode> {
         debug_assert!(level.is_unique_per_element());
         // TODO(emilio): Being smarter with lifetimes we could avoid a bit of
         // the refcount churn.
         let mut current = path.clone();
 
         // First walk up until the first less-or-equally specific rule.
         let mut children = vec![];
@@ -242,23 +216,23 @@ impl RuleTree {
 
         // Insert the rule if it's relevant at this level in the cascade.
         //
         // These optimizations are likely to be important, because the levels
         // where replacements apply (style and animations) tend to trigger
         // 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);
                 }
             }
         }
 
         // Now the rule is in the relevant place, push the children as
@@ -302,16 +276,27 @@ pub enum CascadeLevel {
     UserImportant,
     /// User-agent important rules.
     UAImportant,
     /// Transitions
     Transitions,
 }
 
 impl CascadeLevel {
+    /// Select a lock guard for this level
+    pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'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 {
         match *self {
             CascadeLevel::Transitions |
             CascadeLevel::Animations |
             CascadeLevel::StyleAttributeNormal |
             CascadeLevel::StyleAttributeImportant => true,
@@ -445,46 +430,46 @@ impl RuleNode {
         // Store the previous sibling pointer in the next sibling if present,
         // otherwise we're done.
         if next_sibling != ptr::null_mut() {
             let next = &*next_sibling;
             next.prev_sibling.store(prev_sibling, Ordering::Relaxed);
         }
     }
 
-    fn dump<W: Write>(&self, writer: &mut W, indent: usize) {
+    fn dump<W: Write>(&self, guards: &StylesheetGuards, writer: &mut W, indent: usize) {
         const INDENT_INCREMENT: usize = 4;
 
         for _ in 0..indent {
             let _ = write!(writer, " ");
         }
 
         let _ = writeln!(writer, " - {:?} (ref: {:?}, parent: {:?})",
                          self as *const _, self.refcount.load(Ordering::SeqCst),
                          self.parent.as_ref().map(|p| p.ptr()));
 
         for _ in 0..indent {
             let _ = write!(writer, " ");
         }
 
         match self.source {
             Some(ref source) => {
-                source.dump(writer);
+                source.dump(self.level.guard(guards), writer);
             }
             None => {
                 if indent != 0 {
                     warn!("How has this happened?");
                 }
                 let _ = write!(writer, "(root)");
             }
         }
 
         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);
         }
     }
 
     fn iter_children(&self) -> RuleChildrenListIter {
         // FIXME(emilio): Fiddle with memory orderings.
         let first_child = self.first_child.load(Ordering::SeqCst);
         RuleChildrenListIter {
             current: if first_child.is_null() {
@@ -622,16 +607,21 @@ impl StrongRuleNode {
 
     /// Get the style source corresponding to this rule node. May return `None`
     /// if it's the root node, which means that the node hasn't matched any
     /// rules.
     pub fn style_source(&self) -> Option<&StyleSource> {
         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()
     }
 
     /// Get an iterator for this rule node and its ancestors.
     pub fn self_and_ancestors(&self) -> SelfAndAncestors {
         SelfAndAncestors {
--- a/servo/components/style/servo/mod.rs
+++ b/servo/components/style/servo/mod.rs
@@ -4,8 +4,18 @@
 
 //! Servo-specific bits of the style system.
 //!
 //! These get compiled out on a Gecko build.
 
 pub mod media_queries;
 pub mod restyle_damage;
 pub mod selector_parser;
+
+use shared_lock::SharedRwLock;
+
+lazy_static! {
+    /// Per-process shared lock for author-origin stylesheets
+    ///
+    /// FIXME: make it per-document or per-pipeline instead:
+    /// https://github.com/servo/servo/issues/16027
+    pub static ref AUTHOR_SHARED_LOCK: SharedRwLock = SharedRwLock::new();
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/style/shared_lock.rs
@@ -0,0 +1,199 @@
+/* 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<RwLock<()>>,
+}
+
+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<T>(&self, data: T) -> Locked<T> {
+        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<T> {
+    shared_lock: SharedRwLock,
+    data: UnsafeCell<T>,
+}
+
+// Unsafe: the data inside `UnsafeCell` is only accessed in `read_with` and `write_with`,
+// where guards ensure synchronization.
+unsafe impl<T: Send> Send for Locked<T> {}
+unsafe impl<T: Send + Sync> Sync for Locked<T> {}
+
+impl<T: fmt::Debug> fmt::Debug for Locked<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let guard = self.shared_lock.read();
+        self.read_with(&guard).fmt(f)
+    }
+}
+
+impl<T> Locked<T> {
+    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<T: Clone> Marker1 for T {}
+    impl<'a> Marker1 for SharedRwLockReadGuard<'a> {}  // Assert SharedRwLockReadGuard: !Clone
+    impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {}  // Assert SharedRwLockWriteGuard: !Clone
+
+    trait Marker2 {}
+    impl<T: Copy> Marker2 for T {}
+    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<W>(&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
+    }
+}
+
+/// Guards for a document
+#[derive(Clone)]
+pub struct StylesheetGuards<'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> StylesheetGuards<'a> {
+    /// Same guard for all origins
+    pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
+        StylesheetGuards {
+            author: guard,
+            ua_or_user: guard,
+        }
+    }
+}
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -16,16 +16,17 @@ use keyframes::{Keyframe, parse_keyframe
 use media_queries::{Device, MediaList, parse_media_query_list};
 use parking_lot::RwLock;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
 use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
 use selector_parser::{SelectorImpl, SelectorParser};
 use selectors::parser::SelectorList;
 use servo_config::prefs::PREFS;
 use servo_url::ServoUrl;
+use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard};
 use std::cell::Cell;
 use std::fmt;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, Ordering};
 use style_traits::ToCss;
 use stylist::FnvHashMap;
 use supports::SupportsCondition;
 use values::specified::url::SpecifiedUrl;
@@ -81,18 +82,18 @@ impl From<SingleRuleParseError> for Rule
             SingleRuleParseError::Syntax => RulesMutateError::Syntax,
             SingleRuleParseError::Hierarchy => RulesMutateError::HierarchyRequest,
         }
     }
 }
 
 impl CssRules {
     #[allow(missing_docs)]
-    pub fn new(rules: Vec<CssRule>) -> Arc<RwLock<CssRules>> {
-        Arc::new(RwLock::new(CssRules(rules)))
+    pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
+        Arc::new(shared_lock.wrap(CssRules(rules)))
     }
 
     fn only_ns_or_import(&self) -> bool {
         self.0.iter().all(|r| {
             match *r {
                 CssRule::Namespace(..) |
                 CssRule::Import(..) => true,
                 _ => false
@@ -168,58 +169,62 @@ impl CssRules {
     }
 }
 
 /// The structure servo uses to represent a stylesheet.
 #[derive(Debug)]
 pub struct Stylesheet {
     /// List of rules in the order they were found (important for
     /// cascading order)
-    pub rules: Arc<RwLock<CssRules>>,
+    pub rules: Arc<Locked<CssRules>>,
     /// List of media associated with the Stylesheet.
-    pub media: Arc<RwLock<MediaList>>,
+    pub media: Arc<Locked<MediaList>>,
     /// 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<Namespaces>,
     /// Whether this stylesheet would be dirty when the viewport size changes.
     pub dirty_on_viewport_size_change: AtomicBool,
     /// Whether this stylesheet should be disabled.
     pub disabled: AtomicBool,
 }
 
 
 /// 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<Stylesheet>,
     /// The quirks mode stylesheet.
     pub quirks_mode_stylesheet: Stylesheet,
 }
 
 
 /// A CSS rule.
 ///
 /// TODO(emilio): Lots of spec links should be around.
 #[derive(Debug, Clone)]
 #[allow(missing_docs)]
 pub enum CssRule {
     // No Charset here, CSSCharsetRule has been removed from CSSOM
     // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
 
-    Namespace(Arc<RwLock<NamespaceRule>>),
-    Import(Arc<RwLock<ImportRule>>),
-    Style(Arc<RwLock<StyleRule>>),
-    Media(Arc<RwLock<MediaRule>>),
-    FontFace(Arc<RwLock<FontFaceRule>>),
-    Viewport(Arc<RwLock<ViewportRule>>),
-    Keyframes(Arc<RwLock<KeyframesRule>>),
-    Supports(Arc<RwLock<SupportsRule>>),
+    Namespace(Arc<Locked<NamespaceRule>>),
+    Import(Arc<Locked<ImportRule>>),
+    Style(Arc<Locked<StyleRule>>),
+    Media(Arc<Locked<MediaRule>>),
+    FontFace(Arc<Locked<FontFaceRule>>),
+    Viewport(Arc<Locked<ViewportRule>>),
+    Keyframes(Arc<Locked<KeyframesRule>>),
+    Supports(Arc<Locked<SupportsRule>>),
 }
 
 #[allow(missing_docs)]
 pub enum CssRuleType {
     // https://drafts.csswg.org/cssom/#the-cssrule-interface
     Style               = 1,
     Charset             = 2,
     Import              = 3,
@@ -286,45 +291,45 @@ impl CssRule {
     }
 
     /// Call `f` with the slice of rules directly contained inside this rule.
     ///
     /// Note that only some types of rules can contain rules. An empty slice is
     /// used for others.
     ///
     /// This will not recurse down unsupported @supports rules
-    pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R
+    pub fn with_nested_rules_and_mq<F, R>(&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 rules = rule.stylesheet.rules.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
                 // loaded.
                 f(&rules.0, Some(&media))
             }
             CssRule::Namespace(_) |
             CssRule::Style(_) |
             CssRule::FontFace(_) |
             CssRule::Viewport(_) |
             CssRule::Keyframes(_) => {
                 f(&[], None)
             }
             CssRule::Media(ref lock) => {
-                let media_rule = lock.read();
-                let mq = media_rule.media_queries.read();
-                let rules = &media_rule.rules.read().0;
+                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().0;
+                    let rules = &supports_rule.rules.read_with(guard).0;
                     f(rules, None)
                 } else {
                     f(&[], None)
                 }
             }
         }
     }
 
@@ -344,16 +349,17 @@ impl CssRule {
                                                          extra_data);
         let mut input = Parser::new(css);
 
         // nested rules are in the body state
         let state = state.unwrap_or(State::Body);
         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,
         };
         match parse_one_rule(&mut input, &mut rule_parser) {
             Ok(result) => Ok((result, rule_parser.state.get())),
             Err(_) => {
                 if let State::Invalid = rule_parser.state.get() {
@@ -361,43 +367,45 @@ impl CssRule {
                 } else {
                     Err(SingleRuleParseError::Syntax)
                 }
             }
         }
     }
 }
 
-impl ToCss for CssRule {
+impl ToCssWithGuard for CssRule {
     // https://drafts.csswg.org/cssom/#serialize-a-css-rule
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&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_with(guard).to_css(guard, dest),
+            CssRule::Import(ref lock) => lock.read_with(guard).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),
+            CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest),
+            CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest),
         }
     }
 }
 
 #[derive(Debug, PartialEq)]
 #[allow(missing_docs)]
 pub struct NamespaceRule {
     /// `None` for the default Namespace
     pub prefix: Option<Prefix>,
     pub url: Namespace,
 }
 
-impl ToCss for NamespaceRule {
+impl ToCssWithGuard for NamespaceRule {
     // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&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()));
             try!(dest.write_str(" "));
         }
         try!(dest.write_str("url(\""));
         try!(dest.write_str(&*self.url.to_string()));
         dest.write_str("\");")
@@ -415,123 +423,128 @@ pub struct ImportRule {
 
     /// The stylesheet is always present.
     ///
     /// It contains an empty list of rules and namespace set that is updated
     /// when it loads.
     pub stylesheet: Arc<Stylesheet>,
 }
 
-impl ToCss for ImportRule {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+impl ToCssWithGuard for ImportRule {
+    fn to_css<W>(&self, guard: &SharedRwLockReadGuard, 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 media = self.stylesheet.media.read_with(guard);
         if !media.is_empty() {
             try!(dest.write_str(" "));
             try!(media.to_css(dest));
         }
         dest.write_str(";")
     }
 }
 
 /// A [`@keyframes`][keyframes] rule.
 ///
 /// [keyframes]: https://drafts.csswg.org/css-animations/#keyframes
 #[derive(Debug)]
 pub struct KeyframesRule {
     /// The name of the current animation.
     pub name: Atom,
     /// The keyframes specified for this CSS rule.
-    pub keyframes: Vec<Arc<RwLock<Keyframe>>>,
+    pub keyframes: Vec<Arc<Locked<Keyframe>>>,
 }
 
-impl ToCss for KeyframesRule {
+impl ToCssWithGuard for KeyframesRule {
     // Serialization of KeyframesRule is not specced.
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&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(" { "));
         let iter = self.keyframes.iter();
         let mut first = true;
         for lock in iter {
             if !first {
                 try!(dest.write_str(" "));
             }
             first = false;
-            let keyframe = lock.read();
-            try!(keyframe.to_css(dest));
+            let keyframe = lock.read_with(&guard);
+            try!(keyframe.to_css(guard, dest));
         }
         dest.write_str(" }")
     }
 }
 
 #[allow(missing_docs)]
 #[derive(Debug)]
 pub struct MediaRule {
-    pub media_queries: Arc<RwLock<MediaList>>,
-    pub rules: Arc<RwLock<CssRules>>,
+    pub media_queries: Arc<Locked<MediaList>>,
+    pub rules: Arc<Locked<CssRules>>,
 }
 
-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<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&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() {
+        for rule in self.rules.read_with(guard).0.iter() {
             try!(dest.write_str(" "));
-            try!(rule.to_css(dest));
+            try!(rule.to_css(guard, dest));
         }
         dest.write_str(" }")
     }
 }
 
 
 #[derive(Debug)]
 /// An @supports rule
 pub struct SupportsRule {
     /// The parsed condition
     pub condition: SupportsCondition,
     /// Child rules
-    pub rules: Arc<RwLock<CssRules>>,
+    pub rules: Arc<Locked<CssRules>>,
     /// The result of evaluating the condition
     pub enabled: bool,
 }
 
-impl ToCss for SupportsRule {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+impl ToCssWithGuard for SupportsRule {
+    fn to_css<W>(&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() {
+        for rule in self.rules.read_with(guard).0.iter() {
             try!(dest.write_str(" "));
-            try!(rule.to_css(dest));
+            try!(rule.to_css(guard, dest));
         }
         dest.write_str(" }")
     }
 }
 
 #[allow(missing_docs)]
 #[derive(Debug)]
 pub struct StyleRule {
     pub selectors: SelectorList<SelectorImpl>,
-    pub block: Arc<RwLock<PropertyDeclarationBlock>>,
+    pub block: Arc<Locked<PropertyDeclarationBlock>>,
 }
 
-impl ToCss for StyleRule {
+impl ToCssWithGuard for StyleRule {
     // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&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 {
             try!(write!(dest, " "));
         }
         // Step 5
         try!(dest.write_str("}"));
         Ok(())
@@ -540,82 +553,101 @@ impl ToCss for StyleRule {
 
 impl Stylesheet {
     /// Updates an empty stylesheet from a given string of text.
     pub fn update_from_str(existing: &Stylesheet,
                            css: &str,
                            stylesheet_loader: Option<&StylesheetLoader>,
                            error_reporter: &ParseErrorReporter,
                            extra_data: ParserContextExtraData) {
-        let mut rules = existing.rules.write();
-        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,
+        );
+
+        *existing.namespaces.write() = namespaces;
+        existing.dirty_on_viewport_size_change
+            .store(dirty_on_viewport_size_change, Ordering::Release);
 
-        assert!(rules.is_empty());
+        // 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<CssRule>, bool) {
+        let mut rules = Vec::new();
         let mut input = Parser::new(css);
         let rule_parser = TopLevelRuleParser {
-            stylesheet_origin: existing.origin,
-            namespaces: &mut namespaces,
+            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),
         };
 
         input.look_for_viewport_percentages();
 
         {
             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));
                         log_css_error(iter.input, pos, &*message, &iter.parser.context);
                     }
                 }
             }
         }
 
-        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
     /// and media.
     ///
     /// Effectively creates a new stylesheet and forwards the hard work to
     /// `Stylesheet::update_from_str`.
     pub fn from_str(css: &str,
                     base_url: ServoUrl,
                     origin: Origin,
                     media: MediaList,
+                    shared_lock: SharedRwLock,
                     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![]),
-            media: Arc::new(RwLock::new(media)),
-            dirty_on_viewport_size_change: AtomicBool::new(false),
+            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(dirty_on_viewport_size_change),
             disabled: AtomicBool::new(false),
-        };
-
-        Self::update_from_str(&s,
-                              css,
-                              stylesheet_loader,
-                              error_reporter,
-                              extra_data);
-
-        s
+        }
     }
 
     /// Whether this stylesheet can be dirty on viewport size change.
     pub fn dirty_on_viewport_size_change(&self) -> bool {
         self.dirty_on_viewport_size_change.load(Ordering::SeqCst)
     }
 
     /// When CSSOM inserts a rule or declaration into this stylesheet, it needs to call this method
@@ -632,29 +664,30 @@ impl Stylesheet {
     pub fn inserted_has_viewport_percentages(&self, has_viewport_percentages: bool) {
         self.dirty_on_viewport_size_change.fetch_or(has_viewport_percentages, Ordering::SeqCst);
     }
 
     /// Returns whether the style-sheet applies for the current device depending
     /// on the associated MediaList.
     ///
     /// Always true if no associated MediaList exists.
-    pub fn is_effective_for_device(&self, device: &Device) -> bool {
-        self.media.read().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
     /// according to the supplied `Device`.
     ///
     /// If a condition does not hold, its associated conditional group rule and
     /// nested rules will be skipped. Use `rules` if all rules need to be
     /// examined.
     #[inline]
-    pub fn effective_rules<F>(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) {
-        effective_rules(&self.rules.read().0, device, &mut f);
+    pub fn effective_rules<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
+    where F: FnMut(&CssRule) {
+        effective_rules(&self.rules.read_with(guard).0, device, guard, &mut f);
     }
 
     /// Returns whether the stylesheet has been explicitly disabled through the
     /// CSSOM.
     pub fn disabled(&self) -> bool {
         self.disabled.load(Ordering::SeqCst)
     }
 
@@ -665,39 +698,41 @@ impl Stylesheet {
     ///
     /// Disabled stylesheets remain in the document, but their rules are not
     /// added to the Stylist.
     pub fn set_disabled(&self, disabled: bool) -> bool {
         self.disabled.swap(disabled, Ordering::SeqCst) != disabled
     }
 }
 
-fn effective_rules<F>(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) {
+fn effective_rules<F>(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)
         })
     }
 }
 
 macro_rules! rule_filter {
     ($( $method: ident($variant:ident => $rule_type: ident), )+) => {
         impl Stylesheet {
             $(
                 #[allow(missing_docs)]
-                pub fn $method<F>(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) {
-                    self.effective_rules(device, |rule| {
+                pub fn $method<F>(&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();
+                            let rule = lock.read_with(guard);
                             f(&rule)
                         }
                     })
                 }
             )+
         }
     }
 }
@@ -713,31 +748,55 @@ rule_filter! {
 
 /// The stylesheet loader is the abstraction used to trigger network requests
 /// for `@import` rules.
 pub trait StylesheetLoader {
     /// Request a stylesheet after parsing a given `@import` rule.
     ///
     /// The called code is responsible to update the `stylesheet` rules field
     /// when the sheet is done loading.
-    fn request_stylesheet(&self, import: &Arc<RwLock<ImportRule>>);
+    ///
+    /// 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<Locked<ImportRule>>,
+    ) -> Arc<Locked<ImportRule>>;
 }
 
+struct NoOpLoader;
+
+impl StylesheetLoader for NoOpLoader {
+    fn request_stylesheet(
+        &self,
+        media: MediaList,
+        make_import: &mut FnMut(MediaList) -> ImportRule,
+        make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
+    ) -> Arc<Locked<ImportRule>> {
+        make_arc(make_import(media))
+    }
+}
+
+
 struct TopLevelRuleParser<'a> {
     stylesheet_origin: Origin,
     namespaces: &'a mut Namespaces,
+    shared_lock: &'a SharedRwLock,
     loader: Option<&'a StylesheetLoader>,
     context: ParserContext<'a>,
     state: Cell<State>,
 }
 
 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,
         }
     }
 }
 
 #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
 #[allow(missing_docs)]
@@ -749,17 +808,17 @@ pub enum State {
     Invalid = 5,
 }
 
 
 enum AtRulePrelude {
     /// A @font-face rule prelude.
     FontFace,
     /// A @media rule prelude, with its media queries.
-    Media(Arc<RwLock<MediaList>>),
+    Media(Arc<Locked<MediaList>>),
     /// An @supports rule, with its conditional
     Supports(SupportsCondition),
     /// A @viewport rule prelude.
     Viewport,
     /// A @keyframes rule, with its animation name.
     Keyframes(Atom),
 }
 
@@ -769,48 +828,48 @@ impl<'a> AtRuleParser for TopLevelRulePa
     type AtRule = CssRule;
 
     fn parse_prelude(&mut self, name: &str, input: &mut Parser)
                      -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> {
         match_ignore_ascii_case! { name,
             "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(RwLock::new(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(RwLock::new(
+                    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: Arc::new(RwLock::new(CssRules(vec![]))),
-                                media: media,
+                                rules: CssRules::new(Vec::new(), self.shared_lock),
+                                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(),
                                 namespaces: RwLock::new(Namespaces::default()),
                                 dirty_on_viewport_size_change: AtomicBool::new(false),
                                 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"
                 }
             },
             "namespace" => {
                 if self.state.get() <= State::Namespaces {
                     self.state.set(State::Namespaces);
@@ -822,22 +881,22 @@ impl<'a> AtRuleParser for TopLevelRulePa
                         let prefix = Prefix::from(prefix);
                         self.namespaces.prefixes.insert(prefix.clone(), url.clone());
                         Some(prefix)
                     } else {
                         self.namespaces.default = Some(url.clone());
                         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"
                 }
             },
             // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
             // anything left is invalid.
             "charset" => return Err(()), // (insert appropriate error message)
@@ -874,48 +933,50 @@ impl<'a> QualifiedRuleParser for TopLeve
                    -> Result<CssRule, ()> {
         QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input)
     }
 }
 
 #[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,
 }
 
 impl<'a, 'b> NestedRuleParser<'a, 'b> {
-    fn parse_nested_rules(&self, input: &mut Parser) -> Arc<RwLock<CssRules>> {
+    fn parse_nested_rules(&self, input: &mut Parser) -> Arc<Locked<CssRules>> {
         let mut iter = RuleListParser::new_for_nested_rule(input, self.clone());
         let mut rules = Vec::new();
         while let Some(result) = iter.next() {
             match result {
                 Ok(rule) => rules.push(rule),
                 Err(range) => {
                     let pos = range.start;
                     let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
                     log_css_error(iter.input, pos, &*message, self.context);
                 }
             }
         }
-        CssRules::new(rules)
+        CssRules::new(rules, self.shared_lock)
     }
 }
 
 impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
     type Prelude = AtRulePrelude;
     type AtRule = CssRule;
 
     fn parse_prelude(&mut self, name: &str, input: &mut Parser)
                      -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> {
         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)?;
                 Ok(AtRuleType::WithBlock(AtRulePrelude::Supports(cond)))
             },
             "font-face" => {
                 Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace))
             },
@@ -938,41 +999,41 @@ impl<'a, 'b> AtRuleParser for NestedRule
             },
             _ => Err(())
         }
     }
 
     fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> {
         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),
+                    keyframes: parse_keyframe_list(&self.context, input, self.shared_lock),
                 }))))
             }
         }
     }
 }
 
 impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
     type Prelude = SelectorList<SelectorImpl>;
@@ -983,14 +1044,15 @@ impl<'a, 'b> QualifiedRuleParser for Nes
             stylesheet_origin: self.stylesheet_origin,
             namespaces: self.namespaces,
         };
         SelectorList::parse(&selector_parser, input)
     }
 
     fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
                    -> Result<CssRule, ()> {
-        Ok(CssRule::Style(Arc::new(RwLock::new(StyleRule {
+        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))
         }))))
     }
 }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -7,32 +7,32 @@
 #![deny(missing_docs)]
 
 use {Atom, LocalName};
 use data::ComputedStyle;
 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")]
 use properties::INHERIT_ALL;
 use properties::PropertyDeclarationBlock;
 use restyle_hints::{RestyleHint, DependencySet};
 use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
 use selector_parser::{SelectorImpl, PseudoElement, Snapshot};
 use selectors::Element;
 use selectors::bloom::BloomFilter;
 use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
 use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
 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, StylesheetGuards};
 use sink::Push;
 use smallvec::VecLike;
 use std::borrow::Borrow;
 use std::collections::HashMap;
 use std::fmt;
 use std::hash::Hash;
 use std::sync::Arc;
 use style_traits::viewport::ViewportConstraints;
@@ -153,24 +153,27 @@ impl Stylist {
     /// Update the stylist for the given document stylesheets, and optionally
     /// with a set of user agent stylesheets.
     ///
     /// This method resets all the style data each time the stylesheets change
     /// (which is indicated by the `stylesheets_changed` parameter), or the
     /// device is dirty, which means we need to re-evaluate media queries.
     pub fn update(&mut self,
                   doc_stylesheets: &[Arc<Stylesheet>],
+                  guards: &StylesheetGuards,
                   ua_stylesheets: Option<&UserAgentStylesheets>,
                   stylesheets_changed: bool) -> bool {
         if !(self.is_device_dirty || stylesheets_changed) {
             return false;
         }
 
         let cascaded_rule = ViewportRule {
-            declarations: viewport::Cascade::from_stylesheets(doc_stylesheets, &self.device).finish(),
+            declarations: viewport::Cascade::from_stylesheets(
+                doc_stylesheets, guards.author, &self.device
+            ).finish(),
         };
 
         self.viewport_constraints =
             ViewportConstraints::maybe_new(&self.device, &cascaded_rule);
 
         if let Some(ref constraints) = self.viewport_constraints {
             Arc::get_mut(&mut self.device).unwrap()
                 .account_for_viewport_rule(constraints);
@@ -188,99 +191,101 @@ impl Stylist {
         self.state_deps.clear();
         self.animations.clear();
 
         self.sibling_affecting_selectors.clear();
         self.non_common_style_affecting_attributes_selectors.clear();
 
         if let Some(ua_stylesheets) = ua_stylesheets {
             for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
-                self.add_stylesheet(&stylesheet);
+                self.add_stylesheet(&stylesheet, guards.ua_or_user);
             }
 
             if self.quirks_mode {
-                self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet);
+                self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user);
             }
         }
 
         for ref stylesheet in doc_stylesheets.iter() {
-            self.add_stylesheet(stylesheet);
+            self.add_stylesheet(stylesheet, guards.author);
         }
 
         debug!("Stylist stats:");
         debug!(" - Got {} sibling-affecting selectors",
                self.sibling_affecting_selectors.len());
         debug!(" - Got {} non-common-style-attribute-affecting selectors",
                self.non_common_style_affecting_attributes_selectors.len());
         debug!(" - Got {} deps for style-hint calculation",
                self.state_deps.len());
 
         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);
             }
         });
 
         self.is_device_dirty = false;
         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;
         }
 
         // 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();
-                    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())
                                 .or_insert_with(PerPseudoElementSelectorMap::new)
                                 .borrow_for_origin(&stylesheet.origin)
                         } else {
                             self.element_map.borrow_for_origin(&stylesheet.origin)
                         };
 
                         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());
                         }
 
                         if selector.matches_non_common_style_affecting_attribute() {
                             self.non_common_style_affecting_attributes_selectors.push(selector.clone());
                         }
                     }
                 }
                 CssRule::Import(ref import) => {
-                    let import = import.read();
-                    self.add_stylesheet(&import.stylesheet)
+                    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);
+                    let animation = KeyframesAnimation::from_keyframes(
+                        &keyframes_rule.keyframes, guard);
                     debug!("Found valid keyframe animation: {:?}", animation);
                     self.animations.insert(keyframes_rule.name.clone(), animation);
                 }
                 // We don't care about any other rule.
                 _ => {}
             }
         });
     }
@@ -289,16 +294,17 @@ impl Stylist {
     /// Computes the style for a given "precomputed" pseudo-element, taking the
     /// universal rules and applying them.
     ///
     /// If `inherit_all` is true, then all properties are inherited from the
     /// parent; otherwise, non-inherited properties are reset to their initial
     /// values. The flow constructor uses this flag when constructing anonymous
     /// flows.
     pub fn precomputed_values_for_pseudo(&self,
+                                         guards: &StylesheetGuards,
                                          pseudo: &PseudoElement,
                                          parent: Option<&Arc<ComputedValues>>,
                                          cascade_flags: CascadeFlags)
                                          -> ComputedStyle {
         debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_precomputed());
 
         let rule_node = match self.precomputed_pseudo_element_decls.get(pseudo) {
             Some(declarations) => {
@@ -322,27 +328,29 @@ impl Stylist {
         //
         // In practice, I don't think any anonymous content can be a direct
         // descendant of a display: contents element where display: contents is
         // the actual used value, and the computed value of it would need
         // blockification.
         let computed =
             properties::cascade(&self.device,
                                 &rule_node,
+                                guards,
                                 parent.map(|p| &**p),
                                 parent.map(|p| &**p),
                                 None,
                                 &StdoutErrorReporter,
                                 cascade_flags);
         ComputedStyle::new(rule_node, Arc::new(computed))
     }
 
     /// Returns the style for an anonymous box of the given type.
     #[cfg(feature = "servo")]
     pub fn style_for_anonymous_box(&self,
+                                   guards: &StylesheetGuards,
                                    pseudo: &PseudoElement,
                                    parent_style: &Arc<ComputedValues>)
                                    -> Arc<ComputedValues> {
         // For most (but not all) pseudo-elements, we inherit all values from the parent.
         let inherit_all = match *pseudo {
             PseudoElement::ServoInputText => false,
             PseudoElement::ServoAnonymousBlock |
             PseudoElement::ServoAnonymousTable |
@@ -357,28 +365,29 @@ impl Stylist {
             PseudoElement::DetailsContent => {
                 unreachable!("That pseudo doesn't represent an anonymous box!")
             }
         };
         let mut cascade_flags = CascadeFlags::empty();
         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()
     }
 
     /// Computes a pseudo-element style lazily during layout.
     ///
     /// This can only be done for a certain set of pseudo-elements, like
     /// :selection.
     ///
     /// Check the documentation on lazy pseudo-elements in
     /// docs/components/style.md
     pub fn lazily_compute_pseudo_element_style<E>(&self,
+                                                  guards: &StylesheetGuards,
                                                   element: &E,
                                                   pseudo: &PseudoElement,
                                                   parent: &Arc<ComputedValues>)
                                                   -> Option<ComputedStyle>
         where E: TElement +
                  fmt::Debug +
                  PresentationalHintsSynthetizer
     {
@@ -390,30 +399,32 @@ impl Stylist {
         let mut declarations = vec![];
 
         let mut flags = ElementSelectorFlags::empty();
         self.push_applicable_declarations(element,
                                           None,
                                           None,
                                           AnimationRules(None, None),
                                           Some(pseudo),
+                                          guards,
                                           &mut declarations,
                                           &mut flags);
 
         let rule_node =
             self.rule_tree.insert_ordered_rules(
                 declarations.into_iter().map(|a| (a.source, a.level)));
 
         // Read the comment on `precomputed_values_for_pseudo` to see why it's
         // difficult to assert that display: contents nodes never arrive here
         // (tl;dr: It doesn't apply for replaced elements and such, but the
         // computed value is still "contents").
         let computed =
             properties::cascade(&self.device,
                                 &rule_node,
+                                guards,
                                 Some(&**parent),
                                 Some(&**parent),
                                 None,
                                 &StdoutErrorReporter,
                                 CascadeFlags::empty());
 
         // Apply the selector flags. We should be in sequential mode already,
         // so we can directly apply the parent flags.
@@ -456,51 +467,53 @@ impl Stylist {
     /// `update_device` function?
     ///
     /// feature = "servo" because gecko only has one device, and manually tracks
     /// when the device is dirty.
     ///
     /// 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<Stylesheet>]) {
+    pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard,
+                      stylesheets: &[Arc<Stylesheet>]) {
         let cascaded_rule = ViewportRule {
-            declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(),
+            declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(),
         };
 
         self.viewport_constraints =
             ViewportConstraints::maybe_new(&device, &cascaded_rule);
 
         if let Some(ref constraints) = self.viewport_constraints {
             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
                 }
             }
             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_with(guard).0, &self.device, &device)
         });
 
         self.device = Arc::new(device);
     }
 
     /// Returns the viewport constraints that apply to this document because of
     /// a @viewport rule.
     pub fn viewport_constraints(&self) -> Option<&ViewportConstraints> {
@@ -523,19 +536,20 @@ impl Stylist {
     /// This corresponds to `ElementRuleCollector` in WebKit.
     ///
     /// The returned `StyleRelations` indicate hints about which kind of rules
     /// have matched.
     pub fn push_applicable_declarations<E, V>(
                                         &self,
                                         element: &E,
                                         parent_bf: Option<&BloomFilter>,
-                                        style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
+                                        style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
                                         animation_rules: AnimationRules,
                                         pseudo_element: Option<&PseudoElement>,
+                                        guards: &StylesheetGuards,
                                         applicable_declarations: &mut V,
                                         flags: &mut ElementSelectorFlags) -> StyleRelations
         where E: TElement +
                  fmt::Debug +
                  PresentationalHintsSynthetizer,
               V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>
     {
         debug_assert!(!self.is_device_dirty);
@@ -551,16 +565,17 @@ impl Stylist {
         };
 
         let mut relations = StyleRelations::empty();
 
         debug!("Determining if style is shareable: pseudo: {}", pseudo_element.is_some());
         // 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,
                                               CascadeLevel::UANormal);
         debug!("UA normal: {:?}", relations);
 
         // Step 2: Presentational hints.
         let length_before_preshints = applicable_declarations.len();
@@ -575,32 +590,34 @@ impl Stylist {
             relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
         }
         debug!("preshints: {:?}", relations);
 
         if element.matches_user_and_author_rules() {
             // 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,
                                             CascadeLevel::UserNormal);
             debug!("user normal: {:?}", relations);
             map.author.get_all_matching_rules(element,
                                               parent_bf,
+                                              guards.author,
                                               applicable_declarations,
                                               &mut relations,
                                               flags,
                                               CascadeLevel::AuthorNormal);
             debug!("author normal: {:?}", relations);
 
             // 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,
                         ApplicableDeclarationBlock::from_declarations(sa.clone(),
                                                                       CascadeLevel::StyleAttributeNormal));
                 }
             }
 
@@ -616,52 +633,55 @@ impl Stylist {
                     ApplicableDeclarationBlock::from_declarations(anim.clone(),
                                                                   CascadeLevel::Animations));
             }
             debug!("animation: {:?}", relations);
 
             // Step 6: Author-supplied `!important` rules.
             map.author.get_all_matching_rules(element,
                                               parent_bf,
+                                              guards.author,
                                               applicable_declarations,
                                               &mut relations,
                                               flags,
                                               CascadeLevel::AuthorImportant);
 
             debug!("author important: {:?}", relations);
 
             // 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,
                         ApplicableDeclarationBlock::from_declarations(sa.clone(),
                                                                       CascadeLevel::StyleAttributeImportant));
                 }
             }
 
             debug!("style attr important: {:?}", relations);
 
             // Step 8: User `!important` rules.
             map.user.get_all_matching_rules(element,
                                             parent_bf,
+                                            guards.ua_or_user,
                                             applicable_declarations,
                                             &mut relations,
                                             flags,
                                             CascadeLevel::UserImportant);
 
             debug!("user important: {:?}", relations);
         } else {
             debug!("skipping non-agent rules");
         }
 
         // Step 9: UA `!important` rules.
         map.user_agent.get_all_matching_rules(element,
                                               parent_bf,
+                                              guards.ua_or_user,
                                               applicable_declarations,
                                               &mut relations,
                                               flags,
                                               CascadeLevel::UAImportant);
 
         debug!("UA important: {:?}", relations);
 
         // Step 10: Transitions.
@@ -890,16 +910,17 @@ impl SelectorMap {
 
     /// Append to `rule_list` all Rules in `self` that match element.
     ///
     /// Extract matching rules as per element's ID, classes, tag name, etc..
     /// Sort the Rules at the end to maintain cascading order.
     pub fn get_all_matching_rules<E, V>(&self,
                                         element: &E,
                                         parent_bf: Option<&BloomFilter>,
+                                        guard: &SharedRwLockReadGuard,
                                         matching_rules_list: &mut V,
                                         relations: &mut StyleRelations,
                                         flags: &mut ElementSelectorFlags,
                                         cascade_level: CascadeLevel)
         where E: Element<Impl=SelectorImpl>,
               V: VecLike<ApplicableDeclarationBlock>
     {
         if self.empty {
@@ -908,63 +929,68 @@ impl SelectorMap {
 
         // At the end, we're going to sort the rules that we added, so remember where we began.
         let init_len = matching_rules_list.len();
         if let Some(id) = element.get_id() {
             SelectorMap::get_matching_rules_from_hash(element,
                                                       parent_bf,
                                                       &self.id_hash,
                                                       &id,
+                                                      guard,
                                                       matching_rules_list,
                                                       relations,
                                                       flags,
                                                       cascade_level)
         }
 
         element.each_class(|class| {
             SelectorMap::get_matching_rules_from_hash(element,
                                                       parent_bf,
                                                       &self.class_hash,
                                                       class,
+                                                      guard,
                                                       matching_rules_list,
                                                       relations,
                                                       flags,
                                                       cascade_level);
         });
 
         let local_name_hash = if element.is_html_element_in_html_document() {
             &self.lower_local_name_hash
         } else {
             &self.local_name_hash
         };
         SelectorMap::get_matching_rules_from_hash(element,
                                                   parent_bf,
                                                   local_name_hash,
                                                   element.get_local_name(),
+                                                  guard,
                                                   matching_rules_list,
                                                   relations,
                                                   flags,
                                                   cascade_level);
 
         SelectorMap::get_matching_rules(element,
                                         parent_bf,
                                         &self.other_rules,
+                                        guard,
                                         matching_rules_list,
                                         relations,
                                         flags,
                                         cascade_level);
 
         // Sort only the rules we just added.
         sort_by_key(&mut matching_rules_list[init_len..],
                     |block| (block.specificity, block.source_order));
     }
 
     /// 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<ApplicableDeclarationBlock> {
         debug_assert!(!cascade_level.is_important());
         debug_assert!(important_cascade_level.is_important());
         if self.empty {
             return vec![];
         }
@@ -972,18 +998,18 @@ impl SelectorMap {
         let mut matching_rules_list = vec![];
 
         // We need to insert important rules _after_ normal rules for this to be
         // correct, and also to not trigger rule tree assertions.
         let mut important = vec![];
         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_with(guard);
                 if block.any_normal() {
                     matching_rules_list.push(
                         rule.to_applicable_declaration_block(cascade_level));
                 }
                 if block.any_important() {
                     important.push(
                         rule.to_applicable_declaration_block(important_cascade_level));
                 }
@@ -1001,50 +1027,53 @@ impl SelectorMap {
         matching_rules_list
     }
 
     fn get_matching_rules_from_hash<E, Str, BorrowedStr: ?Sized, Vector>(
         element: &E,
         parent_bf: Option<&BloomFilter>,
         hash: &FnvHashMap<Str, Vec<Rule>>,
         key: &BorrowedStr,
+        guard: &SharedRwLockReadGuard,
         matching_rules: &mut Vector,
         relations: &mut StyleRelations,
         flags: &mut ElementSelectorFlags,
         cascade_level: CascadeLevel)
         where E: Element<Impl=SelectorImpl>,
               Str: Borrow<BorrowedStr> + Eq + Hash,
               BorrowedStr: Eq + Hash,
               Vector: VecLike<ApplicableDeclarationBlock>
     {
         if let Some(rules) = hash.get(key) {
             SelectorMap::get_matching_rules(element,
                                             parent_bf,
                                             rules,
+                                            guard,
                                             matching_rules,
                                             relations,
                                             flags,
                                             cascade_level)
         }
     }
 
     /// Adds rules in `rules` that match `element` to the `matching_rules` list.
     fn get_matching_rules<E, V>(element: &E,
                                 parent_bf: Option<&BloomFilter>,
                                 rules: &[Rule],
+                                guard: &SharedRwLockReadGuard,
                                 matching_rules: &mut V,
                                 relations: &mut StyleRelations,
                                 flags: &mut ElementSelectorFlags,
                                 cascade_level: CascadeLevel)
         where E: Element<Impl=SelectorImpl>,
               V: VecLike<ApplicableDeclarationBlock>
     {
         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_with(guard);
             let any_declaration_for_importance = if cascade_level.is_important() {
                 block.any_important()
             } else {
                 block.any_normal()
             };
             if any_declaration_for_importance &&
                matches_complex_selector(&*rule.selector, element, parent_bf,
                                         relations, flags) {
@@ -1132,17 +1161,17 @@ pub struct Rule {
     /// FIXME(emilio): We should be able to get rid of it and just use the style
     /// rule? This predates the time where the rule was in `selectors`, and the
     /// style rule was a generic parameter to it. It's not trivial though, due
     /// to the specificity.
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
     pub selector: Arc<ComplexSelector<SelectorImpl>>,
     /// The actual style rule.
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-    pub style_rule: Arc<RwLock<StyleRule>>,
+    pub style_rule: Arc<Locked<StyleRule>>,
     /// The source order this style rule appears in.
     pub source_order: usize,
     /// The specificity of the rule this selector represents.
     pub specificity: u32,
 }
 
 impl Rule {
     fn to_applicable_declaration_block(&self, level: CascadeLevel) -> ApplicableDeclarationBlock {
@@ -1173,17 +1202,17 @@ pub struct ApplicableDeclarationBlock {
     /// The specificity of the selector this block is represented by.
     pub specificity: u32,
 }
 
 impl ApplicableDeclarationBlock {
     /// Constructs an applicable declaration block from a given property
     /// declaration block and importance.
     #[inline]
-    pub fn from_declarations(declarations: Arc<RwLock<PropertyDeclarationBlock>>,
+    pub fn from_declarations(declarations: Arc<Locked<PropertyDeclarationBlock>>,
                              level: CascadeLevel)
                              -> Self {
         ApplicableDeclarationBlock {
             source: StyleSource::Declarations(declarations),
             level: level,
             source_order: 0,
             specificity: 0,
         }
--- a/servo/components/style/traversal.rs
+++ b/servo/components/style/traversal.rs
@@ -307,17 +307,18 @@ pub trait DomTraversal<E: TElement> : Sy
     /// NB: We do this check on runtime. We could guarantee correctness in this
     /// regard via the type system via a `TraversalDriver` trait for this trait,
     /// that could be one of two concrete types. It's not clear whether the
     /// potential code size impact of that is worth it.
     fn is_parallel(&self) -> bool;
 }
 
 /// Helper for the function below.
-fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, element: E, ensure_data: &F)
+fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
+                                element: E, ensure_data: &F)
                                 -> Option<E>
     where E: TElement,
           F: Fn(E),
 {
     ensure_data(element);
     let mut data = element.mutate_data().unwrap();
     let mut display_none_root = None;
 
--- a/servo/components/style/viewport.rs
+++ b/servo/components/style/viewport.rs
@@ -10,16 +10,17 @@
 #![deny(missing_docs)]
 
 use app_units::Au;
 use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
 use cssparser::ToCss as ParserToCss;
 use euclid::size::TypedSize2D;
 use media_queries::Device;
 use parser::{ParserContext, log_css_error};
+use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::fmt;
 use std::iter::Enumerate;
 use std::str::Chars;
 use style_traits::{PinchZoomFactor, ToCss};
 use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
 use stylesheets::{Stylesheet, Origin};
@@ -499,19 +500,20 @@ impl ViewportRule {
             Some((end, _)) => &content[start..end],
             _ => &content[start..]
         };
 
         Some((name, value))
     }
 }
 
-impl ToCss for ViewportRule {
+impl ToCssWithGuard for ViewportRule {
     // Serialization of ViewportRule is not specced.
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&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));
         for declaration in iter {
             try!(dest.write_str(" "));
             try!(declaration.to_css(dest));
         }
         dest.write_str(" }")
@@ -550,23 +552,24 @@ pub struct Cascade {
 impl Cascade {
     pub fn new() -> Self {
         Cascade {
             declarations: vec![None; VIEWPORT_DESCRIPTOR_VARIANTS],
             count_so_far: 0,
         }
     }
 
-    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<Stylesheet>,
     {
         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))
                 }
             })
         }
         cascade
     }
 
--- a/servo/ports/geckolib/Cargo.toml
+++ b/servo/ports/geckolib/Cargo.toml
@@ -15,18 +15,16 @@ testing = ["style/testing"]
 
 [dependencies]
 atomic_refcell = "0.1"
 cssparser = "0.12"
 env_logger = {version = "0.4", default-features = false} # disable `regex` to reduce code size
 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"]}
 style_traits = {path = "../../components/style_traits"}
 
 [dev-dependencies]
 stylo_tests = {path = "../../tests/unit/stylo"}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1,34 +1,32 @@
 /* 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 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;
 use std::sync::{Arc, Mutex};
 use style::arc_ptr_eq;
 use style::context::{QuirksMode, SharedStyleContext, StyleContext};
 use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInfo};
 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;
 use style::gecko::wrapper::DUMMY_BASE_URL;
 use style::gecko::wrapper::GeckoElement;
 use style::gecko_bindings::bindings;
 use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut};
 use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
@@ -71,73 +69,37 @@ use style::parser::{ParserContext, Parse
 use style::properties::{CascadeFlags, ComputedValues, Importance, ParsedDeclaration};
 use style::properties::{PropertyDeclarationBlock, PropertyId};
 use style::properties::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
 use style::properties::animated_properties::{AnimationValue, Interpolate, TransitionProperty};
 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, StylesheetGuards, 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::supports::parse_condition_or_declaration;
 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
  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
  * depend on but good enough for our purposes.
  */
 
-struct GlobalStyleData {
-    // How many threads parallel styling can use.
-    pub num_threads: usize,
 
-    // The parallel styling thread pool.
-    pub style_thread_pool: Option<rayon::ThreadPool>,
-}
-
-impl GlobalStyleData {
-    pub fn new() -> Self {
-        let stylo_threads = env::var("STYLO_THREADS")
-            .map(|s| s.parse::<usize>().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,
-        }
-    }
-}
-
-lazy_static! {
-    static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
-        GlobalStyleData::new()
-    };
-}
 
 #[no_mangle]
 pub extern "C" fn Servo_Initialize() {
     // Initialize logging.
     let mut builder = LogBuilder::new();
     let default_level = if cfg!(debug_assertions) { "warn" } else { "error" };
     match env::var("RUST_LOG") {
       Ok(v) => builder.parse(&v).init().unwrap(),
@@ -155,22 +117,24 @@ pub extern "C" fn Servo_Initialize() {
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_Shutdown() {
     // Clear some static data to avoid shutdown leaks.
     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: StylesheetGuards::same(guard),
         running_animations: per_doc_data.running_animations.clone(),
         expired_animations: per_doc_data.expired_animations.clone(),
         // FIXME(emilio): Stop boxing here.
         error_reporter: Box::new(StdoutErrorReporter),
         local_context_creation_data: Mutex::new(local_context_data),
         timer: Timer::new(),
         // FIXME Find the real QuirksMode information for this document
         quirks_mode: QuirksMode::NoQuirks,
@@ -193,18 +157,19 @@ fn traverse_subtree(element: GeckoElemen
     let token = RecalcStyleOnly::pre_traverse(element, &per_doc_data.stylist, unstyled_children_only);
     if !token.should_traverse() {
         return;
     }
 
     debug!("Traversing subtree:");
     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 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
     } else {
         TraversalDriver::Parallel
     };
 
     let traversal = RecalcStyleOnly::new(shared_style_context, traversal_driver);
@@ -323,39 +288,42 @@ pub extern "C" fn Servo_StyleWorkerThrea
 
 #[no_mangle]
 pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) {
     GeckoElement(element).clear_data();
 }
 
 #[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 {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         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()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
                                                  stylesheet: *mut ServoStyleSheet,
                                                  data: *const nsACString,
                                                  mode: SheetParsingMode,
                                                  base_url: *const nsACString,
                                                  base: *mut ThreadSafeURIHolder,
                                                  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 {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
     };
 
@@ -373,18 +341,19 @@ pub extern "C" fn Servo_StyleSheet_FromU
     };
 
     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
     let loader: Option<&StyleStylesheetLoader> = match loader {
         None => None,
         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()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheetBorrowed,
                                                   loader: *mut Loader,
                                                   gecko_stylesheet: *mut ServoStyleSheet,
@@ -408,167 +377,188 @@ pub extern "C" fn Servo_StyleSheet_Clear
 
     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
     let loader: Option<&StyleStylesheetLoader> = match loader {
         None => None,
         Some(ref s) => Some(s),
     };
 
     let sheet = Stylesheet::as_arc(&stylesheet);
-    sheet.rules.write().0.clear();
-
-    Stylesheet::update_from_str(&sheet, input, loader,
-                                &StdoutErrorReporter, extra_data);
+    Stylesheet::update_from_str(&sheet, input, loader, &StdoutErrorReporter, extra_data);
 }
 
 #[no_mangle]
 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);
     }
 }
 
 #[no_mangle]
 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);
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleSetBorrowed,
                                                         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);
     data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
     let index = data.stylesheets.iter().position(|x| arc_ptr_eq(x, reference)).unwrap();
     data.stylesheets.insert(index, sheet.clone());
     data.stylesheets_changed = true;
     if flush {
-        data.flush_stylesheets();
+        data.flush_stylesheets(&guard);
     }
 }
 
 #[no_mangle]
 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]
 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleSetBorrowed) {
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     data.stylesheets_changed = true;
 }
 
 #[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]
 pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) -> ServoCssRulesStrong {
     Stylesheet::as_arc(&sheet).rules.clone().into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
                                            result: nsTArrayBorrowed_uintptr_t) {
-    let rules = RwLock::<CssRules>::as_arc(&rules).read();
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let guard = global_style_data.shared_lock.read();
+    let rules = Locked::<CssRules>::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());
     unsafe { result.set_len(size as u32) };
     result.iter_mut().zip(iter).fold((), |_, (r, v)| *r = v);
 }
 
 #[no_mangle]
 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::<CssRules>::as_arc(&rules);
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let mut guard = global_style_data.shared_lock.write();
+    let rules = Locked::<CssRules>::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
         }
         Err(err) => err.into()
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult {
-    let rules = RwLock::<CssRules>::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::<CssRules>::as_arc(&rules);
+    match rules.write_with(&mut guard).remove_rule(index as usize) {
         Ok(_) => nsresult::NS_OK,
         Err(err) => err.into()
     }
 }
 
 macro_rules! impl_basic_rule_funcs {
     { ($name:ident, $rule_type:ty, $raw_type:ty),
         getter: $getter:ident,
         debug: $debug:ident,
         to_css: $to_css:ident,
     } => {
         #[no_mangle]
         pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> {
-            let rules = RwLock::<CssRules>::as_arc(&rules).read();
+            let global_style_data = &*GLOBAL_STYLE_DATA;
+            let guard = global_style_data.shared_lock.read();
+            let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
             match rules.0[index as usize] {
                 CssRule::$name(ref rule) => rule.clone().into_strong(),
                 _ => {
                     unreachable!(concat!(stringify!($getter), "should only be called ",
                                          "on a ", stringify!($name), " rule"));
                 }
             }
         }
 
         #[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 rule = RwLock::<$rule_type>::as_arc(&rule);
-            rule.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 rule = Locked::<$rule_type>::as_arc(&rule);
+            rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap();
         }
     }
 }
 
 impl_basic_rule_funcs! { (Style, StyleRule, RawServoStyleRule),
     getter: Servo_CssRules_GetStyleRuleAt,
     debug: Servo_StyleRule_Debug,
     to_css: Servo_StyleRule_GetCssText,
@@ -583,75 +573,92 @@ impl_basic_rule_funcs! { (Media, MediaRu
 impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule),
     getter: Servo_CssRules_GetNamespaceRuleAt,
     debug: Servo_NamespaceRule_Debug,
     to_css: Servo_NamespaceRule_GetCssText,
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong {
-    let rule = RwLock::<StyleRule>::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::<StyleRule>::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::<StyleRule>::as_arc(&rule);
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
-    rule.write().block = declarations.clone();
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let mut guard = global_style_data.shared_lock.write();
+    let rule = Locked::<StyleRule>::as_arc(&rule);
+    let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
+    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::<StyleRule>::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::<StyleRule>::as_arc(&rule);
+    rule.read_with(&guard).selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong {
-    let rule = RwLock::<MediaRule>::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::<MediaRule>::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::<MediaRule>::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::<MediaRule>::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::<NamespaceRule>::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::<NamespaceRule>::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::<NamespaceRule>::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::<NamespaceRule>::as_arc(&rule);
+    rule.read_with(&guard).url.0.as_ptr()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: ServoComputedValuesBorrowedOrNull,
                                                           pseudo_tag: *mut nsIAtom,
                                                           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 = 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);
 
 
     let maybe_parent = ComputedValues::arc_from_borrowed(&parent_style_or_null);
     let mut cascade_flags = CascadeFlags::empty();
     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()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
                                            pseudo_tag: *mut nsIAtom, is_probe: bool,
@@ -667,35 +674,39 @@ pub extern "C" fn Servo_ResolvePseudoSty
         warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
         return if is_probe {
             Strong::null()
         } else {
             doc_data.borrow().default_computed_values().clone().into_strong()
         };
     }
 
-    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<Arc<ComputedValues>>
 {
     let pseudo = PseudoElement::from_atom_unchecked(Atom::from(pseudo_tag), false);
     match SelectorImpl::pseudo_element_cascade_type(&pseudo) {
         PseudoElementCascadeType::Eager => styles.pseudos.get(&pseudo).map(|s| s.values().clone()),
         PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
         PseudoElementCascadeType::Lazy => {
             let d = doc_data.borrow_mut();
             let base = styles.primary.values();
-            d.stylist.lazily_compute_pseudo_element_style(&element,
+            let guards = StylesheetGuards::same(guard);
+            d.stylist.lazily_compute_pseudo_element_style(&guards,
+                                                          &element,
                                                           &pseudo,
                                                           base)
                      .map(|s| s.values().clone())
         },
     }
 }
 
 #[no_mangle]
@@ -720,18 +731,20 @@ pub extern "C" fn Servo_ComputedValues_I
 pub extern "C" fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)
   -> RawServoStyleSetOwned {
     let data = Box::new(PerDocumentStyleData::new(pres_context));
     data.into_ffi()
 }
 
 #[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]
 pub extern "C" fn Servo_StyleSet_Drop(data: RawServoStyleSetOwned) {
     let _ = data.into_box::<PerDocumentStyleData>();
 }
 
 // Must be a macro since we need to store the base_url on the stack somewhere
@@ -763,86 +776,104 @@ pub extern "C" fn Servo_ParseProperty(pr
     let reporter = StdoutErrorReporter;
     let context = ParserContext::new_with_extra_data(Origin::Author,
                                                      &base_url,
                                                      &reporter,
                                                      extra_data);
 
     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()
     }
 }
 
 #[no_mangle]
 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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::as_arc(&a).read().declarations() ==
-    *RwLock::<PropertyDeclarationBlock>::as_arc(&b).read().declarations()
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let guard = global_style_data.shared_lock.read();
+    *Locked::<PropertyDeclarationBlock>::as_arc(&a).read_with(&guard).declarations() ==
+    *Locked::<PropertyDeclarationBlock>::as_arc(&b).read_with(&guard).declarations()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed,
                                                     result: *mut nsAString) {
-    let declarations = RwLock::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::as_arc(&declarations);
+    declarations.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap();
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
     declarations: RawServoDeclarationBlockBorrowed,
     property_id: nsCSSPropertyID, buffer: *mut nsAString)
 {
     let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let guard = global_style_data.shared_lock.read();
+    let declarations = Locked::<PropertyDeclarationBlock>::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");
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 {
-     let declarations = RwLock::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::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
     } else {
         false
     }
 }
 
@@ -853,18 +884,22 @@ macro_rules! get_property_id_from_proper
             Ok(property_id) => property_id,
             Err(()) => { return $ret; }
         }
     }}
 }
 
 fn get_property_value(declarations: RawServoDeclarationBlockBorrowed,
                       property_id: PropertyId, value: *mut nsAString) {
-    let declarations = RwLock::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::as_arc(&declarations);
+    declarations.read_with(&guard)
+        .property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() })
+        .unwrap();
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_GetPropertyValue(declarations: RawServoDeclarationBlockBorrowed,
                                                           property: *const nsACString, value: *mut nsAString) {
     get_property_value(declarations, get_property_id_from_property!(property, ()), value)
 }
 
@@ -873,29 +908,34 @@ pub extern "C" fn Servo_DeclarationBlock
                                                               property: nsCSSPropertyID, value: *mut nsAString) {
     get_property_value(declarations, get_property_id_from_nscsspropertyid!(property, ()), value)
 }
 
 #[no_mangle]
 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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::as_arc(&declarations);
+    declarations.read_with(&guard).property_priority(&property_id).important()
 }
 
 fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId,
                 value: *const nsACString, is_important: bool,
                 base: *const nsACString, data: *const structs::GeckoParserExtraData) -> bool {
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     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::<PropertyDeclarationBlock>::as_arc(&declarations).write();
+        let global_style_data = &*GLOBAL_STYLE_DATA;
+        let mut guard = global_style_data.shared_lock.write();
+        let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations)
+            .write_with(&mut guard);
         let importance = if is_important { Importance::Important } else { Importance::Normal };
         let mut changed = false;
         parsed.expand(|decl| {
             changed |= declarations.set_parsed_declaration(decl, importance);
         });
         changed
     } else {
         false
@@ -918,78 +958,92 @@ pub extern "C" fn Servo_DeclarationBlock
                                                          is_important: bool,
                                                          base: *const nsACString,
                                                          data: *const structs::GeckoParserExtraData) -> bool {
     set_property(declarations, get_property_id_from_nscsspropertyid!(property, false),
                  value, is_important, base, data)
 }
 
 fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) {
-    let declarations = RwLock::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::as_arc(&declarations);
+    declarations.write_with(&mut guard).remove_property(&property_id);
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_RemoveProperty(declarations: RawServoDeclarationBlockBorrowed,
                                                         property: *const nsACString) {
     remove_property(declarations, get_property_id_from_property!(property, ()))
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawServoDeclarationBlockBorrowed,
                                                             property: nsCSSPropertyID) {
     remove_property(declarations, get_property_id_from_nscsspropertyid!(property, ()))
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) {
-    let list = RwLock::<MediaList>::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::<MediaList>::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::<MediaList>::as_arc(&list);
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let mut guard = global_style_data.shared_lock.write();
+    let list = Locked::<MediaList>::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::<MediaList>::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::<MediaList>::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::<MediaList>::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::<MediaList>::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 {
         false
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed,
                                                new_medium: *const nsACString) {
-    let list = RwLock::<MediaList>::as_arc(&list);
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let mut guard = global_style_data.shared_lock.write();
+    let list = Locked::<MediaList>::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::<MediaList>::as_arc(&list);
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let mut guard = global_style_data.shared_lock.write();
+    let list = Locked::<MediaList>::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 {
     ($id:expr, $retval:expr) => {
         match PropertyId::from_nscsspropertyid($id) {
             Ok(PropertyId::Longhand(long)) => long,
             _ => {
                 error!("stylo: unknown presentation property with id {:?}", $id);
@@ -1017,50 +1071,54 @@ macro_rules! match_wrap_declared {
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(declarations:
                                                        RawServoDeclarationBlockBorrowed,
                                                        property: nsCSSPropertyID)
         -> bool {
     use style::properties::PropertyDeclarationId;
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::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]
 pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations:
                                                              RawServoDeclarationBlockBorrowed,
                                                              property:
                                                              nsCSSPropertyID,
                                                              value:
                                                              *mut nsIAtom) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_x_lang::computed_value::T as Lang;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::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]
 #[allow(unreachable_code)]
 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations:
                                                          RawServoDeclarationBlockBorrowed,
                                                          property: nsCSSPropertyID,
                                                          value: i32) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands;
     use style::values::specified::{BorderStyle, NoCalcLength};
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let value = value as u32;
 
     let prop = match_wrap_declared! { long,
         MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
         // TextEmphasisPosition => FIXME implement text-emphasis-position
         Display => longhands::display::SpecifiedValue::from_gecko_keyword(value),
         Float => longhands::float::SpecifiedValue::from_gecko_keyword(value),
@@ -1074,45 +1132,49 @@ pub extern "C" fn Servo_DeclarationBlock
         ListStyleType => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value),
         WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
         CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value),
         BorderTopStyle => BorderStyle::from_gecko_keyword(value),
         BorderRightStyle => BorderStyle::from_gecko_keyword(value),
         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]
 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDeclarationBlockBorrowed,
                                                      property: nsCSSPropertyID,
                                                      value: i32) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_x_span::computed_value::T as Span;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::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]
 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
                                                        RawServoDeclarationBlockBorrowed,
                                                        property: nsCSSPropertyID,
                                                        value: f32) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
     use style::values::specified::BorderWidth;
     use style::values::specified::length::NoCalcLength;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let nocalc = NoCalcLength::from_px(value);
 
     let prop = match_wrap_declared! { long,
         Height => nocalc.into(),
         Width => nocalc.into(),
         BorderTopWidth => Box::new(BorderWidth::Width(nocalc.into())),
         BorderRightWidth => Box::new(BorderWidth::Width(nocalc.into())),
@@ -1128,140 +1190,155 @@ pub extern "C" fn Servo_DeclarationBlock
         PaddingLeft => nocalc.into(),
         BorderSpacing => Box::new(
             BorderSpacing {
                 horizontal: nocalc.into(),
                 vertical: nocalc.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]
 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
                                                          RawServoDeclarationBlockBorrowed,
                                                          property: nsCSSPropertyID,
                                                          value: f32) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::values::specified::length::Percentage;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let pc = Percentage(value);
 
     let prop = match_wrap_declared! { long,
         Height => pc.into(),
         Width => pc.into(),
         MarginTop => pc.into(),
         MarginRight => pc.into(),
         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]
 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
                                                       RawServoDeclarationBlockBorrowed,
                                                       property: nsCSSPropertyID) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::values::specified::LengthOrPercentageOrAuto;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let auto = LengthOrPercentageOrAuto::Auto;
 
     let prop = match_wrap_declared! { long,
         Height => auto,
         Width => auto,
         MarginTop => auto,
         MarginRight => auto,
         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]
 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
                                                          RawServoDeclarationBlockBorrowed,
                                                          property: nsCSSPropertyID) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::values::specified::{Color, CSSColor};
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let cc = CSSColor { parsed: Color::CurrentColor, authored: None };
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => cc,
         BorderRightColor => cc,
         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]
 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
                                                        RawServoDeclarationBlockBorrowed,
                                                        property: nsCSSPropertyID,
                                                        value: structs::nscolor) {
     use style::gecko::values::convert_nscolor_to_rgba;
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands;
     use style::values::specified::{Color, CSSColor};
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::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 };
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => color,
         BorderRightColor => color,
         BorderBottomColor => color,
         BorderLeftColor => color,
         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]
 pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations:
                                                        RawServoDeclarationBlockBorrowed,
                                                        value: *const nsAString) {
     use cssparser::Parser;
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let declarations = Locked::<PropertyDeclarationBlock>::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);
         }
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarations:
                                                                 RawServoDeclarationBlockBorrowed) {
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::text_decoration_line;
 
-    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let mut guard = global_style_data.shared_lock.write();
+
+    let declarations = Locked::<PropertyDeclarationBlock>::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]
 pub extern "C" fn Servo_CSSSupports2(property: *const nsACString, value: *const nsACString) -> bool {
     let property = unsafe { property.as_ref().unwrap().as_str_unchecked() };
     let id =  if let Ok(id) = PropertyId::parse(property.into()) {
         id
     } else {
@@ -1352,18 +1429,20 @@ pub extern "C" fn Servo_NoteExplicitHint
         debug!("(Element not styled, discarding hints)");
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ImportRule_GetSheet(import_rule:
                                             RawServoImportRuleBorrowed)
                                             -> RawServoStyleSheetStrong {
-    let import_rule = RwLock::<ImportRule>::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::<ImportRule>::as_arc(&import_rule);
+    import_rule.read_with(&guard).stylesheet.clone().into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed) -> nsChangeHint
 {
     let element = GeckoElement(element);
     let damage = if let Some(mut data) = element.mutate_data() {
         let d = data.get_restyle().map_or(GeckoRestyleDamage::empty(), |r| r.damage);
@@ -1397,37 +1476,39 @@ pub extern "C" fn Servo_ResolveStyle(ele
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
                                            pseudo_tag: *mut nsIAtom,
                                            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<ComputedValues> {
         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
         };
         maybe_pseudo.unwrap_or_else(|| styles.primary.values().clone())
     };
 
     // In the common case we already have the style. Check that before setting
     // up all the computation machinery.
     let mut result = element.mutate_data()
                             .and_then(|d| d.get_styles().map(&finish));
     if result.is_some() {
         return result.unwrap().into_strong();
     }
 
     // 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,
         thread_local: &mut tlc,
     };
     let ensure = |el: GeckoElement| { unsafe { el.ensure_data(); } };
     let clear = |el: GeckoElement| el.clear_data();
     resolve_style(&mut context, element, &ensure, &clear,
@@ -1441,16 +1522,21 @@ pub extern "C" fn Servo_GetComputedKeyfr
                                                   style: ServoComputedValuesBorrowed,
                                                   parent_style: ServoComputedValuesBorrowedOrNull,
                                                   raw_data: RawServoStyleSetBorrowed,
                                                   computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut)
 {
     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);
     let parent_style = parent_style.as_ref().map(|r| &**ComputedValues::as_arc(&r));
 
     let default_values = data.default_computed_values();
 
     let context = Context {
@@ -1467,18 +1553,18 @@ pub extern "C" fn Servo_GetComputedKeyfr
 
         let mut seen = LonghandIdSet::new();
 
         // mServoDeclarationBlock is null in the case where we have an invalid css property.
         let iter = keyframe.mPropertyValues.iter()
                                            .filter(|&property| !property.mServoDeclarationBlock.mRawPtr.is_null());
         for property in iter {
             let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
-            let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
-            let guard = declarations.read();
+            let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
+            let guard = declarations.read_with(&guard);
 
             let anim_iter = guard.declarations()
                             .iter()
                             .filter_map(|&(ref decl, imp)| {
                                 if imp == Importance::Normal {
                                     let property = TransitionProperty::from_declaration(decl);
                                     let animation = AnimationValue::from_declaration(decl, &context, default_values);
                                     debug_assert!(property.is_none() == animation.is_none(),
@@ -1532,92 +1618,99 @@ pub extern "C" fn Servo_AssertTreeIsClea
 pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSetBorrowed,
                                                       name: *const nsACString,
                                                       timing_function: *const nsTimingFunction,
                                                       style: ServoComputedValuesBorrowed,
                                                       keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
     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
           };
 
           let keyframe = unsafe {
                 Gecko_AnimationAppendKeyframe(keyframes,
                                               step.start_percentage.0 as f32,
                                               &timing_function)
           };
 
           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);
                   (*keyframe).mPropertyValues[index].mProperty = property.clone().into();
                   // 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()
                            .iter()
                            .filter(|&&(ref declaration, _)| {
                                declaration.is_animatable()
                            });
 
                   let mut seen = LonghandIdSet::new();
 
                   for (index, &(ref declaration, _)) in animatable.enumerate() {
                       unsafe {
                           let property = TransitionProperty::from_declaration(declaration).unwrap();
                           (*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. {
                               seen.set_transition_property_bit(&property);
                           }
                       }
                   }
 
                   // Append missing property values in the initial or the finial keyframes.
                   if step.start_percentage.0 == 0. ||
                      step.start_percentage.0 == 1. {
                       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;
                           }
                       }
                   }
               },
           }
        }
        return true
--- a/servo/ports/geckolib/lib.rs
+++ b/servo/ports/geckolib/lib.rs
@@ -5,19 +5,17 @@
 #![deny(warnings)]
 
 extern crate atomic_refcell;
 extern crate cssparser;
 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;
 extern crate style_traits;
 
 #[allow(non_snake_case)]
 pub mod glue;
 mod stylesheet_loader;
--- a/servo/ports/geckolib/stylesheet_loader.rs
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -1,47 +1,60 @@
 /* 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 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::media_queries::MediaList;
+use style::shared_lock::Locked;
 use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader};
 use style_traits::ToCss;
 
 pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet);
 
 impl StylesheetLoader {
     pub fn new(loader: *mut Loader, parent: *mut ServoStyleSheet) -> Self {
         StylesheetLoader(loader, parent)
     }
 }
 
 impl StyleStylesheetLoader for StylesheetLoader {
-    fn request_stylesheet(&self, import_rule: &Arc<RwLock<ImportRule>>) {
-        let import = import_rule.read();
-        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<Locked<ImportRule>>,
+    ) -> Arc<Locked<ImportRule>> {
         // TODO(emilio): We probably want to share media representation with
         // Gecko in Stylo.
         //
         // This also allows us to get rid of a bunch of extra work to evaluate
         // and ensure parity, and shouldn't be much Gecko work given we always
         // evaluate them on the main thread.
         //
         // Meanwhile, this works.
-        let media = import.stylesheet.media.read().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<Url> 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
     }
 }
--- a/servo/tests/unit/style/Cargo.toml
+++ b/servo/tests/unit/style/Cargo.toml
@@ -12,17 +12,16 @@ doctest = false
 [features]
 testing = ["style/testing"]
 
 [dependencies]
 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"
 selectors = {path = "../../../components/selectors"}
 servo_atoms = {path = "../../../components/atoms"}
 servo_config = {path = "../../../components/config"}
 style = {path = "../../../components/style"}
 style_traits = {path = "../../../components/style_traits"}
--- a/servo/tests/unit/style/keyframes.rs
+++ b/servo/tests/unit/style/keyframes.rs
@@ -1,86 +1,89 @@
 /* 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 parking_lot::RwLock;
 use std::sync::Arc;
 use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage,  KeyframeSelector};
 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![],
     };
 
     assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
 }
 
 #[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()))
+            block: Arc::new(shared_lock.wrap(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![],
     };
 
     assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
 }
 
 #[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(
+        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(
                     LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
                 Importance::Normal
             );
             block.push(
                 PropertyDeclaration::Height(
                     LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
                 Importance::Normal
             );
             block
         }));
 
     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 {
                 start_percentage: KeyframePercentage(0.),
                 value: KeyframesStepValue::Declarations { block: declarations_on_initial_keyframe },
                 declared_timing_function: false,
             },
             KeyframesStep {
@@ -92,51 +95,52 @@ fn test_missing_property_in_initial_keyf
         properties_changed: vec![TransitionProperty::Width, TransitionProperty::Height],
     };
 
     assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
 }
 
 #[test]
 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(
                     LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
                 Importance::Normal
             );
             block.push(
                 PropertyDeclaration::Height(
                     LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
                 Importance::Normal
             );
             block
         }));
 
     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,
         )));
 
     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 {
                 start_percentage: KeyframePercentage(0.),
                 value: KeyframesStepValue::Declarations { block: declarations_on_initial_keyframe },
                 declared_timing_function: false,
             },
             KeyframesStep {
@@ -148,49 +152,50 @@ fn test_missing_property_in_final_keyfra
         properties_changed: vec![TransitionProperty::Width, TransitionProperty::Height],
     };
 
     assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
 }
 
 #[test]
 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(
                     LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
                 Importance::Normal
             );
             block.push(
                 PropertyDeclaration::Height(
                     LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
                 Importance::Normal
             );
             block
         }));
 
     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()))
+            block: Arc::new(shared_lock.wrap(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 {
                 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()
                     ))
                 },
                 declared_timing_function: false,
             },
             KeyframesStep {
                 start_percentage: KeyframePercentage(0.5),
--- a/servo/tests/unit/style/lib.rs
+++ b/servo/tests/unit/style/lib.rs
@@ -4,34 +4,32 @@
 
 #![cfg(test)]
 #![feature(plugin, test)]
 
 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;
 extern crate selectors;
 #[macro_use] extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_url;
 extern crate style;
 extern crate style_traits;
 extern crate test;
 
 mod animated_properties;
 mod attr;
 mod keyframes;
 mod logical_geometry;
 mod media_queries;
-mod owning_handle;
 mod parsing;
 mod properties;
 mod rule_tree;
 mod size_of;
 mod str;
 mod stylesheets;
 mod stylist;
 mod value;
--- a/servo/tests/unit/style/media_queries.rs
+++ b/servo/tests/unit/style/media_queries.rs
@@ -6,16 +6,17 @@ use cssparser::{Parser, SourcePosition};
 use euclid::size::TypedSize2D;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use style::Atom;
 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;
 
 pub struct CSSErrorReporterTest;
 
 impl ParseErrorReporter for CSSErrorReporterTest {
     fn report_error(&self, _input: &mut Parser, _position: SourcePosition, _message: &str,
@@ -24,48 +25,49 @@ impl ParseErrorReporter for CSSErrorRepo
 }
 
 fn test_media_rule<F>(css: &str, callback: F)
     where F: Fn(&MediaList, &str),
 {
     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_with(&guard).0, &mut |mq| {
         rule_count += 1;
         callback(mq, css);
     });
     assert!(rule_count > 0, css_str);
 }
 
-fn media_queries<F>(rules: &[CssRule], f: &mut F)
+fn media_queries<F>(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)
         })
     }
 }
 
 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;
-    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());
 }
 
 #[test]
 fn test_mq_empty() {
     test_media_rule("@media { }", |list, css| {
         assert!(list.media_queries.len() == 0, css.to_owned());
     });
deleted file mode 100644
--- a/servo/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");
-}
--- a/servo/tests/unit/style/rule_tree/bench.rs
+++ b/servo/tests/unit/style/rule_tree/bench.rs
@@ -1,22 +1,22 @@
 /* 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 cssparser::{Parser, SourcePosition};
-use parking_lot::RwLock;
 use rayon;
 use servo_url::ServoUrl;
 use std::sync::Arc;
 use style::error_reporting::ParseErrorReporter;
 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};
 
 struct ErrorringErrorReporter;
 impl ParseErrorReporter for ErrorringErrorReporter {
     fn report_error(&self, _input: &mut Parser, position: SourcePosition, message: &str,
         url: &ServoUrl) {
         panic!("CSS error: {}\t\n{:?} {}", url.as_str(), position, message);
@@ -39,37 +39,41 @@ impl<'a> Drop for AutoGCRuleTree<'a> {
 
 fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
     let s = Stylesheet::from_str(css,
                                  ServoUrl::parse("http://localhost").unwrap(),
                                  Origin::Author,
                                  MediaList {
                                      media_queries: vec![],
                                  },
+                                 SharedRwLock::new(),
                                  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),
             _ => None,
         }
     }).cloned().map(StyleSource::Style).map(|s| {
         (s, CascadeLevel::UserNormal)
     }).collect()
 }
 
 fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>) -> StrongRuleNode {
     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
     )))), CascadeLevel::UserNormal));
     test_insertion(rule_tree, rules)
 }
 
 #[bench]
@@ -113,21 +117,22 @@ fn bench_expensive_insertion(b: &mut Ben
     // This test case tests a case where you style a bunch of siblings
     // matching the same rules, with a different style attribute each
     // one.
     let rules_matched = parse_rules(
         ".foo { width: 200px; } \
          .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));
         }
     });
 }
 
 #[bench]
 fn bench_insertion_basic_parallel(b: &mut Bencher) {
     let r = RuleTree::new();
 
@@ -162,29 +167,32 @@ fn bench_insertion_basic_parallel(b: &mu
 fn bench_expensive_insersion_parallel(b: &mut Bencher) {
     let r = RuleTree::new();
 
     let rules_matched = parse_rules(
         ".foo { width: 200px; } \
          .bar { height: 500px; } \
          .baz { display: block; }");
 
+    let shared_lock = SharedRwLock::new();
     b.iter(|| {
         let _gc = AutoGCRuleTree::new(&r);
 
         rayon::scope(|s| {
             for _ in 0..4 {
                 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));
                         }
                     })
                 })
             }
         });
     });
 }
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -15,16 +15,17 @@ use std::sync::Mutex;
 use std::sync::atomic::AtomicBool;
 use style::error_reporting::ParseErrorReporter;
 use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
 use style::parser::ParserContextExtraData;
 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};
 
 pub fn block_from<I>(iterable: I) -> PropertyDeclarationBlock
 where I: IntoIterator<Item=(PropertyDeclaration, Importance)> {
     let mut block = PropertyDeclarationBlock::new();
     for (d, i) in iterable {
@@ -57,34 +58,35 @@ fn test_parse_stylesheet() {
                 width: 100%;
                 width: 50% !important; /* !important not allowed here */
                 animation-name: 'foo'; /* animation properties not allowed here */
                 animation-play-state: running; /* … except animation-play-state */
             }
         }";
     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),
         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")
             }))),
-            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 {
                             compound_selector: vec![
                                 SimpleSelector::Namespace(Namespace {
                                     prefix: None,
                                     url: NsAtom::from("http://www.w3.org/1999/xhtml")
                                 }),
@@ -102,25 +104,25 @@ fn test_parse_stylesheet() {
                                 }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
                             ],
                             next: None,
                         }),
                         pseudo_element: None,
                         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"),
                      DeclaredValueOwned::CSSWideKeyword(CSSWideKeyword::Inherit)),
                      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 {
                             compound_selector: vec![
                                 SimpleSelector::Namespace(Namespace {
                                     prefix: None,
                                     url: NsAtom::from("http://www.w3.org/1999/xhtml")
                                 }),
@@ -147,22 +149,22 @@ fn test_parse_stylesheet() {
                                 }),
                             ],
                             next: None,
                         }),
                         pseudo_element: None,
                         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),
                 ]))),
             }))),
-            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 {
                             compound_selector: vec![
                                 SimpleSelector::Namespace(Namespace {
                                     prefix: None,
                                     url: NsAtom::from("http://www.w3.org/1999/xhtml")
                                 }),
@@ -178,17 +180,17 @@ fn test_parse_stylesheet() {
                                 ],
                                 next: None,
                             }), Combinator::Child)),
                         }),
                         pseudo_element: None,
                         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()),
                             parsed: cssparser::Color::RGBA(cssparser::RGBA::new(0, 0, 255, 255)),
                         }
                      ),
                      Importance::Normal),
                     (PropertyDeclaration::BackgroundPositionX(
@@ -228,45 +230,45 @@ fn test_parse_stylesheet() {
                      Importance::Normal),
                     (PropertyDeclaration::BackgroundClip(
                         longhands::background_clip::SpecifiedValue(
                         vec![longhands::background_clip::single_value
                                                    ::get_initial_specified_value()])),
                      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 {
+                    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),
                         ])))
                     })),
-                    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![
+                        block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
                             (PropertyDeclaration::Width(
                                 LengthOrPercentageOrAuto::Percentage(Percentage(1.))),
                              Importance::Normal),
                             (PropertyDeclaration::AnimationPlayState(
                                 animation_play_state::SpecifiedValue(
                                     vec![animation_play_state::SingleSpecifiedValue::running])),
                              Importance::Normal),
                         ]))),
                     })),
                 ]
             })))
 
-        ]),
+        ], &stylesheet.shared_lock),
     };
 
     assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected));
 }
 
 struct CSSError {
     pub url : ServoUrl,
     pub line: usize,
@@ -319,17 +321,17 @@ fn test_report_error_stylesheet() {
     }
     ";
     let url = ServoUrl::parse("about::test").unwrap();
     let error_reporter = CSSInvalidErrorReporterTest::new();
 
     let errors = error_reporter.errors.clone();
 
     Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
-                         None,
+                         SharedRwLock::new(), None,
                          &error_reporter,
                          ParserContextExtraData::default());
 
     let mut errors = errors.lock().unwrap();
 
     let error = errors.pop().unwrap();
     assert_eq!("Unsupported property declaration: 'invalid: true;'", error.message);
     assert_eq!(5, error.line);
--- a/servo/tests/unit/style/stylist.rs
+++ b/servo/tests/unit/style/stylist.rs
@@ -1,117 +1,120 @@
 /* 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 html5ever_atoms::LocalName;
-use parking_lot::RwLock;
 use selectors::parser::LocalName as LocalNameSelector;
 use servo_atoms::Atom;
 use std::sync::Arc;
 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<Vec<Rule>> {
-    css_selectors.iter().enumerate().map(|(i, selectors)| {
+fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, 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(
+            block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
                 PropertyDeclaration::Display(
                     longhands::display::SpecifiedValue::block),
                 Importance::Normal
             ))),
         }));
 
-        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() {
             map.insert(rule)
         }
     }
 
-    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)),
             "The rule that comes later should win.");
 }
 
 
 #[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 {
                         name: LocalName::from(name),
                         lower_name: LocalName::from(lower_name) }))
     };
     check(0, Some(("img", "img")));
     check(1, None);
     check(2, Some(("IMG", "img")));
     check(3, Some(("ImG", "img")));
 }
 
 #[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);
     selector_map.insert(rules_list[0][0].clone());
     assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].source_order);
     assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none());
 }
 
 #[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);
 }
--- a/servo/tests/unit/style/viewport.rs
+++ b/servo/tests/unit/style/viewport.rs
@@ -4,47 +4,52 @@
 
 use cssparser::Parser;
 use euclid::size::TypedSize2D;
 use media_queries::CSSErrorReporterTest;
 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};
 use style::values::specified::ViewportPercentageLength::Vw;
 use style::viewport::*;
 use style_traits::PinchZoomFactor;
 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(),
+            $shared_lock,
             None,
             &$error_reporter,
             ParserContextExtraData::default()
         ))
     }
 }
 
 fn test_viewport_rule<F>(css: &str,
                          device: &Device,
                          callback: F)
     where F: Fn(&Vec<ViewportDescriptorDeclaration>, &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);
     });
     assert!(rule_count > 0);
 }
 
 fn test_meta_viewport<F>(meta: &str, callback: F)
     where F: Fn(&Vec<ViewportDescriptorDeclaration>, &str)
@@ -246,34 +251,41 @@ fn cascading_within_viewport_rule() {
     });
 }
 
 #[test]
 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);
     assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
 }
 
 #[test]
 fn constrain_viewport() {
--- a/servo/tests/unit/stylo/lib.rs
+++ b/servo/tests/unit/stylo/lib.rs
@@ -16,13 +16,10 @@ extern crate rayon;
 extern crate selectors;
 extern crate servo_url;
 #[macro_use] extern crate style;
 extern crate style_traits;
 
 mod sanity_checks;
 mod size_of;
 
-#[path = "../../../ports/geckolib/stylesheet_loader.rs"]
-mod stylesheet_loader;
-
 mod servo_function_signatures;
 
--- a/servo/tests/unit/stylo/servo_function_signatures.rs
+++ b/servo/tests/unit/stylo/servo_function_signatures.rs
@@ -5,16 +5,19 @@
 #![allow(unused)]
 
 use self::glue::*;
 use style::gecko_bindings::bindings;
 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
     // a hack to compensate for the fact that `fn` types cannot coerce to `unsafe fn` types. The
     // imports are populated with the same things so the type assertion should be equivalent
     use geckoservo::*;
     include!(concat!(env!("OUT_DIR"), "/glue.rs"));
 }