Skip to content

Commit 866250c

Browse files
committed
prototype Placer protocol for unstable overloaded-box and placement-in.
1 parent 1829fa5 commit 866250c

File tree

4 files changed

+333
-5
lines changed

4 files changed

+333
-5
lines changed

src/liballoc/boxed.rs

+102-5
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,16 @@
5555

5656
use core::prelude::*;
5757

58+
use heap;
59+
5860
use core::any::Any;
5961
use core::cmp::Ordering;
6062
use core::fmt;
6163
use core::hash::{self, Hash};
62-
use core::marker::Unsize;
64+
use core::marker::{self, Unsize};
6365
use core::mem;
6466
use core::ops::{CoerceUnsized, Deref, DerefMut};
67+
use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
6568
use core::ptr::Unique;
6669
use core::raw::{TraitObject};
6770

@@ -83,15 +86,110 @@ use core::raw::{TraitObject};
8386
#[lang = "exchange_heap"]
8487
#[unstable(feature = "box_heap",
8588
reason = "may be renamed; uncertain about custom allocator design")]
86-
pub const HEAP: () = ();
89+
pub const HEAP: ExchangeHeapSingleton =
90+
ExchangeHeapSingleton { _force_singleton: () };
91+
92+
/// This the singleton type used solely for `boxed::HEAP`.
93+
#[derive(Copy, Clone)]
94+
pub struct ExchangeHeapSingleton { _force_singleton: () }
8795

8896
/// A pointer type for heap allocation.
8997
///
9098
/// See the [module-level documentation](../../std/boxed/index.html) for more.
9199
#[lang = "owned_box"]
92100
#[stable(feature = "rust1", since = "1.0.0")]
93101
#[fundamental]
94-
pub struct Box<T>(Unique<T>);
102+
pub struct Box<T: ?Sized>(Unique<T>);
103+
104+
/// `IntermediateBox` represents uninitialized backing storage for `Box`.
105+
///
106+
/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
107+
/// introducing a separate `IntermediateBox<T>`; but then you hit
108+
/// issues when you e.g. attempt to destructure an instance of `Box`,
109+
/// since it is a lang item and so it gets special handling by the
110+
/// compiler. Easier just to make this parallel type for now.
111+
///
112+
/// FIXME (pnkfelix): Currently the `box` protocol only supports
113+
/// creating instances of sized types. This IntermediateBox is
114+
/// designed to be forward-compatible with a future protocol that
115+
/// supports creating instances of unsized types; that is why the type
116+
/// parameter has the `?Sized` generalization marker, and is also why
117+
/// this carries an explicit size. However, it probably does not need
118+
/// to carry the explicit alignment; that is just a work-around for
119+
/// the fact that the `align_of` intrinsic currently requires the
120+
/// input type to be Sized (which I do not think is strictly
121+
/// necessary).
122+
#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")]
123+
pub struct IntermediateBox<T: ?Sized>{
124+
ptr: *mut u8,
125+
size: usize,
126+
align: usize,
127+
marker: marker::PhantomData<*mut T>,
128+
}
129+
130+
impl<T> Place<T> for IntermediateBox<T> {
131+
fn pointer(&mut self) -> *mut T {
132+
unsafe { ::core::mem::transmute(self.ptr) }
133+
}
134+
}
135+
136+
unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
137+
let p = b.ptr as *mut T;
138+
mem::forget(b);
139+
mem::transmute(p)
140+
}
141+
142+
fn make_place<T>() -> IntermediateBox<T> {
143+
let size = mem::size_of::<T>();
144+
let align = mem::align_of::<T>();
145+
146+
let p = if size == 0 {
147+
heap::EMPTY as *mut u8
148+
} else {
149+
let p = unsafe {
150+
heap::allocate(size, align)
151+
};
152+
if p.is_null() {
153+
panic!("Box make_place allocation failure.");
154+
}
155+
p
156+
};
157+
158+
IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData }
159+
}
160+
161+
impl<T> BoxPlace<T> for IntermediateBox<T> {
162+
fn make_place() -> IntermediateBox<T> { make_place() }
163+
}
164+
165+
impl<T> InPlace<T> for IntermediateBox<T> {
166+
type Owner = Box<T>;
167+
unsafe fn finalize(self) -> Box<T> { finalize(self) }
168+
}
169+
170+
impl<T> Boxed for Box<T> {
171+
type Data = T;
172+
type Place = IntermediateBox<T>;
173+
unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> { finalize(b) }
174+
}
175+
176+
impl<T> Placer<T> for ExchangeHeapSingleton {
177+
type Place = IntermediateBox<T>;
178+
179+
fn make_place(self) -> IntermediateBox<T> {
180+
make_place()
181+
}
182+
}
183+
184+
impl<T: ?Sized> Drop for IntermediateBox<T> {
185+
fn drop(&mut self) {
186+
if self.size > 0 {
187+
unsafe {
188+
heap::deallocate(self.ptr, self.size, self.align)
189+
}
190+
}
191+
}
192+
}
95193

96194
impl<T> Box<T> {
97195
/// Allocates memory on the heap and then moves `x` into it.
@@ -199,8 +297,7 @@ impl<T: Clone> Clone for Box<T> {
199297
/// let y = x.clone();
200298
/// ```
201299
#[inline]
202-
fn clone(&self) -> Box<T> { box {(**self).clone()} }
203-
300+
fn clone(&self) -> Box<T> { box (HEAP) {(**self).clone()} }
204301
/// Copies `source`'s contents into `self` without creating a new allocation.
205302
///
206303
/// # Examples

src/libcore/ops.rs

+112
Original file line numberDiff line numberDiff line change
@@ -1266,3 +1266,115 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
12661266

12671267
// *const T -> *const U
12681268
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
1269+
1270+
/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions
1271+
/// that allocate an intermediate "place" that holds uninitialized
1272+
/// state. The desugaring evaluates EXPR, and writes the result at
1273+
/// the address returned by the `pointer` method of this trait.
1274+
///
1275+
/// A `Place` can be thought of as a special representation for a
1276+
/// hypothetical `&uninit` reference (which Rust cannot currently
1277+
/// express directly). That is, it represents a pointer to
1278+
/// uninitialized storage.
1279+
///
1280+
/// The client is responsible for two steps: First, initializing the
1281+
/// payload (it can access its address via `pointer`). Second,
1282+
/// converting the agent to an instance of the owning pointer, via the
1283+
/// appropriate `finalize` method (see the `InPlace`.
1284+
///
1285+
/// If evaluating EXPR fails, then the destructor for the
1286+
/// implementation of Place to clean up any intermediate state
1287+
/// (e.g. deallocate box storage, pop a stack, etc).
1288+
pub trait Place<Data: ?Sized> {
1289+
/// Returns the address where the input value will be written.
1290+
/// Note that the data at this address is generally uninitialized,
1291+
/// and thus one should use `ptr::write` for initializing it.
1292+
fn pointer(&mut self) -> *mut Data;
1293+
}
1294+
1295+
/// Interface to implementations of `in (PLACE) EXPR`.
1296+
///
1297+
/// `in (PLACE) EXPR` effectively desugars into:
1298+
///
1299+
/// ```rust,ignore
1300+
/// let p = PLACE;
1301+
/// let mut place = Placer::make_place(p);
1302+
/// let raw_place = Place::pointer(&mut place);
1303+
/// let value = EXPR;
1304+
/// unsafe {
1305+
/// std::ptr::write(raw_place, value);
1306+
/// InPlace::finalize(place)
1307+
/// }
1308+
/// ```
1309+
///
1310+
/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`;
1311+
/// if the type of `PLACE` is `P`, then the final type of the whole
1312+
/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed`
1313+
/// traits).
1314+
///
1315+
/// Values for types implementing this trait usually are transient
1316+
/// intermediate values (e.g. the return value of `Vec::emplace_back`)
1317+
/// or `Copy`, since the `make_place` method takes `self` by value.
1318+
pub trait Placer<Data: ?Sized> {
1319+
/// `Place` is the intermedate agent guarding the
1320+
/// uninitialized state for `Data`.
1321+
type Place: InPlace<Data>;
1322+
1323+
/// Creates a fresh place from `self`.
1324+
fn make_place(self) -> Self::Place;
1325+
}
1326+
1327+
/// Specialization of `Place` trait supporting `in (PLACE) EXPR`.
1328+
pub trait InPlace<Data: ?Sized>: Place<Data> {
1329+
/// `Owner` is the type of the end value of `in (PLACE) EXPR`
1330+
///
1331+
/// Note that when `in (PLACE) EXPR` is solely used for
1332+
/// side-effecting an existing data-structure,
1333+
/// e.g. `Vec::emplace_back`, then `Owner` need not carry any
1334+
/// information at all (e.g. it can be the unit type `()` in that
1335+
/// case).
1336+
type Owner;
1337+
1338+
/// Converts self into the final value, shifting
1339+
/// deallocation/cleanup responsibilities (if any remain), over to
1340+
/// the returned instance of `Owner` and forgetting self.
1341+
unsafe fn finalize(self) -> Self::Owner;
1342+
}
1343+
1344+
/// Core trait for the `box EXPR` form.
1345+
///
1346+
/// `box EXPR` effectively desugars into:
1347+
///
1348+
/// ```rust,ignore
1349+
/// let mut place = BoxPlace::make_place();
1350+
/// let raw_place = Place::pointer(&mut place);
1351+
/// let value = EXPR;
1352+
/// unsafe {
1353+
/// ::std::ptr::write(raw_place, value);
1354+
/// Boxed::finalize(place)
1355+
/// }
1356+
/// ```
1357+
///
1358+
/// The type of `box EXPR` is supplied from its surrounding
1359+
/// context; in the above expansion, the result type `T` is used
1360+
/// to determine which implementation of `Boxed` to use, and that
1361+
/// `<T as Boxed>` in turn dictates determines which
1362+
/// implementation of `BoxPlace` to use, namely:
1363+
/// `<<T as Boxed>::Place as BoxPlace>`.
1364+
pub trait Boxed {
1365+
/// The kind of data that is stored in this kind of box.
1366+
type Data; /* (`Data` unused b/c cannot yet express below bound.) */
1367+
/// The place that will negotiate the storage of the data.
1368+
type Place; /* should be bounded by BoxPlace<Self::Data> */
1369+
1370+
/// Converts filled place into final owning value, shifting
1371+
/// deallocation/cleanup responsibilities (if any remain), over to
1372+
/// returned instance of `Self` and forgetting `filled`.
1373+
unsafe fn finalize(filled: Self::Place) -> Self;
1374+
}
1375+
1376+
/// Specialization of `Place` trait supporting `box EXPR`.
1377+
pub trait BoxPlace<Data: ?Sized> : Place<Data> {
1378+
/// Creates a globally fresh place.
1379+
fn make_place() -> Self;
1380+
}

src/librustc/middle/expr_use_visitor.rs

+5
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,11 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
555555
None => {}
556556
}
557557
self.consume_expr(&**base);
558+
if place.is_some() {
559+
self.tcx().sess.span_bug(
560+
expr.span,
561+
"box with explicit place remains after expansion");
562+
}
558563
}
559564

560565
ast::ExprMac(..) => {

0 commit comments

Comments
 (0)