rustc: When revoking a cleanup of a unique pointer, zero it out so that the GC won't try to visit it

This commit is contained in:
Patrick Walton 2011-09-07 18:16:08 -07:00 committed by Marijn Haverbeke
parent 7a0c9759fe
commit fb9ab95a15
2 changed files with 25 additions and 15 deletions

View File

@ -2179,18 +2179,15 @@ fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
if src.is_mem { ret zero_alloca(cx, src.res.val, t).bcx; }
// If we're here, it must be a temporary.
revoke_clean(cx, src_val);
ret cx;
ret revoke_clean(cx, src_val, t);
} else if ty::type_is_unique(tcx, t) ||
type_is_structural_or_param(tcx, t) {
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
cx = memmove_ty(cx, dst, src_val, t).bcx;
if src.is_mem {
ret zero_alloca(cx, src_val, t).bcx;
} else { // Temporary value
revoke_clean(cx, src_val);
ret cx;
}
if src.is_mem { ret zero_alloca(cx, src_val, t).bcx; }
// If we're here, it must be a temporary.
ret revoke_clean(cx, src_val, t);
}
bcx_ccx(cx).sess.bug("unexpected type in trans::move_val: " +
ty_to_str(tcx, t));
@ -3620,7 +3617,8 @@ fn trans_bind_1(cx: &@block_ctxt, f: &@ast::expr, f_res: &lval_result,
fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef,
to_zero: &mutable [{v: ValueRef, t: ty::t}],
to_revoke: &mutable [ValueRef], e: &@ast::expr) -> result {
to_revoke: &mutable [{v: ValueRef, t: ty::t}],
e: &@ast::expr) -> result {
let ccx = bcx_ccx(cx);
let e_ty = ty::expr_ty(ccx.tcx, e);
let is_bot = ty::type_is_bot(ccx.tcx, e_ty);
@ -3672,7 +3670,9 @@ fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef,
// Use actual ty, not declared ty -- anything else doesn't make
// sense if declared ty is a ty param
to_zero += [{v: lv.res.val, t: e_ty}];
} else { to_revoke += [lv.res.val]; }
} else {
to_revoke += [{v: lv.res.val, t: e_ty}];
}
}
ret rslt(bcx, val);
}
@ -3691,7 +3691,7 @@ fn trans_args(cx: &@block_ctxt, llenv: ValueRef,
args: [ValueRef],
retslot: ValueRef,
to_zero: [{v: ValueRef, t: ty::t}],
to_revoke: [ValueRef]} {
to_revoke: [{v: ValueRef, t: ty::t}]} {
let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
let llargs: [ValueRef] = [];
@ -3869,9 +3869,11 @@ fn trans_call(in_cx: &@block_ctxt, f: &@ast::expr,
// Forget about anything we moved out.
for {v: v, t: t}: {v: ValueRef, t: ty::t} in args_res.to_zero {
zero_alloca(bcx, v, t)
bcx = zero_alloca(bcx, v, t).bcx;
}
for {v: v, t: t} in args_res.to_revoke {
bcx = revoke_clean(bcx, v, t);
}
for v: ValueRef in args_res.to_revoke { revoke_clean(bcx, v) }
bcx = trans_block_cleanups(bcx, cx);
let next_cx = new_sub_block_ctxt(in_cx, "next");
Br(bcx, next_cx.llbb);

View File

@ -314,7 +314,13 @@ fn add_clean_temp(cx: &@block_ctxt, val: ValueRef, ty: ty::t) {
// to a system where we can also cancel the cleanup on local variables, but
// this will be more involved. For now, we simply zero out the local, and the
// drop glue checks whether it is zero.
fn revoke_clean(cx: &@block_ctxt, val: ValueRef) {
fn revoke_clean(cx: &@block_ctxt, val: ValueRef, t: ty::t) -> @block_ctxt {
if ty::type_is_unique(bcx_tcx(cx), t) {
// Just zero out the allocation. This ensures that the GC won't try to
// traverse dangling pointers.
ret trans::zero_alloca(cx, val, t).bcx;
}
let sc_cx = find_scope_cx(cx);
let found = -1;
let i = 0;
@ -329,12 +335,14 @@ fn revoke_clean(cx: &@block_ctxt, val: ValueRef) {
}
// The value does not have a cleanup associated with it. Might be a
// constant or some immediate value.
if found == -1 { ret; }
if found == -1 { ret cx; }
// We found the cleanup and remove it
sc_cx.cleanups =
std::vec::slice(sc_cx.cleanups, 0u, found as uint) +
std::vec::slice(sc_cx.cleanups, (found as uint) + 1u,
std::vec::len(sc_cx.cleanups));
ret cx;
}
fn get_res_dtor(ccx: &@crate_ctxt, sp: &span, did: &ast::def_id,