Semantics for ProtectedHashMap.

MozReview-Commit-ID: K0m65uZi7iw
This commit is contained in:
Bobby Holley 2017-09-26 12:33:21 -07:00
parent e2c0ca5110
commit 98f370130d
9 changed files with 311 additions and 8 deletions

View file

@ -13,11 +13,16 @@ use fnv;
pub use hashglobe::hash_map::HashMap;
#[cfg(feature = "gecko")]
pub use hashglobe::hash_set::HashSet;
#[cfg(feature = "gecko")]
pub use hashglobe::protected::ProtectedHashMap;
#[cfg(feature = "servo")]
pub use hashglobe::fake::{HashMap, HashSet};
/// Alias to use regular HashMaps everywhere in Servo.
#[cfg(feature = "servo")]
pub type ProtectedHashMap<K, V, S> = HashMap<K, V, S>;
/// Appropriate reexports of hash_map types
pub mod map {
#[cfg(feature = "gecko")]

View file

@ -299,6 +299,24 @@ impl InvalidationMap {
Ok(())
}
/// Allows mutation of this InvalidationMap.
#[cfg(feature = "gecko")]
pub fn begin_mutation(&mut self) {
self.class_to_selector.begin_mutation();
self.id_to_selector.begin_mutation();
self.state_affecting_selectors.begin_mutation();
self.other_attribute_affecting_selectors.begin_mutation();
}
/// Disallows mutation of this InvalidationMap.
#[cfg(feature = "gecko")]
pub fn end_mutation(&mut self) {
self.class_to_selector.end_mutation();
self.id_to_selector.end_mutation();
self.state_affecting_selectors.end_mutation();
self.other_attribute_affecting_selectors.end_mutation();
}
}
/// A struct that collects invalidations for a given compound selector.

View file

@ -10,7 +10,7 @@ use applicable_declarations::ApplicableDeclarationBlock;
use context::QuirksMode;
use dom::TElement;
use fallible::FallibleVec;
use hash::{HashMap, HashSet};
use hash::{HashMap, HashSet, ProtectedHashMap};
use hash::map as hash_map;
use hashglobe::FailedAllocationError;
use pdqsort::sort_by;
@ -38,6 +38,9 @@ impl Default for PrecomputedHasher {
/// A simple alias for a hashmap using PrecomputedHasher.
pub type PrecomputedHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PrecomputedHasher>>;
/// A simple alias for a hashmap using PrecomputedHasher.
pub type PrecomputedProtectedHashMap<K, V> = ProtectedHashMap<K, V, BuildHasherDefault<PrecomputedHasher>>;
/// A simple alias for a hashset using PrecomputedHasher.
pub type PrecomputedHashSet<K> = HashSet<K, BuildHasherDefault<PrecomputedHasher>>;
@ -102,7 +105,7 @@ pub struct SelectorMap<T: 'static> {
/// A hash from a class name to rules which contain that class selector.
pub class_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
/// A hash from local name to rules which contain that local name selector.
pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
pub local_name_hash: PrecomputedProtectedHashMap<LocalName, SmallVec<[T; 1]>>,
/// Rules that don't have ID, class, or element selectors.
pub other: SmallVec<[T; 1]>,
/// The number of entries in this map.
@ -123,7 +126,7 @@ impl<T: 'static> SelectorMap<T> {
SelectorMap {
id_hash: MaybeCaseInsensitiveHashMap::new(),
class_hash: MaybeCaseInsensitiveHashMap::new(),
local_name_hash: HashMap::default(),
local_name_hash: ProtectedHashMap::default(),
other: SmallVec::new(),
count: 0,
}
@ -147,6 +150,30 @@ impl<T: 'static> SelectorMap<T> {
pub fn len(&self) -> usize {
self.count
}
/// Allows mutation of this SelectorMap.
#[cfg(feature = "gecko")]
pub fn begin_mutation(&mut self) {
self.id_hash.begin_mutation();
self.class_hash.begin_mutation();
self.local_name_hash.begin_mutation();
}
/// Allows mutation of this SelectorMap. Not enforced in Servo.
#[cfg(feature = "servo")]
pub fn begin_mutation(&mut self) {}
/// Disallows mutation of this SelectorMap.
#[cfg(feature = "gecko")]
pub fn end_mutation(&mut self) {
self.id_hash.end_mutation();
self.class_hash.end_mutation();
self.local_name_hash.end_mutation();
}
/// Disallows mutation of this SelectorMap. Not enforced in Servo.
#[cfg(feature = "servo")]
pub fn end_mutation(&mut self) {}
}
impl SelectorMap<Rule> {
@ -463,7 +490,7 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> {
#[derive(Debug)]
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'static>(PrecomputedHashMap<K, V>);
pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'static>(PrecomputedProtectedHashMap<K, V>);
// FIXME(Manishearth) the 'static bound can be removed when
// our HashMap fork (hashglobe) is able to use NonZero,
@ -471,7 +498,7 @@ pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'stati
impl<V: 'static> MaybeCaseInsensitiveHashMap<Atom, V> {
/// Empty map
pub fn new() -> Self {
MaybeCaseInsensitiveHashMap(PrecomputedHashMap::default())
MaybeCaseInsensitiveHashMap(PrecomputedProtectedHashMap::default())
}
/// HashMap::entry
@ -512,5 +539,17 @@ impl<V: 'static> MaybeCaseInsensitiveHashMap<Atom, V> {
self.0.get(key)
}
}
/// ProtectedHashMap::begin_mutation
#[cfg(feature = "gecko")]
pub fn begin_mutation(&mut self) {
self.0.begin_mutation();
}
/// ProtectedHashMap::end_mutation
#[cfg(feature = "gecko")]
pub fn end_mutation(&mut self) {
self.0.end_mutation();
}
}

