mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Cache the parent CV identity on ValidationData.
This will make the linear probing faster. If we end up implementing the two-tier cache setup, this code will be unnecessary and can go away. MozReview-Commit-ID: BRfV5ump34n
This commit is contained in:
parent
7b019f807b
commit
729db5ccec
2 changed files with 60 additions and 24 deletions
|
@ -10,26 +10,30 @@ use Atom;
|
||||||
use bloom::StyleBloom;
|
use bloom::StyleBloom;
|
||||||
use context::{SelectorFlagsMap, SharedStyleContext};
|
use context::{SelectorFlagsMap, SharedStyleContext};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use servo_arc::Arc;
|
|
||||||
use sharing::{StyleSharingCandidate, StyleSharingTarget};
|
use sharing::{StyleSharingCandidate, StyleSharingTarget};
|
||||||
|
|
||||||
/// Whether styles may be shared across the children of the given parent elements.
|
/// Determines whether a target and a candidate have compatible parents for sharing.
|
||||||
/// This is used to share style across cousins.
|
pub fn parents_allow_sharing<E>(
|
||||||
///
|
target: &mut StyleSharingTarget<E>,
|
||||||
/// Both elements need to be styled already.
|
candidate: &mut StyleSharingCandidate<E>
|
||||||
pub fn can_share_style_across_parents<E>(first: Option<E>, second: Option<E>) -> bool
|
) -> bool
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
{
|
{
|
||||||
let (first, second) = match (first, second) {
|
// If the identity of the parent style isn't equal, we can't share. We check
|
||||||
(Some(f), Some(s)) => (f, s),
|
// this first, because the result is cached.
|
||||||
_ => return false,
|
if target.parent_style_identity() != candidate.parent_style_identity() {
|
||||||
};
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
debug_assert_ne!(first, second);
|
// Siblings can always share.
|
||||||
|
let parent = target.inheritance_parent().unwrap();
|
||||||
let first_data = first.borrow_data().unwrap();
|
let candidate_parent = candidate.element.inheritance_parent().unwrap();
|
||||||
let second_data = second.borrow_data().unwrap();
|
if parent == candidate_parent {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cousins are a bit more complicated.
|
||||||
|
//
|
||||||
// If a parent element was already styled and we traversed past it without
|
// If a parent element was already styled and we traversed past it without
|
||||||
// restyling it, that may be because our clever invalidation logic was able
|
// restyling it, that may be because our clever invalidation logic was able
|
||||||
// to prove that the styles of that element would remain unchanged despite
|
// to prove that the styles of that element would remain unchanged despite
|
||||||
|
@ -40,14 +44,14 @@ pub fn can_share_style_across_parents<E>(first: Option<E>, second: Option<E>) ->
|
||||||
//
|
//
|
||||||
// This is a somewhat conservative check. We could tighten it by having the
|
// This is a somewhat conservative check. We could tighten it by having the
|
||||||
// invalidation logic explicitly flag elements for which it ellided styling.
|
// invalidation logic explicitly flag elements for which it ellided styling.
|
||||||
if first_data.traversed_without_styling() || second_data.traversed_without_styling() {
|
let parent_data = parent.borrow_data().unwrap();
|
||||||
|
let candidate_parent_data = candidate_parent.borrow_data().unwrap();
|
||||||
|
if parent_data.traversed_without_styling() ||
|
||||||
|
candidate_parent_data.traversed_without_styling() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let same_computed_values =
|
true
|
||||||
Arc::ptr_eq(first_data.styles.primary(), second_data.styles.primary());
|
|
||||||
|
|
||||||
same_computed_values
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether two elements have the same same style attribute (by pointer identity).
|
/// Whether two elements have the same same style attribute (by pointer identity).
|
||||||
|
|
|
@ -76,7 +76,7 @@ use matching::MatchMethods;
|
||||||
use owning_ref::OwningHandle;
|
use owning_ref::OwningHandle;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
||||||
use servo_arc::Arc;
|
use servo_arc::{Arc, NonZeroPtrMut};
|
||||||
use smallbitvec::SmallBitVec;
|
use smallbitvec::SmallBitVec;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -108,6 +108,16 @@ pub enum StyleSharingBehavior {
|
||||||
Disallow,
|
Disallow,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opaque pointer type to compare ComputedValues identities.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct OpaqueComputedValues(NonZeroPtrMut<()>);
|
||||||
|
impl OpaqueComputedValues {
|
||||||
|
fn from(cv: &ComputedValues) -> Self {
|
||||||
|
let p = NonZeroPtrMut::new(cv as *const ComputedValues as *const () as *mut ());
|
||||||
|
OpaqueComputedValues(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Some data we want to avoid recomputing all the time while trying to share
|
/// Some data we want to avoid recomputing all the time while trying to share
|
||||||
/// style.
|
/// style.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -121,6 +131,9 @@ pub struct ValidationData {
|
||||||
/// The list of presentational attributes of the element.
|
/// The list of presentational attributes of the element.
|
||||||
pres_hints: Option<SmallVec<[ApplicableDeclarationBlock; 5]>>,
|
pres_hints: Option<SmallVec<[ApplicableDeclarationBlock; 5]>>,
|
||||||
|
|
||||||
|
/// The pointer identity of the parent ComputedValues.
|
||||||
|
parent_style_identity: Option<OpaqueComputedValues>,
|
||||||
|
|
||||||
/// The cached result of matching this entry against the revalidation
|
/// The cached result of matching this entry against the revalidation
|
||||||
/// selectors.
|
/// selectors.
|
||||||
revalidation_match_results: Option<SmallBitVec>,
|
revalidation_match_results: Option<SmallBitVec>,
|
||||||
|
@ -167,6 +180,18 @@ impl ValidationData {
|
||||||
&*self.class_list.as_ref().unwrap()
|
&*self.class_list.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get or compute the parent style identity.
|
||||||
|
pub fn parent_style_identity<E>(&mut self, el: E) -> OpaqueComputedValues
|
||||||
|
where E: TElement,
|
||||||
|
{
|
||||||
|
if self.parent_style_identity.is_none() {
|
||||||
|
let parent = el.inheritance_parent().unwrap();
|
||||||
|
self.parent_style_identity =
|
||||||
|
Some(OpaqueComputedValues::from(parent.borrow_data().unwrap().styles.primary()));
|
||||||
|
}
|
||||||
|
self.parent_style_identity.as_ref().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 so we know at compile time what bloom_known_valid is.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -250,6 +275,11 @@ impl<E: TElement> StyleSharingCandidate<E> {
|
||||||
self.validation_data.pres_hints(self.element)
|
self.validation_data.pres_hints(self.element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the parent style identity.
|
||||||
|
fn parent_style_identity(&mut self) -> OpaqueComputedValues {
|
||||||
|
self.validation_data.parent_style_identity(self.element)
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the bit vector of revalidation selector match results
|
/// Compute the bit vector of revalidation selector match results
|
||||||
/// for this candidate.
|
/// for this candidate.
|
||||||
fn revalidation_match_results(
|
fn revalidation_match_results(
|
||||||
|
@ -304,6 +334,11 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
self.validation_data.pres_hints(self.element)
|
self.validation_data.pres_hints(self.element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the parent style identity.
|
||||||
|
fn parent_style_identity(&mut self) -> OpaqueComputedValues {
|
||||||
|
self.validation_data.parent_style_identity(self.element)
|
||||||
|
}
|
||||||
|
|
||||||
fn revalidation_match_results(
|
fn revalidation_match_results(
|
||||||
&mut self,
|
&mut self,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
|
@ -615,10 +650,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
// share styles and permit sharing across their children. The latter
|
// share styles and permit sharing across their children. The latter
|
||||||
// check allows us to share style between cousins if the parents
|
// check allows us to share style between cousins if the parents
|
||||||
// shared style.
|
// shared style.
|
||||||
let parent = target.inheritance_parent();
|
if !checks::parents_allow_sharing(target, candidate) {
|
||||||
let candidate_parent = candidate.element.inheritance_parent();
|
|
||||||
if parent != candidate_parent &&
|
|
||||||
!checks::can_share_style_across_parents(parent, candidate_parent) {
|
|
||||||
trace!("Miss: Parent");
|
trace!("Miss: Parent");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue