servo: Merge #18431 - Use SmallBitVec to optimize size of PropertyDeclarationBlock (from mbrubeck:pdb-size); r=SimonSapin
authorMatt Brubeck <mbrubeck@limpet.net>
Mon, 11 Sep 2017 08:57:07 -0500
changeset 429545 002ebb2eb2b708d72bbc82c2cac7bb5c3451cfb1
parent 429544 3be0f512422bcf03178c3c1160328d2e6e7ca678
child 429546 b9c7d951bf57ddeb19f0c940a258607884ecbcee
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersSimonSapin
milestone57.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 #18431 - Use SmallBitVec to optimize size of PropertyDeclarationBlock (from mbrubeck:pdb-size); r=SimonSapin https://bugzilla.mozilla.org/show_bug.cgi?id=1398322 Source-Repo: https://github.com/servo/servo Source-Revision: e7f45028dcd4d7015b4eed2ecc193e176b1fbd1c
servo/Cargo.lock
servo/components/script/dom/cssstyledeclaration.rs
servo/components/style/Cargo.toml
servo/components/style/animation.rs
servo/components/style/lib.rs
servo/components/style/properties/declaration_block.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/rule_tree/mod.rs
servo/components/style/sharing/mod.rs
servo/components/style/stylesheets/keyframes_rule.rs
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -3023,16 +3023,21 @@ dependencies = [
 ]
 
 [[package]]
 name = "slab"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "smallbitvec"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "smallvec"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -3080,17 +3085,16 @@ source = "registry+https://github.com/ru
 name = "style"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "arraydeque 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bindgen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fallible 0.0.1",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3116,16 +3120,17 @@ dependencies = [
  "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
+ "smallbitvec 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_derive 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3952,16 +3957,17 @@ dependencies = [
 "checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
 "checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
 "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5"
 "checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>"
 "checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
 "checksum skeptic 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7d8dc1315094150052d0ab767840376335a98ac66ef313ff911cdf439a5b69"
 "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
+"checksum smallbitvec 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1ebf4681dc284c22efb7248986bbdf8aa23c2749ea85a0107e0e787038d303e"
 "checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"
 "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
 "checksum string_cache 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "413fc7852aeeb5472f1986ef755f561ddf0c789d3d796e65f0b6fe293ecd4ef8"
 "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
 "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
 "checksum swapper 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca610b32bb8bfc5e7f705480c3a1edfeb70b6582495d343872c8bee0dcf758c"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
--- a/servo/components/script/dom/cssstyledeclaration.rs
+++ b/servo/components/script/dom/cssstyledeclaration.rs
@@ -405,20 +405,20 @@ impl CSSStyleDeclarationMethods for CSSS
     // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
     fn SetCssFloat(&self, value: DOMString) -> ErrorResult {
         self.SetPropertyValue(DOMString::from("float"), value)
     }
 
     // https://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
     fn IndexedGetter(&self, index: u32) -> Option<DOMString> {
         self.owner.with_block(|pdb| {
-            pdb.declarations().get(index as usize).map(|entry| {
-                let (ref declaration, importance) = *entry;
+            pdb.declarations().get(index as usize).map(|declaration| {
+                let important = pdb.declarations_importance().get(index);
                 let mut css = declaration.to_css_string();
-                if importance.important() {
+                if important {
                     css += " !important";
                 }
                 DOMString::from(css)
             })
         })
     }
 
     // https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-csstext
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -29,17 +29,16 @@ servo = ["serde", "heapsize", "heapsize_
 gecko_debug = ["nsstring_vendor/gecko_debug"]
 
 [dependencies]
 app_units = "0.5.5"
 arrayvec = "0.3.20"
 arraydeque = "0.2.3"
 atomic_refcell = "0.1"
 bitflags = "0.7"
-bit-vec = "0.4.3"
 byteorder = "1.0"
 cfg-if = "0.1.0"
 cssparser = "0.20"
 encoding = {version = "0.2", optional = true}
 euclid = "0.15"
 fallible = { path = "../fallible" }
 fnv = "1.0"
 hashglobe = { path = "../hashglobe" }
@@ -61,16 +60,17 @@ parking_lot = "0.4"
 pdqsort = "0.1.0"
 precomputed-hash = "0.1"
 rayon = "0.8"
 selectors = { path = "../selectors" }
 serde = {version = "1.0", optional = true, features = ["derive"]}
 servo_arc = { path = "../servo_arc" }
 servo_atoms = {path = "../atoms", optional = true}
 servo_config = {path = "../config", optional = true}
+smallbitvec = "1.0"
 smallvec = "0.4"
 style_derive = {path = "../style_derive"}
 style_traits = {path = "../style_traits"}
 servo_url = {path = "../url", optional = true}
 time = "0.1"
 unicode-bidi = "0.3"
 unicode-segmentation = "1.0"
 
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -5,17 +5,17 @@
 //! CSS transitions and animations.
 #![deny(missing_docs)]
 
 use Atom;
 use bezier::Bezier;
 use context::SharedStyleContext;
 use dom::OpaqueNode;
 use font_metrics::FontMetricsProvider;
-use properties::{self, CascadeFlags, ComputedValues, Importance};
+use properties::{self, CascadeFlags, ComputedValues};
 use properties::animated_properties::{AnimatableLonghand, AnimatedProperty, TransitionProperty};
 use properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
 use properties::longhands::animation_iteration_count::single_value::computed_value::T as AnimationIterationCount;
 use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
 use rule_tree::CascadeLevel;
 use servo_arc::Arc;
 use std::sync::mpsc::Sender;
 use stylesheets::keyframes_rule::{KeyframesStep, KeyframesStepValue};
@@ -477,22 +477,21 @@ fn compute_style_for_animation_step(cont
                                     font_metrics_provider: &FontMetricsProvider)
                                     -> Arc<ComputedValues> {
     match step.value {
         KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
         KeyframesStepValue::Declarations { block: ref declarations } => {
             let guard = declarations.read_with(context.guards.author);
 
             // No !important in keyframes.
-            debug_assert!(guard.declarations().iter()
-                            .all(|&(_, importance)| importance == Importance::Normal));
+            debug_assert!(!guard.any_important());
 
             let iter = || {
                 guard.declarations().iter().rev()
-                     .map(|&(ref decl, _importance)| (decl, CascadeLevel::Animations))
+                     .map(|decl| (decl, CascadeLevel::Animations))
             };
 
             // This currently ignores visited styles, which seems acceptable,
             // as existing browsers don't appear to animate visited styles.
             let computed =
                 properties::apply_declarations(context.stylist.device(),
                                                /* pseudo = */ None,
                                                previous_style.rules(),
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -35,17 +35,16 @@
 //#![deny(unsafe_code)]
 #![allow(unused_unsafe)]
 
 #![recursion_limit = "500"]  // For define_css_keyword_enum! in -moz-appearance
 
 extern crate app_units;
 extern crate arrayvec;
 extern crate atomic_refcell;
-extern crate bit_vec;
 #[macro_use]
 extern crate bitflags;
 #[allow(unused_extern_crates)] extern crate byteorder;
 #[cfg(feature = "gecko")] #[macro_use] #[no_link] extern crate cfg_if;
 #[macro_use] extern crate cssparser;
 extern crate euclid;
 extern crate fallible;
 extern crate fnv;
@@ -76,16 +75,17 @@ extern crate pdqsort;
 extern crate precomputed_hash;
 extern crate rayon;
 extern crate selectors;
 #[cfg(feature = "servo")] #[macro_use] extern crate serde;
 pub extern crate servo_arc;
 #[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
 #[cfg(feature = "servo")] extern crate servo_config;
 #[cfg(feature = "servo")] extern crate servo_url;
+extern crate smallbitvec;
 extern crate smallvec;
 #[macro_use]
 extern crate style_derive;
 #[macro_use]
 extern crate style_traits;
 extern crate time;
 extern crate unicode_bidi;
 #[allow(unused_extern_crates)]
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -9,18 +9,20 @@
 use context::QuirksMode;
 use cssparser::{DeclarationListParser, parse_important, ParserInput, CowRcStr};
 use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter, ParseError as CssParseError};
 use error_reporting::{ParseErrorReporter, ContextualParseError};
 use parser::{ParserContext, ParserErrorContext};
 use properties::animated_properties::AnimationValue;
 use selectors::parser::SelectorParseError;
 use shared_lock::Locked;
+use smallbitvec::{self, SmallBitVec};
 use smallvec::SmallVec;
 use std::fmt;
+use std::iter::{DoubleEndedIterator, Zip};
 use std::slice::Iter;
 use style_traits::{PARSING_MODE_DEFAULT, ToCss, ParseError, ParsingMode, StyleParseError};
 use stylesheets::{CssRuleType, Origin, UrlExtraData};
 use stylesheets::{MallocSizeOf, MallocSizeOfFn};
 use super::*;
 use values::computed::Context;
 #[cfg(feature = "gecko")] use properties::animated_properties::AnimationValueMap;
 
@@ -68,73 +70,87 @@ impl Importance {
 }
 
 /// Overridden declarations are skipped.
 #[derive(Clone)]
 pub struct PropertyDeclarationBlock {
     /// The group of declarations, along with their importance.
     ///
     /// Only deduplicated declarations appear here.
-    declarations: Vec<(PropertyDeclaration, Importance)>,
+    declarations: Vec<PropertyDeclaration>,
 
-    /// The number of entries in `self.declaration` with `Importance::Important`
-    important_count: usize,
+    /// The "important" flag for each declaration in `declarations`.
+    declarations_importance: SmallBitVec,
 
     longhands: LonghandIdSet,
 }
 
 impl MallocSizeOf for PropertyDeclarationBlock {
     fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize {
         self.declarations.malloc_size_of_children(malloc_size_of)
     }
 }
 
-/// Iterator for PropertyDeclaration to be generated from PropertyDeclarationBlock.
-#[derive(Clone)]
-pub struct PropertyDeclarationIterator<'a> {
-    iter: Iter<'a, (PropertyDeclaration, Importance)>,
+/// Iterator over `(PropertyDeclaration, Importance)` pairs.
+pub struct DeclarationImportanceIterator<'a> {
+    iter: Zip<Iter<'a, PropertyDeclaration>, smallbitvec::Iter<'a>>,
+}
+
+impl<'a> DeclarationImportanceIterator<'a> {
+    /// Constructor
+    pub fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
+        DeclarationImportanceIterator {
+            iter: declarations.iter().zip(important.iter()),
+        }
+    }
 }
 
-impl<'a> Iterator for PropertyDeclarationIterator<'a> {
-    type Item = &'a PropertyDeclaration;
-    #[inline]
-    fn next(&mut self) -> Option<&'a PropertyDeclaration> {
-        self.iter.next().map(|&(ref decl, _)| decl)
+impl<'a> Iterator for DeclarationImportanceIterator<'a> {
+    type Item = (&'a PropertyDeclaration, Importance);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().map(|(decl, important)|
+            (decl, if important { Importance::Important } else { Importance::Normal }))
+    }
+}
+
+impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.iter.next_back().map(|(decl, important)|
+            (decl, if important { Importance::Important } else { Importance::Normal }))
     }
 }
 
 /// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
 pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> {
-    iter: Iter<'a, (PropertyDeclaration, Importance)>,
+    iter: DeclarationImportanceIterator<'a>,
     context: &'cx mut Context<'cx_a>,
     default_values: &'a ComputedValues,
 }
 
 impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
     fn new(declarations: &'a PropertyDeclarationBlock,
            context: &'cx mut Context<'cx_a>,
            default_values: &'a ComputedValues) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
         AnimationValueIterator {
-            iter: declarations.declarations().iter(),
+            iter: declarations.declaration_importance_iter(),
             context: context,
             default_values: default_values,
         }
     }
 }
 
 impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
     type Item = (AnimatableLonghand, AnimationValue);
     #[inline]
     fn next(&mut self) -> Option<Self::Item> {
-        use properties::Importance;
-
         loop {
             let next = self.iter.next();
             match next {
-                Some(&(ref decl, importance)) => {
+                Some((decl, importance)) => {
                     if importance == Importance::Normal {
                         let property = AnimatableLonghand::from_declaration(decl);
                         let animation = AnimationValue::from_declaration(decl, &mut self.context,
                                                                          self.default_values);
                         debug_assert!(property.is_none() == animation.is_none(),
                                       "The failure condition of AnimatableLonghand::from_declaration \
                                        and AnimationValue::from_declaration should be the same");
                         // Skip the property if either ::from_declaration fails.
@@ -161,77 +177,85 @@ impl PropertyDeclarationBlock {
     pub fn len(&self) -> usize {
         self.declarations.len()
     }
 
     /// Create an empty block
     pub fn new() -> Self {
         PropertyDeclarationBlock {
             declarations: Vec::new(),
-            important_count: 0,
+            declarations_importance: SmallBitVec::new(),
             longhands: LonghandIdSet::new(),
         }
     }
 
     /// Create a block with a single declaration
     pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
         let mut longhands = LonghandIdSet::new();
         if let PropertyDeclarationId::Longhand(id) = declaration.id() {
             longhands.insert(id);
         }
         PropertyDeclarationBlock {
-            declarations: vec![(declaration, importance)],
-            important_count: if importance.important() { 1 } else { 0 },
+            declarations: vec![declaration],
+            declarations_importance: SmallBitVec::from_elem(1, importance.important()),
             longhands: longhands,
         }
     }
 
     /// The declarations in this block
-    pub fn declarations(&self) -> &[(PropertyDeclaration, Importance)] {
+    pub fn declarations(&self) -> &[PropertyDeclaration] {
         &self.declarations
     }
 
-    /// Iterate over only PropertyDeclaration.
-    pub fn declarations_iter(&self) -> PropertyDeclarationIterator {
-        PropertyDeclarationIterator {
-            iter: self.declarations.iter(),
-        }
+    /// The `important` flags for declarations in this block
+    pub fn declarations_importance(&self) -> &SmallBitVec {
+        &self.declarations_importance
+    }
+
+    /// Iterate over `(PropertyDeclaration, Importance)` pairs
+    pub fn declaration_importance_iter(&self) -> DeclarationImportanceIterator {
+        DeclarationImportanceIterator::new(&self.declarations, &self.declarations_importance)
     }
 
     /// Return an iterator of (AnimatableLonghand, AnimationValue).
     pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>(&'a self,
                                                        context: &'cx mut Context<'cx_a>,
                                                        default_values: &'a ComputedValues)
                                                        -> AnimationValueIterator<'a, 'cx, 'cx_a> {
         AnimationValueIterator::new(self, context, default_values)
     }
 
     /// Returns whether this block contains any declaration with `!important`.
     ///
-    /// This is based on the `important_count` counter,
+    /// This is based on the `declarations_importance` bit-vector,
     /// which should be maintained whenever `declarations` is changed.
-    // FIXME: make fields private and maintain it here in methods?
     pub fn any_important(&self) -> bool {
-        self.important_count > 0
+        !self.declarations_importance.all_false()
     }
 
     /// Returns whether this block contains any declaration without `!important`.
     ///
-    /// This is based on the `important_count` counter,
+    /// This is based on the `declarations_importance` bit-vector,
     /// which should be maintained whenever `declarations` is changed.
-    // FIXME: make fields private and maintain it here in methods?
     pub fn any_normal(&self) -> bool {
-        self.declarations.len() > self.important_count
+        !self.declarations_importance.all_true()
     }
 
     /// Get a declaration for a given property.
     ///
     /// NOTE: This is linear time.
-    pub fn get(&self, property: PropertyDeclarationId) -> Option< &(PropertyDeclaration, Importance)> {
-        self.declarations.iter().find(|&&(ref decl, _)| decl.id() == property)
+    pub fn get(&self, property: PropertyDeclarationId) -> Option<(&PropertyDeclaration, Importance)> {
+        self.declarations.iter().enumerate().find(|&(_, decl)| decl.id() == property).map(|(i, decl)| {
+            let importance = if self.declarations_importance.get(i as u32) {
+                Importance::Important
+            } else {
+                Importance::Normal
+            };
+            (decl, importance)
+        })
     }
 
     /// Find the value of the given property in this block and serialize it
     ///
     /// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
     pub fn property_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
         where W: fmt::Write,
     {
@@ -246,17 +270,17 @@ impl PropertyDeclarationBlock {
 
                 // Step 1.2.2
                 for &longhand in shorthand.longhands() {
                     // Step 1.2.2.1
                     let declaration = self.get(PropertyDeclarationId::Longhand(longhand));
 
                     // Step 1.2.2.2 & 1.2.2.3
                     match declaration {
-                        Some(&(ref declaration, importance)) => {
+                        Some((declaration, importance)) => {
                             list.push(declaration);
                             if importance.important() {
                                 important_count += 1;
                             }
                         },
                         None => return Ok(()),
                     }
                 }
@@ -272,17 +296,17 @@ impl PropertyDeclarationBlock {
                 // so we treat this as a normal-importance property
                 match shorthand.get_shorthand_appendable_value(list) {
                     Some(appendable_value) =>
                         append_declaration_value(dest, appendable_value),
                     None => return Ok(()),
                 }
             }
             Err(longhand_or_custom) => {
-                if let Some(&(ref value, _importance)) = self.get(longhand_or_custom) {
+                if let Some((value, _importance)) = self.get(longhand_or_custom) {
                     // Step 2
                     value.to_css(dest)
                 } else {
                     // Step 3
                     Ok(())
                 }
             }
         }
@@ -293,26 +317,26 @@ impl PropertyDeclarationBlock {
         // Step 1: done when parsing a string to PropertyId
 
         // Step 2
         match property.as_shorthand() {
             Ok(shorthand) => {
                 // Step 2.1 & 2.2 & 2.3
                 if shorthand.longhands().iter().all(|&l| {
                     self.get(PropertyDeclarationId::Longhand(l))
-                        .map_or(false, |&(_, importance)| importance.important())
+                        .map_or(false, |(_, importance)| importance.important())
                 }) {
                     Importance::Important
                 } else {
                     Importance::Normal
                 }
             }
             Err(longhand_or_custom) => {
                 // Step 3
-                self.get(longhand_or_custom).map_or(Importance::Normal, |&(_, importance)| importance)
+                self.get(longhand_or_custom).map_or(Importance::Normal, |(_, importance)| importance)
             }
         }
     }
 
     /// Adds or overrides the declaration for a given property in this block,
     /// **except** if an existing declaration for the same property is more
     /// important.
     ///
@@ -404,111 +428,103 @@ impl PropertyDeclarationBlock {
 
         let definitely_new = longhand_id.map_or(false, |id| {
             !self.longhands.contains(id)
         });
 
         if !definitely_new {
             let mut index_to_remove = None;
             for (i, slot) in self.declarations.iter_mut().enumerate() {
-                if slot.0.id() == declaration.id() {
-                    match (slot.1, importance) {
-                        (Importance::Normal, Importance::Important) => {
-                            self.important_count += 1;
-                        }
-                        (Importance::Important, Importance::Normal) => {
-                            if overwrite_more_important_and_reuse_slot {
-                                self.important_count -= 1;
-                            } else {
+                if slot.id() == declaration.id() {
+                    let important = self.declarations_importance.get(i as u32);
+                    match (important, importance.important()) {
+                        (false, true) => {}
+
+                        (true, false) => {
+                            if !overwrite_more_important_and_reuse_slot {
                                 return false
                             }
                         }
-                        _ => if slot.0 == declaration {
+                        _ => if *slot == declaration {
                             return false;
                         }
                     }
 
                     if overwrite_more_important_and_reuse_slot {
-                        *slot = (declaration, importance);
+                        *slot = declaration;
+                        self.declarations_importance.set(i as u32, importance.important());
                         return true;
                     }
 
                     // NOTE(emilio): We could avoid this and just override for
                     // properties not affected by logical props, but it's not
                     // clear it's worth it given the `definitely_new` check.
                     index_to_remove = Some(i);
                     break;
                 }
             }
 
             if let Some(index) = index_to_remove {
                 self.declarations.remove(index);
-                self.declarations.push((declaration, importance));
+                self.declarations_importance.remove(index as u32);
+                self.declarations.push(declaration);
+                self.declarations_importance.push(importance.important());
                 return true;
             }
         }
 
         if let Some(id) = longhand_id {
             self.longhands.insert(id);
         }
-        self.declarations.push((declaration, importance));
-        if importance.important() {
-            self.important_count += 1;
-        }
+        self.declarations.push(declaration);
+        self.declarations_importance.push(importance.important());
         true
     }
 
     /// Set the declaration importance for a given property, if found.
     ///
     /// Returns whether any declaration was updated.
     pub fn set_importance(&mut self, property: &PropertyId, new_importance: Importance) -> bool {
         let mut updated_at_least_one = false;
-        for &mut (ref declaration, ref mut importance) in &mut self.declarations {
+        for (i, declaration) in self.declarations.iter().enumerate() {
             if declaration.id().is_or_is_longhand_of(property) {
-                match (*importance, new_importance) {
-                    (Importance::Normal, Importance::Important) => {
-                        self.important_count += 1;
-                    }
-                    (Importance::Important, Importance::Normal) => {
-                        self.important_count -= 1;
-                    }
-                    _ => {
-                        continue;
-                    }
+                let is_important = new_importance.important();
+                if self.declarations_importance.get(i as u32) != is_important {
+                    self.declarations_importance.set(i as u32, is_important);
+                    updated_at_least_one = true;
                 }
-                updated_at_least_one = true;
-                *importance = new_importance;
             }
         }
         updated_at_least_one
     }
 
     /// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
     ///
     /// Returns whether any declaration was actually removed.
     pub fn remove_property(&mut self, property: &PropertyId) -> bool {
         if let PropertyId::Longhand(id) = *property {
             if !self.longhands.contains(id) {
                 return false
             }
         }
-        let important_count = &mut self.important_count;
         let mut removed_at_least_one = false;
         let longhands = &mut self.longhands;
-        self.declarations.retain(|&(ref declaration, importance)| {
+        let declarations_importance = &mut self.declarations_importance;
+        let mut i = 0;
+        self.declarations.retain(|declaration| {
             let id = declaration.id();
             let remove = id.is_or_is_longhand_of(property);
             if remove {
                 removed_at_least_one = true;
                 if let PropertyDeclarationId::Longhand(id) = id {
-                    longhands.remove(id)
+                    longhands.remove(id);
                 }
-                if importance.important() {
-                    *important_count -= 1
-                }
+                declarations_importance.remove(i);
+            } else {
+                i += 1;
             }
             !remove
         });
 
         if let PropertyId::Longhand(_) = *property {
             debug_assert!(removed_at_least_one);
         }
         removed_at_least_one
@@ -522,17 +538,17 @@ impl PropertyDeclarationBlock {
         computed_values: Option<&ComputedValues>,
     ) -> fmt::Result
     where
         W: fmt::Write,
     {
         match property.as_shorthand() {
             Err(_longhand_or_custom) => {
                 if self.declarations.len() == 1 {
-                    let declaration = &self.declarations[0].0;
+                    let declaration = &self.declarations[0];
                     // If we have a longhand declaration with variables, those variables will be
                     // stored as unparsed values. As a temporary measure to produce sensible results
                     // in Gecko's getKeyframes() implementation for CSS animations, if
                     // |computed_values| is supplied, we use it to expand such variable
                     // declarations. This will be fixed properly in Gecko bug 1391537.
                     match (declaration, computed_values) {
                         (&PropertyDeclaration::WithVariables(id, ref unparsed),
                          Some(ref computed_values)) => unparsed
@@ -544,61 +560,62 @@ impl PropertyDeclarationBlock {
                             .to_css(dest),
                         (ref d, _) => d.to_css(dest),
                     }
                 } else {
                     Err(fmt::Error)
                 }
             }
             Ok(shorthand) => {
-                if !self.declarations.iter().all(|decl| decl.0.shorthands().contains(&shorthand)) {
+                if !self.declarations.iter().all(|decl| decl.shorthands().contains(&shorthand)) {
                     return Err(fmt::Error)
                 }
-                let iter = self.declarations_iter();
+                let iter = self.declarations.iter();
                 match shorthand.get_shorthand_appendable_value(iter) {
                     Some(AppendableValue::Css { css, .. }) => {
                         dest.write_str(css)
                     },
                     Some(AppendableValue::DeclarationsForShorthand(_, decls)) => {
                         shorthand.longhands_to_css(decls, dest)
                     }
                     _ => Ok(())
                 }
             }
         }
     }
 
     /// Convert AnimationValueMap to PropertyDeclarationBlock.
     #[cfg(feature = "gecko")]
     pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self {
-        let mut declarations = vec![];
+        let len = animation_value_map.len();
+        let mut declarations = Vec::with_capacity(len);
         let mut longhands = LonghandIdSet::new();
 
         for (property, animation_value) in animation_value_map.iter() {
           longhands.set_animatable_longhand_bit(property);
-          declarations.push((animation_value.uncompute(), Importance::Normal));
+          declarations.push(animation_value.uncompute());
         }
 
         PropertyDeclarationBlock {
             declarations: declarations,
-            important_count: 0,
+            declarations_importance: SmallBitVec::from_elem(len as u32, false),
             longhands: longhands,
         }
     }
 
     /// Returns true if the declaration block has a CSSWideKeyword for the given
     /// property.
     #[cfg(feature = "gecko")]
     pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
         if let PropertyId::Longhand(id) = *property {
             if !self.longhands.contains(id) {
                 return false
             }
         }
-        self.declarations.iter().any(|&(ref decl, _)|
+        self.declarations.iter().any(|decl|
             decl.id().is_or_is_longhand_of(property) &&
             decl.get_css_wide_keyword().is_some()
         )
     }
 }
 
 impl ToCss for PropertyDeclarationBlock {
     // https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
@@ -608,17 +625,17 @@ impl ToCss for PropertyDeclarationBlock 
         let mut is_first_serialization = true; // trailing serializations should have a prepended space
 
         // Step 1 -> dest = result list
 
         // Step 2
         let mut already_serialized = PropertyDeclarationIdSet::new();
 
         // Step 3
-        for &(ref declaration, importance) in &*self.declarations {
+        for (declaration, importance) in self.declaration_importance_iter() {
             // Step 3.1
             let property = declaration.id();
 
             // Step 3.2
             if already_serialized.contains(property) {
                 continue;
             }
 
@@ -634,46 +651,46 @@ impl ToCss for PropertyDeclarationBlock 
 
                     // Substep 2 & 3
                     let mut current_longhands = SmallVec::<[_; 10]>::new();
                     let mut important_count = 0;
                     let mut found_system = None;
 
                     let is_system_font =
                         shorthand == ShorthandId::Font &&
-                        self.declarations.iter().any(|&(ref l, _)| {
+                        self.declarations.iter().any(|l| {
                             !already_serialized.contains(l.id()) &&
                             l.get_system().is_some()
                         });
 
                     if is_system_font {
-                        for &(ref longhand, longhand_importance) in &self.declarations {
+                        for (longhand, importance) in self.declaration_importance_iter() {
                             if already_serialized.contains(longhand.id()) {
                                 continue;
                             }
 
                             if longhand.get_system().is_some() || longhand.is_default_line_height() {
                                 current_longhands.push(longhand);
                                 if found_system.is_none() {
                                    found_system = longhand.get_system();
                                 }
-                                if longhand_importance.important() {
+                                if importance.important() {
                                     important_count += 1;
                                 }
                             }
                         }
                     } else {
-                        for &(ref longhand, longhand_importance) in &self.declarations {
+                        for (longhand, importance) in self.declaration_importance_iter() {
                             if already_serialized.contains(longhand.id()) {
                                 continue;
                             }
 
                             if longhand.id().is_longhand_of(shorthand) {
                                 current_longhands.push(longhand);
-                                if longhand_importance.important() {
+                                if importance.important() {
                                     important_count += 1;
                                 }
                             }
                         }
                         // Substep 1:
                         //
                         // Assuming that the PropertyDeclarationBlock contains no
                         // duplicate entries, if the current_longhands length is
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -7,16 +7,17 @@
 // Please note that valid Rust syntax may be mangled by the Mako parser.
 // For example, Vec<&Foo> will be mangled as Vec&Foo>. To work around these issues, the code
 // can be escaped. In the above example, Vec<<&Foo> or Vec< &Foo> achieves the desired result of Vec<&Foo>.
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 #[cfg(feature = "servo")] use app_units::Au;
 use servo_arc::{Arc, UniqueArc};
+use smallbitvec::SmallBitVec;
 use std::borrow::Cow;
 use hash::HashSet;
 use std::{fmt, mem, ops};
 #[cfg(feature = "gecko")] use std::ptr;
 
 #[cfg(feature = "servo")] use cssparser::RGBA;
 use cssparser::{Parser, TokenSerializationType, serialize_identifier};
 use cssparser::ParserInput;
@@ -3023,35 +3024,36 @@ pub fn cascade(
     quirks_mode: QuirksMode
 ) -> Arc<ComputedValues> {
     debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
     #[cfg(feature = "gecko")]
     debug_assert!(parent_style.is_none() ||
                   ptr::eq(parent_style.unwrap(),
                           parent_style_ignoring_first_line.unwrap()) ||
                   parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine));
+    let empty = SmallBitVec::new();
     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)).declarations()
+                source.read(cascade_level.guard(guards)).declaration_importance_iter()
             } else {
                 // The root node has no style source.
-                &[]
+                DeclarationImportanceIterator::new(&[], &empty)
             };
             let node_importance = node.importance();
 
             let property_restriction = pseudo.and_then(|p| p.property_restriction());
 
             declarations
-                .iter()
                 // Yield declarations later in source order (with more precedence) first.
                 .rev()
-                .filter_map(move |&(ref declaration, declaration_importance)| {
+                .filter_map(move |(declaration, declaration_importance)| {
                     if let Some(property_restriction) = property_restriction {
                         // declaration.id() is either a longhand or a custom
                         // property.  Custom properties are always allowed, but
                         // longhands are only allowed if they have our
                         // property_restriction flag set.
                         if let PropertyDeclarationId::Longhand(id) = declaration.id() {
                             if !id.flags().contains(property_restriction) {
                                 return None
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -1206,25 +1206,25 @@ impl StrongRuleNode {
             // https://bugzilla.mozilla.org/show_bug.cgi?id=1363088
 
             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.read(node.cascade_level().guard(guards)).declarations()
+                    source.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();
-                let longhands = declarations.iter().rev()
-                    .filter_map(|&(ref declaration, importance)| {
+                let longhands = declarations.rev()
+                    .filter_map(|(declaration, importance)| {
                         if importance != node_importance { return None }
                         match declaration.id() {
                             PropertyDeclarationId::Longhand(id) => {
                                 Some((id, declaration))
                             }
                             _ => None
                         }
                     });
@@ -1324,19 +1324,18 @@ impl StrongRuleNode {
         // 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();
-            for &(ref decl, important) in style.read(node.cascade_level().guard(guards))
-                                               .declarations()
-                                               .iter() {
+            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
                 // override animations.
                 if important.important() {
                     match decl.id() {
                         PropertyDeclarationId::Longhand(id) => result.0.insert(id),
--- a/servo/components/style/sharing/mod.rs
+++ b/servo/components/style/sharing/mod.rs
@@ -62,27 +62,27 @@
 //! both selectors targeting elements and selectors targeting pseudo-element
 //! originating elements.  We ensure that the pseudo-element parts of all these
 //! selectors are effectively stripped off, so that matching them all against
 //! elements makes sense.
 
 use Atom;
 use applicable_declarations::ApplicableDeclarationBlock;
 use atomic_refcell::{AtomicRefCell, AtomicRefMut};
-use bit_vec::BitVec;
 use bloom::StyleBloom;
 use cache::{LRUCache, LRUCacheMutIterator};
 use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
 use data::ElementStyles;
 use dom::{TElement, SendElement};
 use matching::MatchMethods;
 use owning_ref::OwningHandle;
 use properties::ComputedValues;
 use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
 use servo_arc::Arc;
+use smallbitvec::SmallBitVec;
 use smallvec::SmallVec;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::Deref;
 use stylist::Stylist;
 
 mod checks;
 
@@ -118,17 +118,17 @@ pub struct ValidationData {
     /// a similar fashion as what Boris is doing for the ID attribute.
     class_list: Option<SmallVec<[Atom; 5]>>,
 
     /// The list of presentational attributes of the element.
     pres_hints: Option<SmallVec<[ApplicableDeclarationBlock; 5]>>,
 
     /// The cached result of matching this entry against the revalidation
     /// selectors.
-    revalidation_match_results: Option<BitVec>,
+    revalidation_match_results: Option<SmallBitVec>,
 }
 
 impl ValidationData {
     /// Move the cached data to a new instance, and return it.
     pub fn take(&mut self) -> Self {
         mem::replace(self, Self::default())
     }
 
@@ -172,17 +172,17 @@ impl ValidationData {
     #[inline]
     fn revalidation_match_results<E, F>(
         &mut self,
         element: E,
         stylist: &Stylist,
         bloom: &StyleBloom<E>,
         bloom_known_valid: bool,
         flags_setter: &mut F
-    ) -> &BitVec
+    ) -> &SmallBitVec
         where E: TElement,
               F: FnMut(&E, ElementSelectorFlags),
     {
         if self.revalidation_match_results.is_none() {
             // The bloom filter may already be set up for our element.
             // If it is, use it.  If not, we must be in a candidate
             // (i.e. something in the cache), and the element is one
             // of our cousins, not a sibling.  In that case, we'll
@@ -251,17 +251,17 @@ impl<E: TElement> StyleSharingCandidate<
     }
 
     /// Compute the bit vector of revalidation selector match results
     /// for this candidate.
     fn revalidation_match_results(
         &mut self,
         stylist: &Stylist,
         bloom: &StyleBloom<E>,
-    ) -> &BitVec {
+    ) -> &SmallBitVec {
         self.validation_data.revalidation_match_results(
             self.element,
             stylist,
             bloom,
             /* bloom_known_valid = */ false,
             &mut |_, _| {})
     }
 }
@@ -304,17 +304,17 @@ impl<E: TElement> StyleSharingTarget<E> 
         self.validation_data.pres_hints(self.element)
     }
 
     fn revalidation_match_results(
         &mut self,
         stylist: &Stylist,
         bloom: &StyleBloom<E>,
         selector_flags_map: &mut SelectorFlagsMap<E>
-    ) -> &BitVec {
+    ) -> &SmallBitVec {
         // It's important to set the selector flags. Otherwise, if we succeed in
         // sharing the style, we may not set the slow selector flags for the
         // right elements (which may not necessarily be |element|), causing
         // missed restyles after future DOM mutations.
         //
         // Gecko's test_bug534804.html exercises this. A minimal testcase is:
         // <style> #e:empty + span { ... } </style>
         // <span id="e">
--- a/servo/components/style/stylesheets/keyframes_rule.rs
+++ b/servo/components/style/stylesheets/keyframes_rule.rs
@@ -294,17 +294,17 @@ pub struct KeyframesStep {
 
 impl KeyframesStep {
     #[inline]
     fn new(percentage: KeyframePercentage,
            value: KeyframesStepValue,
            guard: &SharedRwLockReadGuard) -> Self {
         let declared_timing_function = match value {
             KeyframesStepValue::Declarations { ref block } => {
-                block.read_with(guard).declarations().iter().any(|&(ref prop_decl, _)| {
+                block.read_with(guard).declarations().iter().any(|prop_decl| {
                     match *prop_decl {
                         PropertyDeclaration::AnimationTimingFunction(..) => true,
                         _ => false,
                     }
                 })
             }
             _ => false,
         };
@@ -320,17 +320,17 @@ impl KeyframesStep {
     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_with(guard);
-                let &(ref declaration, _) =
+                let (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,
                     PropertyDeclaration::WithVariables(..) => None,
@@ -364,17 +364,17 @@ fn get_animated_properties(keyframes: &[
                            -> Vec<AnimatableLonghand> {
     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_with(&guard);
         let block = keyframe.block.read_with(guard);
-        for &(ref declaration, importance) in block.declarations().iter() {
+        for (declaration, importance) in block.declaration_importance_iter() {
             assert!(!importance.important());
 
             if let Some(property) = AnimatableLonghand::from_declaration(declaration) {
                 // Skip the 'display' property because although it is animatable from SMIL,
                 // it should not be animatable from CSS Animations or Web Animations.
                 if property != AnimatableLonghand::Display &&
                    !seen.has_animatable_longhand_bit(&property) {
                     seen.set_animatable_longhand_bit(&property);
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -1,17 +1,16 @@
 /* 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/. */
 
 //! Selector matching.
 
 use {Atom, LocalName, Namespace};
 use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
-use bit_vec::BitVec;
 use context::{CascadeInputs, QuirksMode};
 use dom::TElement;
 use element_state::ElementState;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")]
 use gecko_bindings::structs::{nsIAtom, ServoStyleSetSizes, StyleRuleInclusion};
 use hashglobe::FailedAllocationError;
 use invalidation::element::invalidation_map::InvalidationMap;
@@ -30,16 +29,17 @@ use selectors::bloom::{BloomFilter, NonC
 use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
 use selectors::matching::VisitedHandlingMode;
 use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
 use selectors::parser::{SelectorIter, SelectorMethods};
 use selectors::sink::Push;
 use selectors::visitor::SelectorVisitor;
 use servo_arc::{Arc, ArcBorrow};
 use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
+use smallbitvec::SmallBitVec;
 use smallvec::VecLike;
 use std::fmt::Debug;
 use std::ops;
 use style_traits::viewport::ViewportConstraints;
 use stylesheet_set::{OriginValidity, SheetRebuildKind, StylesheetSet, StylesheetIterator, StylesheetFlusher};
 #[cfg(feature = "gecko")]
 use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule};
 use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter};
@@ -1555,32 +1555,32 @@ impl Stylist {
 
     /// Computes the match results of a given element against the set of
     /// revalidation selectors.
     pub fn match_revalidation_selectors<E, F>(
         &self,
         element: &E,
         bloom: Option<&BloomFilter>,
         flags_setter: &mut F
-    ) -> BitVec
+    ) -> SmallBitVec
     where
         E: TElement,
         F: FnMut(&E, ElementSelectorFlags),
     {
         // NB: `MatchingMode` doesn't really matter, given we don't share style
         // between pseudos.
         let mut matching_context =
             MatchingContext::new(MatchingMode::Normal, bloom, self.quirks_mode);
 
         // Note that, by the time we're revalidating, we're guaranteed that the
         // candidate and the entry have the same id, classes, and local name.
         // This means we're guaranteed to get the same rulehash buckets for all
         // the lookups, which means that the bitvecs are comparable. We verify
         // this in the caller by asserting that the bitvecs are same-length.
-        let mut results = BitVec::new();
+        let mut results = SmallBitVec::new();
         for (data, _) in self.cascade_data.iter_origins() {
             data.selectors_for_cache_revalidation.lookup(
                 *element,
                 self.quirks_mode,
                 &mut |selector_and_hashes| {
                     results.push(matches_selector(
                         &selector_and_hashes.selector,
                         selector_and_hashes.selector_offset,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -2256,17 +2256,17 @@ pub extern "C" fn Servo_DeclarationBlock
 
 #[no_mangle]
 pub extern "C" fn Servo_SerializeFontValueForCanvas(
     declarations: RawServoDeclarationBlockBorrowed,
     buffer: *mut nsAString) {
     use style::properties::shorthands::font;
 
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
-        let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations_iter()) {
+        let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
             Ok(l) => l,
             Err(()) => {
                 warn!("Unexpected property!");
                 return;
             }
         };
 
         let mut string = String::new();
@@ -2284,17 +2284,17 @@ pub extern "C" fn Servo_DeclarationBlock
         decls.declarations().len() as u32
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed,
                                                         index: u32, result: *mut nsAString) -> bool {
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
-        if let Some(&(ref decl, _)) = decls.declarations().get(index as usize) {
+        if let Some(decl) = decls.declarations().get(index as usize) {
             let result = unsafe { result.as_mut().unwrap() };
             result.assign_utf8(&decl.id().name());
             true
         } else {
             false
         }
     })
 }
@@ -3402,18 +3402,18 @@ pub extern "C" fn Servo_AnimationValue_C
         /* for_smil_animation = */ false
     );
 
     let default_values = data.default_computed_values();
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     // We only compute the first element in declarations.
-    match declarations.read_with(&guard).declarations().first() {
-        Some(&(ref decl, imp)) if imp == Importance::Normal => {
+    match declarations.read_with(&guard).declaration_importance_iter().next() {
+        Some((decl, imp)) if imp == Importance::Normal => {
             let animation = AnimationValue::from_declaration(decl, &mut context, default_values);
             animation.map_or(RawServoAnimationValueStrong::null(), |value| {
                 Arc::new(value).into_strong()
             })
         },
         _ => RawServoAnimationValueStrong::null()
     }
 }
@@ -3549,21 +3549,19 @@ pub extern "C" fn Servo_StyleSet_GetKeyf
                 }
             },
             KeyframesStepValue::Declarations { ref block } => {
                 let guard = block.read_with(&guard);
                 // Filter out non-animatable properties.
                 let animatable =
                     guard.declarations()
                          .iter()
-                         .filter(|&&(ref declaration, _)| {
-                             declaration.is_animatable()
-                         });
-
-                for &(ref declaration, _) in animatable {
+                         .filter(|declaration| declaration.is_animatable());
+
+                for declaration in animatable {
                     let property = AnimatableLonghand::from_declaration(declaration).unwrap();
                     // Skip the 'display' property because although it is animatable from SMIL,
                     // it should not be animatable from CSS Animations.
                     if property != AnimatableLonghand::Display &&
                         !properties_set_at_current_offset.has_animatable_longhand_bit(&property) {
                         properties_set_at_current_offset.set_animatable_longhand_bit(&property);
                         if current_offset == 0.0 {
                             properties_set_at_start.set_animatable_longhand_bit(&property);