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

No checkin: overloaded-box protocol changes #22006

Closed
wants to merge 10 commits into from
3 changes: 2 additions & 1 deletion src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ use core::nonzero::NonZero;
use core::ops::Deref;
use core::ptr;
use core::hash::{Hash, Hasher};
use boxed::Box;
use heap::deallocate;

/// An atomically reference counted wrapper for shared state.
Expand Down Expand Up @@ -160,7 +161,7 @@ impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T> {
// Start the weak pointer count as 1 which is the weak pointer that's
// held by all the strong pointers (kinda), see std/rc.rs for more info
let x = box ArcInner {
let x : Box<_> = box ArcInner {
strong: atomic::AtomicUsize::new(1),
weak: atomic::AtomicUsize::new(1),
data: data,
Expand Down
112 changes: 104 additions & 8 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

#![stable]

use heap;

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
Expand All @@ -53,10 +55,12 @@ use core::error::{Error, FromError};
use core::fmt;
use core::hash::{self, Hash};
use core::iter::Iterator;
use core::marker::Sized;
use core::marker::{Copy, Sized};
use core::mem;
use core::ops::{Deref, DerefMut};
use core::ops::{Deref, DerefMut, Drop};
use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
use core::option::Option;
use core::ptr::PtrExt;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result::{Ok, Err};
Expand All @@ -78,14 +82,107 @@ use core::result::Result;
/// ```
#[lang = "exchange_heap"]
#[unstable = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();
pub const HEAP: ExchangeHeapSingleton =
ExchangeHeapSingleton { _force_singleton: () };

/// This the singleton type used solely for `boxed::HEAP`.
pub struct ExchangeHeapSingleton { _force_singleton: () }
impl Copy for ExchangeHeapSingleton { }

/// A pointer type for heap allocation.
///
/// See the [module-level documentation](../../std/boxed/index.html) for more.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);
pub struct Box<T: ?Sized>(Unique<T>);

/// `IntermediateBox` represents uninitialized backing storage for `Box`.
///
/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
/// introducing a separate `IntermediateBox<T>`; but then you hit
/// issues when you e.g. attempt to destructure an instance of `Box`,
/// since it is a lang item and so it gets special handling by the
/// compiler. Easier just to make this parallel type for now.
///
/// FIXME (pnkfelix): Currently the `box` protocol only supports
/// creating instances of sized types. This IntermediateBox is
/// designed to be forward-compatible with a future protocol that
/// supports creating instances of unsized types; that is why the type
/// parameter has the `?Sized` generalization marker, and is also why
/// this carries an explicit size. However, it probably does not need
/// to carry the explicit alignment; that is just a work-around for
/// the fact that the `align_of` intrinsic currently requires the
/// input type to be Sized (which I do not think is strictly
/// necessary).
#[experimental = "placement box design is still being worked out."]
pub struct IntermediateBox<T: ?Sized>{
ptr: *mut u8,
size: uint,
align: uint,
}

impl<T: ?Sized> Place<T> for IntermediateBox<T> {
fn pointer(&mut self) -> *mut T { self.ptr as *mut T }
}

unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
let p = b.ptr as *mut T;
mem::forget(b);
mem::transmute(p)
}

fn make_place<T>() -> IntermediateBox<T> {
let size = mem::size_of::<T>();
let align = mem::align_of::<T>();

let p = if size == 0 {
heap::EMPTY as *mut u8
} else {
let p = unsafe {
heap::allocate(size, align)
};
if p.is_null() {
panic!("Box make_place allocation failure.");
}
p
};

IntermediateBox { ptr: p, size: size, align: align }
}

impl<T> BoxPlace<T> for IntermediateBox<T> {
fn make_place() -> IntermediateBox<T> { make_place() }
}

impl<T> InPlace<T> for IntermediateBox<T> {
type Owner = Box<T>;
unsafe fn finalize(self) -> Box<T> { finalize(self) }
}

impl<T> Boxed for Box<T> {
type Data = T;
type Place = IntermediateBox<T>;
unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> { finalize(b) }
}

impl<T> Placer<T> for ExchangeHeapSingleton {
type Place = IntermediateBox<T>;

fn make_place(self) -> IntermediateBox<T> {
make_place()
}
}

#[unsafe_destructor]
impl<T: ?Sized> Drop for IntermediateBox<T> {
fn drop(&mut self) {
if self.size > 0 {
unsafe {
heap::deallocate(self.ptr, self.size, self.align)
}
}
}
}

impl<T> Box<T> {
/// Allocates memory on the heap and then moves `x` into it.
Expand All @@ -104,13 +201,13 @@ impl<T> Box<T> {
#[stable]
impl<T: Default> Default for Box<T> {
#[stable]
fn default() -> Box<T> { box Default::default() }
fn default() -> Box<T> { box (HEAP) Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
#[stable]
fn default() -> Box<[T]> { box [] }
fn default() -> Box<[T]> { box (HEAP) [] }
}

#[stable]
Expand All @@ -124,8 +221,7 @@ impl<T: Clone> Clone for Box<T> {
/// let y = x.clone();
/// ```
#[inline]
fn clone(&self) -> Box<T> { box {(**self).clone()} }

fn clone(&self) -> Box<T> { box (HEAP) {(**self).clone()} }
/// Copies `source`'s contents into `self` without creating a new allocation.
///
/// # Examples
Expand Down
7 changes: 7 additions & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,14 @@ pub mod heap;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::HEAP;` declaration.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed { pub use std::boxed::HEAP; }
#[cfg(test)]
mod boxed_test;
pub mod arc;
pub mod rc;
Expand Down Expand Up @@ -127,5 +132,7 @@ pub fn fixme_14344_be_sure_to_link_to_collections() {}
#[doc(hidden)]
mod std {
pub use core::fmt;
pub use core::ops;
pub use core::option;
pub use core::ptr;
}
6 changes: 5 additions & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ use core::ptr::{self, PtrExt};
use core::result::Result;
use core::result::Result::{Ok, Err};

use boxed::HEAP;
use heap::deallocate;

struct RcBox<T> {
Expand Down Expand Up @@ -202,7 +203,10 @@ impl<T> Rc<T> {
// there is an implicit weak pointer owned by all the strong pointers, which
// ensures that the weak destructor never frees the allocation while the strong
// destructor is running, even if the weak pointer is stored inside the strong one.
_ptr: NonZero::new(transmute(box RcBox {
//
// SNAP 9006c3c
// Change `box (HEAP)` to `in (HEAP)` after snapshot.
_ptr: NonZero::new(transmute(box (HEAP) RcBox {
value: value,
strong: Cell::new(1),
weak: Cell::new(1)
Expand Down
2 changes: 2 additions & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ mod std {
pub use core::cmp; // derive(Eq, Ord, etc.)
pub use core::marker; // derive(Copy)
pub use core::hash; // derive(Hash)
pub use core::ops; // necessary for box <expr>
pub use core::ptr; // necessary for box <expr>
}

#[cfg(test)]
Expand Down
111 changes: 111 additions & 0 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,3 +1148,114 @@ impl<F,A,R> FnOnce<A,R> for F
self.call_mut(args)
}
}

/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions
/// that allocate an intermediate "place" that holds uninitialized
/// state. The desugaring evaluates EXPR, and writes the result at
/// the address returned by the `pointer` method of this trait.
///
/// A `Place` can be thought of as a special representation for a
/// hypothetical `&uninit` reference (which Rust cannot currently
/// express directly). That is, it represents a pointer to
/// uninitialized storage.
///
/// The client is responsible for two steps: First, initializing the
/// payload (it can access its address via `pointer`). Second,
/// converting the agent to an instance of the owning pointer, via the
/// appropriate `finalize` method (see the `InPlace`.
///
/// If evaluating EXPR fails, then the destructor for the
/// implementation of Place to clean up any intermediate state
/// (e.g. deallocate box storage, pop a stack, etc).
pub trait Place<Data: ?Sized> {
/// Returns the address where the input value will be written.
/// Note that the data at this address is generally uninitialized,
/// and thus one should use `ptr::write` for initializing it.
fn pointer(&mut self) -> *mut Data;
}

/// Interface to implementations of `in (PLACE) EXPR`.
///
/// `in (PLACE) EXPR` effectively desugars into:
///
/// ```
/// let p = PLACE;
/// let mut place = Placer::make_place(p);
/// let raw_place = Place::pointer(&mut place);
/// let value = EXPR;
/// unsafe {
/// std::ptr::write(raw_place, value);
/// InPlace::finalize(place)
/// }
/// ```
///
/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`;
/// if the type of `PLACE` is `P`, then the final type of the whole
/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed`
/// traits).
///
/// Values for types implementing this trait usually are transient
/// intermediate values (e.g. the return value of `Vec::emplace_back`)
/// or `Copy`, since the `make_place` method takes `self` by value.
pub trait Placer<Data: ?Sized> {
/// `Place` is the intermedate agent guarding the
/// uninitialized state for `Data`.
type Place: InPlace<Data>;

/// Creates a fresh place from `self`.
fn make_place(self) -> Self::Place;
}

/// Specialization of `Place` trait supporting `in (PLACE) EXPR`.
pub trait InPlace<Data: ?Sized>: Place<Data> {
/// `Owner` is the type of the end value of `in (PLACE) EXPR`
///
/// Note that when `in (PLACE) EXPR` is solely used for
/// side-effecting an existing data-structure,
/// e.g. `Vec::emplace_back`, then `Owner` need not carry any
/// information at all (e.g. it can be the unit type `()` in that
/// case).
type Owner;

/// Converts self into the final value, shifting
/// deallocation/cleanup responsibilities (if any remain), over to
/// the returned instance of `Owner` and forgetting self.
unsafe fn finalize(self) -> Self::Owner;
}

/// Core trait for the `box EXPR` form.
///
/// `box EXPR` effectively desugars into:
///
/// ```
/// let mut place = BoxPlace::make_place();
/// let raw_place = Place::pointer(&mut place);
/// let value = $value;
/// unsafe {
/// ::std::ptr::write(raw_place, value);
/// Boxed::finalize(place)
/// }
/// ```
///
/// The type of `box EXPR` is supplied from its surrounding
/// context; in the above expansion, the result type `T` is used
/// to determine which implementation of `Boxed` to use, and that
/// `<T as Boxed>` in turn dictates determines which
/// implementation of `BoxPlace` to use, namely:
/// `<<T as Boxed>::Place as BoxPlace>`.
pub trait Boxed {
/// The kind of data that is stored in this kind of box.
type Data; /* (`Data` unused b/c cannot yet express below bound.) */
type Place; /* should be bounded by BoxPlace<Self::Data> */

/// Converts filled place into final owning value, shifting
/// deallocation/cleanup responsibilities (if any remain), over to
/// returned instance of `Self` and forgetting `filled`.
unsafe fn finalize(filled: Self::Place) -> Self;
}

/// Specialization of `Place` trait supporting `box EXPR`.
pub trait BoxPlace<Data: ?Sized> : Place<Data> {
/// Creates a globally fresh place.
fn make_place() -> Self;
}
2 changes: 1 addition & 1 deletion src/libcore/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ impl<T> PartialOrd for *mut T {
/// Useful for building abstractions like `Vec<T>` or `Box<T>`, which
/// internally use raw pointers to manage the memory that they own.
#[unstable = "recently added to this module"]
pub struct Unique<T>(pub *mut T);
pub struct Unique<T: ?Sized>(pub *mut T);

/// `Unique` pointers are `Send` if `T` is `Send` because the data they
/// reference is unaliased. Note that this aliasing invariant is
Expand Down
7 changes: 4 additions & 3 deletions src/liblog/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@
#![allow(unstable)]
#![deny(missing_docs)]

use std::boxed::HEAP;
use std::cell::RefCell;
use std::fmt;
use std::io::LineBufferedWriter;
Expand Down Expand Up @@ -294,7 +295,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
let mut logger = LOCAL_LOGGER.with(|s| {
s.borrow_mut().take()
}).unwrap_or_else(|| {
box DefaultLogger { handle: io::stderr() } as Box<Logger + Send>
box (HEAP) DefaultLogger { handle: io::stderr() } as Box<Logger + Send>
});
logger.log(&LogRecord {
level: LogLevel(level),
Expand Down Expand Up @@ -416,12 +417,12 @@ fn init() {

assert!(FILTER.is_null());
match filter {
Some(f) => FILTER = mem::transmute(box f),
Some(f) => FILTER = mem::transmute(box (HEAP) f),
None => {}
}

assert!(DIRECTIVES.is_null());
DIRECTIVES = mem::transmute(box directives);
DIRECTIVES = mem::transmute(box (HEAP) directives);

// Schedule the cleanup for the globals for when the runtime exits.
rt::at_exit(move |:| {
Expand Down
Loading