aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/bloom.rs
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2017-05-24 16:30:18 +0200
committerBobby Holley <bobbyholley@gmail.com>2017-06-21 19:53:15 -0700
commit5d5c715152f30b944353470830138379bfd6ae34 (patch)
tree64bd58ee71878409d3ba0ac61bc19142f7abed38 /components/style/bloom.rs
parent0f0e0d81fbed3c29bb10a452a294487f21b4e66c (diff)
downloadservo-5d5c715152f30b944353470830138379bfd6ae34.tar.gz
servo-5d5c715152f30b944353470830138379bfd6ae34.zip
Switch the bloom element list to a SmallVec and track pushed hashes.
Diffstat (limited to 'components/style/bloom.rs')
-rw-r--r--components/style/bloom.rs61
1 files changed, 48 insertions, 13 deletions
diff --git a/components/style/bloom.rs b/components/style/bloom.rs
index 07d245a1e4a..5033ff6ce83 100644
--- a/components/style/bloom.rs
+++ b/components/style/bloom.rs
@@ -46,8 +46,29 @@ pub struct StyleBloom<E: TElement> {
/// The bloom filter per se.
filter: Box<BloomFilter>,
- /// The stack of elements that this bloom filter contains.
- elements: Vec<SendElement<E>>,
+ /// The stack of elements that this bloom filter contains, along with the
+ /// number of hashes pushed for each element.
+ elements: SmallVec<[PushedElement<E>; 16]>,
+
+ /// Stack of hashes that have been pushed onto this filter.
+ pushed_hashes: SmallVec<[u32; 64]>,
+}
+
+struct PushedElement<E: TElement> {
+ /// The element that was pushed.
+ element: SendElement<E>,
+
+ /// The number of hashes pushed for the element.
+ num_hashes: usize,
+}
+
+impl<E: TElement> PushedElement<E> {
+ fn new(el: E, num_hashes: usize) -> Self {
+ PushedElement {
+ element: unsafe { SendElement::new(el) },
+ num_hashes: num_hashes,
+ }
+ }
}
fn each_relevant_element_hash<E, F>(element: E, mut f: F)
@@ -75,7 +96,8 @@ impl<E: TElement> StyleBloom<E> {
pub fn new() -> Self {
StyleBloom {
filter: Box::new(BloomFilter::new()),
- elements: vec![],
+ elements: Default::default(),
+ pushed_hashes: Default::default(),
}
}
@@ -98,23 +120,36 @@ impl<E: TElement> StyleBloom<E> {
/// Same as `push`, but without asserting, in order to use it from
/// `rebuild`.
fn push_internal(&mut self, element: E) {
+ let mut count = 0;
each_relevant_element_hash(element, |hash| {
+ count += 1;
self.filter.insert_hash(hash);
+ self.pushed_hashes.push(hash);
});
- self.elements.push(unsafe { SendElement::new(element) });
+ self.elements.push(PushedElement::new(element, count));
}
/// Pop the last element in the bloom filter and return it.
+ #[inline]
fn pop(&mut self) -> Option<E> {
- let popped = self.elements.pop().map(|el| *el);
+ let (popped_element, num_hashes) = match self.elements.pop() {
+ None => return None,
+ Some(x) => (*x.element, x.num_hashes),
+ };
+
+ // Verify that the pushed hashes match the ones we'd get from the element.
+ let mut expected_hashes = vec![];
+ if cfg!(debug_assertions) {
+ each_relevant_element_hash(popped_element, |hash| expected_hashes.push(hash));
+ }
- if let Some(popped) = popped {
- each_relevant_element_hash(popped, |hash| {
- self.filter.remove_hash(hash);
- })
+ for _ in 0..num_hashes {
+ let hash = self.pushed_hashes.pop().unwrap();
+ debug_assert_eq!(expected_hashes.pop().unwrap(), hash);
+ self.filter.remove_hash(hash);
}
- popped
+ Some(popped_element)
}
/// Returns true if the bloom filter is empty.
@@ -158,7 +193,7 @@ impl<E: TElement> StyleBloom<E> {
if cfg!(debug_assertions) {
let mut checked = 0;
while let Some(parent) = element.traversal_parent() {
- assert_eq!(parent, *self.elements[self.elements.len() - 1 - checked]);
+ assert_eq!(parent, *(self.elements[self.elements.len() - 1 - checked].element));
element = parent;
checked += 1;
}
@@ -171,7 +206,7 @@ impl<E: TElement> StyleBloom<E> {
/// (if any) and its ancestors.
#[inline]
pub fn current_parent(&self) -> Option<E> {
- self.elements.last().map(|el| **el)
+ self.elements.last().map(|ref el| *el.element)
}
/// Insert the parents of an element in the bloom filter, trying to recover
@@ -268,7 +303,7 @@ impl<E: TElement> StyleBloom<E> {
//
// Thus it's possible with Gecko that we do not find any common
// ancestor.
- while **self.elements.last().unwrap() != common_parent {
+ while *(self.elements.last().unwrap().element) != common_parent {
parents_to_insert.push(common_parent);
self.pop().unwrap();
common_parent = match common_parent.traversal_parent() {