use core::prelude::*;
+use heap;
+
use core::any::Any;
use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
-use core::marker::Unsize;
+use core::marker::{self, Unsize};
use core::mem;
use core::ops::{CoerceUnsized, Deref, DerefMut};
+use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
use core::ptr::Unique;
use core::raw::{TraitObject};
#[lang = "exchange_heap"]
#[unstable(feature = "box_heap",
reason = "may be renamed; uncertain about custom allocator design")]
-pub const HEAP: () = ();
+pub const HEAP: ExchangeHeapSingleton =
+ ExchangeHeapSingleton { _force_singleton: () };
+
+/// This the singleton type used solely for `boxed::HEAP`.
+#[derive(Copy, Clone)]
+pub struct ExchangeHeapSingleton { _force_singleton: () }
/// A pointer type for heap allocation.
///
#[lang = "owned_box"]
#[stable(feature = "rust1", since = "1.0.0")]
#[fundamental]
-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).
+#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")]
+pub struct IntermediateBox<T: ?Sized>{
+ ptr: *mut u8,
+ size: usize,
+ align: usize,
+ marker: marker::PhantomData<*mut T>,
+}
+
+impl<T> Place<T> for IntermediateBox<T> {
+ fn pointer(&mut self) -> *mut T {
+ unsafe { ::core::mem::transmute(self.ptr) }
+ }
+}
+
+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, marker: marker::PhantomData }
+}
+
+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()
+ }
+}
+
+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.
/// 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
// *const T -> *const U
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+
+/// 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:
+///
+/// ```rust,ignore
+/// 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:
+///
+/// ```rust,ignore
+/// let mut place = BoxPlace::make_place();
+/// let raw_place = Place::pointer(&mut place);
+/// let value = EXPR;
+/// 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.) */
+ /// The place that will negotiate the storage of the data.
+ 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;
+}
None => {}
}
self.consume_expr(&**base);
+ if place.is_some() {
+ self.tcx().sess.span_bug(
+ expr.span,
+ "box with explicit place remains after expansion");
+ }
}
ast::ExprMac(..) => {
use visit::Visitor;
use std_inject;
+// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
+fn mk_core_path(fld: &mut MacroExpander,
+ span: Span,
+ suffix: &[&'static str]) -> ast::Path {
+ let mut idents = vec![fld.cx.ident_of_std("core")];
+ for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); }
+ fld.cx.path_global(span, idents)
+}
+
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) {
fld.cx.bt_push(ExpnInfo {
}
e.and_then(|ast::Expr {id, node, span}| match node {
+
// expr_mac should really be expr_ext or something; it's the
// entry-point for all syntax extensions.
ast::ExprMac(mac) => {
})
}
+ // Desugar ExprBox: `in (PLACE) EXPR`
+ ast::ExprBox(Some(placer), value_expr) => {
+ // to:
+ //
+ // let p = PLACE;
+ // let mut place = Placer::make_place(p);
+ // let raw_place = InPlace::pointer(&mut place);
+ // let value = EXPR;
+ // unsafe {
+ // std::ptr::write(raw_place, value);
+ // InPlace::finalize(place)
+ // }
+
+ let value_span = value_expr.span;
+ let placer_span = placer.span;
+
+ let placer_expr = fld.fold_expr(placer);
+ let value_expr = fld.fold_expr(value_expr);
+
+ let placer_ident = token::gensym_ident("placer");
+ let agent_ident = token::gensym_ident("place");
+ let value_ident = token::gensym_ident("value");
+ let p_ptr_ident = token::gensym_ident("p_ptr");
+
+ let placer = fld.cx.expr_ident(span, placer_ident);
+ let agent = fld.cx.expr_ident(span, agent_ident);
+ let value = fld.cx.expr_ident(span, value_ident);
+ let p_ptr = fld.cx.expr_ident(span, p_ptr_ident);
+
+ let make_place = ["ops", "Placer", "make_place"];
+ let place_pointer = ["ops", "Place", "pointer"];
+ let ptr_write = ["ptr", "write"];
+ let inplace_finalize = ["ops", "InPlace", "finalize"];
+
+ let make_call = |fld: &mut MacroExpander, p, args| {
+ let path = mk_core_path(fld, placer_span, p);
+ let path = fld.cx.expr_path(path);
+ fld.cx.expr_call(span, path, args)
+ };
+
+ let stmt_let = |fld: &mut MacroExpander, bind, expr| {
+ fld.cx.stmt_let(placer_span, false, bind, expr)
+ };
+ let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| {
+ fld.cx.stmt_let(placer_span, true, bind, expr)
+ };
+
+ // let placer = <placer_expr> ;
+ let s1 = stmt_let(fld, placer_ident, placer_expr);
+
+ // let mut place = Placer::make_place(placer);
+ let s2 = {
+ let call = make_call(fld, &make_place, vec![placer]);
+ stmt_let_mut(fld, agent_ident, call)
+ };
+
+ // let p_ptr = Place::pointer(&mut place);
+ let s3 = {
+ let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())];
+ let call = make_call(fld, &place_pointer, args);
+ stmt_let(fld, p_ptr_ident, call)
+ };
+
+ // let value = <value_expr>;
+ let s4 = fld.cx.stmt_let(value_span, false, value_ident, value_expr);
+
+ // unsafe { ptr::write(p_ptr, value); InPlace::finalize(place) }
+ let expr = {
+ let call_ptr_write = StmtSemi(make_call(
+ fld, &ptr_write, vec![p_ptr, value]), ast::DUMMY_NODE_ID);
+ let call_ptr_write = codemap::respan(value_span, call_ptr_write);
+
+ let call = make_call(fld, &inplace_finalize, vec![agent]);
+ Some(fld.cx.expr_block(P(ast::Block {
+ stmts: vec![P(call_ptr_write)],
+ expr: Some(call),
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::UnsafeBlock(ast::CompilerGenerated),
+ span: span,
+ })))
+ };
+
+ let block = fld.cx.block_all(span, vec![s1, s2, s3, s4], expr);
+ fld.cx.expr_block(block)
+ }
+
+ // Issue #22181:
+ // Eventually a desugaring for `box EXPR`
+ // (similar to the desugaring above for `in PLACE BLOCK`)
+ // should go here, desugaring
+ //
+ // to:
+ //
+ // 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)
+ // }
+ //
+ // But for now there are type-inference issues doing that.
+
ast::ExprWhile(cond, body, opt_ident) => {
let cond = fld.fold_expr(cond);
let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);