author | Cameron McCormack <cam@mcc.id.au> |
Sat, 30 Mar 2019 00:15:59 +0000 | |
changeset 466890 | dbaaaa587dfe2be8ad2df5019e7eb62936cbdef9 |
parent 466889 | f10b3a04f246c17d0280999f89aef842c92be8d2 |
child 466891 | e3103dfb3c84ff62e7bad17b39b0e79dd729abd4 |
push id | 35784 |
push user | nerli@mozilla.com |
push date | Sat, 30 Mar 2019 09:32:04 +0000 |
treeherder | mozilla-central@d42c60ccf0d0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | emilio |
bugs | 1474793 |
milestone | 68.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,8 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. [[package]] name = "Inflector" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2720,16 +2718,17 @@ dependencies = [ "selectors 0.21.0", "servo_arc 0.1.1", "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "style_derive 0.0.1", "style_traits 0.0.1", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "to_shmem 0.0.1", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "uluru 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2921,16 +2920,20 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] [[package]] +name = "to_shmem" +version = "0.0.1" + +[[package]] name = "tokio" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/servo/components/style/Cargo.toml +++ b/servo/components/style/Cargo.toml @@ -64,16 +64,17 @@ servo_atoms = {path = "../atoms", option servo_config = {path = "../config", optional = true} smallbitvec = "2.3.0" smallvec = "0.6.6" string_cache = { version = "0.7", optional = true } style_derive = {path = "../style_derive"} style_traits = {path = "../style_traits"} servo_url = {path = "../url", optional = true} thin-slice = "0.1.0" +to_shmem = {path = "../to_shmem"} time = "0.1" uluru = "0.3" unicode-bidi = "0.3" unicode-segmentation = "1.0" void = "1.0.2" [build-dependencies] lazy_static = "1"
--- a/servo/components/style/lib.rs +++ b/servo/components/style/lib.rs @@ -94,16 +94,17 @@ extern crate smallvec; #[cfg(feature = "servo")] extern crate string_cache; #[macro_use] extern crate style_derive; extern crate style_traits; #[cfg(feature = "gecko")] extern crate thin_slice; extern crate time; +extern crate to_shmem; extern crate uluru; extern crate unicode_bidi; #[allow(unused_extern_crates)] extern crate unicode_segmentation; extern crate void; #[macro_use] mod macros;
new file mode 100644 --- /dev/null +++ b/servo/components/to_shmem/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "to_shmem" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +publish = false + +[lib] +name = "to_shmem" +path = "lib.rs" + +[features] +servo = [] +gecko = [] + +[dependencies]
new file mode 100644 --- /dev/null +++ b/servo/components/to_shmem/lib.rs @@ -0,0 +1,175 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Trait for cloning data into a shared memory buffer. +//! +//! This module contains the SharedMemoryBuilder type and ToShmem trait. +//! +//! We put them here (and not in style_traits) so that we can derive ToShmem +//! from the selectors and style crates. + +#![crate_name = "to_shmem"] +#![crate_type = "rlib"] + +use std::alloc::Layout; +#[cfg(debug_assertions)] +use std::any::TypeId; +use std::isize; +#[cfg(debug_assertions)] +use std::collections::HashSet; +use std::mem::{self, ManuallyDrop}; +#[cfg(debug_assertions)] +use std::os::raw::c_void; +use std::ptr::{self, NonNull}; + +// Various pointer arithmetic functions in this file can be replaced with +// functions on `Layout` once they have stabilized: +// +// https://github.com/rust-lang/rust/issues/55724 + +/// A builder object that transforms and copies values into a fixed size buffer. +pub struct SharedMemoryBuilder { + /// The buffer into which values will be copied. + buffer: *mut u8, + /// The size of the buffer. + capacity: usize, + /// The current position in the buffer, where the next value will be written + /// at. + index: usize, + /// Pointers to every sharable value that we store in the shared memory + /// buffer. We use this to assert against encountering the same value + /// twice, e.g. through another Arc reference, so that we don't + /// inadvertently store duplicate copies of values. + #[cfg(debug_assertions)] + shared_values: HashSet<*const c_void>, + /// Types of values that we may duplicate in the shared memory buffer when + /// there are shared references to them, such as in Arcs. + #[cfg(debug_assertions)] + allowed_duplication_types: HashSet<TypeId>, +} + +/// Amount of padding needed after `size` bytes to ensure that the following +/// address will satisfy `align`. +fn padding_needed_for(size: usize, align: usize) -> usize { + padded_size(size, align).wrapping_sub(size) +} + +/// Rounds up `size` so that the following address will satisfy `align`. +fn padded_size(size: usize, align: usize) -> usize { + size.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1) +} + +impl SharedMemoryBuilder { + /// Creates a new SharedMemoryBuilder using the specified buffer. + pub unsafe fn new(buffer: *mut u8, capacity: usize) -> SharedMemoryBuilder { + SharedMemoryBuilder { + buffer, + capacity, + index: 0, + #[cfg(debug_assertions)] + shared_values: HashSet::new(), + #[cfg(debug_assertions)] + allowed_duplication_types: HashSet::new(), + } + } + + /// Notes a type as being allowed for duplication when being copied to the + /// shared memory buffer, such as Arcs referencing the same value. + #[inline] + pub fn add_allowed_duplication_type<T: 'static>(&mut self) { + #[cfg(debug_assertions)] + self.allowed_duplication_types.insert(TypeId::of::<T>()); + } + + /// Returns the number of bytes currently used in the buffer. + #[inline] + pub fn len(&self) -> usize { + self.index + } + + /// Writes a value into the shared memory buffer and returns a pointer to + /// it in the buffer. + /// + /// The value is cloned and converted into a form suitable for placing into + /// a shared memory buffer by calling ToShmem::to_shmem on it. + /// + /// Panics if there is insufficient space in the buffer. + pub fn write<T: ToShmem>(&mut self, value: &T) -> *mut T { + // Reserve space for the value. + let dest: *mut T = self.alloc_value(); + + // Make a clone of the value with all of its heap allocations + // placed in the shared memory buffer. + let value = value.to_shmem(self); + + unsafe { + // Copy the value into the buffer. + ptr::write(dest, ManuallyDrop::into_inner(value)); + } + + // Return a pointer to the shared value. + dest + } + + /// Reserves space in the shared memory buffer to fit a value of type T, + /// and returns a pointer to that reserved space. + /// + /// Panics if there is insufficient space in the buffer. + pub fn alloc_value<T>(&mut self) -> *mut T { + self.alloc(Layout::new::<T>()) + } + + /// Reserves space in the shared memory buffer to fit an array of values of + /// type T, and returns a pointer to that reserved space. + /// + /// Panics if there is insufficient space in the buffer. + pub fn alloc_array<T>(&mut self, len: usize) -> *mut T { + if len == 0 { + return NonNull::dangling().as_ptr(); + } + + let size = mem::size_of::<T>(); + let align = mem::align_of::<T>(); + + self.alloc(Layout::from_size_align(padded_size(size, align) * len, align).unwrap()) + } + + /// Reserves space in the shared memory buffer that conforms to the + /// specified layout, and returns a pointer to that reserved space. + /// + /// Panics if there is insufficient space in the buffer. + pub fn alloc<T>(&mut self, layout: Layout) -> *mut T { + // Amount of padding to align the value. + // + // The addition can't overflow, since self.index <= self.capacity, and + // for us to have successfully allocated the buffer, `buffer + capacity` + // can't overflow. + let padding = padding_needed_for(self.buffer as usize + self.index, layout.align()); + + // Reserve space for the padding. + let start = self.index.checked_add(padding).unwrap(); + assert!(start <= std::isize::MAX as usize); // for the cast below + + // Reserve space for the value. + let end = start.checked_add(layout.size()).unwrap(); + assert!(end <= self.capacity); + + self.index = end; + unsafe { self.buffer.offset(start as isize) as *mut T } + } +} + +/// A type that can be copied into a SharedMemoryBuilder. +pub trait ToShmem: Sized { + /// Clones this value into a form suitable for writing into a + /// SharedMemoryBuilder. + /// + /// If this value owns any heap allocations, they should be written into + /// `builder` so that the return value of this function can point to the + /// copy in the shared memory buffer. + /// + /// The return type is wrapped in ManuallyDrop to make it harder to + /// accidentally invoke the destructor of the value that is produced. + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop<Self>; +}
--- a/servo/moz.build +++ b/servo/moz.build @@ -14,13 +14,16 @@ with Files("components/style_derive/**") BUG_COMPONENT = ("Core", "CSS Parsing and Computation") with Files("components/style_traits/**"): BUG_COMPONENT = ("Core", "CSS Parsing and Computation") with Files("components/selectors/**"): BUG_COMPONENT = ("Core", "CSS Parsing and Computation") +with Files("components/to_shmem/**"): + BUG_COMPONENT = ("Core", "CSS Parsing and Computation") + with Files("ports/geckolib/**"): BUG_COMPONENT = ("Core", "CSS Parsing and Computation") with Files("tests/unit/style/**"): BUG_COMPONENT = ("Core", "CSS Parsing and Computation")