diff options
Diffstat (limited to 'components/style_traits')
-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 |
3 files changed, 41 insertions, 9 deletions
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; |