forked from mirrors/gecko-dev
Bug 1474793 - Part 7: Add SharedMemoryBuilder type and ToShmem trait. r=emilio
Depends on D17186 Differential Revision: https://phabricator.services.mozilla.com/D17187 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
ea948106dd
commit
b3a8e5cfb6
6 changed files with 201 additions and 2 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -1,5 +1,3 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "Inflector"
|
||||
version = "0.11.2"
|
||||
|
|
@ -2725,6 +2723,7 @@ dependencies = [
|
|||
"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)",
|
||||
|
|
@ -2925,6 +2924,10 @@ dependencies = [
|
|||
"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"
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ 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"
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ 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)]
|
||||
|
|
|
|||
16
servo/components/to_shmem/Cargo.toml
Normal file
16
servo/components/to_shmem/Cargo.toml
Normal file
|
|
@ -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]
|
||||
175
servo/components/to_shmem/lib.rs
Normal file
175
servo/components/to_shmem/lib.rs
Normal file
|
|
@ -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>;
|
||||
}
|
||||
|
|
@ -19,6 +19,9 @@ with Files("components/style_traits/**"):
|
|||
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")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue