Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: sync changes from mozilla-central #23503

Merged
merged 17 commits into from Jun 4, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

style: Add refcount logging to servo_arc.

  • Loading branch information
emilio committed Jun 4, 2019
commit 9a9a4e12d51c983db25e3517332f3f7346ef7b22
@@ -12,6 +12,7 @@ path = "lib.rs"

[features]
servo = ["serde"]
gecko = []

[dependencies]
nodrop = {version = "0.1.8"}
@@ -42,7 +42,7 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::{ExactSizeIterator, Iterator};
use std::marker::PhantomData;
use std::mem;
use std::mem::{self, align_of, size_of};
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
use std::process;
@@ -115,7 +115,10 @@ pub struct Arc<T: ?Sized> {
/// Once the mutation is finished, you can call `.shareable()` and get a regular `Arc`
/// out of it.
///
/// ```rust
/// Ignore the doctest below there's no way to skip building with refcount
/// logging during doc tests (see rust-lang/rust#45599).
///
/// ```rust,ignore
/// # use servo_arc::UniqueArc;
/// let data = [1, 2, 3, 4, 5];
/// let mut x = UniqueArc::new(data);
@@ -169,18 +172,35 @@ impl<T> Arc<T> {
/// Construct an `Arc<T>`
#[inline]
pub fn new(data: T) -> Self {
let x = Box::new(ArcInner {
let ptr = Box::into_raw(Box::new(ArcInner {
count: atomic::AtomicUsize::new(1),
data,
});
}));

#[cfg(all(feature = "gecko", debug_assertions))]
unsafe {
// FIXME(emilio): Would be so amazing to have
// std::intrinsics::type_name() around, so that we could also report
// a real size.
NS_LogCtor(ptr as *const _, b"ServoArc\0".as_ptr() as *const _, 8);
}

unsafe {
Arc {
p: ptr::NonNull::new_unchecked(Box::into_raw(x)),
p: ptr::NonNull::new_unchecked(ptr),
phantom: PhantomData,
}
}
}

/// Construct an intentionally-leaked arc.
#[inline]
pub fn new_leaked(data: T) -> Self {
let arc = Self::new(data);
arc.mark_as_intentionally_leaked();
arc
}

/// Convert the Arc<T> to a raw pointer, suitable for use across FFI
///
/// Note: This returns a pointer to the data T, which is offset in the allocation.
@@ -290,9 +310,29 @@ impl<T: ?Sized> Arc<T> {
unsafe { &*self.ptr() }
}

// Non-inlined part of `drop`. Just invokes the destructor.
#[inline(always)]
fn record_drop(&self) {
#[cfg(all(feature = "gecko", debug_assertions))]
unsafe {
NS_LogDtor(self.ptr() as *const _, b"ServoArc\0".as_ptr() as *const _, 8);
}
}

/// Marks this `Arc` as intentionally leaked for the purposes of refcount
/// logging.
///
/// It's a logic error to call this more than once, but it's not unsafe, as
/// it'd just report negative leaks.
#[inline(always)]
pub fn mark_as_intentionally_leaked(&self) {
self.record_drop();
}

// Non-inlined part of `drop`. Just invokes the destructor and calls the
// refcount logging machinery if enabled.
#[inline(never)]
unsafe fn drop_slow(&mut self) {
self.record_drop();
let _ = Box::from_raw(self.ptr());
}

@@ -308,6 +348,12 @@ impl<T: ?Sized> Arc<T> {
}
}

#[cfg(all(feature = "gecko", debug_assertions))]
extern "C" {
fn NS_LogCtor(aPtr: *const std::os::raw::c_void, aTypeName: *const std::os::raw::c_char, aSize: u32);
fn NS_LogDtor(aPtr: *const std::os::raw::c_void, aTypeName: *const std::os::raw::c_char, aSize: u32);
}

impl<T: ?Sized> Clone for Arc<T> {
#[inline]
fn clone(&self) -> Self {
@@ -612,7 +658,6 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
F: FnOnce(Layout) -> *mut u8,
I: Iterator<Item = T> + ExactSizeIterator,
{
use std::mem::{align_of, size_of};
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");

let inner_align = align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
@@ -700,6 +745,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
);
}

#[cfg(all(feature = "gecko", debug_assertions))]
unsafe {
if !is_static {
// FIXME(emilio): Would be so amazing to have
// std::intrinsics::type_name() around.
NS_LogCtor(ptr as *const _, b"ServoArc\0".as_ptr() as *const _, 8)
}
}

// Return the fat Arc.
assert_eq!(
size_of::<Self>(),
@@ -19,7 +19,7 @@ thread_local! {
/// such that they can be reused across style traversals. StyleBloom is responsible
/// for ensuring that the bloom filter is zeroed when it is dropped.
static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
Arc::new(AtomicRefCell::new(BloomFilter::new()));
Arc::new_leaked(AtomicRefCell::new(BloomFilter::new()));
}

/// A struct that allows us to fast-reject deep descendant selectors avoiding
@@ -1736,7 +1736,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::TextAlign(SpecifiedTextAlign::MozCenterOrInherit),
Importance::Normal,
);
let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
static ref TABLE_COLOR_RULE: ApplicableDeclarationBlock = {
@@ -1745,7 +1745,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::Color(SpecifiedColor(Color::InheritFromBodyQuirk.into())),
Importance::Normal,
);
let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
static ref MATHML_LANG_RULE: ApplicableDeclarationBlock = {
@@ -1754,7 +1754,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::XLang(SpecifiedLang(atom!("x-math"))),
Importance::Normal,
);
let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
static ref SVG_TEXT_DISABLE_ZOOM_RULE: ApplicableDeclarationBlock = {
@@ -1763,7 +1763,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::XTextZoom(SpecifiedZoom(false)),
Importance::Normal,
);
let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
};
@@ -125,7 +125,7 @@ lazy_static! {
};
/// Global style data
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = GlobalStyleData {
shared_lock: SharedRwLock::new(),
shared_lock: SharedRwLock::new_leaked(),
options: StyleSystemOptions::default(),
};
}
@@ -755,8 +755,7 @@ unsafe impl Sync for RuleTree {}
unsafe impl Send for RuleTree {}

// On Gecko builds, hook into the leak checking machinery.
#[cfg(feature = "gecko")]
#[cfg(debug_assertions)]
#[cfg(all(feature = "gecko", debug_assertions))]
mod gecko_leak_checking {
use super::RuleNode;
use std::mem::size_of;
@@ -789,15 +788,13 @@ mod gecko_leak_checking {

#[inline(always)]
fn log_new(_ptr: *const RuleNode) {
#[cfg(feature = "gecko")]
#[cfg(debug_assertions)]
#[cfg(all(feature = "gecko", debug_assertions))]
gecko_leak_checking::log_ctor(_ptr);
}

#[inline(always)]
fn log_drop(_ptr: *const RuleNode) {
#[cfg(feature = "gecko")]
#[cfg(debug_assertions)]
#[cfg(all(feature = "gecko", debug_assertions))]
gecko_leak_checking::log_dtor(_ptr);
}

@@ -71,6 +71,14 @@ impl SharedRwLock {
}
}

/// Create a new global shared lock (gecko).
#[cfg(feature = "gecko")]
pub fn new_leaked() -> Self {
SharedRwLock {
cell: Some(Arc::new_leaked(AtomicRefCell::new(SomethingZeroSizedButTyped))),
}
}

/// Create a new read-only shared lock (gecko).
#[cfg(feature = "gecko")]
pub fn read_only() -> Self {
@@ -485,8 +485,12 @@ type SharingCache<E> = SharingCacheBase<StyleSharingCandidate<E>>;
type TypelessSharingCache = SharingCacheBase<FakeCandidate>;
type StoredSharingCache = Arc<AtomicRefCell<TypelessSharingCache>>;

thread_local!(static SHARING_CACHE_KEY: StoredSharingCache =
Arc::new(AtomicRefCell::new(TypelessSharingCache::default())));
thread_local! {
// TODO(emilio): Looks like a few of these should just be Rc<RefCell<>> or
// something. No need for atomics in the thread-local code.
static SHARING_CACHE_KEY: StoredSharingCache =
Arc::new_leaked(AtomicRefCell::new(TypelessSharingCache::default()));
}

/// An LRU cache of the last few nodes seen, so that we can aggressively try to
/// reuse their styles.
@@ -10,7 +10,7 @@ pub use crate::values::specified::list::MozListReversed;
pub use crate::values::specified::list::{QuotePair, Quotes};

lazy_static! {
static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter(
static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter_leaked(
vec![
QuotePair {
opening: "\u{201c}".to_owned().into(),
@@ -40,7 +40,7 @@ impl<T> Deref for ArcSlice<T> {
lazy_static! {
// ThinArc doesn't support alignments greater than align_of::<u64>.
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
ArcSlice::from_iter_leaked(iter::empty())
};
}

@@ -74,6 +74,19 @@ impl<T> ArcSlice<T> {
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
}

/// Creates an Arc for a slice using the given iterator to generate the
/// slice, and marks the arc as intentionally leaked from the refcount
/// logging point of view.
#[inline]
pub fn from_iter_leaked<I>(items: I) -> Self
where
I: Iterator<Item = T> + ExactSizeIterator,
{
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
/// altogether.
#[inline]
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.