diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2017-05-26 14:56:26 +0200 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2017-07-12 16:38:06 -0700 |
commit | 06140105524fb38693c47f7361c0fc3e2865b79d (patch) | |
tree | 70e821de6dd038c25bc32f7f9480210c43c5c2a7 | |
parent | d1c31f7eafed2708354423852642c3dd8efe077a (diff) | |
download | servo-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.rs | 4 | ||||
-rw-r--r-- | components/style/bloom.rs | 32 |
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(), } |