diff --git a/selectors/builder.rs b/selectors/builder.rs index bcafacd48..63a6323c5 100644 --- a/selectors/builder.rs +++ b/selectors/builder.rs @@ -19,7 +19,7 @@ use crate::parser::{Combinator, Component, RelativeSelector, Selector, SelectorImpl}; use crate::sink::Push; -use servo_arc::{Arc, ThinArc}; +use servo_arc::{Arc, HeaderWithLength, ThinArc}; use smallvec::{self, SmallVec}; use std::cmp; use std::iter; @@ -105,22 +105,32 @@ impl SelectorBuilder { &mut self, spec: SpecificityAndFlags, ) -> ThinArc> { + // First, compute the total number of Components we'll need to allocate + // space for. + let full_len = self.simple_selectors.len() + self.combinators.len(); + + // Create the header. + let header = HeaderWithLength::new(spec, full_len); + // Create the Arc using an iterator that drains our buffers. - // Panic-safety: if SelectorBuilderIter is not iterated to the end, some simple selectors - // will safely leak. - let raw_simple_selectors = unsafe { - let simple_selectors_len = self.simple_selectors.len(); - self.simple_selectors.set_len(0); - std::slice::from_raw_parts(self.simple_selectors.as_ptr(), simple_selectors_len) - }; - let (rest, current) = split_from_end(raw_simple_selectors, self.current_len); + + // Use a raw pointer to be able to call set_len despite "borrowing" the slice. + // This is similar to SmallVec::drain, but we use a slice here because + // we’re gonna traverse it non-linearly. + let raw_simple_selectors: *const [Component] = &*self.simple_selectors; + unsafe { + // Panic-safety: if SelectorBuilderIter is not iterated to the end, + // some simple selectors will safely leak. + self.simple_selectors.set_len(0) + } + let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len); let iter = SelectorBuilderIter { current_simple_selectors: current.iter(), rest_of_simple_selectors: rest, combinators: self.combinators.drain(..).rev(), }; - Arc::from_header_and_iter(spec, iter) + Arc::into_thin(Arc::from_header_and_iter(header, iter)) } } diff --git a/selectors/parser.rs b/selectors/parser.rs index 40636f253..8bd87bbdf 100644 --- a/selectors/parser.rs +++ b/selectors/parser.rs @@ -19,7 +19,7 @@ use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind use cssparser::{CowRcStr, Delimiter, SourceLocation}; use cssparser::{Parser as CssParser, ToCss, Token}; use precomputed_hash::PrecomputedHash; -use servo_arc::{ThinArc, UniqueArc}; +use servo_arc::{HeaderWithLength, ThinArc, UniqueArc}; use smallvec::SmallVec; use std::borrow::{Borrow, Cow}; use std::fmt::{self, Debug}; @@ -649,7 +649,7 @@ pub struct Selector( impl Selector { /// See Arc::mark_as_intentionally_leaked pub fn mark_as_intentionally_leaked(&self) { - self.0.mark_as_intentionally_leaked() + self.0.with_arc(|a| a.mark_as_intentionally_leaked()) } fn ampersand() -> Self { @@ -664,32 +664,32 @@ impl Selector { #[inline] pub fn specificity(&self) -> u32 { - self.0.header.specificity() + self.0.header.header.specificity() } #[inline] fn flags(&self) -> SelectorFlags { - self.0.header.flags + self.0.header.header.flags } #[inline] pub fn has_pseudo_element(&self) -> bool { - self.0.header.has_pseudo_element() + self.0.header.header.has_pseudo_element() } #[inline] pub fn has_parent_selector(&self) -> bool { - self.0.header.has_parent_selector() + self.0.header.header.has_parent_selector() } #[inline] pub fn is_slotted(&self) -> bool { - self.0.header.is_slotted() + self.0.header.header.is_slotted() } #[inline] pub fn is_part(&self) -> bool { - self.0.header.is_part() + self.0.header.header.is_part() } #[inline] @@ -779,7 +779,7 @@ impl Selector { } SelectorIter { - iter: self.0.slice()[..self.len() - 2].iter(), + iter: self.0.slice[..self.len() - 2].iter(), next_combinator: None, } } @@ -811,7 +811,7 @@ impl Selector { /// skipping the rightmost |offset| Components. #[inline] pub fn iter_from(&self, offset: usize) -> SelectorIter { - let iter = self.0.slice()[offset..].iter(); + let iter = self.0.slice[offset..].iter(); SelectorIter { iter, next_combinator: None, @@ -822,7 +822,7 @@ impl Selector { /// or panics if the component is not a combinator. #[inline] pub fn combinator_at_match_order(&self, index: usize) -> Combinator { - match self.0.slice()[index] { + match self.0.slice[index] { Component::Combinator(c) => c, ref other => panic!( "Not a combinator: {:?}, {:?}, index: {}", @@ -835,14 +835,14 @@ impl Selector { /// combinators, in matching order (from right to left). #[inline] pub fn iter_raw_match_order(&self) -> slice::Iter> { - self.0.slice().iter() + self.0.slice.iter() } /// Returns the combinator at index `index` (zero-indexed from the left), /// or panics if the component is not a combinator. #[inline] pub fn combinator_at_parse_order(&self, index: usize) -> Combinator { - match self.0.slice()[self.len() - index - 1] { + match self.0.slice[self.len() - index - 1] { Component::Combinator(c) => c, ref other => panic!( "Not a combinator: {:?}, {:?}, index: {}", @@ -856,7 +856,7 @@ impl Selector { /// `offset`. #[inline] pub fn iter_raw_parse_order_from(&self, offset: usize) -> Rev>> { - self.0.slice()[..self.len() - offset].iter().rev() + self.0.slice[..self.len() - offset].iter().rev() } /// Creates a Selector from a vec of Components, specified in parse order. Used in tests. @@ -981,7 +981,8 @@ impl Selector { .chain(std::iter::once(Component::Is( parent.to_vec().into_boxed_slice(), ))); - UniqueArc::from_header_and_iter_with_size(specificity_and_flags, iter, len) + let header = HeaderWithLength::new(specificity_and_flags, len); + UniqueArc::from_header_and_iter_with_size(header, iter, len) } else { let iter = self.iter_raw_match_order().map(|component| { use self::Component::*; @@ -1073,16 +1074,17 @@ impl Selector { )), } }); - UniqueArc::from_header_and_iter(specificity_and_flags, iter) + let header = HeaderWithLength::new(specificity_and_flags, iter.len()); + UniqueArc::from_header_and_iter(header, iter) }; items.header_mut().specificity = specificity.into(); - Selector(items.shareable()) + Selector(items.shareable_thin()) } /// Returns count of simple selectors and combinators in the Selector. #[inline] pub fn len(&self) -> usize { - self.0.len() + self.0.slice.len() } /// Returns the address on the heap of the ThinArc for memory reporting. @@ -1481,13 +1483,13 @@ impl NthOfSelectorData { /// Returns the An+B part of the selector #[inline] pub fn nth_data(&self) -> &NthSelectorData { - &self.0.header + &self.0.header.header } /// Returns the selector list part of the selector #[inline] pub fn selectors(&self) -> &[Selector] { - self.0.slice() + &self.0.slice } } diff --git a/servo_arc/lib.rs b/servo_arc/lib.rs index 50953989f..cc7182728 100644 --- a/servo_arc/lib.rs +++ b/servo_arc/lib.rs @@ -45,6 +45,7 @@ use std::ops::{Deref, DerefMut}; use std::os::raw::c_void; use std::process; use std::ptr; +use std::slice; use std::sync::atomic; use std::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use std::{isize, usize}; @@ -350,11 +351,6 @@ impl Arc { fn ptr(&self) -> *mut ArcInner { self.p.as_ptr() } - - /// Returns a raw ptr to the underlying allocation. - pub fn raw_ptr(&self) -> *const c_void { - self.p.as_ptr() as *const _ - } } #[cfg(feature = "gecko_refcount_logging")] @@ -647,68 +643,14 @@ impl Serialize for Arc { /// Structure to allow Arc-managing some fixed-sized data and a variably-sized /// slice in a single allocation. -/// -/// cbindgen:derive-eq=false -/// cbindgen:derive-neq=false -#[derive(Debug, Eq)] +#[derive(Debug, Eq, PartialEq, PartialOrd)] #[repr(C)] -pub struct HeaderSlice { +pub struct HeaderSlice { /// The fixed-sized data. pub header: H, - /// The length of the slice at our end. - len: usize, - /// The dynamically-sized data. - data: [T; 0], -} - -impl PartialEq for HeaderSlice { - fn eq(&self, other: &Self) -> bool { - self.header == other.header && self.slice() == other.slice() - } -} - -impl Drop for HeaderSlice { - fn drop(&mut self) { - unsafe { - let mut ptr = self.data_mut(); - for _ in 0..self.len { - std::ptr::drop_in_place(ptr); - ptr = ptr.offset(1); - } - } - } -} - -impl HeaderSlice { - /// Returns the dynamically sized slice in this HeaderSlice. - #[inline(always)] - pub fn slice(&self) -> &[T] { - unsafe { std::slice::from_raw_parts(self.data(), self.len) } - } - - #[inline(always)] - fn data(&self) -> *const T { - std::ptr::addr_of!(self.data) as *const _ - } - - #[inline(always)] - fn data_mut(&mut self) -> *mut T { - std::ptr::addr_of_mut!(self.data) as *mut _ - } - - /// Returns the dynamically sized slice in this HeaderSlice. - #[inline(always)] - pub fn slice_mut(&mut self) -> &mut [T] { - unsafe { std::slice::from_raw_parts_mut(self.data_mut(), self.len) } - } - - /// Returns the len of the slice. - #[inline(always)] - pub fn len(&self) -> usize { - self.len - } + pub slice: T, } #[inline(always)] @@ -716,7 +658,7 @@ fn divide_rounding_up(dividend: usize, divisor: usize) -> usize { (dividend + divisor - 1) / divisor } -impl Arc> { +impl Arc> { /// Creates an Arc for a HeaderSlice using the given header struct and /// iterator to generate the slice. /// @@ -729,7 +671,7 @@ impl Arc> { /// then `alloc` must return an allocation that can be dellocated /// by calling Box::from_raw::>> on it. #[inline] - pub fn from_header_and_iter_alloc( + fn from_header_and_iter_alloc( alloc: F, header: H, mut items: I, @@ -742,11 +684,31 @@ impl Arc> { { assert_ne!(size_of::(), 0, "Need to think about ZST"); - let size = size_of::>>() + size_of::() * num_items; - let inner_align = align_of::>>(); + let inner_align = align_of::>>(); debug_assert!(inner_align >= align_of::()); - let ptr: *mut ArcInner>; + // Compute the required size for the allocation. + let size = { + // Next, synthesize a totally garbage (but properly aligned) pointer + // to a sequence of 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. + let fake_slice = unsafe { slice::from_raw_parts(fake_slice_ptr, num_items) }; + + // Pretend the garbage address points to our allocation target (with + // a trailing sequence of T), rather than just a sequence of T. + let fake_ptr = fake_slice as *const [T] as *const ArcInner>; + let fake_ref: &ArcInner> = unsafe { &*fake_ptr }; + + // Use size_of_val, which will combine static information about the + // type with the length from the fat pointer. The garbage address + // will not be used. + mem::size_of_val(fake_ref) + }; + + let ptr: *mut ArcInner>; unsafe { // Allocate the buffer. let layout = if inner_align <= align_of::() { @@ -761,7 +723,15 @@ impl Arc> { }; let buffer = alloc(layout); - ptr = buffer as *mut ArcInner>; + + // Synthesize the fat pointer. We do this by claiming we have a direct + // pointer to a [T], and then changing the type of the borrow. The key + // point here is that the length portion of the fat pointer applies + // only to the number of elements in the dynamically-sized portion of + // the type, so the value will be the same whether it points to a [T] + // or something else with a [T] as its last member. + let fake_slice: &mut [T] = slice::from_raw_parts_mut(buffer as *mut T, num_items); + ptr = fake_slice as *mut [T] as *mut ArcInner>; // Write the data. // @@ -774,9 +744,8 @@ impl Arc> { }; ptr::write(&mut ((*ptr).count), count); ptr::write(&mut ((*ptr).data.header), header); - ptr::write(&mut ((*ptr).data.len), num_items); if num_items != 0 { - let mut current = std::ptr::addr_of_mut!((*ptr).data.data) as *mut T; + let mut current: *mut T = &mut (*ptr).data.slice[0]; for _ in 0..num_items { ptr::write( current, @@ -809,8 +778,8 @@ impl Arc> { // Return the fat Arc. assert_eq!( size_of::(), - size_of::(), - "The Arc should be thin" + size_of::() * 2, + "The Arc will be fat" ); unsafe { Arc { @@ -870,18 +839,208 @@ impl Arc> { } } +/// 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 { + /// The fixed-sized data. + pub header: H, + + /// The slice length. + length: usize, +} + +impl HeaderWithLength { + /// Creates a new HeaderWithLength. + pub fn new(header: H, length: usize) -> Self { + HeaderWithLength { header, length } + } +} + +type HeaderSliceWithLength = HeaderSlice, T>; + +/// A "thin" `Arc` containing dynamically sized data +/// /// This is functionally equivalent to Arc<(H, [T])> /// -/// When you create an `Arc` containing a dynamically sized type like a slice, the `Arc` is -/// represented on the stack as a "fat pointer", where the length of the slice is stored alongside -/// the `Arc`'s pointer. In some situations you may wish to have a thin pointer instead, perhaps -/// for FFI compatibility or space efficiency. `ThinArc` solves this by storing the length in the -/// allocation itself, via `HeaderSlice`. -pub type ThinArc = Arc>; - -impl UniqueArc> { +/// When you create an `Arc` containing a dynamically sized type +/// like `HeaderSlice`, the `Arc` is represented on the stack +/// as a "fat pointer", where the length of the slice is stored +/// alongside the `Arc`'s pointer. In some situations you may wish to +/// 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 { + ptr: ptr::NonNull>>, + phantom: PhantomData<(H, T)>, +} + +impl fmt::Debug for ThinArc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.deref(), f) + } +} + +unsafe impl Send for ThinArc {} +unsafe impl Sync for ThinArc {} + +// Synthesize a fat pointer from a thin pointer. +// +// See the comment around the analogous operation in from_header_and_iter. +fn thin_to_thick( + thin: *mut ArcInner>, +) -> *mut ArcInner> { + let len = unsafe { (*thin).data.header.length }; + let fake_slice: *mut [T] = unsafe { slice::from_raw_parts_mut(thin as *mut T, len) }; + + fake_slice as *mut ArcInner> +} + +impl ThinArc { + /// Temporarily converts |self| into a bonafide Arc and exposes it to the + /// provided callback. The refcount is not modified. #[inline] + pub fn with_arc(&self, f: F) -> U + where + F: FnOnce(&Arc>) -> U, + { + // Synthesize transient Arc, which never touches the refcount of the ArcInner. + let transient = unsafe { + mem::ManuallyDrop::new(Arc { + p: ptr::NonNull::new_unchecked(thin_to_thick(self.ptr.as_ptr())), + phantom: PhantomData, + }) + }; + + // Expose the transient Arc to the callback, which may clone it if it wants. + let result = f(&transient); + + // Forward the result. + result + } + + /// Creates a `ThinArc` for a HeaderSlice using the given header struct and + /// iterator to generate the slice. pub fn from_header_and_iter(header: H, items: I) -> Self + where + I: Iterator + ExactSizeIterator, + { + let header = HeaderWithLength::new(header, items.len()); + Arc::into_thin(Arc::from_header_and_iter(header, items)) + } + + /// Create a static `ThinArc` for a HeaderSlice using the given header + /// struct and iterator to generate the slice, placing it in the allocation + /// provided by the specified `alloc` function. + /// + /// `alloc` must return a pointer into a static allocation suitable for + /// storing data with the `Layout` passed into it. The pointer returned by + /// `alloc` will not be freed. + pub unsafe fn static_from_header_and_iter(alloc: F, header: H, items: I) -> Self + where + F: FnOnce(Layout) -> *mut u8, + I: Iterator + ExactSizeIterator, + { + let len = items.len(); + let header = HeaderWithLength::new(header, len); + Arc::into_thin(Arc::from_header_and_iter_alloc( + alloc, header, items, len, /* is_static = */ true, + )) + } + + /// Returns the address on the heap of the ThinArc itself -- not the T + /// within it -- for memory reporting, and bindings. + #[inline] + pub fn ptr(&self) -> *const c_void { + self.ptr.as_ptr() as *const ArcInner as *const c_void + } + + /// If this is a static ThinArc, this returns null. + #[inline] + pub fn heap_ptr(&self) -> *const c_void { + let is_static = + ThinArc::with_arc(self, |a| a.inner().count.load(Relaxed) == STATIC_REFCOUNT); + if is_static { + ptr::null() + } else { + self.ptr() + } + } +} + +impl Deref for ThinArc { + type Target = HeaderSliceWithLength; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &(*thin_to_thick(self.ptr.as_ptr())).data } + } +} + +impl Clone for ThinArc { + #[inline] + fn clone(&self) -> Self { + ThinArc::with_arc(self, |a| Arc::into_thin(a.clone())) + } +} + +impl Drop for ThinArc { + #[inline] + fn drop(&mut self) { + let _ = Arc::from_thin(ThinArc { + ptr: self.ptr, + phantom: PhantomData, + }); + } +} + +impl Arc> { + /// Converts an `Arc` into a `ThinArc`. This consumes the `Arc`, so the refcount + /// is not modified. + #[inline] + pub fn into_thin(a: Self) -> ThinArc { + assert_eq!( + a.header.length, + a.slice.len(), + "Length needs to be correct for ThinArc to work" + ); + let fat_ptr: *mut ArcInner> = a.ptr(); + mem::forget(a); + let thin_ptr = fat_ptr as *mut [usize] as *mut usize; + ThinArc { + ptr: unsafe { + ptr::NonNull::new_unchecked( + thin_ptr as *mut ArcInner>, + ) + }, + phantom: PhantomData, + } + } + + /// Converts a `ThinArc` into an `Arc`. This consumes the `ThinArc`, so the refcount + /// is not modified. + #[inline] + pub fn from_thin(a: ThinArc) -> Self { + let ptr = thin_to_thick(a.ptr.as_ptr()); + mem::forget(a); + unsafe { + Arc { + p: ptr::NonNull::new_unchecked(ptr), + phantom: PhantomData, + } + } + } +} + +impl UniqueArc> { + #[inline] + pub fn from_header_and_iter(header: HeaderWithLength, items: I) -> Self where I: Iterator + ExactSizeIterator, { @@ -890,7 +1049,7 @@ impl UniqueArc> { #[inline] pub fn from_header_and_iter_with_size( - header: H, + header: HeaderWithLength, items: I, num_items: usize, ) -> Self @@ -905,16 +1064,29 @@ impl UniqueArc> { /// Returns a mutable reference to the header. pub fn header_mut(&mut self) -> &mut H { // We know this to be uniquely owned - unsafe { &mut (*self.0.ptr()).data.header } + unsafe { &mut (*self.0.ptr()).data.header.header } } /// Returns a mutable reference to the slice. pub fn data_mut(&mut self) -> &mut [T] { // We know this to be uniquely owned - unsafe { (*self.0.ptr()).data.slice_mut() } + unsafe { &mut (*self.0.ptr()).data.slice } + } + + pub fn shareable_thin(self) -> ThinArc { + Arc::into_thin(self.0) } } +impl PartialEq for ThinArc { + #[inline] + fn eq(&self, other: &ThinArc) -> bool { + ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| *a == *b)) + } +} + +impl Eq for ThinArc {} + /// A "borrowed `Arc`". This is a pointer to /// a T that is known to have been allocated within an /// `Arc`. @@ -1135,7 +1307,7 @@ impl fmt::Debug for ArcUnion { #[cfg(test)] mod tests { - use super::{Arc, ThinArc}; + use super::{Arc, HeaderWithLength, ThinArc}; use std::clone::Clone; use std::ops::Drop; use std::sync::atomic; @@ -1154,9 +1326,13 @@ mod tests { #[test] fn empty_thin() { - let x = Arc::from_header_and_iter(100u32, std::iter::empty::()); - assert_eq!(x.header, 100); - assert!(x.slice().is_empty()); + let header = HeaderWithLength::new(100u32, 0); + let x = Arc::from_header_and_iter(header, std::iter::empty::()); + 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] @@ -1168,11 +1344,12 @@ mod tests { } // 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(0i32, items.into_iter()); - assert_eq!(a.len(), 2); - assert_eq!(a.slice()[0].i, 0xdead); - assert_eq!(a.slice()[1].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] @@ -1180,10 +1357,13 @@ mod tests { let mut canary = atomic::AtomicUsize::new(0); let c = Canary(&mut canary as *mut atomic::AtomicUsize); let v = vec![5, 6]; + let header = HeaderWithLength::new(c, v.len()); { - let x = Arc::from_header_and_iter(c, v.into_iter()); - let _ = x.clone(); + let x = Arc::into_thin(Arc::from_header_and_iter(header, v.into_iter())); + let y = ThinArc::with_arc(&x, |q| q.clone()); + let _ = y.clone(); let _ = x == x; + Arc::from_thin(x.clone()); } assert_eq!(canary.load(Acquire), 1); } diff --git a/style/values/computed/font.rs b/style/values/computed/font.rs index be0e940e6..68a4391cf 100644 --- a/style/values/computed/font.rs +++ b/style/values/computed/font.rs @@ -375,7 +375,7 @@ impl FontFamily { generic_font_family!(MOZ_EMOJI, MozEmoji); generic_font_family!(SYSTEM_UI, SystemUi); - let family = match generic { + match generic { GenericFontFamily::None => { debug_assert!(false, "Bogus caller!"); &*SERIF @@ -388,9 +388,7 @@ impl FontFamily { #[cfg(feature = "gecko")] GenericFontFamily::MozEmoji => &*MOZ_EMOJI, GenericFontFamily::SystemUi => &*SYSTEM_UI, - }; - debug_assert_eq!(*family.families.iter().next().unwrap(), SingleFontFamily::Generic(generic)); - family + } } } diff --git a/style_traits/arc_slice.rs b/style_traits/arc_slice.rs index 43f31cb28..1f10ed945 100644 --- a/style_traits/arc_slice.rs +++ b/style_traits/arc_slice.rs @@ -24,6 +24,9 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf}; const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3; /// A wrapper type for a refcounted slice using ThinArc. +/// +/// cbindgen:derive-eq=false +/// cbindgen:derive-neq=false #[repr(C)] #[derive(Debug, Eq, PartialEq, ToShmem)] pub struct ArcSlice(#[shmem(field_bound)] ThinArc); @@ -33,8 +36,8 @@ impl Deref for ArcSlice { #[inline] fn deref(&self) -> &Self::Target { - debug_assert_eq!(self.0.header, ARC_SLICE_CANARY); - self.0.slice() + debug_assert_eq!(self.0.header.header, ARC_SLICE_CANARY); + &self.0.slice } } @@ -108,9 +111,9 @@ impl ArcSlice { where I: Iterator + ExactSizeIterator, { - let arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items); - arc.mark_as_intentionally_leaked(); - ArcSlice(arc) + let thin_arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items); + thin_arc.with_arc(|a| a.mark_as_intentionally_leaked()); + ArcSlice(thin_arc) } /// Creates a value that can be passed via FFI, and forgets this value @@ -119,7 +122,7 @@ impl ArcSlice { #[allow(unsafe_code)] pub fn forget(self) -> ForgottenArcSlicePtr { let ret = unsafe { - ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.raw_ptr() as *const _ as *mut _)) + ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.ptr() as *const _ as *mut _)) }; mem::forget(self); ret @@ -130,14 +133,14 @@ impl ArcSlice { #[inline] pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void { let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone(); - let ptr = empty.0.raw_ptr(); + let ptr = empty.0.ptr(); std::mem::forget(empty); ptr as *mut _ } /// Returns whether there's only one reference to this ArcSlice. pub fn is_unique(&self) -> bool { - self.0.is_unique() + self.0.with_arc(|arc| arc.is_unique()) } } diff --git a/to_shmem/lib.rs b/to_shmem/lib.rs index 1e7069716..717209b7c 100644 --- a/to_shmem/lib.rs +++ b/to_shmem/lib.rs @@ -20,7 +20,7 @@ extern crate smallvec; extern crate string_cache; extern crate thin_vec; -use servo_arc::{Arc, HeaderSlice}; +use servo_arc::{Arc, ThinArc}; use smallbitvec::{InternalStorage, SmallBitVec}; use smallvec::{Array, SmallVec}; use std::alloc::Layout; @@ -463,7 +463,7 @@ impl ToShmem for Arc { } } -impl ToShmem for Arc> { +impl ToShmem for ThinArc { fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // We don't currently have any shared ThinArc values in stylesheets, // so don't support them for now. @@ -476,27 +476,26 @@ impl ToShmem for Arc> { // Make a clone of the Arc-owned header and slice values with all of // their heap allocations placed in the shared memory buffer. - let header = self.header.to_shmem(builder)?; - let mut values = Vec::with_capacity(self.len()); - for v in self.slice().iter() { + let header = self.header.header.to_shmem(builder)?; + let mut values = Vec::with_capacity(self.slice.len()); + for v in self.slice.iter() { values.push(v.to_shmem(builder)?); } // Create a new ThinArc with the shared value and have it place // its ArcInner in the shared memory buffer. - let len = values.len(); - let static_arc = Self::from_header_and_iter_alloc( - |layout| builder.alloc(layout), - ManuallyDrop::into_inner(header), - values.into_iter().map(ManuallyDrop::into_inner), - len, - /* is_static = */ true, - ); + unsafe { + let static_arc = ThinArc::static_from_header_and_iter( + |layout| builder.alloc(layout), + ManuallyDrop::into_inner(header), + values.into_iter().map(ManuallyDrop::into_inner), + ); - #[cfg(debug_assertions)] - builder.shared_values.insert(self.heap_ptr()); + #[cfg(debug_assertions)] + builder.shared_values.insert(self.heap_ptr()); - Ok(ManuallyDrop::new(static_arc)) + Ok(ManuallyDrop::new(static_arc)) + } } }