mirror of
https://github.com/servo/servo.git
synced 2025-06-25 01:24:37 +01:00
style: Implement ArcSlice::default().
Share a singleton to avoid allocating for empty lists. Differential Revision: https://phabricator.services.mozilla.com/D30543
This commit is contained in:
parent
ab8776a144
commit
5e4fdf647d
4 changed files with 52 additions and 21 deletions
|
@ -612,16 +612,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
use std::mem::{align_of, size_of};
|
use std::mem::{align_of, size_of};
|
||||||
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
|
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
|
||||||
|
|
||||||
|
let inner_align = align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
|
||||||
|
debug_assert!(inner_align >= align_of::<T>());
|
||||||
|
|
||||||
// Compute the required size for the allocation.
|
// Compute the required size for the allocation.
|
||||||
let num_items = items.len();
|
let num_items = items.len();
|
||||||
let size = {
|
let size = {
|
||||||
// First, determine the alignment of a hypothetical pointer to a
|
|
||||||
// HeaderSlice.
|
|
||||||
let fake_slice_ptr_align: usize = mem::align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
|
|
||||||
|
|
||||||
// Next, synthesize a totally garbage (but properly aligned) pointer
|
// Next, synthesize a totally garbage (but properly aligned) pointer
|
||||||
// to a sequence of T.
|
// to a sequence of T.
|
||||||
let fake_slice_ptr = fake_slice_ptr_align as *const T;
|
let fake_slice_ptr = inner_align as *const T;
|
||||||
|
|
||||||
// Convert that sequence to a fat pointer. The address component of
|
// Convert that sequence to a fat pointer. The address component of
|
||||||
// the fat pointer will be garbage, but the length will be correct.
|
// the fat pointer will be garbage, but the length will be correct.
|
||||||
|
@ -641,13 +640,13 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
let ptr: *mut ArcInner<HeaderSlice<H, [T]>>;
|
let ptr: *mut ArcInner<HeaderSlice<H, [T]>>;
|
||||||
unsafe {
|
unsafe {
|
||||||
// Allocate the buffer.
|
// Allocate the buffer.
|
||||||
let layout = if mem::align_of::<T>() <= mem::align_of::<usize>() {
|
let layout = if inner_align <= align_of::<usize>() {
|
||||||
Layout::from_size_align_unchecked(size, mem::align_of::<usize>())
|
Layout::from_size_align_unchecked(size, align_of::<usize>())
|
||||||
} else if mem::align_of::<T>() <= mem::align_of::<u64>() {
|
} else if inner_align <= align_of::<u64>() {
|
||||||
// On 32-bit platforms <T> may have 8 byte alignment while usize has 4 byte aligment.
|
// On 32-bit platforms <T> may have 8 byte alignment while usize
|
||||||
// Use u64 to avoid over-alignment.
|
// has 4 byte aligment. Use u64 to avoid over-alignment.
|
||||||
// This branch will compile away in optimized builds.
|
// This branch will compile away in optimized builds.
|
||||||
Layout::from_size_align_unchecked(size, mem::align_of::<u64>())
|
Layout::from_size_align_unchecked(size, align_of::<u64>())
|
||||||
} else {
|
} else {
|
||||||
panic!("Over-aligned type not handled");
|
panic!("Over-aligned type not handled");
|
||||||
};
|
};
|
||||||
|
@ -689,7 +688,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
// for some padding from the alignment.
|
// for some padding from the alignment.
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
(buffer.offset(size as isize) as usize - current as *mut u8 as usize) <
|
(buffer.offset(size as isize) as usize - current as *mut u8 as usize) <
|
||||||
align_of::<Self>()
|
inner_align
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
@ -18,6 +18,7 @@ app_units = "0.7"
|
||||||
cssparser = "0.25"
|
cssparser = "0.25"
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
|
lazy_static = "1"
|
||||||
malloc_size_of = { path = "../malloc_size_of" }
|
malloc_size_of = { path = "../malloc_size_of" }
|
||||||
malloc_size_of_derive = "0.1"
|
malloc_size_of_derive = "0.1"
|
||||||
selectors = { path = "../selectors" }
|
selectors = { path = "../selectors" }
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! A thin atomically-reference-counted slice.
|
//! A thin atomically-reference-counted slice.
|
||||||
|
|
||||||
use servo_arc::ThinArc;
|
use servo_arc::ThinArc;
|
||||||
use std::mem;
|
use std::{iter, mem};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
@ -14,7 +14,10 @@ use std::ptr::NonNull;
|
||||||
/// Given we cannot use a zero-sized-type for the header, since well, C++
|
/// Given we cannot use a zero-sized-type for the header, since well, C++
|
||||||
/// doesn't have zsts, and we want to use cbindgen for this type, we may as well
|
/// doesn't have zsts, and we want to use cbindgen for this type, we may as well
|
||||||
/// assert some sanity at runtime.
|
/// assert some sanity at runtime.
|
||||||
const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3;
|
///
|
||||||
|
/// We use an u64, to guarantee that we can use a single singleton for every
|
||||||
|
/// empty slice, even if the types they hold are aligned differently.
|
||||||
|
const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
|
||||||
|
|
||||||
/// A wrapper type for a refcounted slice using ThinArc.
|
/// A wrapper type for a refcounted slice using ThinArc.
|
||||||
///
|
///
|
||||||
|
@ -22,7 +25,7 @@ const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3;
|
||||||
/// cbindgen:derive-neq=false
|
/// cbindgen:derive-neq=false
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, ToShmem)]
|
#[derive(Clone, Debug, Eq, PartialEq, ToShmem)]
|
||||||
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u32, T>);
|
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>);
|
||||||
|
|
||||||
impl<T> Deref for ArcSlice<T> {
|
impl<T> Deref for ArcSlice<T> {
|
||||||
type Target = [T];
|
type Target = [T];
|
||||||
|
@ -34,12 +37,28 @@ impl<T> Deref for ArcSlice<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
|
lazy_static! {
|
||||||
/// The type of the pointer is a bit of a lie, we just want to preserve the type
|
// ThinArc doesn't support alignments greater than align_of::<u64>.
|
||||||
/// but these pointers cannot be constructed outside of this crate, so we're
|
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
|
||||||
/// good.
|
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
|
||||||
#[repr(C)]
|
};
|
||||||
pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
|
}
|
||||||
|
|
||||||
|
impl<T> Default for ArcSlice<T> {
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn default() -> Self {
|
||||||
|
debug_assert!(
|
||||||
|
mem::align_of::<T>() <= mem::align_of::<u64>(),
|
||||||
|
"Need to increase the alignment of EMPTY_ARC_SLICE"
|
||||||
|
);
|
||||||
|
unsafe {
|
||||||
|
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
|
||||||
|
let empty: Self = mem::transmute(empty);
|
||||||
|
debug_assert_eq!(empty.len(), 0);
|
||||||
|
empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> ArcSlice<T> {
|
impl<T> ArcSlice<T> {
|
||||||
/// Creates an Arc for a slice using the given iterator to generate the
|
/// Creates an Arc for a slice using the given iterator to generate the
|
||||||
|
@ -49,6 +68,9 @@ impl<T> ArcSlice<T> {
|
||||||
where
|
where
|
||||||
I: Iterator<Item = T> + ExactSizeIterator,
|
I: Iterator<Item = T> + ExactSizeIterator,
|
||||||
{
|
{
|
||||||
|
if items.len() == 0 {
|
||||||
|
return Self::default();
|
||||||
|
}
|
||||||
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
|
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,3 +86,10 @@ impl<T> ArcSlice<T> {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
|
||||||
|
/// The type of the pointer is a bit of a lie, we just want to preserve the type
|
||||||
|
/// but these pointers cannot be constructed outside of this crate, so we're
|
||||||
|
/// good.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
|
||||||
|
|
|
@ -16,6 +16,8 @@ extern crate bitflags;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cssparser;
|
extern crate cssparser;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
extern crate malloc_size_of;
|
extern crate malloc_size_of;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate malloc_size_of_derive;
|
extern crate malloc_size_of_derive;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue