aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2017-05-26 14:56:26 +0200
committerBobby Holley <bobbyholley@gmail.com>2017-07-12 16:38:06 -0700
commit06140105524fb38693c47f7361c0fc3e2865b79d (patch)
tree70e821de6dd038c25bc32f7f9480210c43c5c2a7
parentd1c31f7eafed2708354423852642c3dd8efe077a (diff)
downloadservo-06140105524fb38693c47f7361c0fc3e2865b79d.tar.gz
servo-06140105524fb38693c47f7361c0fc3e2865b79d.zip
Store the bloom filter in TLS and reuse it across traversals.
MozReview-Commit-ID: EbzDehr2Y2L
-rw-r--r--components/servo_arc/lib.rs4
-rw-r--r--components/style/bloom.rs32
2 files changed, 32 insertions, 4 deletions
diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs
index 5dc261eefb6..ff4074767f8 100644
--- a/components/servo_arc/lib.rs
+++ b/components/servo_arc/lib.rs
@@ -31,6 +31,7 @@ use heapsize::HeapSizeOf;
use nodrop::NoDrop;
#[cfg(feature = "servo")]
use serde::{Deserialize, Serialize};
+use stable_deref_trait::{CloneStableDeref, StableDeref};
use std::{isize, usize};
use std::borrow;
use std::cmp::Ordering;
@@ -433,6 +434,9 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
}
}
+unsafe impl<T: ?Sized> StableDeref for Arc<T> {}
+unsafe impl<T: ?Sized> CloneStableDeref for Arc<T> {}
+
// This is what the HeapSize crate does for regular arc, but is questionably
// sound. See https://github.com/servo/heapsize/issues/37
#[cfg(feature = "servo")]
diff --git a/components/style/bloom.rs b/components/style/bloom.rs
index 34b6b608962..d6d05c2ed20 100644
--- a/components/style/bloom.rs
+++ b/components/style/bloom.rs
@@ -7,9 +7,18 @@
#![deny(missing_docs)]
+use atomic_refcell::{AtomicRefMut, AtomicRefCell};
use dom::{SendElement, TElement};
+use owning_ref::OwningHandle;
use selectors::bloom::BloomFilter;
use smallvec::SmallVec;
+use stylearc::Arc;
+
+/// Bloom filters are large allocations, so we store them in thread-local storage
+/// such that they can be reused across style traversals. StyleBloom is responsible
+/// for ensuring that the bloom filter is zeroed when it is dropped.
+thread_local!(static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
+ Arc::new(AtomicRefCell::new(BloomFilter::new())));
/// A struct that allows us to fast-reject deep descendant selectors avoiding
/// selector-matching.
@@ -43,8 +52,11 @@ use smallvec::SmallVec;
/// immutable during a restyle.
///
pub struct StyleBloom<E: TElement> {
- /// The bloom filter per se.
- filter: Box<BloomFilter>,
+ /// A handle to the bloom filter from the thread upon which this StyleBloom
+ /// was created. We use AtomicRefCell so that this is all |Send|, which allows
+ /// StyleBloom to live in ThreadLocalStyleContext, which is dropped from the
+ /// parent thread.
+ filter: OwningHandle<Arc<AtomicRefCell<BloomFilter>>, AtomicRefMut<'static, BloomFilter>>,
/// The stack of elements that this bloom filter contains, along with the
/// number of hashes pushed for each element.
@@ -101,11 +113,23 @@ fn each_relevant_element_hash<E, F>(element: E, mut f: F)
});
}
+impl<E: TElement> Drop for StyleBloom<E> {
+ fn drop(&mut self) {
+ // Leave the reusable bloom filter in a zeroed state.
+ self.clear();
+ }
+}
+
impl<E: TElement> StyleBloom<E> {
- /// Create an empty `StyleBloom`.
+ /// Create an empty `StyleBloom`. Because StyleBloom acquires the thread-
+ /// local filter buffer, creating multiple live StyleBloom instances at
+ /// the same time on the same thread will panic.
pub fn new() -> Self {
+ let bloom_arc = BLOOM_KEY.with(|b| b.clone());
+ let filter = OwningHandle::new_with_fn(bloom_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
+ debug_assert!(filter.is_zeroed(), "Forgot to zero the bloom filter last time");
StyleBloom {
- filter: Box::new(BloomFilter::new()),
+ filter: filter,
elements: Default::default(),
pushed_hashes: Default::default(),
}