librustc: Implement placement box for GC and unique pointers.

This commit is contained in:
Patrick Walton 2013-12-17 16:46:18 -08:00
parent dd11fe17c7
commit e12711540a
22 changed files with 297 additions and 43 deletions

View File

@ -394,6 +394,10 @@ impl CFGBuilder {
self.straightline(expr, pred, [l, r])
}
ast::ExprBox(p, e) => {
self.straightline(expr, pred, [p, e])
}
ast::ExprAddrOf(_, e) |
ast::ExprDoBody(e) |
ast::ExprCast(e, _) |

View File

@ -721,6 +721,11 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
self.walk_expr(e, in_out, loop_scopes);
}
ast::ExprBox(s, e) => {
self.walk_expr(s, in_out, loop_scopes);
self.walk_expr(e, in_out, loop_scopes);
}
ast::ExprInlineAsm(ref inline_asm) => {
for &(_, expr) in inline_asm.inputs.iter() {
self.walk_expr(expr, in_out, loop_scopes);

View File

@ -207,7 +207,7 @@ pub fn collect_language_items(crate: &ast::Crate,
}
lets_do_this! {
There are 37 lang items.
There are 40 lang items.
// ID, Variant name, Name, Method name;
0, FreezeTraitLangItem, "freeze", freeze_trait;
@ -256,5 +256,9 @@ lets_do_this! {
35, TypeIdLangItem, "type_id", type_id;
36, EhPersonalityLangItem, "eh_personality", eh_personality_fn;
37, ManagedHeapLangItem, "managed_heap", managed_heap;
38, ExchangeHeapLangItem, "exchange_heap", exchange_heap;
39, GcLangItem, "gc", gc;
}

View File

@ -556,7 +556,7 @@ fn visit_expr(v: &mut LivenessVisitor, expr: &Expr, this: @IrMaps) {
ExprAgain(_) | ExprLit(_) | ExprRet(..) | ExprBlock(..) |
ExprAssign(..) | ExprAssignOp(..) | ExprMac(..) |
ExprStruct(..) | ExprRepeat(..) | ExprParen(..) |
ExprInlineAsm(..) => {
ExprInlineAsm(..) | ExprBox(..) => {
visit::walk_expr(v, expr, this);
}
}
@ -1252,7 +1252,8 @@ impl Liveness {
}
ExprIndex(_, l, r) |
ExprBinary(_, _, l, r) => {
ExprBinary(_, _, l, r) |
ExprBox(l, r) => {
self.propagate_through_exprs([l, r], succ)
}
@ -1546,7 +1547,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) |
ExprSelf(..) => {
ExprSelf(..) | ExprBox(..) => {
visit::walk_expr(this, expr, ());
}
ExprForLoop(..) => fail!("non-desugared expr_for_loop")

View File

@ -438,7 +438,7 @@ impl mem_categorization_ctxt {
ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
ast::ExprInlineAsm(..) => {
ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
return self.cat_rvalue_node(expr, expr_ty);
}

View File

@ -591,6 +591,11 @@ impl VisitContext {
self.use_expr(base, comp_mode);
}
ExprBox(place, base) => {
self.use_expr(place, comp_mode);
self.use_expr(base, comp_mode);
}
ExprMac(..) => {
self.tcx.sess.span_bug(
expr.span,

View File

@ -2616,6 +2616,11 @@ fn populate_scope_map(cx: &CrateContext,
ast::ExprField(@ref sub_exp, _, _) |
ast::ExprParen(@ref sub_exp) => walk_expr(cx, sub_exp, scope_stack, scope_map),
ast::ExprBox(@ref place, @ref sub_expr) => {
walk_expr(cx, place, scope_stack, scope_map);
walk_expr(cx, sub_expr, scope_stack, scope_map);
}
ast::ExprRet(exp_opt) => match exp_opt {
Some(@ref sub_exp) => walk_expr(cx, sub_exp, scope_stack, scope_map),
None => ()

View File

@ -619,6 +619,14 @@ fn trans_rvalue_datum_unadjusted<'a>(bcx: &'a Block<'a>, expr: &ast::Expr)
return tvec::trans_uniq_or_managed_vstore(bcx, heap,
expr, contents);
}
ast::ExprBox(_, contents) => {
// Special case for `~T`. (The other case, for GC, is handled in
// `trans_rvalue_dps_unadjusted`.)
let box_ty = expr_ty(bcx, expr);
let contents_ty = expr_ty(bcx, contents);
let heap = heap_for_unique(bcx, contents_ty);
return trans_boxed_expr(bcx, box_ty, contents, contents_ty, heap)
}
ast::ExprLit(lit) => {
return trans_immediate_lit(bcx, expr, *lit);
}
@ -828,6 +836,11 @@ fn trans_rvalue_dps_unadjusted<'a>(
ast::ExprAssignOp(callee_id, op, dst, src) => {
return trans_assign_op(bcx, expr, callee_id, op, dst, src);
}
ast::ExprBox(_, contents) => {
// Special case for `Gc<T>` for now. The other case, for unique
// pointers, is handled in `trans_rvalue_datum_unadjusted`.
return trans_gc(bcx, expr, contents, dest)
}
_ => {
bcx.tcx().sess.span_bug(
expr.span,
@ -1463,35 +1476,35 @@ fn trans_unary_datum<'a>(
trans_unary_datum()")
}
};
}
fn trans_boxed_expr<'a>(
bcx: &'a Block<'a>,
box_ty: ty::t,
contents: &ast::Expr,
contents_ty: ty::t,
heap: heap)
-> DatumBlock<'a> {
let _icx = push_ctxt("trans_boxed_expr");
if heap == heap_exchange {
let llty = type_of::type_of(bcx.ccx(), contents_ty);
let size = llsize_of(bcx.ccx(), llty);
let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
heap_exchange, size);
add_clean_free(bcx, val, heap_exchange);
let bcx = trans_into(bcx, contents, SaveIn(val));
revoke_clean(bcx, val);
return immediate_rvalue_bcx(bcx, val, box_ty);
} else {
let base::MallocResult {
bcx,
smart_ptr: bx,
body
} = base::malloc_general(bcx, contents_ty, heap);
add_clean_free(bcx, bx, heap);
let bcx = trans_into(bcx, contents, SaveIn(body));
revoke_clean(bcx, bx);
return immediate_rvalue_bcx(bcx, bx, box_ty);
}
fn trans_boxed_expr<'a>(
bcx: &'a Block<'a>,
box_ty: ty::t,
contents: &ast::Expr,
contents_ty: ty::t,
heap: heap)
-> DatumBlock<'a> {
let _icx = push_ctxt("trans_boxed_expr");
if heap == heap_exchange {
let llty = type_of::type_of(bcx.ccx(), contents_ty);
let size = llsize_of(bcx.ccx(), llty);
let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
heap_exchange, size);
add_clean_free(bcx, val, heap_exchange);
let bcx = trans_into(bcx, contents, SaveIn(val));
revoke_clean(bcx, val);
return immediate_rvalue_bcx(bcx, val, box_ty);
} else {
let base::MallocResult {
bcx,
smart_ptr: bx,
body
} = base::malloc_general(bcx, contents_ty, heap);
add_clean_free(bcx, bx, heap);
let bcx = trans_into(bcx, contents, SaveIn(body));
revoke_clean(bcx, bx);
return immediate_rvalue_bcx(bcx, bx, box_ty);
}
}
@ -1507,6 +1520,42 @@ fn trans_addr_of<'a>(
return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
}
pub fn trans_gc<'a>(
mut bcx: &'a Block<'a>,
expr: &ast::Expr,
contents: &ast::Expr,
dest: Dest)
-> &'a Block<'a> {
let contents_ty = expr_ty(bcx, contents);
let box_ty = ty::mk_box(bcx.tcx(), contents_ty);
let expr_ty = expr_ty(bcx, expr);
let addr = match dest {
Ignore => {
return trans_boxed_expr(bcx,
box_ty,
contents,
contents_ty,
heap_managed).bcx
}
SaveIn(addr) => addr,
};
let repr = adt::represent_type(bcx.ccx(), expr_ty);
adt::trans_start_init(bcx, repr, addr, 0);
let field_dest = adt::trans_field_ptr(bcx, repr, addr, 0, 0);
let contents_datum_block = trans_boxed_expr(bcx,
box_ty,
contents,
contents_ty,
heap_managed);
bcx = contents_datum_block.bcx;
bcx = contents_datum_block.datum.move_to(bcx, INIT, field_dest);
// Next, wrap it up in the struct.
bcx
}
// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
fn trans_eager_binop<'a>(

View File

@ -13,8 +13,8 @@ use back::abi;
use lib;
use lib::llvm::{llvm, ValueRef};
use middle::lang_items::StrDupUniqFnLangItem;
use middle::trans::base;
use middle::trans::base::*;
use middle::trans::base;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::common::*;
@ -23,14 +23,12 @@ use middle::trans::expr::{Dest, Ignore, SaveIn};
use middle::trans::expr;
use middle::trans::glue;
use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
use middle::trans::type_::Type;
use middle::trans::type_of;
use middle::ty;
use util::common::indenter;
use util::ppaux::ty_to_str;
use middle::trans::type_::Type;
use std::option::None;
use syntax::ast;
use syntax::codemap;
@ -689,3 +687,4 @@ pub fn iter_vec_unboxed<'r,
let dataptr = get_dataptr(bcx, body_ptr);
return iter_vec_raw(bcx, dataptr, vec_ty, fill, f);
}

View File

@ -12,8 +12,8 @@ use driver::session;
use metadata::csearch;
use metadata;
use middle::const_eval;
use middle::lang_items::{ExchangeHeapLangItem, OpaqueStructLangItem};
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
use middle::lang_items::OpaqueStructLangItem;
use middle::freevars;
use middle::resolve;
use middle::resolve_lifetime;
@ -3241,6 +3241,20 @@ pub fn expr_kind(tcx: ctxt,
RvalueDatumExpr
}
ast::ExprBox(place, _) => {
// Special case `~T` for now:
let def_map = tcx.def_map.borrow();
let definition = match def_map.get().find(&place.id) {
Some(&def) => def,
None => fail!("no def for place"),
};
let def_id = ast_util::def_id_of_def(definition);
match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
Some(item_def_id) if def_id == item_def_id => RvalueDatumExpr,
Some(_) | None => RvalueDpsExpr,
}
}
ast::ExprParen(e) => expr_kind(tcx, method_map, e),
ast::ExprMac(..) => {

View File

@ -78,9 +78,11 @@ type parameter).
use middle::const_eval;
use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
use middle::lang_items::{ManagedHeapLangItem};
use middle::lint::unreachable_code;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::lint::unreachable_code;
use middle::subst::Subst;
use middle::ty::{FnSig, VariantInfo};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
@ -2679,6 +2681,73 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
fcx.write_ty(id, typ);
}
ast::ExprBox(place, subexpr) => {
check_expr(fcx, place);
check_expr(fcx, subexpr);
let mut checked = false;
match place.node {
ast::ExprPath(ref path) => {
// XXX(pcwalton): For now we hardcode the two permissible
// places: the exchange heap and the managed heap.
let definition = lookup_def(fcx, path.span, place.id);
let def_id = ast_util::def_id_of_def(definition);
match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
Some(item_def_id) if def_id == item_def_id => {
fcx.write_ty(id, ty::mk_uniq(tcx, ty::mt {
ty: fcx.expr_ty(subexpr),
mutbl: ast::MutImmutable,
}));
checked = true
}
Some(_) | None => {}
}
if !checked {
match tcx.lang_items
.items[ManagedHeapLangItem as uint] {
Some(item_def_id) if def_id == item_def_id => {
// Assign the magic `Gc<T>` struct.
let gc_struct_id =
match tcx.lang_items
.require(GcLangItem) {
Ok(id) => id,
Err(msg) => {
tcx.sess.span_err(expr.span, msg);
ast::DefId {
crate: ast::CRATE_NODE_ID,
node: ast::DUMMY_NODE_ID,
}
}
};
let regions =
ty::NonerasedRegions(opt_vec::Empty);
let sty = ty::mk_struct(tcx,
gc_struct_id,
substs {
self_ty: None,
tps: ~[
fcx.expr_ty(
subexpr)
],
regions: regions,
});
fcx.write_ty(id, sty);
checked = true
}
Some(_) | None => {}
}
}
}
_ => {}
}
if !checked {
tcx.sess.span_err(expr.span,
"only the managed heap and exchange heap are \
currently supported")
}
}
ast::ExprLit(lit) => {
let typ = check_lit(fcx, lit);
fcx.write_ty(id, typ);

View File

@ -1048,6 +1048,7 @@ pub mod guarantor {
ast::ExprAddrOf(..) |
ast::ExprBinary(..) |
ast::ExprVstore(..) |
ast::ExprBox(..) |
ast::ExprBreak(..) |
ast::ExprAgain(..) |
ast::ExprRet(..) |

View File

@ -21,6 +21,14 @@ use clone::{Clone, DeepClone};
use managed;
/// Immutable garbage-collected pointer type
#[lang="gc"]
#[cfg(not(test))]
#[no_send]
pub struct Gc<T> {
priv ptr: @T
}
#[cfg(test)]
#[no_send]
pub struct Gc<T> {
priv ptr: @T
@ -54,6 +62,16 @@ impl<T> Clone for Gc<T> {
}
}
/// An value that represents the task-local managed heap.
///
/// Use this like `let foo = box(GC) Bar::new(...);`
#[lang="managed_heap"]
#[cfg(not(test))]
pub static GC: () = ();
#[cfg(test)]
pub static GC: () = ();
/// The `Send` bound restricts this to acyclic graphs where it is well-defined.
///
/// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed.

View File

@ -12,6 +12,20 @@
#[cfg(not(test))] use cmp::*;
/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// let foo = box(HEAP) Bar::new(...);
/// let foo = box Bar::new(...);
#[lang="exchange_heap"]
#[cfg(not(test))]
pub static HEAP: () = ();
#[cfg(test)]
pub static HEAP: () = ();
#[cfg(not(test))]
impl<T:Eq> Eq for ~T {
#[inline]

View File

@ -86,6 +86,10 @@ pub use vec::{Vector, VectorVector, CopyableVector, ImmutableVector};
pub use comm::{Port, Chan, SharedChan};
pub use task::spawn;
// Reexported statics
#[cfg(not(test))]
pub use gc::GC;
/// Disposes of a value.
#[inline]
pub fn drop<T>(_x: T) { }

View File

@ -547,6 +547,8 @@ pub enum CallSugar {
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum Expr_ {
ExprVstore(@Expr, ExprVstore),
// First expr is the place; second expr is the value.
ExprBox(@Expr, @Expr),
ExprVec(~[@Expr], Mutability),
ExprCall(@Expr, ~[@Expr], CallSugar),
ExprMethodCall(NodeId, @Expr, Ident, ~[P<Ty>], ~[@Expr], CallSugar),

View File

@ -724,6 +724,9 @@ pub fn noop_fold_expr<T: ast_fold>(e: @Expr, folder: &mut T) -> @Expr {
ExprVstore(e, v) => {
ExprVstore(folder.fold_expr(e), v)
}
ExprBox(p, e) => {
ExprBox(folder.fold_expr(p), folder.fold_expr(e))
}
ExprVec(ref exprs, mutt) => {
ExprVec(exprs.map(|&x| folder.fold_expr(x)), mutt)
}

View File

@ -23,7 +23,7 @@ use ast::{BlockCheckMode, UnBox};
use ast::{Crate, CrateConfig, Decl, DeclItem};
use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, enum_def, explicit_self};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock};
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac};
@ -2325,6 +2325,20 @@ impl Parser {
token::IDENT(_, _) if self.is_keyword(keywords::Box) => {
self.bump();
// Check for a place: `box(PLACE) EXPR`.
if self.eat(&token::LPAREN) {
// Support `box() EXPR` as the default.
if !self.eat(&token::RPAREN) {
let place = self.parse_expr();
self.expect(&token::RPAREN);
let subexpression = self.parse_prefix_expr();
hi = subexpression.span.hi;
ex = ExprBox(place, subexpression);
return self.mk_expr(lo, hi, ex);
}
}
// Otherwise, we use the unique pointer default.
let subexpression = self.parse_prefix_expr();
hi = subexpression.span.hi;
// HACK: turn `box [...]` into a boxed-evec

View File

@ -1155,6 +1155,13 @@ pub fn print_expr(s: &mut ps, expr: &ast::Expr) {
print_expr_vstore(s, v);
print_expr(s, e);
},
ast::ExprBox(p, e) => {
word(&mut s.s, "box");
word(&mut s.s, "(");
print_expr(s, p);
word_space(s, ")");
print_expr(s, e);
}
ast::ExprVec(ref exprs, mutbl) => {
ibox(s, indent_unit);
word(&mut s.s, "[");

View File

@ -618,6 +618,10 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
ExprVstore(subexpression, _) => {
visitor.visit_expr(subexpression, env.clone())
}
ExprBox(place, subexpression) => {
visitor.visit_expr(place, env.clone());
visitor.visit_expr(subexpression, env.clone())
}
ExprVec(ref subexpressions, _) => {
walk_exprs(visitor, *subexpressions, env.clone())
}

View File

@ -0,0 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the new `box` syntax works with unique pointers and GC pointers.
use std::gc::Gc;
use std::owned::HEAP;
pub fn main() {
let x: Gc<int> = box(HEAP) 2; //~ ERROR mismatched types
let y: Gc<int> = box(HEAP)(1 + 2); //~ ERROR mismatched types
let z: ~int = box(GC)(4 + 5); //~ ERROR mismatched types
}

View File

@ -1,8 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
pub fn main() {
let x: ~int = box 3;
println!("{}", *x);
// Tests that the new `box` syntax works with unique pointers and GC pointers.
use std::gc::Gc;
use std::owned::HEAP;
struct Structure {
x: int,
y: int,
}
pub fn main() {
let x: ~int = box(HEAP) 2;
let y: ~int = box 2;
let z: Gc<int> = box(GC) 2;
let a: Gc<Structure> = box(GC) Structure {
x: 10,
y: 20,
};
let b: ~int = box()(1 + 2);
let c = box()(3 + 4);
let d = box(GC)(5 + 6);
}