From b9c0fe789cb3997208d9ced2575bfe1c59c9f809 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 12 Aug 2015 12:00:46 -0700 Subject: [PATCH 1/4] stablize weak pointers and uniqueness ops on Rc --- src/liballoc/rc.rs | 86 ++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index b750e051f28d5..d75bfd13fdf01 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -161,7 +161,7 @@ use core::fmt; use core::hash::{Hasher, Hash}; use core::intrinsics::{assume, drop_in_place, abort}; use core::marker::{self, Unsize}; -use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget}; +use core::mem::{self, align_of_val, size_of_val, forget}; use core::nonzero::NonZero; use core::ops::{CoerceUnsized, Deref}; use core::ptr; @@ -218,10 +218,10 @@ impl Rc { } } - /// Unwraps the contained value if the `Rc` is unique. + /// Unwraps the contained value if the `Rc` has only one strong reference. + /// This will succeed even if there are outstanding weak references. /// - /// If the `Rc` is not unique, an `Err` is returned with the same - /// `Rc`. + /// Otherwise, an `Err` is returned with the same `Rc`. /// /// # Examples /// @@ -238,15 +238,22 @@ impl Rc { /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4))); /// ``` #[inline] - #[unstable(feature = "rc_unique")] + #[stable(feature = "rc_unique", since="1.4.0")] pub fn try_unwrap(rc: Rc) -> Result> { - if Rc::is_unique(&rc) { + if Rc::strong_count(&rc) == 1 { unsafe { + let ptr = *rc._ptr; let val = ptr::read(&*rc); // copy the contained object - // destruct the box and skip our Drop - // we can ignore the refcounts because we know we're unique - deallocate(*rc._ptr as *mut u8, size_of::>(), - align_of::>()); + + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. + rc.dec_weak(); + + if rc.weak() == 0 { + deallocate(ptr as *mut u8, + size_of_val(&*ptr), + align_of_val(&*ptr)) + } forget(rc); Ok(val) } @@ -270,8 +277,7 @@ impl Rc { /// /// let weak_five = five.downgrade(); /// ``` - #[unstable(feature = "rc_weak", - reason = "Weak pointers may not belong in this module")] + #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(&self) -> Weak { self.inc_weak(); Weak { _ptr: self._ptr } @@ -279,12 +285,12 @@ impl Rc { /// Get the number of weak references to this value. #[inline] - #[unstable(feature = "rc_counts")] + #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "27718")] pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. #[inline] - #[unstable(feature = "rc_counts")] + #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "27718")] pub fn strong_count(this: &Rc) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak` values that share @@ -302,13 +308,13 @@ impl Rc { /// assert!(Rc::is_unique(&five)); /// ``` #[inline] - #[unstable(feature = "rc_unique")] + #[unstable(feature = "rc_counts", reason = "uniqueness has unclear meaning", issue = "27718")] pub fn is_unique(rc: &Rc) -> bool { Rc::weak_count(rc) == 0 && Rc::strong_count(rc) == 1 } - /// Returns a mutable reference to the contained value if the `Rc` is - /// unique. + /// Returns a mutable reference to the contained value if the `Rc` has + /// one strong reference and no weak references. /// /// Returns `None` if the `Rc` is not unique. /// @@ -327,7 +333,7 @@ impl Rc { /// assert!(Rc::get_mut(&mut x).is_none()); /// ``` #[inline] - #[unstable(feature = "rc_unique")] + #[stable(feature = "rc_unique", since = "1.4.0")] pub fn get_mut(rc: &mut Rc) -> Option<&mut T> { if Rc::is_unique(rc) { let inner = unsafe { &mut **rc._ptr }; @@ -339,25 +345,40 @@ impl Rc { } impl Rc { - /// Make a mutable reference from the given `Rc`. + #[inline] + #[unstable(feature = "renamed_rc_unique", reason = "renamed to make_mut", issue = "27718")] + #[deprecated(since = "1.4.0", reason = "renamed to make_mut")] + pub fn make_unique(&mut self) -> &mut T { + Rc::make_mut(self) + } + + /// Make a mutable reference into the given `Rc` by cloning the inner + /// data if the `Rc` doesn't have one strong reference and no weak + /// references. /// - /// This is also referred to as a copy-on-write operation because the inner - /// data is cloned if the reference count is greater than one. + /// This is also referred to as a copy-on-write. /// /// # Examples /// /// ``` - /// #![feature(rc_unique)] - /// /// use std::rc::Rc; /// - /// let mut five = Rc::new(5); + /// let mut data = Rc::new(5); + /// + /// *data.make_mut() += 1; // Won't clone anything + /// let mut other_data = data.clone(); // Won't clone inner data + /// *data.make_mut() += 1; // Clones inner data + /// *data.make_mut() += 1; // Won't clone anything + /// *other_data.make_mut() *= 2; // Won't clone anything + /// + /// // Note: data and other_data now point to different numbers + /// assert_eq!(*data, 8); + /// assert_eq!(*other_data, 12); /// - /// let mut_five = five.make_unique(); /// ``` #[inline] - #[unstable(feature = "rc_unique")] - pub fn make_unique(&mut self) -> &mut T { + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn make_mut(&mut self) -> &mut T { if !Rc::is_unique(self) { *self = Rc::new((**self).clone()) } @@ -412,7 +433,7 @@ impl Drop for Rc { unsafe { let ptr = *self._ptr; if !(*(&ptr as *const _ as *const *const ())).is_null() && - ptr as *const () as usize != mem::POST_DROP_USIZE { + ptr as *const () as usize != mem::POST_DROP_USIZE { self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -652,8 +673,7 @@ impl fmt::Pointer for Rc { /// /// See the [module level documentation](./index.html) for more. #[unsafe_no_drop_flag] -#[unstable(feature = "rc_weak", - reason = "Weak pointers may not belong in this module.")] +#[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref @@ -665,8 +685,6 @@ impl !marker::Sync for Weak {} impl, U: ?Sized> CoerceUnsized> for Weak {} -#[unstable(feature = "rc_weak", - reason = "Weak pointers may not belong in this module.")] impl Weak { /// Upgrades a weak reference to a strong reference. @@ -689,6 +707,7 @@ impl Weak { /// /// let strong_five: Option> = weak_five.upgrade(); /// ``` + #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { if self.strong() == 0 { None @@ -745,8 +764,7 @@ impl Drop for Weak { } } -#[unstable(feature = "rc_weak", - reason = "Weak pointers may not belong in this module.")] +#[stable(feature = "rc_weak", since = "1.4.0")] impl Clone for Weak { /// Makes a clone of the `Weak`. From d66c0b0700e6d18772ae4b99d1a6187492edeebf Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 12 Aug 2015 14:37:27 -0700 Subject: [PATCH 2/4] stablize weak pointers and uniqueness ops on Arc --- src/liballoc/arc.rs | 94 +++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 09a4f9e0a62b8..052d1ccf63b8b 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -136,8 +136,7 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} /// Weak pointers will not keep the data inside of the `Arc` alive, and can be /// used to break cycles between `Arc` pointers. #[unsafe_no_drop_flag] -#[unstable(feature = "arc_weak", - reason = "Weak pointers may not belong in this module.")] +#[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref @@ -161,7 +160,7 @@ struct ArcInner { // the value usize::MAX acts as a sentinel for temporarily "locking" the // ability to upgrade weak pointers or downgrade strong ones; this is used - // to avoid races in `make_unique` and `get_mut`. + // to avoid races in `make_mut` and `get_mut`. weak: atomic::AtomicUsize, data: T, @@ -200,16 +199,13 @@ impl Arc { /// # Examples /// /// ``` - /// #![feature(arc_weak)] - /// /// use std::sync::Arc; /// /// let five = Arc::new(5); /// /// let weak_five = five.downgrade(); /// ``` - #[unstable(feature = "arc_weak", - reason = "Weak pointers may not belong in this module.")] + #[stable(feature = "arc_weak", since = "1.4.0")] pub fn downgrade(&self) -> Weak { loop { // This Relaxed is OK because we're checking the value in the CAS @@ -234,14 +230,14 @@ impl Arc { /// Get the number of weak references to this value. #[inline] - #[unstable(feature = "arc_counts")] + #[unstable(feature = "arc_counts", reason = "not clearly useful, and racy", issue = "27718")] pub fn weak_count(this: &Arc) -> usize { this.inner().weak.load(SeqCst) - 1 } /// Get the number of strong references to this value. #[inline] - #[unstable(feature = "arc_counts")] + #[unstable(feature = "arc_counts", reason = "not clearly useful, and racy", issue = "27718")] pub fn strong_count(this: &Arc) -> usize { this.inner().strong.load(SeqCst) } @@ -330,27 +326,40 @@ impl Deref for Arc { } impl Arc { - /// Make a mutable reference from the given `Arc`. + + #[unstable(feature = "renamed_arc_unique", reason = "renamed to make_mut", issue = "27718")] + #[deprecated(since = "1.4.0", reason = "renamed to make_mut")] + pub fn make_unique(this: &mut Arc) -> &mut T { + Arc::make_mut(this) + } + + /// Make a mutable reference into the given `Arc` by cloning the inner + /// data if the `Arc` doesn't have one strong reference and no weak + /// references. /// - /// This is also referred to as a copy-on-write operation because the inner - /// data is cloned if the (strong) reference count is greater than one. If - /// we hold the only strong reference, any existing weak references will no - /// longer be upgradeable. + /// This is also referred to as a copy-on-write. /// /// # Examples /// /// ``` - /// #![feature(arc_unique)] - /// /// use std::sync::Arc; /// - /// let mut five = Arc::new(5); + /// let mut data = Arc::new(5); + /// + /// *data.make_mut() += 1; // Won't clone anything + /// let mut other_data = data.clone(); // Won't clone inner data + /// *data.make_mut() += 1; // Clones inner data + /// *data.make_mut() += 1; // Won't clone anything + /// *other_data.make_mut() *= 2; // Won't clone anything + /// + /// // Note: data and other_data now point to different numbers + /// assert_eq!(*data, 8); + /// assert_eq!(*other_data, 12); /// - /// let mut_five = Arc::make_unique(&mut five); /// ``` #[inline] - #[unstable(feature = "arc_unique")] - pub fn make_unique(this: &mut Arc) -> &mut T { + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn make_mut(this: &mut Arc) -> &mut T { // Note that we hold both a strong reference and a weak reference. // Thus, releasing our strong reference only will not, by itself, cause // the memory to be deallocated. @@ -405,18 +414,13 @@ impl Arc { } impl Arc { - /// Returns a mutable reference to the contained value if the `Arc` is unique. - /// - /// Returns `None` if the `Arc` is not unique. + /// Returns a mutable reference to the contained value if the `Arc` has + /// one strong reference and no weak references. /// /// # Examples /// /// ``` - /// #![feature(arc_unique, alloc)] - /// - /// extern crate alloc; - /// # fn main() { - /// use alloc::arc::Arc; + /// use std::sync::Arc; /// /// let mut x = Arc::new(3); /// *Arc::get_mut(&mut x).unwrap() = 4; @@ -424,10 +428,9 @@ impl Arc { /// /// let _y = x.clone(); /// assert!(Arc::get_mut(&mut x).is_none()); - /// # } /// ``` #[inline] - #[unstable(feature = "arc_unique")] + #[stable(feature = "arc_unique", since = "1.4.0")] pub fn get_mut(this: &mut Arc) -> Option<&mut T> { if this.is_unique() { // This unsafety is ok because we're guaranteed that the pointer @@ -540,8 +543,6 @@ impl Drop for Arc { } } -#[unstable(feature = "arc_weak", - reason = "Weak pointers may not belong in this module.")] impl Weak { /// Upgrades a weak reference to a strong reference. /// @@ -553,8 +554,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(arc_weak)] - /// /// use std::sync::Arc; /// /// let five = Arc::new(5); @@ -563,6 +562,7 @@ impl Weak { /// /// let strong_five: Option> = weak_five.upgrade(); /// ``` + #[stable(feature = "arc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { // We use a CAS loop to increment the strong count instead of a // fetch_add because once the count hits 0 it must never be above 0. @@ -588,8 +588,7 @@ impl Weak { } } -#[unstable(feature = "arc_weak", - reason = "Weak pointers may not belong in this module.")] +#[stable(feature = "arc_weak", since = "1.4.0")] impl Clone for Weak { /// Makes a clone of the `Weak`. /// @@ -598,8 +597,6 @@ impl Clone for Weak { /// # Examples /// /// ``` - /// #![feature(arc_weak)] - /// /// use std::sync::Arc; /// /// let weak_five = Arc::new(5).downgrade(); @@ -632,8 +629,6 @@ impl Drop for Weak { /// # Examples /// /// ``` - /// #![feature(arc_weak)] - /// /// use std::sync::Arc; /// /// { @@ -891,18 +886,18 @@ mod tests { } #[test] - fn test_cowarc_clone_make_unique() { + fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); let mut cow1 = cow0.clone(); let mut cow2 = cow1.clone(); - assert!(75 == *Arc::make_unique(&mut cow0)); - assert!(75 == *Arc::make_unique(&mut cow1)); - assert!(75 == *Arc::make_unique(&mut cow2)); + assert!(75 == *Arc::make_mut(&mut cow0)); + assert!(75 == *Arc::make_mut(&mut cow1)); + assert!(75 == *Arc::make_mut(&mut cow2)); - *Arc::make_unique(&mut cow0) += 1; - *Arc::make_unique(&mut cow1) += 2; - *Arc::make_unique(&mut cow2) += 3; + *Arc::make_mut(&mut cow0) += 1; + *Arc::make_mut(&mut cow1) += 2; + *Arc::make_mut(&mut cow2) += 3; assert!(76 == *cow0); assert!(77 == *cow1); @@ -924,8 +919,7 @@ mod tests { assert!(75 == *cow1); assert!(75 == *cow2); - *Arc::make_unique(&mut cow0) += 1; - + *Arc::make_mut(&mut cow0) += 1; assert!(76 == *cow0); assert!(75 == *cow1); assert!(75 == *cow2); @@ -945,7 +939,7 @@ mod tests { assert!(75 == *cow0); assert!(75 == *cow1_weak.upgrade().unwrap()); - *Arc::make_unique(&mut cow0) += 1; + *Arc::make_mut(&mut cow0) += 1; assert!(76 == *cow0); assert!(cow1_weak.upgrade().is_none()); From fee500a75189053b21e710a836778bf1062a4c51 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 12 Aug 2015 15:32:46 -0700 Subject: [PATCH 3/4] add Arc::try_unwrap --- src/liballoc/arc.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 052d1ccf63b8b..5602e8c55ceb8 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -191,6 +191,45 @@ impl Arc { }; Arc { _ptr: unsafe { NonZero::new(Box::into_raw(x)) } } } + + /// Unwraps the contained value if the `Arc` has only one strong reference. + /// This will succeed even if there are outstanding weak references. + /// + /// Otherwise, an `Err` is returned with the same `Arc`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(3); + /// assert_eq!(Arc::try_unwrap(x), Ok(3)); + /// + /// let x = Arc::new(4); + /// let _y = x.clone(); + /// assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); + /// ``` + #[inline] + #[unstable(feature = "arc_unwrap", reason = "was missing, so is technically new")] + pub fn try_unwrap(this: Arc) -> Result> { + // See `drop` for impl details + if self.inner().strong.compare_and_swap(1, 0, Release) != 1 { return Err(self) } + + // ~~ magic ~~ + atomic::fence(Acquire); + + unsafe { + let ptr = *self._ptr; + + let elem = ptr::read(&(*ptr).data); + + if self.inner().weak.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) + } + Ok(elem) + } + } } impl Arc { @@ -885,6 +924,18 @@ mod tests { assert!(Arc::get_mut(&mut x).is_none()); } + #[test] + fn try_unwrap() { + let x = Arc::new(3); + assert_eq!(Arc::try_unwrap(x), Ok(3)); + let x = Arc::new(4); + let _y = x.clone(); + assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); + let x = Arc::new(5); + let _w = x.downgrade(); + assert_eq!(Arc::try_unwrap(x), Ok(5)); + } + #[test] fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); From 3a80e035388cff2ddeee72220151582eff2ceaa9 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 12 Aug 2015 15:40:32 -0700 Subject: [PATCH 4/4] remove needless stability attributes --- src/librustc_resolve/lib.rs | 1 - src/librustc_trans/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e63dbd2092a60..c44b718645e11 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -21,7 +21,6 @@ #![feature(associated_consts)] #![feature(borrow_state)] -#![feature(rc_weak)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(slice_splits)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f4daa6e86e9c0..7f1b859fcf9c3 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -36,7 +36,6 @@ #![feature(path_relative_from)] #![feature(path_relative_from)] #![feature(quote)] -#![feature(rc_weak)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)]