diff --git a/servo/Cargo.lock b/servo/Cargo.lock index 8dbc8c812d28..955269456cd1 100644 --- a/servo/Cargo.lock +++ b/servo/Cargo.lock @@ -1022,7 +1022,7 @@ dependencies = [ "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "nsstring_vendor 0.1.0", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.19.0", "style 0.0.1", "style_traits 0.0.1", @@ -1451,7 +1451,7 @@ dependencies = [ "msg 0.0.1", "net_traits 0.0.1", "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "profile_traits 0.0.1", "range 0.0.1", "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1497,7 +1497,7 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "net_traits 0.0.1", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "profile_traits 0.0.1", "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", @@ -2068,15 +2068,18 @@ dependencies = [ [[package]] name = "owning_ref" -version = "0.2.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "parking_lot" -version = "0.3.8" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2450,7 +2453,7 @@ dependencies = [ "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2757,6 +2760,7 @@ dependencies = [ "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2908,6 +2912,11 @@ dependencies = [ "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "stable_deref_trait" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "string_cache" version = "0.6.0" @@ -2974,7 +2983,8 @@ dependencies = [ "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3013,7 +3023,7 @@ dependencies = [ "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.19.0", @@ -3746,8 +3756,8 @@ dependencies = [ "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8" "checksum osmesa-src 12.0.1 (git+https://github.com/servo/osmesa-src)" = "" "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" -"checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc" -"checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" +"checksum parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "37f364e2ce5efa24c7d0b6646d5bb61145551a0112f107ffd7499f1a3e322fbd" "checksum parking_lot_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0ad2c4d148942b3560034785bf19df586ebba53351e8c78f84984147d5795eef" "checksum parse-hosts 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9aebf4a4f84ce5d940a30a919c93325a66ab4ddb646f5f0a3d77483eb99595a6" "checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c" @@ -3805,6 +3815,7 @@ dependencies = [ "checksum skeptic 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7d8dc1315094150052d0ab767840376335a98ac66ef313ff911cdf439a5b69" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e40af10aafe98b4d8294ae8388d8a5cd0707c65d364872efe72d063ec44bee0" +"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum string_cache 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23429a3aca80e7cc7f0060853a97fbba9a90e30ef36b29d13e22559cd7f3dc54" "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" diff --git a/servo/components/layout/Cargo.toml b/servo/components/layout/Cargo.toml index a230bff46ef6..35860b3f236a 100644 --- a/servo/components/layout/Cargo.toml +++ b/servo/components/layout/Cargo.toml @@ -26,7 +26,7 @@ log = "0.3.5" msg = {path = "../msg"} net_traits = {path = "../net_traits"} ordered-float = "0.4" -parking_lot = "0.3.3" +parking_lot = "0.4" profile_traits = {path = "../profile_traits"} range = {path = "../range"} rayon = "0.8" diff --git a/servo/components/layout_thread/Cargo.toml b/servo/components/layout_thread/Cargo.toml index 7e713f85f1e6..9ad239eb0071 100644 --- a/servo/components/layout_thread/Cargo.toml +++ b/servo/components/layout_thread/Cargo.toml @@ -23,7 +23,7 @@ lazy_static = "0.2" log = "0.3.5" msg = {path = "../msg"} net_traits = {path = "../net_traits"} -parking_lot = {version = "0.3.3", features = ["nightly"]} +parking_lot = {version = "0.4", features = ["nightly"]} profile_traits = {path = "../profile_traits"} rayon = "0.8" script = {path = "../script"} diff --git a/servo/components/script/Cargo.toml b/servo/components/script/Cargo.toml index 110710a59cd2..cc9ae75842a7 100644 --- a/servo/components/script/Cargo.toml +++ b/servo/components/script/Cargo.toml @@ -65,7 +65,7 @@ net_traits = {path = "../net_traits"} num-traits = "0.1.32" offscreen_gl_context = { version = "0.11", features = ["serde"] } open = "1.1.1" -parking_lot = "0.3" +parking_lot = "0.4" phf = "0.7.18" profile_traits = {path = "../profile_traits"} range = {path = "../range"} diff --git a/servo/components/servo_arc/Cargo.toml b/servo/components/servo_arc/Cargo.toml index 8f73bd618100..51e4dcccc16a 100644 --- a/servo/components/servo_arc/Cargo.toml +++ b/servo/components/servo_arc/Cargo.toml @@ -14,5 +14,6 @@ servo = ["serde", "heapsize"] [dependencies] heapsize = {version = "0.4.0", optional = true} -serde = {version = "1.0", optional = true} nodrop = {version = "0.1.8"} +serde = {version = "1.0", optional = true} +stable_deref_trait = "1.0.0" diff --git a/servo/components/servo_arc/lib.rs b/servo/components/servo_arc/lib.rs index 0040fdea6d1c..ff4074767f87 100644 --- a/servo/components/servo_arc/lib.rs +++ b/servo/components/servo_arc/lib.rs @@ -22,14 +22,16 @@ // duplicate those here. #![allow(missing_docs)] -#[cfg(feature = "servo")] extern crate serde; extern crate nodrop; +#[cfg(feature = "servo")] extern crate serde; +extern crate stable_deref_trait; #[cfg(feature = "servo")] 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; @@ -432,6 +434,9 @@ impl AsRef for Arc { } } +unsafe impl StableDeref for Arc {} +unsafe impl CloneStableDeref for Arc {} + // 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/servo/components/style/Cargo.toml b/servo/components/style/Cargo.toml index c6d23ab2b8c7..860c652cd02d 100644 --- a/servo/components/style/Cargo.toml +++ b/servo/components/style/Cargo.toml @@ -54,7 +54,8 @@ num_cpus = {version = "1.1.0", optional = true} num-integer = "0.1.32" num-traits = "0.1.32" ordered-float = "0.4" -parking_lot = "0.3.3" +owning_ref = "0.3.3" +parking_lot = "0.4" pdqsort = "0.1.0" precomputed-hash = "0.1" rayon = "0.8" diff --git a/servo/components/style/bloom.rs b/servo/components/style/bloom.rs index 34b6b6089623..d6d05c2ed20f 100644 --- a/servo/components/style/bloom.rs +++ b/servo/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> = + 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 { - /// The bloom filter per se. - filter: Box, + /// 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>, 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(element: E, mut f: F) }); } +impl Drop for StyleBloom { + fn drop(&mut self) { + // Leave the reusable bloom filter in a zeroed state. + self.clear(); + } +} + impl StyleBloom { - /// 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(), } diff --git a/servo/components/style/context.rs b/servo/components/style/context.rs index 103c3a5a7d3a..31915a38d192 100644 --- a/servo/components/style/context.rs +++ b/servo/components/style/context.rs @@ -23,7 +23,7 @@ use selectors::matching::ElementSelectorFlags; use shared_lock::StylesheetGuards; use sharing::StyleSharingCandidateCache; use std::fmt; -use std::ops::Add; +use std::ops; #[cfg(feature = "servo")] use std::sync::Mutex; #[cfg(feature = "servo")] use std::sync::mpsc::Sender; use stylearc::Arc; @@ -306,7 +306,7 @@ pub struct TraversalStatistics { } /// Implementation of Add to aggregate statistics across different threads. -impl<'a> Add for &'a TraversalStatistics { +impl<'a> ops::Add for &'a TraversalStatistics { type Output = TraversalStatistics; fn add(self, other: Self) -> TraversalStatistics { debug_assert!(self.traversal_time_ms == 0.0 && other.traversal_time_ms == 0.0, @@ -505,6 +505,43 @@ impl SelectorFlagsMap { } } +/// A list of SequentialTasks that get executed on Drop. +pub struct SequentialTaskList(Vec>) +where + E: TElement; + +impl ops::Deref for SequentialTaskList +where + E: TElement, +{ + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl ops::DerefMut for SequentialTaskList +where + E: TElement, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Drop for SequentialTaskList +where + E: TElement, +{ + fn drop(&mut self) { + debug_assert!(thread_state::get() == thread_state::LAYOUT); + for task in self.0.drain(..) { + task.execute() + } + } +} + /// A thread-local style context. /// /// This context contains data that needs to be used during restyling, but is @@ -520,9 +557,13 @@ pub struct ThreadLocalStyleContext { #[cfg(feature = "servo")] pub new_animations_sender: Sender, /// A set of tasks to be run (on the parent thread) in sequential mode after - /// the rest of the styling is complete. This is useful for infrequently-needed - /// non-threadsafe operations. - pub tasks: Vec>, + /// the rest of the styling is complete. This is useful for + /// infrequently-needed non-threadsafe operations. + /// + /// It's important that goes after the style sharing cache and the bloom + /// filter, to ensure they're dropped before we execute the tasks, which + /// could create another ThreadLocalStyleContext for style computation. + pub tasks: SequentialTaskList, /// ElementSelectorFlags that need to be applied after the traversal is /// complete. This map is used in cases where the matching algorithm needs /// to set flags on elements it doesn't have exclusive access to (i.e. other @@ -545,7 +586,7 @@ impl ThreadLocalStyleContext { style_sharing_candidate_cache: StyleSharingCandidateCache::new(), bloom_filter: StyleBloom::new(), new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(), - tasks: Vec::new(), + tasks: SequentialTaskList(Vec::new()), selector_flags: SelectorFlagsMap::new(), statistics: TraversalStatistics::default(), current_element_info: None, @@ -559,7 +600,7 @@ impl ThreadLocalStyleContext { ThreadLocalStyleContext { style_sharing_candidate_cache: StyleSharingCandidateCache::new(), bloom_filter: StyleBloom::new(), - tasks: Vec::new(), + tasks: SequentialTaskList(Vec::new()), selector_flags: SelectorFlagsMap::new(), statistics: TraversalStatistics::default(), current_element_info: None, @@ -601,11 +642,6 @@ impl Drop for ThreadLocalStyleContext { // Apply any slow selector flags that need to be set on parents. self.selector_flags.apply_flags(); - - // Execute any enqueued sequential tasks. - for task in self.tasks.drain(..) { - task.execute(); - } } } diff --git a/servo/components/style/lib.rs b/servo/components/style/lib.rs index 5775dc1001b3..3280caa5cb3e 100644 --- a/servo/components/style/lib.rs +++ b/servo/components/style/lib.rs @@ -67,6 +67,7 @@ pub extern crate nsstring_vendor as nsstring; extern crate num_integer; extern crate num_traits; extern crate ordered_float; +extern crate owning_ref; extern crate parking_lot; extern crate pdqsort; #[cfg(feature = "gecko")] extern crate precomputed_hash; diff --git a/servo/components/style/sharing/mod.rs b/servo/components/style/sharing/mod.rs index 8aa66d4739eb..f934d8cd5ab3 100644 --- a/servo/components/style/sharing/mod.rs +++ b/servo/components/style/sharing/mod.rs @@ -66,6 +66,7 @@ use Atom; use applicable_declarations::ApplicableDeclarationBlock; +use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use bit_vec::BitVec; use bloom::StyleBloom; use cache::{LRUCache, LRUCacheMutIterator}; @@ -73,11 +74,14 @@ use context::{SelectorFlagsMap, SharedStyleContext, StyleContext}; use data::ElementStyles; use dom::{TElement, SendElement}; use matching::MatchMethods; +use owning_ref::OwningHandle; use properties::ComputedValues; use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode}; use smallvec::SmallVec; +use std::marker::PhantomData; use std::mem; use std::ops::Deref; +use stylearc::Arc; use stylist::Stylist; mod checks; @@ -92,7 +96,8 @@ mod checks; /// improvements (e.g. 3x fewer styles having to be resolved than at size 8) and /// slight performance improvements. Sizes larger than 32 haven't really been /// tested. -pub const STYLE_SHARING_CANDIDATE_CACHE_SIZE: usize = 31; +pub const SHARING_CACHE_SIZE: usize = 31; +const SHARING_CACHE_BACKING_STORE_SIZE: usize = SHARING_CACHE_SIZE + 1; /// Controls whether the style sharing cache is used. #[derive(Clone, Copy, PartialEq)] @@ -210,14 +215,21 @@ impl ValidationData { /// Note that this information is stored in TLS and cleared after the traversal, /// and once here, the style information of the element is immutable, so it's /// safe to access. +/// +/// Important: If you change the members/layout here, You need to do the same for +/// FakeCandidate below. #[derive(Debug)] pub struct StyleSharingCandidate { - /// The element. We use SendElement here so that the cache may live in - /// ScopedTLS. - element: SendElement, + /// The element. + element: E, validation_data: ValidationData, } +struct FakeCandidate { + _element: usize, + _validation_data: ValidationData, +} + impl Deref for StyleSharingCandidate { type Target = E; @@ -230,12 +242,12 @@ impl Deref for StyleSharingCandidate { impl StyleSharingCandidate { /// Get the classlist of this candidate. fn class_list(&mut self) -> &[Atom] { - self.validation_data.class_list(*self.element) + self.validation_data.class_list(self.element) } /// Get the pres hints of this candidate. fn pres_hints(&mut self) -> &[ApplicableDeclarationBlock] { - self.validation_data.pres_hints(*self.element) + self.validation_data.pres_hints(self.element) } /// Compute the bit vector of revalidation selector match results @@ -246,7 +258,7 @@ impl StyleSharingCandidate { bloom: &StyleBloom, ) -> &BitVec { self.validation_data.revalidation_match_results( - *self.element, + self.element, stylist, bloom, /* bloom_known_valid = */ false, @@ -399,35 +411,81 @@ pub enum StyleSharingResult { StyleWasShared(usize, ElementStyles), } +/// Style sharing caches are are large allocations, so we store them in thread-local +/// storage such that they can be reused across style traversals. Ideally, we'd just +/// stack-allocate these buffers with uninitialized memory, but right now rustc can't +/// avoid memmoving the entire cache during setup, which gets very expensive. See +/// issues like [1] and [2]. +/// +/// Given that the cache stores entries of type TElement, we transmute to usize +/// before storing in TLS. This is safe as long as we make sure to empty the cache +/// before we let it go. +/// +/// [1] https://github.com/rust-lang/rust/issues/42763 +/// [2] https://github.com/rust-lang/rust/issues/13707 +type SharingCacheBase = LRUCache<[Candidate; SHARING_CACHE_BACKING_STORE_SIZE]>; +type SharingCache = SharingCacheBase>; +type TypelessSharingCache = SharingCacheBase; +type StoredSharingCache = Arc>; + +thread_local!(static SHARING_CACHE_KEY: StoredSharingCache = + Arc::new(AtomicRefCell::new(LRUCache::new()))); + /// An LRU cache of the last few nodes seen, so that we can aggressively try to /// reuse their styles. /// /// Note that this cache is flushed every time we steal work from the queue, so /// storing nodes here temporarily is safe. pub struct StyleSharingCandidateCache { - cache: LRUCache<[StyleSharingCandidate; STYLE_SHARING_CANDIDATE_CACHE_SIZE + 1]>, + /// The LRU cache, with the type cast away to allow persisting the allocation. + cache_typeless: OwningHandle>, + /// Bind this structure to the lifetime of E, since that's what we effectively store. + marker: PhantomData>, /// The DOM depth we're currently at. This is used as an optimization to /// clear the cache when we change depths, since we know at that point /// nothing in the cache will match. dom_depth: usize, } +impl Drop for StyleSharingCandidateCache { + fn drop(&mut self) { + self.clear(); + } +} + impl StyleSharingCandidateCache { + fn cache(&self) -> &SharingCache { + let base: &TypelessSharingCache = &*self.cache_typeless; + unsafe { mem::transmute(base) } + } + + fn cache_mut(&mut self) -> &mut SharingCache { + let base: &mut TypelessSharingCache = &mut *self.cache_typeless; + unsafe { mem::transmute(base) } + } + /// Create a new style sharing candidate cache. pub fn new() -> Self { + assert_eq!(mem::size_of::>(), mem::size_of::()); + assert_eq!(mem::align_of::>(), mem::align_of::()); + let cache_arc = SHARING_CACHE_KEY.with(|c| c.clone()); + let cache = OwningHandle::new_with_fn(cache_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); + debug_assert_eq!(cache.num_entries(), 0); + StyleSharingCandidateCache { - cache: LRUCache::new(), + cache_typeless: cache, + marker: PhantomData, dom_depth: 0, } } /// Returns the number of entries in the cache. pub fn num_entries(&self) -> usize { - self.cache.num_entries() + self.cache().num_entries() } fn iter_mut(&mut self) -> LRUCacheMutIterator> { - self.cache.iter_mut() + self.cache_mut().iter_mut() } /// Tries to insert an element in the style sharing cache. @@ -472,20 +530,20 @@ impl StyleSharingCandidateCache { self.clear(); self.dom_depth = dom_depth; } - self.cache.insert(StyleSharingCandidate { - element: unsafe { SendElement::new(*element) }, + self.cache_mut().insert(StyleSharingCandidate { + element: *element, validation_data: validation_data, }); } /// Touch a given index in the style sharing candidate cache. pub fn touch(&mut self, index: usize) { - self.cache.touch(index); + self.cache_mut().touch(index); } /// Clear the style sharing candidate cache. pub fn clear(&mut self) { - self.cache.evict_all() + self.cache_mut().evict_all() } /// Attempts to share a style with another node. @@ -534,7 +592,7 @@ impl StyleSharingCandidateCache { } debug!("{:?} Cannot share style: {} cache entries", target.element, - self.cache.num_entries()); + self.cache().num_entries()); StyleSharingResult::CannotShare } diff --git a/servo/ports/geckolib/Cargo.toml b/servo/ports/geckolib/Cargo.toml index 5c50eb6bf7a6..01c4012a4ae9 100644 --- a/servo/ports/geckolib/Cargo.toml +++ b/servo/ports/geckolib/Cargo.toml @@ -21,7 +21,7 @@ env_logger = {version = "0.4", default-features = false} # disable `regex` to re libc = "0.2" log = {version = "0.3.5", features = ["release_max_level_info"]} nsstring_vendor = {path = "../../components/style/gecko_bindings/nsstring_vendor"} -parking_lot = "0.3" +parking_lot = "0.4" selectors = {path = "../../components/selectors"} style = {path = "../../components/style", features = ["gecko"]} style_traits = {path = "../../components/style_traits"} diff --git a/servo/tests/unit/style/Cargo.toml b/servo/tests/unit/style/Cargo.toml index f5121de85a36..15acba42a027 100644 --- a/servo/tests/unit/style/Cargo.toml +++ b/servo/tests/unit/style/Cargo.toml @@ -18,7 +18,7 @@ app_units = "0.5" cssparser = "0.17.0" euclid = "0.15" html5ever = "0.18" -parking_lot = "0.3" +parking_lot = "0.4" rayon = "0.8" rustc-serialize = "0.3" selectors = {path = "../../../components/selectors"}