View file

@ -159,6 +159,15 @@ impl<T> PerPseudoElementMap<T> {
*self = Self::default();
}
/// Invokes a callback on each non-None entry.
pub fn for_each<F: FnMut(&mut T)>(&mut self, mut f: F) {
for entry in self.entries.iter_mut() {
if entry.is_some() {
f(entry.as_mut().unwrap());
}
}
}
/// Set an entry value.
///
/// Returns an error if the element is not a simple pseudo.

View file

@ -1870,6 +1870,32 @@ impl CascadeData {
}
}
#[cfg(feature = "gecko")]
fn begin_mutation(&mut self, rebuild_kind: &SheetRebuildKind) {
self.element_map.begin_mutation();
self.pseudos_map.for_each(|m| m.begin_mutation());
if rebuild_kind.should_rebuild_invalidation() {
self.invalidation_map.begin_mutation();
self.selectors_for_cache_revalidation.begin_mutation();
}
}
#[cfg(feature = "servo")]
fn begin_mutation(&mut self, _: &SheetRebuildKind) {}
#[cfg(feature = "gecko")]
fn end_mutation(&mut self, rebuild_kind: &SheetRebuildKind) {
self.element_map.end_mutation();
self.pseudos_map.for_each(|m| m.end_mutation());
if rebuild_kind.should_rebuild_invalidation() {
self.invalidation_map.end_mutation();
self.selectors_for_cache_revalidation.end_mutation();
}
}
#[cfg(feature = "servo")]
fn end_mutation(&mut self, _: &SheetRebuildKind) {}
/// Collects all the applicable media query results into `results`.
///
/// This duplicates part of the logic in `add_stylesheet`, which is
@ -1933,6 +1959,7 @@ impl CascadeData {
self.effective_media_query_results.saw_effective(stylesheet);
}
self.begin_mutation(&rebuild_kind);
for rule in stylesheet.effective_rules(device, guard) {
match *rule {
CssRule::Style(ref locked) => {
@ -1969,8 +1996,11 @@ impl CascadeData {
None => &mut self.element_map,
Some(pseudo) => {
self.pseudos_map
.get_or_insert_with(&pseudo.canonical(), || Box::new(SelectorMap::new()))
.expect("Unexpected tree pseudo-element?")
.get_or_insert_with(&pseudo.canonical(), || {
let mut map = Box::new(SelectorMap::new());
map.begin_mutation();
map
}).expect("Unexpected tree pseudo-element?")
}
};
@ -2064,6 +2094,7 @@ impl CascadeData {
_ => {}
}
}
self.end_mutation(&rebuild_kind);
Ok(())
}