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 Arc> { use std::mem::{align_of, size_of}; assert_ne!(size_of::(), 0, "Need to think about ZST"); + let inner_align = align_of::>>(); + debug_assert!(inner_align >= align_of::()); + // 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::>>(); - // 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 Arc> { let ptr: *mut ArcInner>; unsafe { // Allocate the buffer. - let layout = if mem::align_of::() <= mem::align_of::() { - Layout::from_size_align_unchecked(size, mem::align_of::()) - } else if mem::align_of::() <= mem::align_of::() { - // On 32-bit platforms may have 8 byte alignment while usize has 4 byte aligment. - // Use u64 to avoid over-alignment. + let layout = if inner_align <= align_of::() { + Layout::from_size_align_unchecked(size, align_of::()) + } else if inner_align <= align_of::() { + // On 32-bit platforms 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::()) + Layout::from_size_align_unchecked(size, align_of::()) } else { panic!("Over-aligned type not handled"); }; @@ -689,7 +688,7 @@ impl Arc> { // for some padding from the alignment. debug_assert!( (buffer.offset(size as isize) as usize - current as *mut u8 as usize) < - align_of::() + 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(#[shmem(field_bound)] ThinArc); +pub struct ArcSlice(#[shmem(field_bound)] ThinArc); impl Deref for ArcSlice { type Target = [T]; @@ -34,12 +37,28 @@ impl Deref for ArcSlice { } } -/// The inner pointer of an ArcSlice, 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(NonNull); +lazy_static! { + // ThinArc doesn't support alignments greater than align_of::. + static ref EMPTY_ARC_SLICE: ArcSlice = { + ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty())) + }; +} + +impl Default for ArcSlice { + #[allow(unsafe_code)] + fn default() -> Self { + debug_assert!( + mem::align_of::() <= mem::align_of::(), + "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 ArcSlice { /// Creates an Arc for a slice using the given iterator to generate the @@ -49,6 +68,9 @@ impl ArcSlice { where I: Iterator + ExactSizeIterator, { + if items.len() == 0 { + return Self::default(); + } ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items)) } @@ -64,3 +86,10 @@ impl ArcSlice { ret } } + +/// The inner pointer of an ArcSlice, 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(NonNull); 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;