Bug 1455784 - Update StyleSource to use ArcUnion. r=Manishearth
authorBobby Holley <bobbyholley@gmail.com>
Fri, 20 Apr 2018 16:28:33 -0700
changeset 471624 af621dc793aaeb4a787748981cde5ca2bd0709b8
parent 471623 5a517a7c8cf23646603c65da037cd6b979c84682
child 471625 b7a347f011cb8c1eb15e8357f2dae0f97eef9bd8
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
bugs1455784
milestone61.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
Bug 1455784 - Update StyleSource to use ArcUnion. r=Manishearth MozReview-Commit-ID: AT4sud9goGV
servo/components/style/applicable_declarations.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/rule_cache.rs
servo/components/style/rule_tree/mod.rs
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/tests/size_of.rs
--- a/servo/components/style/applicable_declarations.rs
+++ b/servo/components/style/applicable_declarations.rs
@@ -111,17 +111,17 @@ impl ApplicableDeclarationBlock {
     /// Constructs an applicable declaration block from a given property
     /// declaration block and importance.
     #[inline]
     pub fn from_declarations(
         declarations: Arc<Locked<PropertyDeclarationBlock>>,
         level: CascadeLevel,
     ) -> Self {
         ApplicableDeclarationBlock {
-            source: StyleSource::Declarations(declarations),
+            source: StyleSource::from_declarations(declarations),
             bits: ApplicableDeclarationBits::new(0, level, 0),
             specificity: 0,
         }
     }
 
     /// Constructs an applicable declaration block from the given components
     #[inline]
     pub fn new(
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -3415,17 +3415,17 @@ where
     let property_restriction = pseudo.and_then(|p| p.property_restriction());
 
     let iter_declarations = || {
         rule_node.self_and_ancestors().flat_map(|node| {
             let cascade_level = node.cascade_level();
             let source = node.style_source();
 
             let declarations = if source.is_some() {
-                source.read(cascade_level.guard(guards)).declaration_importance_iter()
+                source.as_ref().unwrap().read(cascade_level.guard(guards)).declaration_importance_iter()
             } else {
                 // The root node has no style source.
                 DeclarationImportanceIterator::new(&[], &empty)
             };
             let node_importance = node.importance();
 
             declarations
                 // Yield declarations later in source order (with more precedence) first.
--- a/servo/components/style/rule_cache.rs
+++ b/servo/components/style/rule_cache.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! A cache from rule node to computed values, in order to cache reset
 //! properties.
 
 use fnv::FnvHashMap;
 use logical_geometry::WritingMode;
 use properties::{ComputedValues, StyleBuilder};
-use rule_tree::{StrongRuleNode, StyleSource};
+use rule_tree::StrongRuleNode;
 use selector_parser::PseudoElement;
 use servo_arc::Arc;
 use shared_lock::StylesheetGuards;
 use smallvec::SmallVec;
 use values::computed::NonNegativeLength;
 
 /// The conditions for caching and matching a style in the rule cache.
 #[derive(Clone, Debug, Default)]
@@ -92,26 +92,28 @@ impl RuleCache {
     /// to address common cases that rule cache would fail to share
     /// when using the rule node directly, like preshint, style attrs,
     /// and animations.
     fn get_rule_node_for_cache<'r>(
         guards: &StylesheetGuards,
         mut rule_node: Option<&'r StrongRuleNode>,
     ) -> Option<&'r StrongRuleNode> {
         while let Some(node) = rule_node {
-            match *node.style_source() {
-                StyleSource::Declarations(ref decls) => {
-                    let cascade_level = node.cascade_level();
-                    let decls = decls.read_with(cascade_level.guard(guards));
-                    if decls.contains_any_reset() {
-                        break;
-                    }
+            match node.style_source() {
+                Some(s) => match s.as_declarations() {
+                    Some(decls) => {
+                        let cascade_level = node.cascade_level();
+                        let decls = decls.read_with(cascade_level.guard(guards));
+                        if decls.contains_any_reset() {
+                            break;
+                        }
+                    },
+                    None => break,
                 },
-                StyleSource::None => {},
-                StyleSource::Style(_) => break,
+                None => {},
             }
             rule_node = node.parent();
         }
         rule_node
     }
 
     /// Finds a node in the properties matched cache.
     ///
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -7,17 +7,17 @@
 //! The rule tree.
 
 use applicable_declarations::ApplicableDeclarationList;
 #[cfg(feature = "gecko")]
 use gecko::selector_parser::PseudoElement;
 #[cfg(feature = "gecko")]
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
-use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut};
+use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow, NonZeroPtrMut};
 use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use smallvec::SmallVec;
 use std::io::{self, Write};
 use std::mem;
 use std::ptr;
 use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
 use stylesheets::StyleRule;
 use thread_state;
@@ -84,75 +84,73 @@ impl MallocSizeOf for RuleTree {
 /// A style source for the rule node. It can either be a CSS style rule or a
 /// declaration block.
 ///
 /// 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(Clone, Debug)]
-pub enum StyleSource {
-    /// A style rule stable pointer.
-    Style(Arc<Locked<StyleRule>>),
-    /// A declaration block stable pointer.
-    Declarations(Arc<Locked<PropertyDeclarationBlock>>),
-    /// Indicates no style source. Used to save an Option wrapper around the stylesource in
-    /// RuleNode
-    None,
-}
+pub struct StyleSource(ArcUnion<Locked<StyleRule>, Locked<PropertyDeclarationBlock>>);
 
 impl PartialEq for StyleSource {
     fn eq(&self, other: &Self) -> bool {
-        self.ptr_equals(other)
+        ArcUnion::ptr_eq(&self.0, &other.0)
     }
 }
 
 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),
-            (&None, _) | (_, &None) => {
-                panic!("Should not check for equality between null StyleSource objects")
-            },
-            _ => false,
-        }
+    /// Creates a StyleSource from a StyleRule.
+    pub fn from_rule(rule: Arc<Locked<StyleRule>>) -> Self {
+        StyleSource(ArcUnion::from_first(rule))
+    }
+
+    /// Creates a StyleSource from a PropertyDeclarationBlock.
+    pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
+        StyleSource(ArcUnion::from_second(decls))
     }
 
     fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
-        use self::StyleSource::*;
-
-        if let Style(ref rule) = *self {
+        if let Some(ref rule) = self.0.as_first() {
             let rule = rule.read_with(guard);
             let _ = write!(writer, "{:?}", rule.selectors);
         }
 
         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, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock {
-        let block = match *self {
-            StyleSource::Style(ref rule) => &rule.read_with(guard).block,
-            StyleSource::Declarations(ref block) => block,
-            StyleSource::None => panic!("Cannot call read on StyleSource::None"),
+        let block: &Locked<PropertyDeclarationBlock> = match self.0.borrow() {
+            ArcUnionBorrow::First(ref rule) => &rule.get().read_with(guard).block,
+            ArcUnionBorrow::Second(ref block) => block.get(),
         };
         block.read_with(guard)
     }
 
-    /// Indicates if this StyleSource has a value
-    pub fn is_some(&self) -> bool {
-        match *self {
-            StyleSource::None => false,
-            _ => true,
-        }
+    /// Indicates if this StyleSource is a style rule.
+    pub fn is_rule(&self) -> bool {
+        self.0.is_first()
+    }
+
+    /// Indicates if this StyleSource is a PropertyDeclarationBlock.
+    pub fn is_declarations(&self) -> bool {
+        self.0.is_second()
+    }
+
+    /// Returns the style rule if applicable, otherwise None.
+    pub fn as_rule(&self) -> Option<ArcBorrow<Locked<StyleRule>>> {
+        self.0.as_first()
+    }
+
+    /// Returns the declaration block if applicable, otherwise None.
+    pub fn as_declarations(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
+        self.0.as_second()
     }
 }
 
 /// 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.
@@ -243,21 +241,22 @@ impl RuleTree {
                             "Not really ordered"
                         );
                         if shadow_cascade_order > last_cascade_order &&
                             !important_inner_shadow.last().unwrap().is_empty()
                         {
                             last_cascade_order = shadow_cascade_order;
                             important_inner_shadow.push(SmallVec::new());
                         }
-                        important_inner_shadow.last_mut().unwrap().push(source.clone())
-                    }
-                    SameTreeAuthorNormal => {
-                        important_same_tree.push(source.clone())
+                        important_inner_shadow
+                            .last_mut()
+                            .unwrap()
+                            .push(source.clone())
                     },
+                    SameTreeAuthorNormal => important_same_tree.push(source.clone()),
                     UANormal => important_ua.push(source.clone()),
                     UserNormal => important_user.push(source.clone()),
                     StyleAttributeNormal => {
                         debug_assert!(important_style_attr.is_none());
                         important_style_attr = Some(source.clone());
                     },
                     _ => {},
                 };
@@ -386,17 +385,20 @@ impl RuleTree {
         // TODO(emilio): Being smarter with lifetimes we could avoid a bit of
         // the refcount churn.
         let mut current = path.clone();
         *important_rules_changed = false;
 
         // First walk up until the first less-or-equally specific rule.
         let mut children = SmallVec::<[_; 10]>::new();
         while current.get().level > level {
-            children.push((current.get().source.clone(), current.get().level));
+            children.push((
+                current.get().source.as_ref().unwrap().clone(),
+                current.get().level,
+            ));
             current = current.parent().unwrap().clone();
         }
 
         // Then remove the one at the level we want to replace, if any.
         //
         // NOTE: Here we assume that only one rule can be at the level we're
         // replacing.
         //
@@ -413,23 +415,24 @@ impl RuleTree {
                 // same as `pdb`, we're done, and `path` is still valid.
                 //
                 // TODO(emilio): Another potential optimization is the one where
                 // we can just replace the rule at that level for `pdb`, and
                 // then we don't need to re-create the children, and `path` is
                 // also equally valid. This is less likely, and would require an
                 // in-place mutation of the source, which is, at best, fiddly,
                 // so let's skip it for now.
-                let is_here_already = match current.get().source {
-                    StyleSource::Declarations(ref already_here) => {
-                        pdb.with_arc(|arc| Arc::ptr_eq(arc, already_here))
-                    },
-                    _ => unreachable!("Replacing non-declarations style?"),
-                };
-
+                let current_decls = current
+                    .get()
+                    .source
+                    .as_ref()
+                    .unwrap()
+                    .as_declarations()
+                    .expect("Replacing non-declarations style?");
+                let is_here_already = ArcBorrow::ptr_eq(&pdb, &current_decls);
                 if is_here_already {
                     debug!("Picking the fast path in rule replacement");
                     return None;
                 }
             }
             current = current.parent().unwrap().clone();
         }
         debug_assert!(
@@ -442,25 +445,25 @@ impl RuleTree {
         // 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_with(level.guard(guards)).any_important() {
                     current = current.ensure_child(
                         self.root.downgrade(),
-                        StyleSource::Declarations(pdb.clone_arc()),
+                        StyleSource::from_declarations(pdb.clone_arc()),
                         level,
                     );
                 }
             } else {
                 if pdb.read_with(level.guard(guards)).any_normal() {
                     current = current.ensure_child(
                         self.root.downgrade(),
-                        StyleSource::Declarations(pdb.clone_arc()),
+                        StyleSource::from_declarations(pdb.clone_arc()),
                         level,
                     );
                 }
             }
         }
 
         // Now the rule is in the relevant place, push the children as
         // necessary.
@@ -486,17 +489,20 @@ impl RuleTree {
         }
 
         let iter = path.self_and_ancestors()
             .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride);
         let mut last = path;
         let mut children = SmallVec::<[_; 10]>::new();
         for node in iter {
             if !node.cascade_level().is_animation() {
-                children.push((node.get().source.clone(), node.cascade_level()));
+                children.push((
+                    node.get().source.as_ref().unwrap().clone(),
+                    node.cascade_level(),
+                ));
             }
             last = node;
         }
 
         let rule =
             self.insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain().rev());
         rule
     }
