From a05d12b38603c9f684ec023bac8390b11ee28bb4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 15 Feb 2019 12:36:44 +0200 Subject: [PATCH] syntax: try ref-counting the AST. --- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/ptr.rs | 71 +++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 420f7426ad786..9920d92c75841 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -735,7 +735,7 @@ impl HasAttrs for ThinVec { } } -impl HasAttrs for P { +impl HasAttrs for P { fn attrs(&self) -> &[Attribute] { (**self).attrs() } diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index bc43630ae59b3..b75277994473f 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -33,40 +33,42 @@ use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_data_structures::sync::Lrc; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq)] pub struct P { - ptr: Box + ptr: Lrc } #[allow(non_snake_case)] /// Construct a `P` from a `T` value. pub fn P(value: T) -> P { P { - ptr: Box::new(value) + ptr: Lrc::new(value) } } -impl P { +impl P { /// Move out of the pointer. /// Intended for chaining transformations not covered by `map`. pub fn and_then(self, f: F) -> U where F: FnOnce(T) -> U, { - f(*self.ptr) + f(self.into_inner()) } /// Equivalent to and_then(|x| x) pub fn into_inner(self) -> T { - *self.ptr + Lrc::try_unwrap(self.ptr).unwrap_or_else(|ptr| (*ptr).clone()) } /// Produce a new `P` from `self` without reallocating. pub fn map(mut self, f: F) -> P where F: FnOnce(T) -> T, { - let p: *mut T = &mut *self.ptr; + // FIXME(eddyb) How can we reuse the original if unchanged? + let p: *mut T = Lrc::make_mut(&mut self.ptr); // Leak self in case of panic. // FIXME(eddyb) Use some sort of "free guard" that @@ -78,7 +80,7 @@ impl P { ptr::write(p, f(ptr::read(p))); // Recreate self from the raw pointer. - P { ptr: Box::from_raw(p) } + P { ptr: Lrc::from_raw(p) } } } @@ -86,7 +88,8 @@ impl P { pub fn filter_map(mut self, f: F) -> Option> where F: FnOnce(T) -> Option, { - let p: *mut T = &mut *self.ptr; + // FIXME(eddyb) How can we reuse the original if unchanged? + let p: *mut T = Lrc::make_mut(&mut self.ptr); // Leak self in case of panic. // FIXME(eddyb) Use some sort of "free guard" that @@ -99,9 +102,9 @@ impl P { ptr::write(p, v); // Recreate self from the raw pointer. - Some(P { ptr: Box::from_raw(p) }) + Some(P { ptr: Lrc::from_raw(p) }) } else { - drop(Box::from_raw(p)); + drop(Lrc::from_raw(p)); None } } @@ -116,15 +119,17 @@ impl Deref for P { } } -impl DerefMut for P { +impl DerefMut for P { fn deref_mut(&mut self) -> &mut T { - &mut self.ptr + Lrc::make_mut(&mut self.ptr) } } -impl Clone for P { +impl Clone for P { fn clone(&self) -> P { - P((**self).clone()) + P { + ptr: self.ptr.clone(), + } } } @@ -160,17 +165,21 @@ impl Encodable for P { impl P<[T]> { pub fn new() -> P<[T]> { - P { ptr: Default::default() } + P { ptr: Lrc::new([]) } } + // FIXME(eddyb) this is inefficient because it needs to + // move all the elements to accomodate `Lrc`'s allocation. #[inline(never)] pub fn from_vec(v: Vec) -> P<[T]> { - P { ptr: v.into_boxed_slice() } + P { ptr: v.into() } } + // FIXME(eddyb) this is inefficient because it needs to + // clone all the elements out of the `Lrc<[T]>`. #[inline(never)] - pub fn into_vec(self) -> Vec { - self.ptr.into_vec() + pub fn into_vec(self) -> Vec where T: Clone { + self.ptr.to_vec() } } @@ -181,31 +190,41 @@ impl Default for P<[T]> { } } -impl Clone for P<[T]> { - fn clone(&self) -> P<[T]> { - P::from_vec(self.to_vec()) - } -} - impl From> for P<[T]> { fn from(v: Vec) -> Self { P::from_vec(v) } } -impl Into> for P<[T]> { +// FIXME(eddyb) this is inefficient because it needs to +// clone all the elements out of the `Lrc<[T]>`. +impl Into> for P<[T]> { fn into(self) -> Vec { self.into_vec() } } +// FIXME(eddyb) this is inefficient because it needs to +// clone all the elements out of the `Lrc<[T]>`. +impl DerefMut for P<[T]> { + fn deref_mut(&mut self) -> &mut [T] { + // HACK(eddyb) this emulates `make_mut` for `Lrc<[T]>`. + if Lrc::get_mut(&mut self.ptr).is_none() { + self.ptr = self.ptr.to_vec().into(); + } + Lrc::get_mut(&mut self.ptr).unwrap() + } +} + impl FromIterator for P<[T]> { fn from_iter>(iter: I) -> P<[T]> { P::from_vec(iter.into_iter().collect()) } } -impl IntoIterator for P<[T]> { +// FIXME(eddyb) this is inefficient because it needs to +// clone all the elements out of the `Lrc<[T]>`. +impl IntoIterator for P<[T]> { type Item = T; type IntoIter = vec::IntoIter;