mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #17197 - bholley:nonzero_arc, r=Manishearth
Force the NonZero optimization for servo_arc and StrongRuleNode https://bugzilla.mozilla.org/show_bug.cgi?id=1370711 Also addressing followup feedback from https://bugzilla.mozilla.org/show_bug.cgi?id=1370107 <!-- 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/17197) <!-- Reviewable:end -->
This commit is contained in:
commit
ffc47e89b3
7 changed files with 142 additions and 88 deletions
|
@ -62,7 +62,7 @@ macro_rules! with_all_bounds {
|
||||||
/// NB: We need Clone so that we can derive(Clone) on struct with that
|
/// NB: We need Clone so that we can derive(Clone) on struct with that
|
||||||
/// are parameterized on SelectorImpl. See
|
/// are parameterized on SelectorImpl. See
|
||||||
/// https://github.com/rust-lang/rust/issues/26925
|
/// https://github.com/rust-lang/rust/issues/26925
|
||||||
pub trait SelectorImpl: Clone + Sized {
|
pub trait SelectorImpl: Clone + Sized + 'static {
|
||||||
type AttrValue: $($InSelector)*;
|
type AttrValue: $($InSelector)*;
|
||||||
type Identifier: $($InSelector)* + PrecomputedHash;
|
type Identifier: $($InSelector)* + PrecomputedHash;
|
||||||
type ClassName: $($InSelector)* + PrecomputedHash;
|
type ClassName: $($InSelector)* + PrecomputedHash;
|
||||||
|
|
|
@ -69,22 +69,64 @@ macro_rules! offset_of {
|
||||||
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
|
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
|
||||||
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
||||||
|
|
||||||
pub struct Arc<T: ?Sized> {
|
/// Wrapper type for pointers to get the non-zero optimization. When
|
||||||
// FIXME(bholley): When NonZero/Shared/Unique are stabilized, we should use
|
/// NonZero/Shared/Unique are stabilized, we should just use Shared
|
||||||
// Shared here to get the NonZero optimization. Gankro is working on this.
|
/// here to get the same effect. Gankro is working on this in [1].
|
||||||
//
|
///
|
||||||
// If we need a compact Option<Arc<T>> beforehand, we can make a helper
|
/// It's unfortunate that this needs to infect all the caller types
|
||||||
// class that wraps the result of Arc::into_raw.
|
/// with 'static. It would be nice to just use a &() and a PhantomData<T>
|
||||||
//
|
/// instead, but then the compiler can't determine whether the &() should
|
||||||
// https://github.com/rust-lang/rust/issues/27730
|
/// be thin or fat (which depends on whether or not T is sized). Given
|
||||||
ptr: *mut ArcInner<T>,
|
/// that this is all a temporary hack, this restriction is fine for now.
|
||||||
|
///
|
||||||
|
/// [1] https://github.com/rust-lang/rust/issues/27730
|
||||||
|
pub struct NonZeroPtrMut<T: ?Sized + 'static>(&'static mut T);
|
||||||
|
impl<T: ?Sized> NonZeroPtrMut<T> {
|
||||||
|
pub fn new(ptr: *mut T) -> Self {
|
||||||
|
assert!(!(ptr as *mut u8).is_null());
|
||||||
|
NonZeroPtrMut(unsafe { mem::transmute(ptr) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr(&self) -> *mut T {
|
||||||
|
self.0 as *const T as *mut T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> Clone for NonZeroPtrMut<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
NonZeroPtrMut::new(self.ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> fmt::Pointer for NonZeroPtrMut<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Pointer::fmt(&self.ptr(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> fmt::Debug for NonZeroPtrMut<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
<Self as fmt::Pointer>::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> PartialEq for NonZeroPtrMut<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ptr() == other.ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> Eq for NonZeroPtrMut<T> {}
|
||||||
|
|
||||||
|
pub struct Arc<T: ?Sized + 'static> {
|
||||||
|
p: NonZeroPtrMut<ArcInner<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An Arc that is known to be uniquely owned
|
/// An Arc that is known to be uniquely owned
|
||||||
///
|
///
|
||||||
/// This lets us build arcs that we can mutate before
|
/// This lets us build arcs that we can mutate before
|
||||||
/// freezing, without needing to change the allocation
|
/// freezing, without needing to change the allocation
|
||||||
pub struct UniqueArc<T: ?Sized>(Arc<T>);
|
pub struct UniqueArc<T: ?Sized + 'static>(Arc<T>);
|
||||||
|
|
||||||
impl<T> UniqueArc<T> {
|
impl<T> UniqueArc<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -110,7 +152,7 @@ impl<T> Deref for UniqueArc<T> {
|
||||||
impl<T> DerefMut for UniqueArc<T> {
|
impl<T> DerefMut for UniqueArc<T> {
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
// We know this to be uniquely owned
|
// We know this to be uniquely owned
|
||||||
unsafe { &mut (*self.0.ptr).data }
|
unsafe { &mut (*self.0.ptr()).data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +174,11 @@ impl<T> Arc<T> {
|
||||||
count: atomic::AtomicUsize::new(1),
|
count: atomic::AtomicUsize::new(1),
|
||||||
data: data,
|
data: data,
|
||||||
});
|
});
|
||||||
Arc { ptr: Box::into_raw(x) }
|
Arc { p: NonZeroPtrMut::new(Box::into_raw(x)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_raw(this: Self) -> *const T {
|
pub fn into_raw(this: Self) -> *const T {
|
||||||
let ptr = unsafe { &((*this.ptr).data) as *const _ };
|
let ptr = unsafe { &((*this.ptr()).data) as *const _ };
|
||||||
mem::forget(this);
|
mem::forget(this);
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
@ -146,7 +188,7 @@ impl<T> Arc<T> {
|
||||||
// to subtract the offset of the `data` field from the pointer.
|
// to subtract the offset of the `data` field from the pointer.
|
||||||
let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data));
|
let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data));
|
||||||
Arc {
|
Arc {
|
||||||
ptr: ptr as *mut ArcInner<T>,
|
p: NonZeroPtrMut::new(ptr as *mut ArcInner<T>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,19 +201,23 @@ impl<T: ?Sized> Arc<T> {
|
||||||
// `ArcInner` structure itself is `Sync` because the inner data is
|
// `ArcInner` structure itself is `Sync` because the inner data is
|
||||||
// `Sync` as well, so we're ok loaning out an immutable pointer to these
|
// `Sync` as well, so we're ok loaning out an immutable pointer to these
|
||||||
// contents.
|
// contents.
|
||||||
unsafe { &*self.ptr }
|
unsafe { &*self.ptr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-inlined part of `drop`. Just invokes the destructor.
|
// Non-inlined part of `drop`. Just invokes the destructor.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe fn drop_slow(&mut self) {
|
unsafe fn drop_slow(&mut self) {
|
||||||
let _ = Box::from_raw(self.ptr);
|
let _ = Box::from_raw(self.ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||||
this.ptr == other.ptr
|
this.ptr() == other.ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ptr(&self) -> *mut ArcInner<T> {
|
||||||
|
self.p.ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +256,7 @@ impl<T: ?Sized> Clone for Arc<T> {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
Arc { ptr: self.ptr }
|
Arc { p: NonZeroPtrMut::new(self.ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +283,7 @@ impl<T: Clone> Arc<T> {
|
||||||
// reference count is guaranteed to be 1 at this point, and we required
|
// reference count is guaranteed to be 1 at this point, and we required
|
||||||
// the Arc itself to be `mut`, so we're returning the only possible
|
// the Arc itself to be `mut`, so we're returning the only possible
|
||||||
// reference to the inner data.
|
// reference to the inner data.
|
||||||
&mut (*this.ptr).data
|
&mut (*this.ptr()).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +294,7 @@ impl<T: ?Sized> Arc<T> {
|
||||||
if this.is_unique() {
|
if this.is_unique() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// See make_mut() for documentation of the threadsafety here.
|
// See make_mut() for documentation of the threadsafety here.
|
||||||
Some(&mut (*this.ptr).data)
|
Some(&mut (*this.ptr()).data)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -357,7 +403,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Arc<T> {
|
||||||
|
|
||||||
impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Pointer::fmt(&self.ptr, f)
|
fmt::Pointer::fmt(&self.ptr(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,6 +527,8 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
//
|
//
|
||||||
// To avoid alignment issues, we allocate words rather than bytes,
|
// To avoid alignment issues, we allocate words rather than bytes,
|
||||||
// rounding up to the nearest word size.
|
// rounding up to the nearest word size.
|
||||||
|
assert!(mem::align_of::<T>() <= mem::align_of::<usize>(),
|
||||||
|
"We don't handle over-aligned types");
|
||||||
let words_to_allocate = divide_rounding_up(size, size_of::<usize>());
|
let words_to_allocate = divide_rounding_up(size, size_of::<usize>());
|
||||||
let mut vec = Vec::<usize>::with_capacity(words_to_allocate);
|
let mut vec = Vec::<usize>::with_capacity(words_to_allocate);
|
||||||
vec.set_len(words_to_allocate);
|
vec.set_len(words_to_allocate);
|
||||||
|
@ -496,6 +544,9 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
ptr = fake_slice as *mut [T] as *mut ArcInner<HeaderSlice<H, [T]>>;
|
ptr = fake_slice as *mut [T] as *mut ArcInner<HeaderSlice<H, [T]>>;
|
||||||
|
|
||||||
// Write the data.
|
// Write the data.
|
||||||
|
//
|
||||||
|
// Note that any panics here (i.e. from the iterator) are safe, since
|
||||||
|
// we'll just leak the uninitialized memory.
|
||||||
ptr::write(&mut ((*ptr).count), atomic::AtomicUsize::new(1));
|
ptr::write(&mut ((*ptr).count), atomic::AtomicUsize::new(1));
|
||||||
ptr::write(&mut ((*ptr).data.header), header);
|
ptr::write(&mut ((*ptr).data.header), header);
|
||||||
let mut current: *mut T = &mut (*ptr).data.slice[0];
|
let mut current: *mut T = &mut (*ptr).data.slice[0];
|
||||||
|
@ -511,7 +562,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
|
|
||||||
// Return the fat Arc.
|
// Return the fat Arc.
|
||||||
assert_eq!(size_of::<Self>(), size_of::<usize>() * 2, "The Arc will be fat");
|
assert_eq!(size_of::<Self>(), size_of::<usize>() * 2, "The Arc will be fat");
|
||||||
Arc { ptr: ptr }
|
Arc { p: NonZeroPtrMut::new(ptr) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,8 +587,9 @@ impl<H> HeaderWithLength<H> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ThinArc<H, T> {
|
type HeaderSliceWithLength<H, T> = HeaderSlice<HeaderWithLength<H>, T>;
|
||||||
ptr: *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T; 1]>>,
|
pub struct ThinArc<H: 'static, T: 'static> {
|
||||||
|
ptr: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<H: Sync + Send, T: Sync + Send> Send for ThinArc<H, T> {}
|
unsafe impl<H: Sync + Send, T: Sync + Send> Send for ThinArc<H, T> {}
|
||||||
|
@ -546,27 +598,27 @@ unsafe impl<H: Sync + Send, T: Sync + Send> Sync for ThinArc<H, T> {}
|
||||||
// Synthesize a fat pointer from a thin pointer.
|
// Synthesize a fat pointer from a thin pointer.
|
||||||
//
|
//
|
||||||
// See the comment around the analogous operation in from_header_and_iter.
|
// See the comment around the analogous operation in from_header_and_iter.
|
||||||
fn thin_to_thick<H, T>(thin: *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T; 1]>>)
|
fn thin_to_thick<H, T>(thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>)
|
||||||
-> *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T]>>
|
-> *mut ArcInner<HeaderSliceWithLength<H, [T]>>
|
||||||
{
|
{
|
||||||
let len = unsafe { (*thin).data.header.length };
|
let len = unsafe { (*thin).data.header.length };
|
||||||
let fake_slice: *mut [T] = unsafe {
|
let fake_slice: *mut [T] = unsafe {
|
||||||
slice::from_raw_parts_mut(thin as *mut T, len)
|
slice::from_raw_parts_mut(thin as *mut T, len)
|
||||||
};
|
};
|
||||||
|
|
||||||
fake_slice as *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T]>>
|
fake_slice as *mut ArcInner<HeaderSliceWithLength<H, [T]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> ThinArc<H, T> {
|
impl<H: 'static, T: 'static> ThinArc<H, T> {
|
||||||
/// Temporarily converts |self| into a bonafide Arc and exposes it to the
|
/// Temporarily converts |self| into a bonafide Arc and exposes it to the
|
||||||
/// provided callback. The refcount is not modified.
|
/// provided callback. The refcount is not modified.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_arc<F, U>(&self, f: F) -> U
|
pub fn with_arc<F, U>(&self, f: F) -> U
|
||||||
where F: FnOnce(&Arc<HeaderSlice<HeaderWithLength<H>, [T]>>) -> U
|
where F: FnOnce(&Arc<HeaderSliceWithLength<H, [T]>>) -> U
|
||||||
{
|
{
|
||||||
// Synthesize transient Arc, which never touches the refcount of the ArcInner.
|
// Synthesize transient Arc, which never touches the refcount of the ArcInner.
|
||||||
let transient = NoDrop::new(Arc {
|
let transient = NoDrop::new(Arc {
|
||||||
ptr: thin_to_thick(self.ptr)
|
p: NonZeroPtrMut::new(thin_to_thick(self.ptr))
|
||||||
});
|
});
|
||||||
|
|
||||||
// Expose the transient Arc to the callback, which may clone it if it wants.
|
// Expose the transient Arc to the callback, which may clone it if it wants.
|
||||||
|
@ -581,35 +633,35 @@ impl<H, T> ThinArc<H, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> Deref for ThinArc<H, T> {
|
impl<H, T> Deref for ThinArc<H, T> {
|
||||||
type Target = HeaderSlice<HeaderWithLength<H>, [T]>;
|
type Target = HeaderSliceWithLength<H, [T]>;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
unsafe { &(*thin_to_thick(self.ptr)).data }
|
unsafe { &(*thin_to_thick(self.ptr)).data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> Clone for ThinArc<H, T> {
|
impl<H: 'static, T: 'static> Clone for ThinArc<H, T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ThinArc::with_arc(self, |a| Arc::into_thin(a.clone()))
|
ThinArc::with_arc(self, |a| Arc::into_thin(a.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> Drop for ThinArc<H, T> {
|
impl<H: 'static, T: 'static> Drop for ThinArc<H, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = Arc::from_thin(ThinArc { ptr: self.ptr });
|
let _ = Arc::from_thin(ThinArc { ptr: self.ptr });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> Arc<HeaderSlice<HeaderWithLength<H>, [T]>> {
|
impl<H: 'static, T: 'static> Arc<HeaderSliceWithLength<H, [T]>> {
|
||||||
/// Converts an Arc into a ThinArc. This consumes the Arc, so the refcount
|
/// Converts an Arc into a ThinArc. This consumes the Arc, so the refcount
|
||||||
/// is not modified.
|
/// is not modified.
|
||||||
pub fn into_thin(a: Self) -> ThinArc<H, T> {
|
pub fn into_thin(a: Self) -> ThinArc<H, T> {
|
||||||
assert!(a.header.length == a.slice.len(),
|
assert!(a.header.length == a.slice.len(),
|
||||||
"Length needs to be correct for ThinArc to work");
|
"Length needs to be correct for ThinArc to work");
|
||||||
let fat_ptr: *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T]>> = a.ptr;
|
let fat_ptr: *mut ArcInner<HeaderSliceWithLength<H, [T]>> = a.ptr();
|
||||||
mem::forget(a);
|
mem::forget(a);
|
||||||
let thin_ptr = fat_ptr as *mut [usize] as *mut usize;
|
let thin_ptr = fat_ptr as *mut [usize] as *mut usize;
|
||||||
ThinArc {
|
ThinArc {
|
||||||
ptr: thin_ptr as *mut ArcInner<HeaderSlice<HeaderWithLength<H>, [T; 1]>>
|
ptr: thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,12 +671,12 @@ impl<H, T> Arc<HeaderSlice<HeaderWithLength<H>, [T]>> {
|
||||||
let ptr = thin_to_thick(a.ptr);
|
let ptr = thin_to_thick(a.ptr);
|
||||||
mem::forget(a);
|
mem::forget(a);
|
||||||
Arc {
|
Arc {
|
||||||
ptr: ptr
|
p: NonZeroPtrMut::new(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: PartialEq, T: PartialEq> PartialEq for ThinArc<H, T> {
|
impl<H: PartialEq + 'static, T: PartialEq + 'static> PartialEq for ThinArc<H, T> {
|
||||||
fn eq(&self, other: &ThinArc<H, T>) -> bool {
|
fn eq(&self, other: &ThinArc<H, T>) -> bool {
|
||||||
ThinArc::with_arc(self, |a| {
|
ThinArc::with_arc(self, |a| {
|
||||||
ThinArc::with_arc(other, |b| {
|
ThinArc::with_arc(other, |b| {
|
||||||
|
@ -634,7 +686,7 @@ impl<H: PartialEq, T: PartialEq> PartialEq for ThinArc<H, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Eq, T: Eq> Eq for ThinArc<H, T> {}
|
impl<H: Eq + 'static, T: Eq + 'static> Eq for ThinArc<H, T> {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -649,13 +701,7 @@ mod tests {
|
||||||
|
|
||||||
impl Drop for Canary {
|
impl Drop for Canary {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe { (*self.0).fetch_add(1, SeqCst); }
|
||||||
match *self {
|
|
||||||
Canary(c) => {
|
|
||||||
(*c).fetch_add(1, SeqCst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::ptr;
|
||||||
use stylearc::Arc;
|
use stylearc::Arc;
|
||||||
|
|
||||||
/// Indicates that a given Servo type has a corresponding Gecko FFI type.
|
/// Indicates that a given Servo type has a corresponding Gecko FFI type.
|
||||||
pub unsafe trait HasFFI : Sized {
|
pub unsafe trait HasFFI : Sized + 'static {
|
||||||
/// The corresponding Gecko type that this rust type represents.
|
/// The corresponding Gecko type that this rust type represents.
|
||||||
///
|
///
|
||||||
/// See the examples in `components/style/gecko/conversions.rs`.
|
/// See the examples in `components/style/gecko/conversions.rs`.
|
||||||
|
|
|
@ -2193,7 +2193,7 @@ pub fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> Wri
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reference to a style struct of the parent, or our own style struct.
|
/// A reference to a style struct of the parent, or our own style struct.
|
||||||
pub enum StyleStructRef<'a, T: 'a> {
|
pub enum StyleStructRef<'a, T: 'static> {
|
||||||
/// A borrowed struct from the parent, for example, for inheriting style.
|
/// A borrowed struct from the parent, for example, for inheriting style.
|
||||||
Borrowed(&'a Arc<T>),
|
Borrowed(&'a Arc<T>),
|
||||||
/// An owned struct, that we've already mutated.
|
/// An owned struct, that we've already mutated.
|
||||||
|
|
|
@ -14,7 +14,7 @@ use smallvec::SmallVec;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||||
use stylearc::Arc;
|
use stylearc::{Arc, NonZeroPtrMut};
|
||||||
use stylesheets::StyleRule;
|
use stylesheets::StyleRule;
|
||||||
use stylist::ApplicableDeclarationList;
|
use stylist::ApplicableDeclarationList;
|
||||||
use thread_state;
|
use thread_state;
|
||||||
|
@ -637,7 +637,7 @@ impl RuleNode {
|
||||||
current: if first_child.is_null() {
|
current: if first_child.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(WeakRuleNode { ptr: first_child })
|
Some(WeakRuleNode::from_ptr(first_child))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,15 +645,13 @@ impl RuleNode {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct WeakRuleNode {
|
struct WeakRuleNode {
|
||||||
ptr: *mut RuleNode,
|
p: NonZeroPtrMut<RuleNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A strong reference to a rule node.
|
/// A strong reference to a rule node.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct StrongRuleNode {
|
pub struct StrongRuleNode {
|
||||||
// TODO: Mark this as NonZero once stable to save space inside Option.
|
p: NonZeroPtrMut<RuleNode>,
|
||||||
// https://github.com/rust-lang/rust/issues/27730
|
|
||||||
ptr: *mut RuleNode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
@ -670,15 +668,17 @@ impl StrongRuleNode {
|
||||||
|
|
||||||
debug!("Creating rule node: {:p}", ptr);
|
debug!("Creating rule node: {:p}", ptr);
|
||||||
|
|
||||||
|
StrongRuleNode::from_ptr(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ptr(ptr: *mut RuleNode) -> Self {
|
||||||
StrongRuleNode {
|
StrongRuleNode {
|
||||||
ptr: ptr,
|
p: NonZeroPtrMut::new(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downgrade(&self) -> WeakRuleNode {
|
fn downgrade(&self) -> WeakRuleNode {
|
||||||
WeakRuleNode {
|
WeakRuleNode::from_ptr(self.ptr())
|
||||||
ptr: self.ptr,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_sibling(&self) -> Option<WeakRuleNode> {
|
fn next_sibling(&self) -> Option<WeakRuleNode> {
|
||||||
|
@ -688,9 +688,7 @@ impl StrongRuleNode {
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(WeakRuleNode {
|
Some(WeakRuleNode::from_ptr(ptr))
|
||||||
ptr: ptr
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,7 +746,7 @@ impl StrongRuleNode {
|
||||||
|
|
||||||
// Existing is not null: some thread inserted a child node since
|
// Existing is not null: some thread inserted a child node since
|
||||||
// we accessed `last`.
|
// we accessed `last`.
|
||||||
strong = WeakRuleNode { ptr: existing }.upgrade();
|
strong = WeakRuleNode::from_ptr(existing).upgrade();
|
||||||
|
|
||||||
if strong.get().source.as_ref().unwrap().ptr_equals(&source) {
|
if strong.get().source.as_ref().unwrap().ptr_equals(&source) {
|
||||||
// That node happens to be for the same style source, use
|
// That node happens to be for the same style source, use
|
||||||
|
@ -764,15 +762,15 @@ impl StrongRuleNode {
|
||||||
|
|
||||||
/// Raw pointer to the RuleNode
|
/// Raw pointer to the RuleNode
|
||||||
pub fn ptr(&self) -> *mut RuleNode {
|
pub fn ptr(&self) -> *mut RuleNode {
|
||||||
self.ptr
|
self.p.ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self) -> &RuleNode {
|
fn get(&self) -> &RuleNode {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let node = unsafe { &*self.ptr };
|
let node = unsafe { &*self.ptr() };
|
||||||
assert!(node.refcount.load(Ordering::Relaxed) > 0);
|
assert!(node.refcount.load(Ordering::Relaxed) > 0);
|
||||||
}
|
}
|
||||||
unsafe { &*self.ptr }
|
unsafe { &*self.ptr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the style source corresponding to this rule node. May return `None`
|
/// Get the style source corresponding to this rule node. May return `None`
|
||||||
|
@ -808,7 +806,7 @@ impl StrongRuleNode {
|
||||||
unsafe fn pop_from_free_list(&self) -> Option<WeakRuleNode> {
|
unsafe fn pop_from_free_list(&self) -> Option<WeakRuleNode> {
|
||||||
// NB: This can run from the root node destructor, so we can't use
|
// NB: This can run from the root node destructor, so we can't use
|
||||||
// `get()`, since it asserts the refcount is bigger than zero.
|
// `get()`, since it asserts the refcount is bigger than zero.
|
||||||
let me = &*self.ptr;
|
let me = &*self.ptr();
|
||||||
|
|
||||||
debug_assert!(me.is_root());
|
debug_assert!(me.is_root());
|
||||||
|
|
||||||
|
@ -831,7 +829,7 @@ impl StrongRuleNode {
|
||||||
debug_assert!(!current.is_null(),
|
debug_assert!(!current.is_null(),
|
||||||
"Multiple threads are operating on the free list at the \
|
"Multiple threads are operating on the free list at the \
|
||||||
same time?");
|
same time?");
|
||||||
debug_assert!(current != self.ptr,
|
debug_assert!(current != self.ptr(),
|
||||||
"How did the root end up in the free list?");
|
"How did the root end up in the free list?");
|
||||||
|
|
||||||
let next = (*current).next_free.swap(ptr::null_mut(), Ordering::Relaxed);
|
let next = (*current).next_free.swap(ptr::null_mut(), Ordering::Relaxed);
|
||||||
|
@ -843,17 +841,17 @@ impl StrongRuleNode {
|
||||||
|
|
||||||
debug!("Popping from free list: cur: {:?}, next: {:?}", current, next);
|
debug!("Popping from free list: cur: {:?}, next: {:?}", current, next);
|
||||||
|
|
||||||
Some(WeakRuleNode { ptr: current })
|
Some(WeakRuleNode::from_ptr(current))
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn assert_free_list_has_no_duplicates_or_null(&self) {
|
unsafe fn assert_free_list_has_no_duplicates_or_null(&self) {
|
||||||
assert!(cfg!(debug_assertions), "This is an expensive check!");
|
assert!(cfg!(debug_assertions), "This is an expensive check!");
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
let me = &*self.ptr;
|
let me = &*self.ptr();
|
||||||
assert!(me.is_root());
|
assert!(me.is_root());
|
||||||
|
|
||||||
let mut current = self.ptr;
|
let mut current = self.ptr();
|
||||||
let mut seen = HashSet::new();
|
let mut seen = HashSet::new();
|
||||||
while current != FREE_LIST_SENTINEL {
|
while current != FREE_LIST_SENTINEL {
|
||||||
let next = (*current).next_free.load(Ordering::Relaxed);
|
let next = (*current).next_free.load(Ordering::Relaxed);
|
||||||
|
@ -872,7 +870,7 @@ impl StrongRuleNode {
|
||||||
|
|
||||||
// NB: This can run from the root node destructor, so we can't use
|
// NB: This can run from the root node destructor, so we can't use
|
||||||
// `get()`, since it asserts the refcount is bigger than zero.
|
// `get()`, since it asserts the refcount is bigger than zero.
|
||||||
let me = &*self.ptr;
|
let me = &*self.ptr();
|
||||||
|
|
||||||
debug_assert!(me.is_root(), "Can't call GC on a non-root node!");
|
debug_assert!(me.is_root(), "Can't call GC on a non-root node!");
|
||||||
|
|
||||||
|
@ -1237,19 +1235,17 @@ impl Clone for StrongRuleNode {
|
||||||
debug!("{:?}: {:?}+", self.ptr(), self.get().refcount.load(Ordering::Relaxed));
|
debug!("{:?}: {:?}+", self.ptr(), self.get().refcount.load(Ordering::Relaxed));
|
||||||
debug_assert!(self.get().refcount.load(Ordering::Relaxed) > 0);
|
debug_assert!(self.get().refcount.load(Ordering::Relaxed) > 0);
|
||||||
self.get().refcount.fetch_add(1, Ordering::Relaxed);
|
self.get().refcount.fetch_add(1, Ordering::Relaxed);
|
||||||
StrongRuleNode {
|
StrongRuleNode::from_ptr(self.ptr())
|
||||||
ptr: self.ptr,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for StrongRuleNode {
|
impl Drop for StrongRuleNode {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let node = unsafe { &*self.ptr };
|
let node = unsafe { &*self.ptr() };
|
||||||
|
|
||||||
debug!("{:?}: {:?}-", self.ptr(), node.refcount.load(Ordering::Relaxed));
|
debug!("{:?}: {:?}-", self.ptr(), node.refcount.load(Ordering::Relaxed));
|
||||||
debug!("Dropping node: {:?}, root: {:?}, parent: {:?}",
|
debug!("Dropping node: {:?}, root: {:?}, parent: {:?}",
|
||||||
self.ptr,
|
self.ptr(),
|
||||||
node.root.as_ref().map(|r| r.ptr()),
|
node.root.as_ref().map(|r| r.ptr()),
|
||||||
node.parent.as_ref().map(|p| p.ptr()));
|
node.parent.as_ref().map(|p| p.ptr()));
|
||||||
let should_drop = {
|
let should_drop = {
|
||||||
|
@ -1330,9 +1326,7 @@ impl Drop for StrongRuleNode {
|
||||||
|
|
||||||
impl<'a> From<&'a StrongRuleNode> for WeakRuleNode {
|
impl<'a> From<&'a StrongRuleNode> for WeakRuleNode {
|
||||||
fn from(node: &'a StrongRuleNode) -> Self {
|
fn from(node: &'a StrongRuleNode) -> Self {
|
||||||
WeakRuleNode {
|
WeakRuleNode::from_ptr(node.ptr())
|
||||||
ptr: node.ptr(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,15 +1334,19 @@ impl WeakRuleNode {
|
||||||
fn upgrade(&self) -> StrongRuleNode {
|
fn upgrade(&self) -> StrongRuleNode {
|
||||||
debug!("Upgrading weak node: {:p}", self.ptr());
|
debug!("Upgrading weak node: {:p}", self.ptr());
|
||||||
|
|
||||||
let node = unsafe { &*self.ptr };
|
let node = unsafe { &*self.ptr() };
|
||||||
node.refcount.fetch_add(1, Ordering::Relaxed);
|
node.refcount.fetch_add(1, Ordering::Relaxed);
|
||||||
StrongRuleNode {
|
StrongRuleNode::from_ptr(self.ptr())
|
||||||
ptr: self.ptr,
|
}
|
||||||
|
|
||||||
|
fn from_ptr(ptr: *mut RuleNode) -> Self {
|
||||||
|
WeakRuleNode {
|
||||||
|
p: NonZeroPtrMut::new(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr(&self) -> *mut RuleNode {
|
fn ptr(&self) -> *mut RuleNode {
|
||||||
self.ptr
|
self.p.ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,10 @@ macro_rules! sizeof_checker (
|
||||||
// Update the sizes here
|
// Update the sizes here
|
||||||
sizeof_checker!(size_event_target, EventTarget, 40);
|
sizeof_checker!(size_event_target, EventTarget, 40);
|
||||||
sizeof_checker!(size_node, Node, 184);
|
sizeof_checker!(size_node, Node, 184);
|
||||||
sizeof_checker!(size_element, Element, 352);
|
sizeof_checker!(size_element, Element, 344);
|
||||||
sizeof_checker!(size_htmlelement, HTMLElement, 368);
|
sizeof_checker!(size_htmlelement, HTMLElement, 360);
|
||||||
sizeof_checker!(size_div, HTMLDivElement, 368);
|
sizeof_checker!(size_div, HTMLDivElement, 360);
|
||||||
sizeof_checker!(size_span, HTMLSpanElement, 368);
|
sizeof_checker!(size_span, HTMLSpanElement, 360);
|
||||||
sizeof_checker!(size_text, Text, 216);
|
sizeof_checker!(size_text, Text, 216);
|
||||||
sizeof_checker!(size_characterdata, CharacterData, 216);
|
sizeof_checker!(size_characterdata, CharacterData, 216);
|
||||||
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
||||||
|
|
|
@ -3,9 +3,13 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use selectors::gecko_like_types as dummies;
|
use selectors::gecko_like_types as dummies;
|
||||||
|
use servo_arc::Arc;
|
||||||
use std::mem::{size_of, align_of};
|
use std::mem::{size_of, align_of};
|
||||||
use style;
|
use style;
|
||||||
|
use style::data::{ComputedStyle, ElementData, ElementStyles};
|
||||||
use style::gecko::selector_parser as real;
|
use style::gecko::selector_parser as real;
|
||||||
|
use style::properties::ComputedValues;
|
||||||
|
use style::rule_tree::StrongRuleNode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn size_of_selectors_dummy_types() {
|
fn size_of_selectors_dummy_types() {
|
||||||
|
@ -24,6 +28,12 @@ fn size_of_selectors_dummy_types() {
|
||||||
// selectors (with the inline hashes) with as few cache misses as possible.
|
// selectors (with the inline hashes) with as few cache misses as possible.
|
||||||
size_of_test!(test_size_of_rule, style::stylist::Rule, 40);
|
size_of_test!(test_size_of_rule, style::stylist::Rule, 40);
|
||||||
|
|
||||||
|
size_of_test!(test_size_of_option_arc_cv, Option<Arc<ComputedValues>>, 8);
|
||||||
|
size_of_test!(test_size_of_option_rule_node, Option<StrongRuleNode>, 8);
|
||||||
|
size_of_test!(test_size_of_computed_style, ComputedStyle, 32);
|
||||||
|
size_of_test!(test_size_of_element_styles, ElementStyles, 48);
|
||||||
|
size_of_test!(test_size_of_element_data, ElementData, 56);
|
||||||
|
|
||||||
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
|
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
|
||||||
|
|
||||||
// This is huge, but we allocate it on the stack and then never move it,
|
// This is huge, but we allocate it on the stack and then never move it,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue