diff options
-rw-r--r-- | Cargo.lock | 12 | ||||
-rw-r--r-- | components/layout/Cargo.toml | 1 | ||||
-rw-r--r-- | components/layout/lib.rs | 1 | ||||
-rw-r--r-- | components/layout/traversal.rs | 2 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 2 | ||||
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/layout_wrapper.rs | 2 | ||||
-rw-r--r-- | components/script/lib.rs | 1 | ||||
-rw-r--r-- | components/script_layout_interface/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script_layout_interface/lib.rs | 3 | ||||
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 2 | ||||
-rw-r--r-- | components/style/Cargo.toml | 1 | ||||
-rw-r--r-- | components/style/atomic_refcell.rs | 346 | ||||
-rw-r--r-- | components/style/lib.rs | 2 | ||||
-rw-r--r-- | ports/geckolib/Cargo.toml | 1 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 2 | ||||
-rw-r--r-- | ports/geckolib/lib.rs | 1 | ||||
-rw-r--r-- | tests/unit/style/atomic_refcell.rs | 127 | ||||
-rw-r--r-- | tests/unit/style/lib.rs | 1 | ||||
-rw-r--r-- | tests/unit/stylo/Cargo.toml | 1 | ||||
-rw-r--r-- | tests/unit/stylo/lib.rs | 1 |
21 files changed, 30 insertions, 481 deletions
diff --git a/Cargo.lock b/Cargo.lock index 1fe2fe5505e..117493224ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,11 @@ dependencies = [ ] [[package]] +name = "atomic_refcell" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "audio-video-metadata" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -883,6 +888,7 @@ name = "geckoservo" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1290,6 +1296,7 @@ name = "layout" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2240,6 +2247,7 @@ version = "0.0.1" dependencies = [ "angle 0.1.2 (git+https://github.com/servo/angle?branch=servo)", "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "bluetooth_traits 0.0.1", @@ -2308,6 +2316,7 @@ name = "script_layout_interface" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2713,6 +2722,7 @@ name = "style" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2794,6 +2804,7 @@ name = "stylo_tests" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3312,6 +3323,7 @@ dependencies = [ "checksum app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "636ee56f12e31dbc11dc0a1ac6004f08b04e6e6595963716fc8130e90d4e04cf" "checksum arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d89f1b0e242270b5b797778af0c8d182a1a2ccac5d8d6fadf414223cc0fab096" "checksum aster 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88bb8ecdf6a7eaddb7bfd872ebf5e085d343ca42ce98c582dba8046e3450b524" +"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21" "checksum audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "03da2550cb89fe3faf218c179261c26cf7891c4234707c15f5d09ebb32ae2400" "checksum azure 0.9.2 (git+https://github.com/servo/rust-azure)" = "<none>" "checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f" diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index d3da21bf1a6..2d896fb5eae 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -11,6 +11,7 @@ path = "lib.rs" [dependencies] app_units = "0.3" +atomic_refcell = "0.1" bitflags = "0.7" canvas_traits = {path = "../canvas_traits"} cssparser = {version = "0.7", features = ["heap_size", "serde-serialization"]} diff --git a/components/layout/lib.rs b/components/layout/lib.rs index b2aaa006a2a..e71616dafed 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -16,6 +16,7 @@ #![plugin(plugins)] extern crate app_units; +extern crate atomic_refcell; #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index b3672ecf32c..a1109b51443 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -4,6 +4,7 @@ //! Traversals over the DOM and flow trees, running the layout computations. +use atomic_refcell::AtomicRefCell; use construct::FlowConstructor; use context::{LayoutContext, ScopedThreadLocalLayoutContext, SharedLayoutContext}; use display_list_builder::DisplayListBuildState; @@ -11,7 +12,6 @@ use flow::{self, PreorderFlowTraversal}; use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal}; use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use servo_config::opts; -use style::atomic_refcell::AtomicRefCell; use style::context::{SharedStyleContext, StyleContext}; use style::data::ElementData; use style::dom::{TElement, TNode}; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 32f24558ec0..d4910c40f87 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -30,12 +30,12 @@ #![allow(unsafe_code)] +use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use core::nonzero::NonZero; use data::{LayoutDataFlags, PersistentLayoutData}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use script_layout_interface::wrapper_traits::GetLayoutData; -use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use style::computed_values::content::{self, ContentItem}; pub type NonOpaqueStyleAndLayoutData = AtomicRefCell<PersistentLayoutData>; diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 05af21f1dc1..01e4079ccde 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -24,6 +24,7 @@ tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"} angle = {git = "https://github.com/servo/angle", branch = "servo"} app_units = "0.3" audio-video-metadata = "0.1.2" +atomic_refcell = "0.1" bitflags = "0.7" bluetooth_traits = {path = "../bluetooth_traits"} canvas_traits = {path = "../canvas_traits"} diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 3e245ccdd35..25150d60dfe 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -30,6 +30,7 @@ #![allow(unsafe_code)] +use atomic_refcell::AtomicRefCell; use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId}; use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId}; use dom::bindings::js::LayoutJS; @@ -58,7 +59,6 @@ use std::marker::PhantomData; use std::mem::transmute; use std::sync::Arc; use std::sync::atomic::Ordering; -use style::atomic_refcell::AtomicRefCell; use style::attr::AttrValue; use style::computed_values::display; use style::context::{QuirksMode, SharedStyleContext}; diff --git a/components/script/lib.rs b/components/script/lib.rs index 52c0cd6f358..d47156b126f 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -28,6 +28,7 @@ extern crate angle; extern crate app_units; +extern crate atomic_refcell; extern crate audio_video_metadata; #[allow(unused_extern_crates)] #[macro_use] diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 8650fb7e025..f6cf201d1e7 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -11,6 +11,7 @@ path = "lib.rs" [dependencies] app_units = "0.3" +atomic_refcell = "0.1" bitflags = "0.7" canvas_traits = {path = "../canvas_traits"} cssparser = {version = "0.7", features = ["heap_size", "serde-serialization"]} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index d52990fa8f4..d09e3e2823e 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -14,6 +14,7 @@ #![plugin(plugins)] extern crate app_units; +extern crate atomic_refcell; #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; @@ -44,12 +45,12 @@ pub mod reporter; pub mod rpc; pub mod wrapper_traits; +use atomic_refcell::AtomicRefCell; use canvas_traits::CanvasMsg; use core::nonzero::NonZero; use ipc_channel::ipc::IpcSender; use libc::c_void; use std::sync::atomic::AtomicIsize; -use style::atomic_refcell::AtomicRefCell; use style::data::ElementData; pub struct PartialPersistentLayoutData { diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index e141cb581c3..77414fa48d5 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -8,6 +8,7 @@ use HTMLCanvasData; use LayoutNodeType; use OpaqueStyleAndLayoutData; use SVGSVGData; +use atomic_refcell::AtomicRefCell; use gfx_traits::{ByteIndex, FragmentType, ScrollRootId}; use html5ever_atoms::{Namespace, LocalName}; use msg::constellation_msg::PipelineId; @@ -15,7 +16,6 @@ use range::Range; use servo_url::ServoUrl; use std::fmt::Debug; use std::sync::Arc; -use style::atomic_refcell::AtomicRefCell; use style::computed_values::display; use style::context::SharedStyleContext; use style::data::ElementData; diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 51a250b00a9..b300f1fd595 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -23,6 +23,7 @@ testing = [] [dependencies] app_units = "0.3" +atomic_refcell = "0.1" bitflags = "0.7" cfg-if = "0.1.0" cssparser = "0.7" diff --git a/components/style/atomic_refcell.rs b/components/style/atomic_refcell.rs deleted file mode 100644 index fa6c76bfde6..00000000000 --- a/components/style/atomic_refcell.rs +++ /dev/null @@ -1,346 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! Implements a container type providing RefCell-like semantics for objects -//! shared across threads. -//! -//! RwLock is traditionally considered to be the |Sync| analogue of RefCell. -//! However, for consumers that can guarantee that they will never mutably -//! borrow the contents concurrently with immutable borrows, an RwLock is -//! overkill, and has key disadvantages: -//! * Performance: Even the fastest existing implementation of RwLock (that of -//! parking_lot) performs at least two atomic operations during immutable -//! borrows. This makes mutable borrows significantly cheaper than immutable -//! borrows, leading to weird incentives when writing performance-critical -//! code. -//! * Features: Implementing AtomicRefCell on top of RwLock makes it impossible -//! to implement useful things like AtomicRef{,Mut}::map. -//! -//! As such, we re-implement RefCell semantics from scratch with a single atomic -//! reference count. The primary complication of this scheme relates to keeping -//! things in a consistent state when one thread performs an illegal borrow and -//! panics. Since an AtomicRefCell can be accessed by multiple threads, and since -//! panics are recoverable, we need to ensure that an illegal (panicking) access by -//! one thread does not lead to undefined behavior on other, still-running threads. -//! -//! So we represent things as follows: -//! * Any value with the high bit set (so half the total refcount space) indicates -//! a mutable borrow. -//! * Mutable borrows perform an atomic compare-and-swap, swapping in the high bit -//! if the current value is zero. If the current value is non-zero, the thread -//! panics and the value is left undisturbed. -//! * Immutable borrows perform an atomic increment. If the new value has the high -//! bit set, the thread panics. The incremented refcount is left as-is, since it -//! still represents a valid mutable borrow. When the mutable borrow is released, -//! the refcount is set unconditionally to zero, clearing any stray increments by -//! panicked threads. -//! -//! There are a few additional purely-academic complications to handle overflow, -//! which are documented in the implementation. -//! -//! The rest of this module is mostly derived by copy-pasting the implementation of -//! RefCell and fixing things up as appropriate. Certain non-threadsafe methods -//! have been removed. We segment the concurrency logic from the rest of the code to -//! keep the tricky parts small and easy to audit. - -#![allow(unsafe_code)] -#![deny(missing_docs)] - -use std::cell::UnsafeCell; -use std::cmp; -use std::fmt; -use std::fmt::Debug; -use std::ops::{Deref, DerefMut}; -use std::sync::atomic; -use std::sync::atomic::AtomicUsize; - -/// A threadsafe analogue to RefCell. -pub struct AtomicRefCell<T: ?Sized> { - borrow: AtomicUsize, - value: UnsafeCell<T>, -} - -impl<T> AtomicRefCell<T> { - /// Creates a new `AtomicRefCell` containing `value`. - #[inline] - pub fn new(value: T) -> AtomicRefCell<T> { - AtomicRefCell { - borrow: AtomicUsize::new(0), - value: UnsafeCell::new(value), - } - } - - /// Consumes the `AtomicRefCell`, returning the wrapped value. - #[inline] - pub fn into_inner(self) -> T { - debug_assert!(self.borrow.load(atomic::Ordering::Acquire) == 0); - unsafe { self.value.into_inner() } - } -} - -impl<T: ?Sized> AtomicRefCell<T> { - /// Immutably borrows the wrapped value. - #[inline] - pub fn borrow(&self) -> AtomicRef<T> { - AtomicRef { - value: unsafe { &*self.value.get() }, - borrow: AtomicBorrowRef::new(&self.borrow), - } - } - - /// Mutably borrows the wrapped value. - #[inline] - pub fn borrow_mut(&self) -> AtomicRefMut<T> { - AtomicRefMut { - value: unsafe { &mut *self.value.get() }, - borrow: AtomicBorrowRefMut::new(&self.borrow), - } - } - - /// Returns a raw pointer to the underlying data in this cell. - /// - /// External synchronization is needed to avoid data races when dereferencing - /// the pointer. - #[inline] - pub fn as_ptr(&self) -> *mut T { - self.value.get() - } -} - -// -// Core synchronization logic. Keep this section small and easy to audit. -// - -const HIGH_BIT: usize = !(::std::usize::MAX >> 1); -const MAX_FAILED_BORROWS: usize = HIGH_BIT + (HIGH_BIT >> 1); - -struct AtomicBorrowRef<'b> { - borrow: &'b AtomicUsize, -} - -impl<'b> AtomicBorrowRef<'b> { - #[inline] - fn new(borrow: &'b AtomicUsize) -> Self { - let new = borrow.fetch_add(1, atomic::Ordering::Acquire) + 1; - - // If the new count has the high bit set, panic. The specifics of how - // we panic is interesting for soundness, but irrelevant for real programs. - // - // FIXME(bholley): Counter-intuitively, moving the panic logic below out-of- - // line costs about 2ns on the benchmark. My best guess is that we end up - // predicting the wrong branch, but there's no way to mark something as - // unlikely on stable rust. :-( - if new & HIGH_BIT != 0 { - if new == HIGH_BIT { - // We overflowed into the reserved upper half of the refcount - // space. Before panicking, decrement the refcount to leave things - // in a consistent immutable-borrow state. - // - // This can basically only happen if somebody forget()s AtomicRefs - // in a tight loop. - borrow.fetch_sub(1, atomic::Ordering::Release); - panic!("too many immutable borrows"); - } else if new >= MAX_FAILED_BORROWS { - // During the mutable borrow, an absurd number of threads have - // incremented the refcount and panicked. To avoid hypothetically - // wrapping the refcount, we abort the process once a certain - // threshold is reached. - // - // This requires billions of threads to have panicked already, and - // so will never happen in a real program. - println!("Too many failed borrows"); - ::std::process::exit(1); - } else { - // This is the normal case, and the only one which should happen - // in a real program. - panic!("already mutably borrowed"); - } - } - - AtomicBorrowRef { borrow: borrow } - } -} - -impl<'b> Drop for AtomicBorrowRef<'b> { - #[inline] - fn drop(&mut self) { - let old = self.borrow.fetch_sub(1, atomic::Ordering::Release); - // This assertion is technically incorrect in the case where another - // thread hits the hypothetical overflow case, since we might observe - // the refcount before it fixes it up (and panics). But that never will - // never happen in a real program, and this is a debug_assert! anyway. - debug_assert!(old & HIGH_BIT == 0); - } -} - -struct AtomicBorrowRefMut<'b> { - borrow: &'b AtomicUsize, -} - -impl<'b> Drop for AtomicBorrowRefMut<'b> { - #[inline] - fn drop(&mut self) { - self.borrow.store(0, atomic::Ordering::Release); - } -} - -impl<'b> AtomicBorrowRefMut<'b> { - #[inline] - fn new(borrow: &'b AtomicUsize) -> AtomicBorrowRefMut<'b> { - // Use compare-and-swap to avoid corrupting the immutable borrow count - // on illegal mutable borrows. - let old = match borrow.compare_exchange(0, HIGH_BIT, atomic::Ordering::Acquire, atomic::Ordering::Relaxed) { - Ok(x) => x, - Err(x) => x, - }; - assert!(old == 0, "already {} borrowed", if old & HIGH_BIT == 0 { "immutably" } else { "mutably" }); - AtomicBorrowRefMut { - borrow: borrow - } - } -} - -unsafe impl<T: ?Sized + Send + Sync> Send for AtomicRefCell<T> {} -unsafe impl<T: ?Sized + Send + Sync> Sync for AtomicRefCell<T> {} - -// -// End of core synchronization logic. No tricky thread stuff allowed below -// this point. -// - -impl<T: Clone> Clone for AtomicRefCell<T> { - #[inline] - fn clone(&self) -> AtomicRefCell<T> { - AtomicRefCell::new(self.borrow().clone()) - } -} - -impl<T: Default> Default for AtomicRefCell<T> { - #[inline] - fn default() -> AtomicRefCell<T> { - AtomicRefCell::new(Default::default()) - } -} - -impl<T: ?Sized + PartialEq> PartialEq for AtomicRefCell<T> { - #[inline] - fn eq(&self, other: &AtomicRefCell<T>) -> bool { - *self.borrow() == *other.borrow() - } -} - -impl<T: ?Sized + Eq> Eq for AtomicRefCell<T> {} - -impl<T: ?Sized + PartialOrd> PartialOrd for AtomicRefCell<T> { - #[inline] - fn partial_cmp(&self, other: &AtomicRefCell<T>) -> Option<cmp::Ordering> { - self.borrow().partial_cmp(&*other.borrow()) - } -} - -impl<T: ?Sized + Ord> Ord for AtomicRefCell<T> { - #[inline] - fn cmp(&self, other: &AtomicRefCell<T>) -> cmp::Ordering { - self.borrow().cmp(&*other.borrow()) - } -} - -impl<T> From<T> for AtomicRefCell<T> { - fn from(t: T) -> AtomicRefCell<T> { - AtomicRefCell::new(t) - } -} - -impl<'b> Clone for AtomicBorrowRef<'b> { - #[inline] - fn clone(&self) -> AtomicBorrowRef<'b> { - AtomicBorrowRef::new(self.borrow) - } -} - -/// A wrapper type for an immutably borrowed value from an `AtomicRefCell<T>`. -pub struct AtomicRef<'b, T: ?Sized + 'b> { - value: &'b T, - borrow: AtomicBorrowRef<'b>, -} - - -impl<'b, T: ?Sized> Deref for AtomicRef<'b, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - self.value - } -} - -impl<'b, T: ?Sized> AtomicRef<'b, T> { - /// Copies an `AtomicRef`. - #[inline] - pub fn clone(orig: &AtomicRef<'b, T>) -> AtomicRef<'b, T> { - AtomicRef { - value: orig.value, - borrow: orig.borrow.clone(), - } - } - - /// Make a new `AtomicRef` for a component of the borrowed data. - #[inline] - pub fn map<U: ?Sized, F>(orig: AtomicRef<'b, T>, f: F) -> AtomicRef<'b, U> - where F: FnOnce(&T) -> &U - { - AtomicRef { - value: f(orig.value), - borrow: orig.borrow, - } - } -} - -impl<'b, T: ?Sized> AtomicRefMut<'b, T> { - /// Make a new `AtomicRefMut` for a component of the borrowed data, e.g. an enum - /// variant. - #[inline] - pub fn map<U: ?Sized, F>(orig: AtomicRefMut<'b, T>, f: F) -> AtomicRefMut<'b, U> - where F: FnOnce(&mut T) -> &mut U - { - AtomicRefMut { - value: f(orig.value), - borrow: orig.borrow, - } - } -} - -/// A wrapper type for a mutably borrowed value from an `AtomicRefCell<T>`. -pub struct AtomicRefMut<'b, T: ?Sized + 'b> { - value: &'b mut T, - borrow: AtomicBorrowRefMut<'b>, -} - -impl<'b, T: ?Sized> Deref for AtomicRefMut<'b, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - self.value - } -} - -impl<'b, T: ?Sized> DerefMut for AtomicRefMut<'b, T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - self.value - } -} - -impl<'b, T: ?Sized + Debug + 'b> Debug for AtomicRef<'b, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.value.fmt(f) - } -} - -impl<'b, T: ?Sized + Debug + 'b> Debug for AtomicRefMut<'b, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.value.fmt(f) - } -} diff --git a/components/style/lib.rs b/components/style/lib.rs index 04bf213d92f..910d2cb1cf4 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -40,6 +40,7 @@ #![recursion_limit = "500"] // For define_css_keyword_enum! in -moz-appearance extern crate app_units; +extern crate atomic_refcell; #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; @@ -89,7 +90,6 @@ extern crate time; extern crate unicode_segmentation; pub mod animation; -pub mod atomic_refcell; #[allow(missing_docs)] // TODO. pub mod attr; pub mod bezier; diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 23e9db63a13..40137ef7f45 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -14,6 +14,7 @@ bindgen = ["style/bindgen"] [dependencies] app_units = "0.3" +atomic_refcell = "0.1" cssparser = {version = "0.7"} env_logger = "0.3" euclid = "0.10.1" diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 6c17f8caaef..87ef1c87738 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; +use atomic_refcell::AtomicRefMut; use cssparser::Parser; use cssparser::ToCss as ParserToCss; use env_logger; @@ -16,7 +17,6 @@ use std::mem::transmute; use std::ptr; use std::sync::{Arc, Mutex}; use style::arc_ptr_eq; -use style::atomic_refcell::AtomicRefMut; use style::context::{QuirksMode, ReflowGoal, SharedStyleContext, StyleContext}; use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInfo}; use style::data::{ElementData, ElementStyles, RestyleData}; diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index 1225045e45c..cc67a2f5fa3 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -6,6 +6,7 @@ #[macro_use]extern crate style; extern crate app_units; +extern crate atomic_refcell; extern crate cssparser; extern crate env_logger; extern crate euclid; diff --git a/tests/unit/style/atomic_refcell.rs b/tests/unit/style/atomic_refcell.rs deleted file mode 100644 index 8f131085a42..00000000000 --- a/tests/unit/style/atomic_refcell.rs +++ /dev/null @@ -1,127 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; -use test::Bencher; - -struct Foo { - u: u32, -} - -struct Bar { - f: Foo, -} - -impl Default for Bar { - fn default() -> Self { - Bar { f: Foo { u: 42 } } - } -} - -// FIXME(bholley): Add tests to exercise this in concurrent scenarios. - -#[test] -fn immutable() { - let a = AtomicRefCell::new(Bar::default()); - let _first = a.borrow(); - let _second = a.borrow(); -} - -#[test] -fn mutable() { - let a = AtomicRefCell::new(Bar::default()); - let _ = a.borrow_mut(); -} - -#[test] -fn interleaved() { - let a = AtomicRefCell::new(Bar::default()); - { - let _ = a.borrow_mut(); - } - { - let _first = a.borrow(); - let _second = a.borrow(); - } - { - let _ = a.borrow_mut(); - } -} - -#[test] -#[should_panic(expected = "already immutably borrowed")] -fn immutable_then_mutable() { - let a = AtomicRefCell::new(Bar::default()); - let _first = a.borrow(); - let _second = a.borrow_mut(); -} - -#[test] -#[should_panic(expected = "already mutably borrowed")] -fn mutable_then_immutable() { - let a = AtomicRefCell::new(Bar::default()); - let _first = a.borrow_mut(); - let _second = a.borrow(); -} - -#[test] -#[should_panic(expected = "already mutably borrowed")] -fn double_mutable() { - let a = AtomicRefCell::new(Bar::default()); - let _first = a.borrow_mut(); - let _second = a.borrow_mut(); -} - -#[test] -fn map() { - let a = AtomicRefCell::new(Bar::default()); - let b = a.borrow(); - assert_eq!(b.f.u, 42); - let c = AtomicRef::map(b, |x| &x.f); - assert_eq!(c.u, 42); - let d = AtomicRef::map(c, |x| &x.u); - assert_eq!(*d, 42); -} - -#[bench] -fn immutable_borrow(b: &mut Bencher) { - let a = AtomicRefCell::new(Bar::default()); - b.iter(|| a.borrow()); -} - -#[bench] -fn immutable_second_borrow(b: &mut Bencher) { - let a = AtomicRefCell::new(Bar::default()); - let _first = a.borrow(); - b.iter(|| a.borrow()); -} - -#[bench] -fn immutable_third_borrow(b: &mut Bencher) { - let a = AtomicRefCell::new(Bar::default()); - let _first = a.borrow(); - let _second = a.borrow(); - b.iter(|| a.borrow()); -} - -#[bench] -fn mutable_borrow(b: &mut Bencher) { - let a = AtomicRefCell::new(Bar::default()); - b.iter(|| a.borrow_mut()); -} - -#[test] -fn map_mut() { - let a = AtomicRefCell::new(Bar::default()); - let mut b = a.borrow_mut(); - assert_eq!(b.f.u, 42); - b.f.u = 43; - let mut c = AtomicRefMut::map(b, |x| &mut x.f); - assert_eq!(c.u, 43); - c.u = 44; - let mut d = AtomicRefMut::map(c, |x| &mut x.u); - assert_eq!(*d, 44); - *d = 45; - assert_eq!(*d, 45); -} diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index c9a04d88529..dd174c19dbf 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -23,7 +23,6 @@ extern crate style_traits; extern crate test; mod animated_properties; -mod atomic_refcell; mod attr; mod cache; mod logical_geometry; diff --git a/tests/unit/stylo/Cargo.toml b/tests/unit/stylo/Cargo.toml index 1fd99d8230e..811758f4253 100644 --- a/tests/unit/stylo/Cargo.toml +++ b/tests/unit/stylo/Cargo.toml @@ -13,6 +13,7 @@ doctest = false [dependencies] app_units = "0.3" +atomic_refcell = "0.1" cssparser = {version = "0.7"} env_logger = "0.3" euclid = "0.10.1" diff --git a/tests/unit/stylo/lib.rs b/tests/unit/stylo/lib.rs index 35fcdd01602..54d07147082 100644 --- a/tests/unit/stylo/lib.rs +++ b/tests/unit/stylo/lib.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate app_units; +extern crate atomic_refcell; extern crate cssparser; extern crate env_logger; extern crate euclid; |