diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2019-05-16 23:22:04 +0000 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2019-05-29 16:14:08 +0200 |
commit | 5e4fdf647df1e8186d35f06786eb92f607fff436 (patch) | |
tree | 4316f47d8ea2398a9c2b909b5b2578c10c33f0d4 /components | |
parent | ab8776a144baea462b9ad182855cdd62a6c000be (diff) | |
download | servo-5e4fdf647df1e8186d35f06786eb92f607fff436.tar.gz servo-5e4fdf647df1e8186d35f06786eb92f607fff436.zip |
style: Implement ArcSlice::default().
Share a singleton to avoid allocating for empty lists.
Differential Revision: https://phabricator.services.mozilla.com/D30543
Diffstat (limited to 'components')
-rw-r--r-- | components/servo_arc/lib.rs | 23 | ||||
-rw-r--r-- | components/style_traits/Cargo.toml | 1 | ||||
-rw-r--r-- | components/style_traits/arc_slice.rs | 47 | ||||
-rw-r--r-- | components/style_traits/lib.rs | 2 |
4 files changed, 52 insertions, 21 deletions
diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index f2f9fa00602..09f381c62df 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -612,16 +612,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { use std::mem::{align_of, size_of}; 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. let num_items = items.len(); 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 // 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 // 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]>>; unsafe { // Allocate the buffer. - let layout = if mem::align_of::<T>() <= mem::align_of::<usize>() { - Layout::from_size_align_unchecked(size, mem::align_of::<usize>()) - } else if mem::align_of::<T>() <= mem::align_of::<u64>() { - // On 32-bit platforms <T> may have 8 byte alignment while usize has 4 byte aligment. - // Use u64 to avoid over-alignment. + let layout = if inner_align <= align_of::<usize>() { + Layout::from_size_align_unchecked(size, align_of::<usize>()) + } else if inner_align <= align_of::<u64>() { + // On 32-bit platforms <T> may have 8 byte alignment while usize + // has 4 byte aligment. Use u64 to avoid over-alignment. // 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 { panic!("Over-aligned type not handled"); }; @@ -689,7 +688,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { // for some padding from the alignment. debug_assert!( (buffer.offset(size as isize) as usize - current as *mut u8 as usize) < - align_of::<Self>() + inner_align ); } assert!( diff --git a/components/style_traits/Cargo.toml b/components/style_traits/Cargo.toml index 846579d462c..acf46422861 100644 --- a/components/style_traits/Cargo.toml +++ b/components/style_traits/Cargo.toml @@ -18,6 +18,7 @@ app_units = "0.7" cssparser = "0.25" bitflags = "1.0" euclid = "0.19" +lazy_static = "1" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = "0.1" selectors = { path = "../selectors" } diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs index dd1b99d3424..1541d4be3d9 100644 --- a/components/style_traits/arc_slice.rs +++ b/components/style_traits/arc_slice.rs @@ -5,7 +5,7 @@ //! A thin atomically-reference-counted slice. use servo_arc::ThinArc; -use std::mem; +use std::{iter, mem}; use std::ops::Deref; 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++ /// doesn't have zsts, and we want to use cbindgen for this type, we may as well /// 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. /// @@ -22,7 +25,7 @@ const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3; /// cbindgen:derive-neq=false #[repr(C)] #[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> { 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. -/// 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>); +lazy_static! { + // ThinArc doesn't support alignments greater than align_of::<u64>. + static ref EMPTY_ARC_SLICE: ArcSlice<u64> = { + ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty())) + }; +} + +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> { /// Creates an Arc for a slice using the given iterator to generate the @@ -49,6 +68,9 @@ impl<T> ArcSlice<T> { where I: Iterator<Item = T> + ExactSizeIterator, { + if items.len() == 0 { + return Self::default(); + } ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items)) } @@ -64,3 +86,10 @@ impl<T> ArcSlice<T> { 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>); diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index d4a907fa956..0ba13082fc3 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -16,6 +16,8 @@ extern crate bitflags; #[macro_use] extern crate cssparser; extern crate euclid; +#[macro_use] +extern crate lazy_static; extern crate malloc_size_of; #[macro_use] extern crate malloc_size_of_derive; |