@@ -684,17 +690,19 @@ pub struct RuleNode {
     /// The root node. Only the root has no root pointer, for obvious reasons.
     root: Option<WeakRuleNode>,
 
     /// The parent rule node. Only the root has no parent.
     parent: Option<StrongRuleNode>,
 
     /// The actual style source, either coming from a selector in a StyleRule,
     /// or a raw property declaration block (like the style attribute).
-    source: StyleSource,
+    ///
+    /// None for the root node.
+    source: Option<StyleSource>,
 
     /// The cascade level this rule is positioned at.
     level: CascadeLevel,
 
     refcount: AtomicUsize,
     first_child: AtomicPtr<RuleNode>,
     next_sibling: AtomicPtr<RuleNode>,
 
@@ -770,31 +778,31 @@ impl RuleNode {
         parent: StrongRuleNode,
         source: StyleSource,
         level: CascadeLevel,
     ) -> Self {
         debug_assert!(root.upgrade().parent().is_none());
         RuleNode {
             root: Some(root),
             parent: Some(parent),
-            source: source,
+            source: Some(source),
             level: level,
             refcount: AtomicUsize::new(1),
             first_child: AtomicPtr::new(ptr::null_mut()),
             next_sibling: AtomicPtr::new(ptr::null_mut()),
             prev_sibling_or_free_count: PrevSiblingOrFreeCount::new(),
             next_free: AtomicPtr::new(ptr::null_mut()),
         }
     }
 
     fn root() -> Self {
         RuleNode {
             root: None,
             parent: None,
-            source: StyleSource::None,
+            source: None,
             level: CascadeLevel::UANormal,
             refcount: AtomicUsize::new(1),
             first_child: AtomicPtr::new(ptr::null_mut()),
             next_sibling: AtomicPtr::new(ptr::null_mut()),
             prev_sibling_or_free_count: PrevSiblingOrFreeCount::new(),
             next_free: AtomicPtr::new(FREE_LIST_SENTINEL),
         }
     }
@@ -879,17 +887,20 @@ impl RuleNode {
             self.parent.as_ref().map(|p| p.ptr())
         );
 
         for _ in 0..indent {
             let _ = write!(writer, " ");
         }
 
         if self.source.is_some() {
-            self.source.dump(self.level.guard(guards), writer);
+            self.source
+                .as_ref()
+                .unwrap()
+                .dump(self.level.guard(guards), writer);
         } else {
             if indent != 0 {
                 warn!("How has this happened?");
             }
             let _ = write!(writer, "(root)");
         }
 
         let _ = write!(writer, "\n");
@@ -981,17 +992,17 @@ impl StrongRuleNode {
         //
         // It's fine though, because nothing can make us GC while this happens,
         // and this happens to be hot.
         //
         // TODO(emilio): We could actually make this even less hot returning a
         // WeakRuleNode, and implementing this on WeakRuleNode itself...
         for child in self.get().iter_children() {
             let child_node = unsafe { &*child.ptr() };
-            if child_node.level == level && child_node.source.ptr_equals(&source) {
+            if child_node.level == level && child_node.source.as_ref().unwrap() == &source {
                 return child.upgrade();
             }
             last = Some(child);
         }
 
         let mut node = Box::new(RuleNode::new(root, self.clone(), source.clone(), level));
         let new_ptr: *mut RuleNode = &mut *node;
 
@@ -1021,17 +1032,17 @@ impl StrongRuleNode {
 
                     return StrongRuleNode::new(node);
                 }
 
                 // Existing is not null: some thread inserted a child node since
                 // we accessed `last`.
                 next = WeakRuleNode::from_ptr(existing);
 
-                if unsafe { &*next.ptr() }.source.ptr_equals(&source) {
+                if unsafe { &*next.ptr() }.source.as_ref().unwrap() == &source {
                     // That node happens to be for the same style source, use
                     // that, and let node fall out of scope.
                     return next.upgrade();
                 }
             }
 
             // Try again inserting after the new last child.
             last = Some(next);
@@ -1049,18 +1060,18 @@ impl StrongRuleNode {
             assert!(node.refcount.load(Ordering::Relaxed) > 0);
         }
         unsafe { &*self.ptr() }
     }
 
     /// 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) -> &StyleSource {
-        &self.get().source
+    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.
@@ -1312,16 +1323,18 @@ impl StrongRuleNode {
 
             let mut inherited_properties = LonghandIdSet::new();
             let mut have_explicit_ua_inherit = false;
 
             for node in element_rule_node.self_and_ancestors() {
                 let source = node.style_source();
                 let declarations = if source.is_some() {
                     source
+                        .as_ref()
+                        .unwrap()
                         .read(node.cascade_level().guard(guards))
                         .declaration_importance_iter()
                 } else {
                     continue;
                 };
 
                 // Iterate over declarations of the longhands we care about.
                 let node_importance = node.importance();
@@ -1439,17 +1452,17 @@ impl StrongRuleNode {
         // transitions and animations are present for a given element and
         // property, transitions are suppressed so that they don't actually
         // override animations.
         let iter = self.self_and_ancestors()
             .skip_while(|node| node.cascade_level() == CascadeLevel::Transitions)
             .take_while(|node| node.cascade_level() > CascadeLevel::Animations);
         let mut result = (LonghandIdSet::new(), false);
         for node in iter {
-            let style = node.style_source();
+            let style = node.style_source().unwrap();
             for (decl, important) in style
                 .read(node.cascade_level().guard(guards))
                 .declaration_importance_iter()
             {
                 // Although we are only iterating over cascade levels that
                 // override animations, in a given property declaration block we
                 // can have a mixture of !important and non-!important
                 // declarations but only the !important declarations actually
@@ -1459,43 +1472,16 @@ impl StrongRuleNode {
                         PropertyDeclarationId::Longhand(id) => result.0.insert(id),
                         PropertyDeclarationId::Custom(_) => result.1 = true,
                     }
                 }
             }
         }
         result
     }
-
-    /// Returns PropertyDeclarationBlock for this node.
-    /// This function must be called only for animation level node.
-    fn get_animation_style(&self) -> &Arc<Locked<PropertyDeclarationBlock>> {
-        debug_assert!(
-            self.cascade_level().is_animation(),
-            "The cascade level should be an animation level"
-        );
-        match *self.style_source() {
-            StyleSource::Declarations(ref block) => block,
-            StyleSource::Style(_) => unreachable!("animating style should not be a style rule"),
-            StyleSource::None => unreachable!("animating style should not be none"),
-        }
-    }
-
-    /// Returns SMIL override declaration block if exists.
-    pub fn get_smil_animation_rule(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
-        if cfg!(feature = "servo") {
-            // Servo has no knowledge of a SMIL rule, so just avoid looking for it.
-            return None;
-        }
-
-        self.self_and_ancestors()
-            .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride)
-            .find(|node| node.cascade_level() == CascadeLevel::SMILOverride)
-            .map(|node| node.get_animation_style())
-    }
 }
 
 /// An iterator over a rule node and its ancestors.
 #[derive(Clone)]
 pub struct SelfAndAncestors<'a> {
     current: Option<&'a StrongRuleNode>,
 }
 
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -1518,17 +1518,17 @@ impl Stylist {
     {
         use font_metrics::get_metrics_provider_for_product;
         use std::iter;
 
         // FIXME(emilio): Why do we even need the rule node? We should probably
         // just avoid allocating it and calling `apply_declarations` directly,
         // maybe...
         let rule_node = self.rule_tree.insert_ordered_rules(iter::once((
-            StyleSource::Declarations(declarations),
+            StyleSource::from_declarations(declarations),
             CascadeLevel::StyleAttributeNormal,
         )));
 
         // This currently ignores visited styles.  It appears to be used for
         // font styles in <canvas> via Servo_StyleSet_ResolveForDeclarations.
         // It is unclear if visited styles are meaningful for this case.
         let metrics = get_metrics_provider_for_product();
 
@@ -2172,17 +2172,17 @@ impl CascadeData {
                                 debug_assert!(selector.is_universal());
                                 debug_assert!(matches!(origin, Origin::UserAgent));
 
                                 precomputed_pseudo_element_decls
                                     .as_mut()
                                     .expect("Expected precomputed declarations for the UA level")
                                     .get_or_insert_with(&pseudo.canonical(), Vec::new)
                                     .push(ApplicableDeclarationBlock::new(
-                                        StyleSource::Style(locked.clone()),
+                                        StyleSource::from_rule(locked.clone()),
                                         self.rules_source_order,
                                         CascadeLevel::UANormal,
                                         selector.specificity(),
                                         0,
                                     ));
                                 continue;
                             }
                         }
@@ -2475,17 +2475,17 @@ impl Rule {
 
     /// Turns this rule into an `ApplicableDeclarationBlock` for the given
     /// cascade level.
     pub fn to_applicable_declaration_block(
         &self,
         level: CascadeLevel,
         shadow_cascade_order: ShadowCascadeOrder,
     ) -> ApplicableDeclarationBlock {
-        let source = StyleSource::Style(self.style_rule.clone());
+        let source = StyleSource::from_rule(self.style_rule.clone());
         ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), shadow_cascade_order)
     }
 
     /// Creates a new Rule.
     pub fn new(
         selector: Selector<SelectorImpl>,
         hashes: AncestorHashes,
         style_rule: Arc<Locked<StyleRule>>,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -132,17 +132,17 @@ use style::parser::{Parse, ParserContext
 use style::properties::{ComputedValues, DeclarationSource, Importance};
 use style::properties::{LonghandId, LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
 use style::properties::{PropertyDeclarationId, ShorthandId};
 use style::properties::{SourcePropertyDeclaration, StyleBuilder};
 use style::properties::{parse_one_declaration_into, parse_style_attribute};
 use style::properties::animated_properties::AnimationValue;
 use style::properties::animated_properties::compare_property_priority;
 use style::rule_cache::RuleCacheConditions;
-use style::rule_tree::{CascadeLevel, StrongRuleNode, StyleSource};
+use style::rule_tree::{CascadeLevel, StrongRuleNode};
 use style::selector_parser::{PseudoElementCascadeType, SelectorImpl};
 use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
 use style::string_cache::{Atom, WeakAtom};
 use style::style_adjuster::StyleAdjuster;
 use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, CounterStyleRule};
 use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, ImportRule};
 use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule};
 use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
