Fix SharedArray length in bytes to be a multiple of pointer alignment

This commit is contained in:
Simon Hausmann 2020-07-07 16:00:00 +02:00
parent f646809ff4
commit 89a05245f9

View file

@ -15,25 +15,27 @@ struct PaddingFillingIter<'a, U> {
iter: &'a mut dyn Iterator<Item = MaybeUninit<U>>, iter: &'a mut dyn Iterator<Item = MaybeUninit<U>>,
pos: usize, pos: usize,
len: usize, len: usize,
padding_elements: usize,
} }
impl<'a, U> PaddingFillingIter<'a, U> { impl<'a, U> PaddingFillingIter<'a, U> {
fn new(len: usize, iter: &'a mut dyn Iterator<Item = MaybeUninit<U>>) -> Self { fn new(len: usize, iter: &'a mut dyn Iterator<Item = MaybeUninit<U>>) -> Self {
Self { iter, pos: 0, len } let alignment = core::mem::align_of::<usize>();
} let mut padding_elements = if len == 0 { 1 } else { 0 }; // ThinArc can't deal with empty arrays, so add padding for empty arrays.
fn padded_length(&self) -> usize { // Add padding to ensure that the size in bytes is a multiple of the pointer alignment. This can mean different
// add some padding at the end since the size of the inner will anyway have to be padded // increments depending on whether sizeof(U) is less or greater than align_of(usize).
let align = core::mem::align_of::<usize>() / core::mem::size_of::<U>(); loop {
if self.len > 0 { let size_in_bytes = (len + padding_elements) * core::mem::size_of::<U>();
if align > 0 { let byte_aligned_size = (size_in_bytes + alignment - 1) & !(alignment - 1);
(self.len + align - 1) & !(align - 1) let padding_bytes = byte_aligned_size - size_in_bytes;
} else { if padding_bytes == 0 {
self.len break;
} }
} else { padding_elements += 1;
align
} }
Self { iter, pos: 0, len, padding_elements }
} }
} }
@ -44,14 +46,14 @@ impl<'a, U: Clone> Iterator for PaddingFillingIter<'a, U> {
self.pos += 1; self.pos += 1;
if pos < self.len { if pos < self.len {
self.iter.next() self.iter.next()
} else if pos < self.padded_length() { } else if pos < self.len + self.padding_elements {
Some(MaybeUninit::uninit()) Some(MaybeUninit::uninit())
} else { } else {
None None
} }
} }
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.padded_length() - self.pos; let l = self.len + self.padding_elements;
(l, Some(l)) (l, Some(l))
} }
} }
@ -80,7 +82,7 @@ impl<T: Clone> SharedArray<T> {
SharedArray { SharedArray {
inner: servo_arc::Arc::into_thin(servo_arc::Arc::from_header_and_iter( inner: servo_arc::Arc::into_thin(servo_arc::Arc::from_header_and_iter(
servo_arc::HeaderWithLength::new(len, iter.padded_length()), servo_arc::HeaderWithLength::new(len, iter.size_hint().0),
iter, iter,
)), )),
} }
@ -109,7 +111,7 @@ impl<T: Clone + Copy + Default + Sized + 'static> StaticNull for T {
let iter = PaddingFillingIter::new(len, null_iter); let iter = PaddingFillingIter::new(len, null_iter);
servo_arc::Arc::into_thin(servo_arc::Arc::from_header_and_iter( servo_arc::Arc::into_thin(servo_arc::Arc::from_header_and_iter(
servo_arc::HeaderWithLength::new(len, iter.padded_length()), servo_arc::HeaderWithLength::new(len, iter.size_hint().0),
iter, iter,
)) ))
}); });