diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-05-10 21:20:50 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-10 21:20:50 -0400 |
commit | 887f43b65bacad5490365f14d54bf25af4d3234b (patch) | |
tree | 2c34539b60750aab59c068959cdc6fc8389a90c0 /components/servo_arc/lib.rs | |
parent | 81f750afa770f9bf6f2b0fff8052e5ccf047e4ed (diff) | |
parent | db2f6aa8ca1f23f78a497cb7cc960ff99f23ac04 (diff) | |
download | servo-887f43b65bacad5490365f14d54bf25af4d3234b.tar.gz servo-887f43b65bacad5490365f14d54bf25af4d3234b.zip |
Auto merge of #23353 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central.
See each individual commit for details.
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23353)
<!-- Reviewable:end -->
Diffstat (limited to 'components/servo_arc/lib.rs')
-rw-r--r-- | components/servo_arc/lib.rs | 123 |
1 files changed, 98 insertions, 25 deletions
diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index f4a929e23f8..f2f9fa00602 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -21,7 +21,7 @@ //! //! [1]: https://bugzilla.mozilla.org/show_bug.cgi?id=1360883 -// The semantics of `Arc` are alread documented in the Rust docs, so we don't +// The semantics of `Arc` are already documented in the Rust docs, so we don't // duplicate those here. #![allow(missing_docs)] @@ -86,10 +86,14 @@ const STATIC_REFCOUNT: usize = usize::MAX; /// See the documentation for [`Arc`] in the standard library. Unlike the /// standard library `Arc`, this `Arc` does not support weak reference counting. /// +/// See the discussion in https://github.com/rust-lang/rust/pull/60594 for the +/// usage of PhantomData. +/// /// [`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html #[repr(C)] pub struct Arc<T: ?Sized> { p: ptr::NonNull<ArcInner<T>>, + phantom: PhantomData<T>, } /// An `Arc` that is known to be uniquely owned @@ -164,11 +168,12 @@ impl<T> Arc<T> { pub fn new(data: T) -> Self { let x = Box::new(ArcInner { count: atomic::AtomicUsize::new(1), - data: data, + data, }); unsafe { Arc { p: ptr::NonNull::new_unchecked(Box::into_raw(x)), + phantom: PhantomData, } } } @@ -198,6 +203,7 @@ impl<T> Arc<T> { let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data)); Arc { p: ptr::NonNull::new_unchecked(ptr as *mut ArcInner<T>), + phantom: PhantomData, } } @@ -224,6 +230,7 @@ impl<T> Arc<T> { Arc { p: ptr::NonNull::new_unchecked(ptr), + phantom: PhantomData, } } @@ -301,6 +308,9 @@ impl<T: ?Sized> Arc<T> { impl<T: ?Sized> Clone for Arc<T> { #[inline] fn clone(&self) -> Self { + // NOTE(emilio): If you change anything here, make sure that the + // implementation in layout/style/ServoStyleConstsInlines.h matches! + // // Using a relaxed ordering to check for STATIC_REFCOUNT is safe, since // `count` never changes between STATIC_REFCOUNT and other values. if self.inner().count.load(Relaxed) != STATIC_REFCOUNT { @@ -334,6 +344,7 @@ impl<T: ?Sized> Clone for Arc<T> { unsafe { Arc { p: ptr::NonNull::new_unchecked(self.ptr()), + phantom: PhantomData, } } } @@ -408,6 +419,9 @@ impl<T: ?Sized> Arc<T> { impl<T: ?Sized> Drop for Arc<T> { #[inline] fn drop(&mut self) { + // NOTE(emilio): If you change anything here, make sure that the + // implementation in layout/style/ServoStyleConstsInlines.h matches! + // // Using a relaxed ordering to check for STATIC_REFCOUNT is safe, since // `count` never changes between STATIC_REFCOUNT and other values. if self.inner().count.load(Relaxed) == STATIC_REFCOUNT { @@ -563,6 +577,7 @@ impl<T: Serialize> Serialize for Arc<T> { /// Structure to allow Arc-managing some fixed-sized data and a variably-sized /// slice in a single allocation. #[derive(Debug, Eq, PartialEq, PartialOrd)] +#[repr(C)] pub struct HeaderSlice<H, T: ?Sized> { /// The fixed-sized data. pub header: H, @@ -594,7 +609,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { F: FnOnce(Layout) -> *mut u8, I: Iterator<Item = T> + ExactSizeIterator, { - use std::mem::size_of; + use std::mem::{align_of, size_of}; assert_ne!(size_of::<T>(), 0, "Need to think about ZST"); // Compute the required size for the allocation. @@ -602,7 +617,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { 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; 1]>>>(); + 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. @@ -659,23 +674,28 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { }; ptr::write(&mut ((*ptr).count), count); ptr::write(&mut ((*ptr).data.header), header); - let mut current: *mut T = &mut (*ptr).data.slice[0]; - for _ in 0..num_items { - ptr::write( - current, - items - .next() - .expect("ExactSizeIterator over-reported length"), + if num_items != 0 { + let mut current: *mut T = &mut (*ptr).data.slice[0]; + for _ in 0..num_items { + ptr::write( + current, + items + .next() + .expect("ExactSizeIterator over-reported length"), + ); + current = current.offset(1); + } + // We should have consumed the buffer exactly, maybe accounting + // for some padding from the alignment. + debug_assert!( + (buffer.offset(size as isize) as usize - current as *mut u8 as usize) < + align_of::<Self>() ); - current = current.offset(1); } assert!( items.next().is_none(), "ExactSizeIterator under-reported length" ); - - // We should have consumed the buffer exactly. - debug_assert_eq!(current as *mut u8, buffer.offset(size as isize)); } // Return the fat Arc. @@ -687,6 +707,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { unsafe { Arc { p: ptr::NonNull::new_unchecked(ptr), + phantom: PhantomData, } } } @@ -732,6 +753,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { /// Header data with an inline length. Consumers that use HeaderWithLength as the /// Header type in HeaderSlice can take advantage of ThinArc. #[derive(Debug, Eq, PartialEq, PartialOrd)] +#[repr(C)] pub struct HeaderWithLength<H> { /// The fixed-sized data. pub header: H, @@ -763,11 +785,20 @@ type HeaderSliceWithLength<H, T> = HeaderSlice<HeaderWithLength<H>, T>; /// have a thin pointer instead, perhaps for FFI compatibility /// or space efficiency. /// +/// Note that we use `[T; 0]` in order to have the right alignment for `T`. +/// /// `ThinArc` solves this by storing the length in the allocation itself, /// via `HeaderSliceWithLength`. #[repr(C)] pub struct ThinArc<H, T> { - ptr: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>, + ptr: ptr::NonNull<ArcInner<HeaderSliceWithLength<H, [T; 0]>>>, + phantom: PhantomData<(H, T)>, +} + +impl<H: fmt::Debug, T: fmt::Debug> fmt::Debug for ThinArc<H, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.deref(), f) + } } unsafe impl<H: Sync + Send, T: Sync + Send> Send for ThinArc<H, T> {} @@ -777,7 +808,7 @@ unsafe impl<H: Sync + Send, T: Sync + Send> Sync for ThinArc<H, T> {} // // See the comment around the analogous operation in from_header_and_iter. fn thin_to_thick<H, T>( - thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>, + thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 0]>>, ) -> *mut ArcInner<HeaderSliceWithLength<H, [T]>> { let len = unsafe { (*thin).data.header.length }; let fake_slice: *mut [T] = unsafe { slice::from_raw_parts_mut(thin as *mut T, len) }; @@ -796,7 +827,8 @@ impl<H, T> ThinArc<H, T> { // Synthesize transient Arc, which never touches the refcount of the ArcInner. let transient = unsafe { NoDrop::new(Arc { - p: ptr::NonNull::new_unchecked(thin_to_thick(self.ptr)), + p: ptr::NonNull::new_unchecked(thin_to_thick(self.ptr.as_ptr())), + phantom: PhantomData, }) }; @@ -841,8 +873,12 @@ impl<H, T> ThinArc<H, T> { } /// Returns the address on the heap of the ThinArc itself -- not the T - /// within it -- for memory reporting. - /// + /// within it -- for memory reporting, and bindings. + #[inline] + pub fn ptr(&self) -> *const c_void { + self.ptr.as_ptr() as *const ArcInner<T> as *const c_void + } + /// If this is a static ThinArc, this returns null. #[inline] pub fn heap_ptr(&self) -> *const c_void { @@ -851,7 +887,7 @@ impl<H, T> ThinArc<H, T> { if is_static { ptr::null() } else { - self.ptr as *const ArcInner<T> as *const c_void + self.ptr() } } } @@ -861,7 +897,7 @@ impl<H, T> Deref for ThinArc<H, T> { #[inline] fn deref(&self) -> &Self::Target { - unsafe { &(*thin_to_thick(self.ptr)).data } + unsafe { &(*thin_to_thick(self.ptr.as_ptr())).data } } } @@ -875,7 +911,10 @@ impl<H, T> Clone for ThinArc<H, T> { impl<H, T> Drop for ThinArc<H, T> { #[inline] fn drop(&mut self) { - let _ = Arc::from_thin(ThinArc { ptr: self.ptr }); + let _ = Arc::from_thin(ThinArc { + ptr: self.ptr, + phantom: PhantomData, + }); } } @@ -893,7 +932,12 @@ impl<H, T> Arc<HeaderSliceWithLength<H, [T]>> { mem::forget(a); let thin_ptr = fat_ptr as *mut [usize] as *mut usize; ThinArc { - ptr: thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>, + ptr: unsafe { + ptr::NonNull::new_unchecked( + thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 0]>>, + ) + }, + phantom: PhantomData, } } @@ -901,11 +945,12 @@ impl<H, T> Arc<HeaderSliceWithLength<H, [T]>> { /// is not modified. #[inline] pub fn from_thin(a: ThinArc<H, T>) -> Self { - let ptr = thin_to_thick(a.ptr); + let ptr = thin_to_thick(a.ptr.as_ptr()); mem::forget(a); unsafe { Arc { p: ptr::NonNull::new_unchecked(ptr), + phantom: PhantomData, } } } @@ -1306,6 +1351,34 @@ mod tests { } #[test] + fn empty_thin() { + let header = HeaderWithLength::new(100u32, 0); + let x = Arc::from_header_and_iter(header, std::iter::empty::<i32>()); + let y = Arc::into_thin(x.clone()); + assert_eq!(y.header.header, 100); + assert!(y.slice.is_empty()); + assert_eq!(x.header.header, 100); + assert!(x.slice.is_empty()); + } + + #[test] + fn thin_assert_padding() { + #[derive(Clone, Default)] + #[repr(C)] + struct Padded { + i: u16, + } + + // The header will have more alignment than `Padded` + let header = HeaderWithLength::new(0i32, 2); + let items = vec![Padded { i: 0xdead }, Padded { i: 0xbeef }]; + let a = ThinArc::from_header_and_iter(header, items.into_iter()); + assert_eq!(a.slice.len(), 2); + assert_eq!(a.slice[0].i, 0xdead); + assert_eq!(a.slice[1].i, 0xbeef); + } + + #[test] fn slices_and_thin() { let mut canary = atomic::AtomicUsize::new(0); let c = Canary(&mut canary as *mut atomic::AtomicUsize); |