rustc: add rooting, write-guards to slices etc

This commit is contained in:
Niko Matsakis 2013-05-03 16:26:43 -04:00
parent f3a6ea2643
commit be08c3e514
12 changed files with 194 additions and 32 deletions

View File

@ -866,7 +866,18 @@ pub fn extract_variant_args(bcx: block,
ExtractedBlock { vals: args, bcx: bcx }
}
fn match_datum(bcx: block, val: ValueRef, pat_id: ast::node_id) -> Datum {
//! Helper for converting from the ValueRef that we pass around in
//! the match code, which is always by ref, into a Datum. Eventually
//! we should just pass around a Datum and be done with it.
let ty = node_id_type(bcx, pat_id);
Datum {val: val, ty: ty, mode: datum::ByRef, source: RevokeClean}
}
pub fn extract_vec_elems(bcx: block,
pat_span: span,
pat_id: ast::node_id,
elem_count: uint,
slice: Option<uint>,
@ -874,9 +885,9 @@ pub fn extract_vec_elems(bcx: block,
count: ValueRef)
-> ExtractedBlock {
let _icx = bcx.insn_ctxt("match::extract_vec_elems");
let vec_datum = match_datum(bcx, val, pat_id);
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id);
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
let unboxed = load_if_immediate(bcx, val, vt.vec_ty);
let (base, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty);
let mut elems = do vec::from_fn(elem_count) |i| {
match slice {
@ -1308,10 +1319,14 @@ pub fn compile_submatch(bcx: block,
vec::slice(vals, col + 1u, vals.len()));
let ccx = *bcx.fcx.ccx;
let mut pat_id = 0;
let mut pat_span = dummy_sp();
for vec::each(m) |br| {
// Find a real id (we're adding placeholder wildcard patterns, but
// each column is guaranteed to have at least one real pattern)
if pat_id == 0 { pat_id = br.pats[col].id; }
if pat_id == 0 {
pat_id = br.pats[col].id;
pat_span = br.pats[col].span;
}
}
// If we are not matching against an `@T`, we should not be
@ -1579,8 +1594,8 @@ pub fn compile_submatch(bcx: block,
vec_len_ge(_, i) => Some(i),
_ => None
};
let args = extract_vec_elems(opt_cx, pat_id, n, slice,
val, test_val);
let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice,
val, test_val);
size = args.vals.len();
unpacked = /*bad*/copy args.vals;
opt_cx = args.bcx;

View File

@ -333,7 +333,7 @@ pub fn trans_fail_expr(bcx: block,
bcx, expr::trans_to_datum(bcx, arg_expr));
if ty::type_is_str(arg_datum.ty) {
let (lldata, _lllen) = arg_datum.get_base_and_len(bcx);
let (lldata, _) = arg_datum.get_vec_base_and_len_no_root(bcx);
return trans_fail_value(bcx, sp_opt, lldata);
} else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) {
return bcx;

View File

@ -603,6 +603,8 @@ pub impl Datum {
}
fn perform_write_guard(&self, bcx: block, span: span) -> block {
debug!("perform_write_guard");
// Create scratch space, but do not root it.
let llval = match self.mode {
ByValue => self.val,
@ -682,25 +684,10 @@ pub impl Datum {
{
let ccx = bcx.ccx();
debug!("try_deref(expr_id=%d, derefs=%?, is_auto=%b, self=%?)",
debug!("try_deref(expr_id=%?, derefs=%?, is_auto=%b, self=%?)",
expr_id, derefs, is_auto, self.to_str(bcx.ccx()));
let _indenter = indenter();
// root the autoderef'd value, if necessary:
//
// (Note: root'd values are always boxes)
let key = root_map_key { id: expr_id, derefs: derefs };
let bcx = match ccx.maps.root_map.find(&key) {
None => bcx,
Some(&root_info) => self.root(bcx, span, key, root_info)
};
// Perform the write guard, if necessary.
//
// (Note: write-guarded values are always boxes)
let bcx = if ccx.maps.write_guard_map.contains(&key) {
self.perform_write_guard(bcx, span)
} else { bcx };
let bcx = self.root_and_write_guard(bcx, span, expr_id, derefs);
match ty::get(self.ty).sty {
ty::ty_box(_) | ty::ty_uniq(_) => {
@ -854,8 +841,53 @@ pub impl Datum {
DatumBlock { bcx: bcx, datum: datum }
}
fn get_base_and_len(&self, bcx: block) -> (ValueRef, ValueRef) {
tvec::get_base_and_len(bcx, self.to_appropriate_llval(bcx), self.ty)
fn root_and_write_guard(&self,
mut bcx: block,
span: span,
expr_id: ast::node_id,
derefs: uint) -> block {
let key = root_map_key { id: expr_id, derefs: derefs };
debug!("root_and_write_guard(key=%?)", key);
// root the autoderef'd value, if necessary:
//
// (Note: root'd values are always boxes)
let ccx = bcx.ccx();
bcx = match ccx.maps.root_map.find(&key) {
None => bcx,
Some(&root_info) => self.root(bcx, span, key, root_info)
};
// Perform the write guard, if necessary.
//
// (Note: write-guarded values are always boxes)
if ccx.maps.write_guard_map.contains(&key) {
self.perform_write_guard(bcx, span)
} else {
bcx
}
}
fn get_vec_base_and_len(&self,
mut bcx: block,
span: span,
expr_id: ast::node_id)
-> (block, ValueRef, ValueRef) {
//! Converts a vector into the slice pair. Performs rooting
//! and write guards checks.
// only imp't for @[] and @str, but harmless
bcx = self.root_and_write_guard(bcx, span, expr_id, 0);
let (base, len) = self.get_vec_base_and_len_no_root(bcx);
(bcx, base, len)
}
fn get_vec_base_and_len_no_root(&self, bcx: block) -> (ValueRef, ValueRef) {
//! Converts a vector into the slice pair. Des not root
//! nor perform write guard checks.
let llval = self.to_appropriate_llval(bcx);
tvec::get_base_and_len(bcx, llval, self.ty)
}
fn to_result(&self, bcx: block) -> common::Result {

View File

@ -218,10 +218,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
unpack_datum!(bcx, auto_ref(bcx, datum))
}
Some(AutoBorrowVec(*)) => {
unpack_datum!(bcx, auto_slice(bcx, datum))
unpack_datum!(bcx, auto_slice(bcx, expr, datum))
}
Some(AutoBorrowVecRef(*)) => {
unpack_datum!(bcx, auto_slice_and_ref(bcx, datum))
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
}
Some(AutoBorrowFn(*)) => {
// currently, all closure types are
@ -241,7 +241,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
}
fn auto_slice(bcx: block, datum: Datum) -> DatumBlock {
fn auto_slice(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock {
// This is not the most efficient thing possible; since slices
// are two words it'd be better if this were compiled in
// 'dest' mode, but I can't find a nice way to structure the
@ -250,7 +250,9 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
let tcx = bcx.tcx();
let unit_ty = ty::sequence_element_type(tcx, datum.ty);
let (base, len) = datum.get_base_and_len(bcx);
// NOTE prob need to distinguish "auto-slice" from explicit index?
let (bcx, base, len) =
datum.get_vec_base_and_len(bcx, expr.span, expr.id);
// this type may have a different region/mutability than the
// real one, but it will have the same runtime representation
@ -283,8 +285,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
DatumBlock {bcx: bcx, datum: scratch}
}
fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock {
let DatumBlock { bcx, datum } = auto_slice(bcx, datum);
fn auto_slice_and_ref(bcx: block,
expr: @ast::expr,
datum: Datum) -> DatumBlock {
let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
auto_ref(bcx, datum)
}
}
@ -903,7 +907,8 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
let mut (base, len) = base_datum.get_base_and_len(bcx);
let mut (bcx, base, len) =
base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id);
if ty::type_is_str(base_ty) {
// acccount for null terminator in the case of string

View File

@ -1,5 +1,8 @@
// error-pattern:borrowed
// Test that write guards trigger when there is a write to a field
// of a frozen structure.
struct S {
x: int
}

View File

@ -1,5 +1,8 @@
// error-pattern:borrowed
// Test that write guards trigger when there is a write to a directly
// frozen @mut box.
fn main() {
let x = @mut 3;
let y: &mut int = x;

View File

@ -1,5 +1,8 @@
// error-pattern:borrowed
// Test that write guards trigger when mut box is frozen
// as part of argument coercion.
fn f(_x: &int, y: @mut int) {
*y = 2;
}

View File

@ -0,0 +1,37 @@
// error-pattern:borrowed
// Test that write guards trigger when there is a coercion to
// a slice on the receiver of a method.
trait MyMutSlice {
fn my_mut_slice(self) -> Self;
}
impl<'self, T> MyMutSlice for &'self mut [T] {
fn my_mut_slice(self) -> &'self mut [T] {
self
}
}
trait MySlice {
fn my_slice(self) -> Self;
}
impl<'self, T> MySlice for &'self [T] {
fn my_slice(self) -> &'self [T] {
self
}
}
fn add(x:&mut [int], y:&[int])
{
x[0] = x[0] + y[0];
}
pub fn main()
{
let z = @mut [1,2,3];
let z2 = z;
add(z.my_mut_slice(), z2.my_slice());
print(fmt!("%d\n", z[0]));
}

View File

@ -0,0 +1,16 @@
// error-pattern:borrowed
// Test that write guards trigger when arguments are coerced to slices.
fn add(x:&mut [int], y:&[int])
{
x[0] = x[0] + y[0];
}
pub fn main()
{
let z = @mut [1,2,3];
let z2 = z;
add(z, z2);
print(fmt!("%d\n", z[0]));
}

View File

@ -0,0 +1,17 @@
// error-pattern:borrowed
// Test that write guards trigger when we are indexing into
// an @mut vector.
fn add(x:&mut int, y:&int)
{
*x = *x + *y;
}
pub fn main()
{
let z = @mut [1,2,3];
let z2 = z;
add(&mut z[0], &z2[0]);
print(fmt!("%d\n", z[0]));
}

View File

@ -0,0 +1,17 @@
// error-pattern:borrowed
// Test that arguments trigger when there are *two mutable* borrows
// of indices.
fn add(x:&mut int, y:&mut int)
{
*x = *x + *y;
}
pub fn main()
{
let z = @mut [1,2,3];
let z2 = z;
add(&mut z[0], &mut z2[0]);
print(fmt!("%d\n", z[0]));
}

View File

@ -0,0 +1,14 @@
// Test that we can borrow the same @mut box twice, so long as both are imm.
fn add(x:&int, y:&int)
{
*x + *y;
}
pub fn main()
{
let z = @mut [1,2,3];
let z2 = z;
add(&z[0], &z2[0]);
print(fmt!("%d\n", z[0]));
}