@@ -3118,37 +3118,39 @@ pub extern "C" fn Servo_ComputedValues_G
 ) {
     let rule_node = match values.rules {
         Some(ref r) => r,
         None => return,
     };
 
     let mut result = SmallVec::<[_; 10]>::new();
     for node in rule_node.self_and_ancestors() {
-        let style_rule = match *node.style_source() {
-            StyleSource::Style(ref rule) => rule,
+        let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
+            Some(rule) => rule,
             _ => continue,
         };
 
         // For the rules with any important declaration, we insert them into
         // rule tree twice, one for normal level and another for important
         // level. So, we skip the important one to keep the specificity order of
         // rules.
         if node.importance().important() {
             continue;
         }
 
         result.push(style_rule);
     }
 
     unsafe { rules.set_len(result.len() as u32) };
     for (ref src, ref mut dest) in result.into_iter().zip(rules.iter_mut()) {
-        src.with_raw_offset_arc(|arc| {
-            **dest = *Locked::<StyleRule>::arc_as_borrowed(arc);
-        })
+        src.with_arc(|a| {
+            a.with_raw_offset_arc(|arc| {
+                **dest = *Locked::<StyleRule>::arc_as_borrowed(arc);
+            })
+        });
     }
 }
 
 /// See the comment in `Device` to see why it's ok to pass an owned reference to
 /// the pres context (hint: the context outlives the StyleSet, that holds the
 /// device alive).
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_Init(
--- a/servo/ports/geckolib/tests/size_of.rs
+++ b/servo/ports/geckolib/tests/size_of.rs
@@ -30,18 +30,18 @@ size_of_test!(test_size_of_cv, ComputedV
 size_of_test!(test_size_of_option_arc_cv, Option<Arc<ComputedValues>>, 8);
 size_of_test!(test_size_of_option_rule_node, Option<StrongRuleNode>, 8);
 
 size_of_test!(test_size_of_element_styles, ElementStyles, 16);
 size_of_test!(test_size_of_element_data, ElementData, 24);
 
 size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
 
-size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24);
-size_of_test!(test_size_of_rule_node, RuleNode, 80);
+size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 16);
+size_of_test!(test_size_of_rule_node, RuleNode, 72);
 
 // This is huge, but we allocate it on the stack and then never move it,
 // we only pass `&mut SourcePropertyDeclaration` references around.
 size_of_test!(test_size_of_parsed_declaration, style::properties::SourcePropertyDeclaration, 608);
 
 size_of_test!(test_size_of_computed_image, computed::image::Image, 32);
 size_of_test!(test_size_of_specified_image, specified::image::Image, 32);