diff --git a/Cargo.lock b/Cargo.lock index d340b4860e2..8ed951c806f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2523,6 +2523,7 @@ dependencies = [ "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)", "precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "servo_arc 0.0.1", "size_of_test 0.0.1", "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml index effb612bb43..15aba3d1811 100644 --- a/components/selectors/Cargo.toml +++ b/components/selectors/Cargo.toml @@ -28,6 +28,7 @@ cssparser = "0.13.7" fnv = "1.0" phf = "0.7.18" precomputed-hash = "0.1" +servo_arc = { path = "../servo_arc" } smallvec = "0.4" [dev-dependencies] diff --git a/components/selectors/arcslice.rs b/components/selectors/arcslice.rs deleted file mode 100644 index e5722ba6505..00000000000 --- a/components/selectors/arcslice.rs +++ /dev/null @@ -1,326 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 or the MIT license - * , at your - * option. This file may not be copied, modified, or distributed - * except according to those terms. - * - * See the COPYRIGHT file at the top-level directory of this distribution */ -//! A thread-safe reference-counted slice type. -//! -//! Forked from https://github.com/huonw/shared_slice , which doesn't work on -//! rust stable. - -use std::{cmp, fmt, ops}; -use std::hash::{Hash, Hasher}; -use std::sync::{Arc, Weak}; - - -/// A reference-counted slice type. -pub struct ArcSlice { - data: *const [T], - counts: Arc>, -} - -unsafe impl Send for ArcSlice {} -unsafe impl Sync for ArcSlice {} - -/// A non-owning reference-counted slice type. -/// -/// This is to `ArcSlice` as `std::sync::Weak` is to `std::sync::Arc`, and -/// allows one to have cyclic references without stopping memory from -/// being deallocated. -pub struct WeakSlice { - data: *const [T], - counts: Weak>, -} -unsafe impl Send for WeakSlice {} -unsafe impl Sync for WeakSlice {} - -impl ArcSlice { - /// Construct a new `ArcSlice` containing the elements of `slice`. - /// - /// This reuses the allocation of `slice`. - pub fn new(slice: Box<[T]>) -> ArcSlice { - ArcSlice { - data: &*slice, - counts: Arc::new(slice), - } - } - - /// Downgrade self into a weak slice. - pub fn downgrade(&self) -> WeakSlice { - WeakSlice { - data: self.data, - counts: Arc::downgrade(&self.counts) - } - } - - /// Construct a new `ArcSlice` that only points to elements at - /// indices `lo` (inclusive) through `hi` (exclusive). - /// - /// This consumes `self` to avoid unnecessary reference-count - /// modifications. Use `.clone()` if it is necessary to refer to - /// `self` after calling this. - /// - /// # Panics - /// - /// Panics if `lo > hi` or if either are strictly greater than - /// `self.len()`. - pub fn slice(mut self, lo: usize, hi: usize) -> ArcSlice { - self.data = &self[lo..hi]; - self - } - /// Construct a new `ArcSlice` that only points to elements at - /// indices up to `hi` (exclusive). - /// - /// This consumes `self` to avoid unnecessary reference-count - /// modifications. Use `.clone()` if it is necessary to refer to - /// `self` after calling this. - /// - /// # Panics - /// - /// Panics if `hi > self.len()`. - pub fn slice_to(self, hi: usize) -> ArcSlice { - self.slice(0, hi) - } - /// Construct a new `ArcSlice` that only points to elements at - /// indices starting at `lo` (inclusive). - /// - /// This consumes `self` to avoid unnecessary reference-count - /// modifications. Use `.clone()` if it is necessary to refer to - /// `self` after calling this. - /// - /// # Panics - /// - /// Panics if `lo > self.len()`. - pub fn slice_from(self, lo: usize) -> ArcSlice { - let hi = self.len(); - self.slice(lo, hi) - } -} - -impl Clone for ArcSlice { - fn clone(&self) -> ArcSlice { - ArcSlice { - data: self.data, - counts: self.counts.clone() - } - } -} - -impl ops::Deref for ArcSlice { - type Target = [T]; - fn deref<'a>(&'a self) -> &'a [T] { - unsafe { &*self.data } - } -} - -impl AsRef<[T]> for ArcSlice { - fn as_ref(&self) -> &[T] { &**self } -} - -impl PartialEq for ArcSlice { - fn eq(&self, other: &ArcSlice) -> bool { **self == **other } - fn ne(&self, other: &ArcSlice) -> bool { **self != **other } -} -impl Eq for ArcSlice {} - -impl PartialOrd for ArcSlice { - fn partial_cmp(&self, other: &ArcSlice) -> Option { - (**self).partial_cmp(&**other) - } - fn lt(&self, other: &ArcSlice) -> bool { **self < **other } - fn le(&self, other: &ArcSlice) -> bool { **self <= **other } - fn gt(&self, other: &ArcSlice) -> bool { **self > **other } - fn ge(&self, other: &ArcSlice) -> bool { **self >= **other } -} -impl Ord for ArcSlice { - fn cmp(&self, other: &ArcSlice) -> cmp::Ordering { (**self).cmp(&**other) } -} - -impl Hash for ArcSlice { - fn hash(&self, state: &mut H) { - Hash::hash(&**self, state) - } -} - -impl fmt::Debug for ArcSlice { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl WeakSlice { - /// Attempt to upgrade `self` to a strongly-counted `ArcSlice`. - /// - /// Returns `None` if this is not possible (the data has already - /// been freed). - pub fn upgrade(&self) -> Option> { - self.counts.upgrade().map(|counts| { - ArcSlice { - data: self.data, - counts: counts - } - }) - } -} - -#[cfg(test)] -mod tests { - use std::cell::Cell; - use std::cmp::Ordering; - use std::sync::{Arc, Mutex}; - use super::{ArcSlice, WeakSlice}; - #[test] - fn clone() { - let x = ArcSlice::new(Box::new([Cell::new(false)])); - let y = x.clone(); - - assert_eq!(x[0].get(), false); - assert_eq!(y[0].get(), false); - - x[0].set(true); - assert_eq!(x[0].get(), true); - assert_eq!(y[0].get(), true); - } - - #[test] - fn test_upgrade_downgrade() { - let x = ArcSlice::new(Box::new([1])); - let y: WeakSlice<_> = x.downgrade(); - - assert_eq!(y.upgrade(), Some(x.clone())); - - drop(x); - - assert!(y.upgrade().is_none()) - } - - #[test] - fn test_total_cmp() { - let x = ArcSlice::new(Box::new([1, 2, 3])); - let y = ArcSlice::new(Box::new([1, 2, 3])); - let z = ArcSlice::new(Box::new([1, 2, 4])); - - assert_eq!(x, x); - assert_eq!(x, y); - assert!(x != z); - assert!(y != z); - - assert!(x < z); - assert!(x <= z); - assert!(!(x > z)); - assert!(!(x >= z)); - - assert!(!(z < x)); - assert!(!(z <= x)); - assert!(z > x); - assert!(z >= x); - - assert_eq!(x.partial_cmp(&x), Some(Ordering::Equal)); - assert_eq!(x.partial_cmp(&y), Some(Ordering::Equal)); - assert_eq!(x.partial_cmp(&z), Some(Ordering::Less)); - assert_eq!(z.partial_cmp(&y), Some(Ordering::Greater)); - - assert_eq!(x.cmp(&x), Ordering::Equal); - assert_eq!(x.cmp(&y), Ordering::Equal); - assert_eq!(x.cmp(&z), Ordering::Less); - assert_eq!(z.cmp(&y), Ordering::Greater); - } - - #[test] - fn test_partial_cmp() { - use std::f64; - let x = ArcSlice::new(Box::new([1.0, f64::NAN])); - let y = ArcSlice::new(Box::new([1.0, f64::NAN])); - let z = ArcSlice::new(Box::new([2.0, f64::NAN])); - let w = ArcSlice::new(Box::new([f64::NAN, 1.0])); - assert!(!(x == y)); - assert!(x != y); - - assert!(!(x < y)); - assert!(!(x <= y)); - assert!(!(x > y)); - assert!(!(x >= y)); - - assert!(x < z); - assert!(x <= z); - assert!(!(x > z)); - assert!(!(x >= z)); - - assert!(!(z < w)); - assert!(!(z <= w)); - assert!(!(z > w)); - assert!(!(z >= w)); - - assert_eq!(x.partial_cmp(&x), None); - assert_eq!(x.partial_cmp(&y), None); - assert_eq!(x.partial_cmp(&z), Some(Ordering::Less)); - assert_eq!(z.partial_cmp(&x), Some(Ordering::Greater)); - - assert_eq!(x.partial_cmp(&w), None); - assert_eq!(y.partial_cmp(&w), None); - assert_eq!(z.partial_cmp(&w), None); - assert_eq!(w.partial_cmp(&w), None); - } - - #[test] - fn test_show() { - let x = ArcSlice::new(Box::new([1, 2])); - assert_eq!(format!("{:?}", x), "[1, 2]"); - - let y: ArcSlice = ArcSlice::new(Box::new([])); - assert_eq!(format!("{:?}", y), "[]"); - } - - #[test] - fn test_slice() { - let x = ArcSlice::new(Box::new([1, 2, 3])); - let real = [1, 2, 3]; - for i in 0..3 + 1 { - for j in i..3 + 1 { - let slice: ArcSlice<_> = x.clone().slice(i, j); - assert_eq!(&*slice, &real[i..j]); - } - assert_eq!(&*x.clone().slice_to(i), &real[..i]); - assert_eq!(&*x.clone().slice_from(i), &real[i..]); - } - } - - - #[test] - fn test_send_sync() { - fn assert_send() {} - fn assert_sync() {} - - assert_send::>(); - assert_sync::>(); - assert_send::>(); - assert_sync::>(); - } - - #[test] - fn test_drop() { - let drop_flag = Arc::new(Mutex::new(0)); - struct Foo(Arc>); - - impl Drop for Foo { - fn drop(&mut self) { - let mut n = self.0.lock().unwrap(); - *n += 1; - } - } - - let whole = ArcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())])); - - drop(whole); - assert_eq!(*drop_flag.lock().unwrap(), 2); - - *drop_flag.lock().unwrap() = 0; - - let whole = ArcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())])); - let part = whole.slice(1, 2); - drop(part); - assert_eq!(*drop_flag.lock().unwrap(), 2); - } -} diff --git a/components/selectors/lib.rs b/components/selectors/lib.rs index 3e413c0c08b..a6f4acd3d84 100644 --- a/components/selectors/lib.rs +++ b/components/selectors/lib.rs @@ -9,9 +9,9 @@ extern crate fnv; extern crate phf; extern crate precomputed_hash; #[cfg(test)] #[macro_use] extern crate size_of_test; +extern crate servo_arc; extern crate smallvec; -pub mod arcslice; pub mod attr; pub mod bloom; pub mod matching; diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 0049c4e5286..3aee478311c 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use arcslice::ArcSlice; use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator}; use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint}; use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter}; use precomputed_hash::PrecomputedHash; +use servo_arc::{Arc, HeaderSlice}; use smallvec::SmallVec; use std::ascii::AsciiExt; use std::borrow::{Borrow, Cow}; @@ -302,6 +302,19 @@ pub fn namespace_empty_string() -> Impl::NamespaceUrl { Impl::NamespaceUrl::default() } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct SpecificityAndFlags(u32); + +impl SpecificityAndFlags { + fn specificity(&self) -> u32 { + self.0 & !HAS_PSEUDO_BIT + } + + fn has_pseudo_element(&self) -> bool { + (self.0 & HAS_PSEUDO_BIT) != 0 + } +} + /// A Selector stores a sequence of simple selectors and combinators. The /// iterator classes allow callers to iterate at either the raw sequence level or /// at the level of sequences of simple selectors separated by combinators. Most @@ -311,15 +324,15 @@ pub fn namespace_empty_string() -> Impl::NamespaceUrl { /// canonical iteration order is right-to-left (selector matching order). The /// iterators abstract over these details. #[derive(Clone, Eq, PartialEq)] -pub struct Selector(ArcSlice>, u32); +pub struct Selector(Arc]>>); impl Selector { pub fn specificity(&self) -> u32 { - self.1 & !HAS_PSEUDO_BIT + self.0.header.specificity() } pub fn has_pseudo_element(&self) -> bool { - (self.1 & HAS_PSEUDO_BIT) != 0 + self.0.header.has_pseudo_element() } pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> { @@ -362,8 +375,7 @@ impl Selector { pub fn iter_from(&self, offset: usize) -> SelectorIter { // Note: selectors are stored left-to-right but logical order is right-to-left. - let slice = self.0.as_ref(); - let iter = slice[..(slice.len() - offset)].iter().rev(); + let iter = self.0.slice[..(self.0.slice.len() - offset)].iter().rev(); SelectorIter { iter: iter, next_combinator: None, @@ -379,12 +391,13 @@ impl Selector { /// Returns an iterator over the entire sequence of simple selectors and combinators, /// from left to right. pub fn iter_raw_rev(&self) -> slice::Iter> { - self.0.iter() + self.0.slice.iter() } /// Creates a Selector from a vec of Components. Used in tests. pub fn from_vec(vec: Vec>, specificity_and_flags: u32) -> Self { - Selector(ArcSlice::new(vec.into_boxed_slice()), specificity_and_flags) + let spec = SpecificityAndFlags(specificity_and_flags); + Selector(Arc::from_header_and_iter(spec, vec.into_iter())) } } @@ -985,15 +998,15 @@ fn parse_complex_selector( sequence.push(Component::Combinator(combinator)); } - let mut specificity = specificity(SelectorIter { + let mut spec = SpecificityAndFlags(specificity(SelectorIter { iter: sequence.iter().rev(), next_combinator: None, - }); + })); if parsed_pseudo_element { - specificity |= HAS_PSEUDO_BIT; + spec.0 |= HAS_PSEUDO_BIT; } - let complex = Selector(ArcSlice::new(sequence.into_vec().into_boxed_slice()), specificity); + let complex = Selector(Arc::from_header_and_iter(spec, sequence.into_iter())); Ok(complex) } diff --git a/tests/unit/stylo/size_of.rs b/tests/unit/stylo/size_of.rs index f35177bf058..0cdf3067210 100644 --- a/tests/unit/stylo/size_of.rs +++ b/tests/unit/stylo/size_of.rs @@ -22,7 +22,7 @@ fn size_of_selectors_dummy_types() { // The size of this is critical to performance on the bloom-basic microbenchmark. // When iterating over a large Rule array, we want to be able to fast-reject // selectors (with the inline hashes) with as few cache misses as possible. -size_of_test!(test_size_of_rule, style::stylist::Rule, 64); +size_of_test!(test_size_of_rule, style::stylist::Rule, 48); size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);