diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2023-04-12 21:58:29 +0000 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2023-11-21 15:36:35 +0100 |
commit | 0709e13446ed186d6868e82887ebda4850c69365 (patch) | |
tree | 169a9eefcadc2008600518106efce2329b3844af | |
parent | a2df8f7ea5e76e7753d9649b7dfb1b0329510078 (diff) | |
download | servo-0709e13446ed186d6868e82887ebda4850c69365.tar.gz servo-0709e13446ed186d6868e82887ebda4850c69365.zip |
style: Allow to use ThinVec/nsTArray in the style crate
This allows to clean-up the previous patches by using a single ThinVec
(which stores length / capacity along with the allocation).
Differential Revision: https://phabricator.services.mozilla.com/D175029
-rw-r--r-- | Cargo.lock | 9 | ||||
-rw-r--r-- | components/malloc_size_of/Cargo.toml | 1 | ||||
-rw-r--r-- | components/malloc_size_of/lib.rs | 22 | ||||
-rw-r--r-- | components/style/Cargo.toml | 1 | ||||
-rw-r--r-- | components/style/gecko/pseudo_element_definition.mako.rs | 8 | ||||
-rw-r--r-- | components/style/gecko/selector_parser.rs | 33 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 28 | ||||
-rw-r--r-- | components/to_shmem/Cargo.toml | 1 | ||||
-rw-r--r-- | components/to_shmem/lib.rs | 55 |
9 files changed, 110 insertions, 48 deletions
diff --git a/Cargo.lock b/Cargo.lock index e9073d5f982..05d71cf2a12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3396,6 +3396,7 @@ dependencies = [ "smallbitvec", "smallvec", "string_cache", + "thin-vec", "time 0.1.45", "tokio", "url", @@ -5711,6 +5712,7 @@ dependencies = [ "string_cache", "style_derive", "style_traits", + "thin-vec", "time 0.1.45", "to_shmem", "to_shmem_derive", @@ -5925,6 +5927,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] +name = "thin-vec" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" + +[[package]] name = "thiserror" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6060,6 +6068,7 @@ dependencies = [ "smallbitvec", "smallvec", "string_cache", + "thin-vec", ] [[package]] diff --git a/components/malloc_size_of/Cargo.toml b/components/malloc_size_of/Cargo.toml index feb219f3c83..e1ffcf1c4dd 100644 --- a/components/malloc_size_of/Cargo.toml +++ b/components/malloc_size_of/Cargo.toml @@ -45,6 +45,7 @@ servo_arc = { path = "../servo_arc" } smallbitvec = { workspace = true } smallvec = { workspace = true } string_cache = { workspace = true, optional = true } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } time = { workspace = true, optional = true } tokio = { workspace = true } url = { workspace = true, optional = true } diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index d79375bf96b..2c064f1ebe2 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -396,6 +396,28 @@ where } } +impl<T> MallocShallowSizeOf for thin_vec::ThinVec<T> { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if self.capacity() == 0 { + // If it's the singleton we might not be a heap pointer. + return 0; + } + + assert_eq!(std::mem::size_of::<Self>(), std::mem::size_of::<*const ()>()); + unsafe { ops.malloc_size_of(*(self as *const Self as *const *const ())) } + } +} + +impl<T: MallocSizeOf> MallocSizeOf for thin_vec::ThinVec<T> { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + macro_rules! malloc_size_of_hash_set { ($ty:ty) => { impl<T, S> MallocShallowSizeOf for $ty diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 802aefb988d..3a6ac07539b 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -77,6 +77,7 @@ string_cache = { version = "0.8", optional = true } style_derive = { path = "../style_derive" } style_traits = { workspace = true } time = "0.1" +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } to_shmem = { path = "../to_shmem" } to_shmem_derive = { path = "../to_shmem_derive" } uluru = "3.0" diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index b7f8cca409c..73e7893c998 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -11,7 +11,7 @@ pub enum PseudoElement { % for pseudo in PSEUDOS: /// ${pseudo.value} % if pseudo.is_tree_pseudo_element(): - ${pseudo.capitalized_pseudo()}(Box<Box<[Atom]>>), + ${pseudo.capitalized_pseudo()}(thin_vec::ThinVec<Atom>), % elif pseudo.pseudo_ident == "highlight": ${pseudo.capitalized_pseudo()}(AtomIdent), % else: @@ -210,7 +210,7 @@ impl PseudoElement { }, _ => { if starts_with_ignore_ascii_case(name, "-moz-tree-") { - return PseudoElement::tree_pseudo_element(name, Box::new([])) + return PseudoElement::tree_pseudo_element(name, Default::default()) } const WEBKIT_PREFIX: &str = "-webkit-"; if allow_unkown_webkit && starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) { @@ -228,12 +228,12 @@ impl PseudoElement { /// /// Returns `None` if the pseudo-element is not recognized. #[inline] - pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> { + pub fn tree_pseudo_element(name: &str, args: thin_vec::ThinVec<Atom>) -> Option<Self> { debug_assert!(starts_with_ignore_ascii_case(name, "-moz-tree-")); let tree_part = &name[10..]; % for pseudo in TREE_PSEUDOS: if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") { - return Some(${pseudo_element_variant(pseudo, "args.into()")}); + return Some(${pseudo_element_variant(pseudo, "args")}); } % endfor None diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 2beaaa238d2..db1fda493c4 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -19,7 +19,8 @@ use dom::{DocumentState, ElementState}; use selectors::parser::SelectorParseErrorKind; use selectors::SelectorList; use std::fmt; -use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError, StyleParseErrorKind, ToCss as ToCss_}; +use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_}; +use thin_vec::ThinVec; pub use crate::gecko::pseudo_element::{ PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT, @@ -38,13 +39,9 @@ bitflags! { } /// The type used to store the language argument to the `:lang` pseudo-class. -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] -pub enum Lang { - /// A single language code. - Single(AtomIdent), - /// A list of language codes. - List(Box<Vec<AtomIdent>>), -} +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)] +#[css(comma)] +pub struct Lang(#[css(iterable)] pub ThinVec<AtomIdent>); macro_rules! pseudo_class_name { ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { @@ -66,10 +63,6 @@ macro_rules! pseudo_class_name { } apply_non_ts_list!(pseudo_class_name); -impl OneOrMoreSeparated for AtomIdent { - type S = Comma; -} - impl ToCss for NonTSPseudoClass { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where @@ -79,12 +72,9 @@ impl ToCss for NonTSPseudoClass { ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => concat!(":", $css),)* - NonTSPseudoClass::Lang(ref s) => { + NonTSPseudoClass::Lang(ref lang) => { dest.write_str(":lang(")?; - match &s { - Lang::Single(lang) => cssparser::ToCss::to_css(lang, dest)?, - Lang::List(list) => list.to_css(&mut CssWriter::new(dest))?, - } + lang.to_css(&mut CssWriter::new(dest))?; return dest.write_char(')'); }, NonTSPseudoClass::MozLocaleDir(ref dir) => { @@ -394,11 +384,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { if result.is_empty() { return Err(parser.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } - if result.len() == 1 { - NonTSPseudoClass::Lang(Lang::Single(result[0].clone())) - } else { - NonTSPseudoClass::Lang(Lang::List(Box::new(result))) - } + NonTSPseudoClass::Lang(Lang(result.into())) }, "-moz-locale-dir" => { NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?) @@ -448,7 +434,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { if starts_with_ignore_ascii_case(&name, "-moz-tree-") { // Tree pseudo-elements can have zero or more arguments, separated // by either comma or space. - let mut args = Vec::new(); + let mut args = ThinVec::new(); loop { let location = parser.current_source_location(); match parser.next() { @@ -462,7 +448,6 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { _ => unreachable!("Parser::next() shouldn't return any other error"), } } - let args = args.into_boxed_slice(); if let Some(pseudo) = PseudoElement::tree_pseudo_element(&name, args) { if self.is_pseudo_element_enabled(&pseudo) { return Ok(pseudo); diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 762ff037416..de2bd4c5f4c 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -1566,26 +1566,14 @@ impl<'le> TElement for GeckoElement<'le> { Some(Some(ref atom)) => atom.as_ptr(), _ => ptr::null_mut(), }; - match value { - Lang::Single(lang) => unsafe { - Gecko_MatchLang( - self.0, - override_lang_ptr, - override_lang.is_some(), - lang.as_slice().as_ptr(), - ) - }, - Lang::List(list) => { - list.iter().any(|lang| unsafe { - Gecko_MatchLang( - self.0, - override_lang_ptr, - override_lang.is_some(), - lang.as_slice().as_ptr(), - ) - }) - }, - } + value.0.iter().any(|lang| unsafe { + Gecko_MatchLang( + self.0, + override_lang_ptr, + override_lang.is_some(), + lang.as_slice().as_ptr(), + ) + }) } fn is_html_document_body_element(&self) -> bool { diff --git a/components/to_shmem/Cargo.toml b/components/to_shmem/Cargo.toml index 9ef2cefe112..6de19e47df5 100644 --- a/components/to_shmem/Cargo.toml +++ b/components/to_shmem/Cargo.toml @@ -20,3 +20,4 @@ servo_arc = { path = "../servo_arc" } smallbitvec = { workspace = true } smallvec = { workspace = true } string_cache = { workspace = true, optional = true } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } diff --git a/components/to_shmem/lib.rs b/components/to_shmem/lib.rs index e01c144cae0..5a968c1283b 100644 --- a/components/to_shmem/lib.rs +++ b/components/to_shmem/lib.rs @@ -12,6 +12,8 @@ #![crate_name = "to_shmem"] #![crate_type = "rlib"] +extern crate thin_vec; + use std::alloc::Layout; #[cfg(debug_assertions)] use std::any::TypeId; @@ -31,6 +33,7 @@ use std::{isize, slice, str}; use servo_arc::{Arc, ThinArc}; use smallbitvec::{InternalStorage, SmallBitVec}; use smallvec::{Array, SmallVec}; +use thin_vec::ThinVec; /// Result type for ToShmem::to_shmem. /// @@ -498,6 +501,58 @@ impl<H: 'static + ToShmem, T: 'static + ToShmem> ToShmem for ThinArc<H, T> { } } +impl<T: ToShmem> ToShmem for ThinVec<T> { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result<Self> { + let len = self.len(); + if len == 0 { + return Ok(ManuallyDrop::new(Self::new())) + } + + assert_eq!(mem::size_of::<Self>(), mem::size_of::<*const ()>()); + + // nsTArrayHeader size. + // FIXME: Would be nice not to hard-code this, but in practice thin-vec crate also relies + // on this. + let header_size = 2 * mem::size_of::<u32>(); + let header_align = mem::size_of::<u32>(); + + let item_size = mem::size_of::<T>(); + let item_align = mem::align_of::<T>(); + + // We don't need to support underalignment for now, this could be supported if needed. + assert!(item_align >= header_align); + + // This is explicitly unsupported by ThinVec, see: + // https://searchfox.org/mozilla-central/rev/ad732108b073742d7324f998c085f459674a6846/third_party/rust/thin-vec/src/lib.rs#375-386 + assert!(item_align <= header_size); + let header_padding = 0; + + let layout = Layout::from_size_align(header_size + header_padding + padded_size(item_size, item_align) * len, item_align).unwrap(); + + let shmem_header_ptr = builder.alloc::<u8>(layout); + let shmem_data_ptr = unsafe { shmem_header_ptr.add(header_size + header_padding) }; + + let data_ptr = self.as_ptr() as *const T as *const u8; + let header_ptr = unsafe { data_ptr.sub(header_size + header_padding) }; + + unsafe { + // Copy the header. Note this might copy a wrong capacity, but it doesn't matter, + // because shared memory ptrs are immutable anyways, and we can't relocate. + ptr::copy(header_ptr, shmem_header_ptr, header_size); + // ToShmem + copy the contents into the shared buffer. + to_shmem_slice_ptr(self.iter(), shmem_data_ptr as *mut T, builder)?; + // Return the new ThinVec, which is just a pointer to the shared memory buffer. + let shmem_thinvec: Self = mem::transmute(shmem_header_ptr); + + // Sanity-check that the ptr and length match. + debug_assert_eq!(shmem_thinvec.as_ptr(), shmem_data_ptr as *const T); + debug_assert_eq!(shmem_thinvec.len(), len); + + Ok(ManuallyDrop::new(shmem_thinvec)) + } + } +} + impl ToShmem for SmallBitVec { fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result<Self> { let storage = match self.clone().into_storage() { |