Fix the handling of the Bloom filter in the style sharing cache.

This commit is contained in:
Boris Zbarsky 2017-06-01 23:30:26 -04:00
parent a36edb9970
commit 98f95a32da
5 changed files with 61 additions and 27 deletions

View file

@ -158,6 +158,14 @@ impl<E: TElement> StyleBloom<E> {
} }
} }
/// Get the element that represents the chain of things inserted
/// into the filter right now. That chain is the given element
/// (if any) and its ancestors.
#[inline]
pub fn current_parent(&self) -> Option<E> {
self.elements.last().map(|el| **el)
}
/// Insert the parents of an element in the bloom filter, trying to recover /// Insert the parents of an element in the bloom filter, trying to recover
/// the filter if the last element inserted doesn't match. /// the filter if the last element inserted doesn't match.
/// ///
@ -185,7 +193,7 @@ impl<E: TElement> StyleBloom<E> {
} }
}; };
if self.elements.last().map(|el| **el) == Some(parent_element) { if self.current_parent() == Some(parent_element) {
// Ta da, cache hit, we're all done. // Ta da, cache hit, we're all done.
return; return;
} }

View file

@ -6,10 +6,10 @@
//! quickly whether it's worth to share style, and whether two different //! quickly whether it's worth to share style, and whether two different
//! elements can indeed share the same style. //! elements can indeed share the same style.
use bloom::StyleBloom;
use context::{SelectorFlagsMap, SharedStyleContext}; use context::{SelectorFlagsMap, SharedStyleContext};
use dom::TElement; use dom::TElement;
use element_state::*; use element_state::*;
use selectors::bloom::BloomFilter;
use selectors::matching::StyleRelations; use selectors::matching::StyleRelations;
use sharing::{StyleSharingCandidate, StyleSharingTarget}; use sharing::{StyleSharingCandidate, StyleSharingTarget};
use stylearc::Arc; use stylearc::Arc;
@ -102,7 +102,7 @@ pub fn have_same_state_ignoring_visitedness<E>(element: E,
pub fn revalidate<E>(target: &mut StyleSharingTarget<E>, pub fn revalidate<E>(target: &mut StyleSharingTarget<E>,
candidate: &mut StyleSharingCandidate<E>, candidate: &mut StyleSharingCandidate<E>,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
bloom: &BloomFilter, bloom: &StyleBloom<E>,
selector_flags_map: &mut SelectorFlagsMap<E>) selector_flags_map: &mut SelectorFlagsMap<E>)
-> bool -> bool
where E: TElement, where E: TElement,

View file

@ -7,13 +7,13 @@
use Atom; use Atom;
use bit_vec::BitVec; use bit_vec::BitVec;
use bloom::StyleBloom;
use cache::{LRUCache, LRUCacheMutIterator}; use cache::{LRUCache, LRUCacheMutIterator};
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext}; use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
use data::{ComputedStyle, ElementData, ElementStyles}; use data::{ComputedStyle, ElementData, ElementStyles};
use dom::{TElement, SendElement}; use dom::{TElement, SendElement};
use matching::{ChildCascadeRequirement, MatchMethods}; use matching::{ChildCascadeRequirement, MatchMethods};
use properties::ComputedValues; use properties::ComputedValues;
use selectors::bloom::BloomFilter;
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode, StyleRelations}; use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode, StyleRelations};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::mem; use std::mem;
@ -95,19 +95,40 @@ impl ValidationData {
} }
/// Computes the revalidation results if needed, and returns it. /// Computes the revalidation results if needed, and returns it.
/// Inline so we know at compile time what bloom_known_valid is.
#[inline]
fn revalidation_match_results<E, F>( fn revalidation_match_results<E, F>(
&mut self, &mut self,
element: E, element: E,
stylist: &Stylist, stylist: &Stylist,
bloom: &BloomFilter, bloom: &StyleBloom<E>,
bloom_known_valid: bool,
flags_setter: &mut F flags_setter: &mut F
) -> &BitVec ) -> &BitVec
where E: TElement, where E: TElement,
F: FnMut(&E, ElementSelectorFlags), F: FnMut(&E, ElementSelectorFlags),
{ {
if self.revalidation_match_results.is_none() { 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
// just do revalidation selector matching without a bloom
// filter, to avoid thrashing the filter.
let bloom_to_use = if bloom_known_valid {
debug_assert_eq!(bloom.current_parent(),
element.parent_element());
Some(bloom.filter())
} else {
if bloom.current_parent() == element.parent_element() {
Some(bloom.filter())
} else {
None
}
};
self.revalidation_match_results = self.revalidation_match_results =
Some(stylist.match_revalidation_selectors(&element, bloom, Some(stylist.match_revalidation_selectors(&element,
bloom_to_use,
flags_setter)); flags_setter));
} }
@ -149,16 +170,18 @@ impl<E: TElement> StyleSharingCandidate<E> {
self.validation_data.pres_hints(*self.element) self.validation_data.pres_hints(*self.element)
} }
/// Get the classlist of this candidate. /// Compute the bit vector of revalidation selector match results
/// for this candidate.
fn revalidation_match_results( fn revalidation_match_results(
&mut self, &mut self,
stylist: &Stylist, stylist: &Stylist,
bloom: &BloomFilter, bloom: &StyleBloom<E>,
) -> &BitVec { ) -> &BitVec {
self.validation_data.revalidation_match_results( self.validation_data.revalidation_match_results(
*self.element, *self.element,
stylist, stylist,
bloom, bloom,
/* bloom_known_valid = */ false,
&mut |_, _| {}) &mut |_, _| {})
} }
} }
@ -204,7 +227,7 @@ impl<E: TElement> StyleSharingTarget<E> {
fn revalidation_match_results( fn revalidation_match_results(
&mut self, &mut self,
stylist: &Stylist, stylist: &Stylist,
bloom: &BloomFilter, bloom: &StyleBloom<E>,
selector_flags_map: &mut SelectorFlagsMap<E> selector_flags_map: &mut SelectorFlagsMap<E>
) -> &BitVec { ) -> &BitVec {
// It's important to set the selector flags. Otherwise, if we succeed in // It's important to set the selector flags. Otherwise, if we succeed in
@ -231,6 +254,7 @@ impl<E: TElement> StyleSharingTarget<E> {
self.element, self.element,
stylist, stylist,
bloom, bloom,
/* bloom_known_valid = */ true,
&mut set_selector_flags) &mut set_selector_flags)
} }
@ -243,7 +267,10 @@ impl<E: TElement> StyleSharingTarget<E> {
{ {
let shared_context = &context.shared; let shared_context = &context.shared;
let selector_flags_map = &mut context.thread_local.selector_flags; let selector_flags_map = &mut context.thread_local.selector_flags;
let bloom_filter = context.thread_local.bloom_filter.filter(); let bloom_filter = &context.thread_local.bloom_filter;
debug_assert_eq!(bloom_filter.current_parent(),
self.element.parent_element());
let result = context.thread_local let result = context.thread_local
.style_sharing_candidate_cache .style_sharing_candidate_cache
@ -400,7 +427,7 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
&mut self, &mut self,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
selector_flags_map: &mut SelectorFlagsMap<E>, selector_flags_map: &mut SelectorFlagsMap<E>,
bloom_filter: &BloomFilter, bloom_filter: &StyleBloom<E>,
target: &mut StyleSharingTarget<E>, target: &mut StyleSharingTarget<E>,
data: &mut ElementData data: &mut ElementData
) -> StyleSharingResult { ) -> StyleSharingResult {
@ -498,7 +525,7 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
fn test_candidate(target: &mut StyleSharingTarget<E>, fn test_candidate(target: &mut StyleSharingTarget<E>,
candidate: &mut StyleSharingCandidate<E>, candidate: &mut StyleSharingCandidate<E>,
shared: &SharedStyleContext, shared: &SharedStyleContext,
bloom: &BloomFilter, bloom: &StyleBloom<E>,
selector_flags_map: &mut SelectorFlagsMap<E>) selector_flags_map: &mut SelectorFlagsMap<E>)
-> Result<ComputedStyle, CacheMiss> { -> Result<ComputedStyle, CacheMiss> {
macro_rules! miss { macro_rules! miss {

View file

@ -1092,7 +1092,7 @@ impl Stylist {
/// revalidation selectors. /// revalidation selectors.
pub fn match_revalidation_selectors<E, F>(&self, pub fn match_revalidation_selectors<E, F>(&self,
element: &E, element: &E,
bloom: &BloomFilter, bloom: Option<&BloomFilter>,
flags_setter: &mut F) flags_setter: &mut F)
-> BitVec -> BitVec
where E: TElement, where E: TElement,
@ -1101,7 +1101,7 @@ impl Stylist {
// NB: `MatchingMode` doesn't really matter, given we don't share style // NB: `MatchingMode` doesn't really matter, given we don't share style
// between pseudos. // between pseudos.
let mut matching_context = let mut matching_context =
MatchingContext::new(MatchingMode::Normal, Some(bloom)); MatchingContext::new(MatchingMode::Normal, bloom);
// Note that, by the time we're revalidating, we're guaranteed that the // 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. // candidate and the entry have the same id, classes, and local name.

View file

@ -799,19 +799,6 @@ fn compute_style<E, D>(_traversal: &D,
context.thread_local.statistics.elements_styled += 1; context.thread_local.statistics.elements_styled += 1;
let kind = data.restyle_kind(); let kind = data.restyle_kind();
// First, try the style sharing cache. If we get a match we can skip the rest
// of the work.
if let MatchAndCascade = kind {
let target = StyleSharingTarget::new(element);
let sharing_result = target.share_style_if_possible(context, data);
if let StyleWasShared(index, had_damage) = sharing_result {
context.thread_local.statistics.styles_shared += 1;
context.thread_local.style_sharing_candidate_cache.touch(index);
return had_damage;
}
}
match kind { match kind {
MatchAndCascade => { MatchAndCascade => {
// Ensure the bloom filter is up to date. // Ensure the bloom filter is up to date.
@ -820,6 +807,18 @@ fn compute_style<E, D>(_traversal: &D,
traversal_data.current_dom_depth); traversal_data.current_dom_depth);
context.thread_local.bloom_filter.assert_complete(element); context.thread_local.bloom_filter.assert_complete(element);
// Now that our bloom filter is set up, try the style sharing
// cache. If we get a match we can skip the rest of the work.
let target = StyleSharingTarget::new(element);
let sharing_result = target.share_style_if_possible(context, data);
if let StyleWasShared(index, had_damage) = sharing_result {
context.thread_local.statistics.styles_shared += 1;
context.thread_local.style_sharing_candidate_cache.touch(index);
return had_damage;
}
context.thread_local.statistics.elements_matched += 1; context.thread_local.statistics.elements_matched += 1;
// Perform the matching and cascading. // Perform the matching and cascading.