From fa1295343fdbccb608c95ec49c96eada9cb44f50 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 10 Oct 2011 09:51:09 +0200 Subject: [PATCH] Make free glue take a pointer to the heap part (box) This way, it can be used to drop values without first spilling them. Issue #1012 --- src/comp/middle/trans.rs | 132 +++++++++++++++++----------------- src/comp/middle/trans_uniq.rs | 5 +- 2 files changed, 67 insertions(+), 70 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 92d8d3d371b7..16b70e37cbf2 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -46,6 +46,12 @@ import trans_build::*; import trans_objects::{trans_anon_obj, trans_obj}; import tvec = trans_vec; +fn type_of_1(bcx: @block_ctxt, t: ty::t) -> TypeRef { + let cx = bcx_ccx(bcx); + check type_has_static_size(cx, t); + type_of(cx, bcx.sp, t) +} + fn type_of(cx: @crate_ctxt, sp: span, t: ty::t) : type_has_static_size(cx, t) -> TypeRef { // Should follow from type_has_static_size -- argh. @@ -1335,62 +1341,59 @@ fn incr_refcnt_of_boxed(cx: @block_ctxt, box_ptr: ValueRef) -> @block_ctxt { ret cx; } -fn make_free_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) { - // NB: v is an *alias* of type t here, not a direct value. - let bcx = - alt ty::struct(bcx_tcx(bcx), t) { - ty::ty_box(body_mt) { - let v = Load(bcx, v0); - let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]); - let bcx = drop_ty(bcx, body, body_mt.ty); - if !bcx_ccx(bcx).sess.get_opts().do_gc { - trans_non_gc_free(bcx, v) - } else { bcx } - } - ty::ty_uniq(content_mt) { - check trans_uniq::type_is_unique_box(bcx, t); - trans_uniq::make_free_glue(bcx, v0, t) - } - ty::ty_obj(_) { - // Call through the obj's own fields-drop glue first. - // Then free the body. - let box_cell = - GEP(bcx, v0, [C_int(0), C_int(abi::obj_field_box)]); - let b = Load(bcx, box_cell); - let ccx = bcx_ccx(bcx); - let llbox_ty = T_opaque_obj_ptr(*ccx); - b = PointerCast(bcx, b, llbox_ty); - let body = GEP(bcx, b, [C_int(0), C_int(abi::box_rc_field_body)]); - let tydescptr = - GEP(bcx, body, [C_int(0), C_int(abi::obj_body_elt_tydesc)]); - let tydesc = Load(bcx, tydescptr); - let ti = none; - call_tydesc_glue_full(bcx, body, tydesc, - abi::tydesc_field_drop_glue, ti); - if !bcx_ccx(bcx).sess.get_opts().do_gc { - trans_non_gc_free(bcx, b) - } else { bcx } - } - ty::ty_fn(_, _, _, _, _) { - // Call through the closure's own fields-drop glue first. - // Then free the body. - let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::fn_field_box)]); - let v = Load(bcx, box_cell); - let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]); - let bindings = - GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_bindings)]); - let tydescptr = - GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_tydesc)]); - let ti = none; - call_tydesc_glue_full(bcx, bindings, Load(bcx, tydescptr), - abi::tydesc_field_drop_glue, ti); - if !bcx_ccx(bcx).sess.get_opts().do_gc { - trans_non_gc_free(bcx, v) - } else { bcx } - } - _ { bcx } - }; - +fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) { + // v is a pointer to the actual box component of the type here. The + // ValueRef will have the wrong type here (make_generic_glue is casting + // everything to a pointer to the type that the glue acts on). + let bcx = alt ty::struct(bcx_tcx(bcx), t) { + ty::ty_box(body_mt) { + v = PointerCast(bcx, v, type_of_1(bcx, t)); + let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]); + let bcx = drop_ty(bcx, body, body_mt.ty); + if !bcx_ccx(bcx).sess.get_opts().do_gc { + trans_non_gc_free(bcx, v) + } else { bcx } + } + ty::ty_uniq(content_mt) { + check trans_uniq::type_is_unique_box(bcx, t); + v = PointerCast(bcx, v, type_of_1(bcx, t)); + trans_uniq::make_free_glue(bcx, v, t) + } + ty::ty_obj(_) { + // Call through the obj's own fields-drop glue first. + // Then free the body. + let ccx = bcx_ccx(bcx); + let llbox_ty = T_opaque_obj_ptr(*ccx); + let b = PointerCast(bcx, v, llbox_ty); + let body = GEP(bcx, b, [C_int(0), C_int(abi::box_rc_field_body)]); + let tydescptr = + GEP(bcx, body, [C_int(0), C_int(abi::obj_body_elt_tydesc)]); + let tydesc = Load(bcx, tydescptr); + let ti = none; + call_tydesc_glue_full(bcx, body, tydesc, + abi::tydesc_field_drop_glue, ti); + if !bcx_ccx(bcx).sess.get_opts().do_gc { + trans_non_gc_free(bcx, b) + } else { bcx } + } + ty::ty_fn(_, _, _, _, _) { + // Call through the closure's own fields-drop glue first. + // Then free the body. + v = PointerCast(bcx, v, T_opaque_closure_ptr(*bcx_ccx(bcx))); + let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]); + let bindings = + GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_bindings)]); + let tydescptr = + GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_tydesc)]); + let ti = none; + call_tydesc_glue_full(bcx, bindings, Load(bcx, tydescptr), + abi::tydesc_field_drop_glue, ti); + if !bcx_ccx(bcx).sess.get_opts().do_gc { + trans_non_gc_free(bcx, v) + } else { bcx } + } + _ { bcx } + }; build_return(bcx); } @@ -1401,21 +1404,19 @@ fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) { alt ty::struct(ccx.tcx, t) { ty::ty_vec(_) { tvec::make_drop_glue(bcx, v0, t) } ty::ty_str. { tvec::make_drop_glue(bcx, v0, t) } - ty::ty_box(_) { decr_refcnt_maybe_free(bcx, v0, v0, t) } - ty::ty_uniq(_) { - free_ty(bcx, v0, t) - } + ty::ty_box(_) { decr_refcnt_maybe_free(bcx, Load(bcx, v0), t) } + ty::ty_uniq(_) { free_ty(bcx, Load(bcx, v0), t) } ty::ty_obj(_) { let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::obj_field_box)]); - decr_refcnt_maybe_free(bcx, box_cell, v0, t) + decr_refcnt_maybe_free(bcx, Load(bcx, box_cell), t) } ty::ty_res(did, inner, tps) { trans_res_drop(bcx, v0, did, inner, tps) } ty::ty_fn(_, _, _, _, _) { let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::fn_field_box)]); - decr_refcnt_maybe_free(bcx, box_cell, v0, t) + decr_refcnt_maybe_free(bcx, Load(bcx, box_cell), t) } _ { if ty::type_has_pointers(ccx.tcx, t) && @@ -1470,13 +1471,12 @@ fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: ast::def_id, ret next_cx; } -fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr_alias: ValueRef, - full_alias: ValueRef, t: ty::t) -> @block_ctxt { +fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t) + -> @block_ctxt { let ccx = bcx_ccx(cx); let rc_adj_cx = new_sub_block_ctxt(cx, "rc--"); let free_cx = new_sub_block_ctxt(cx, "free"); let next_cx = new_sub_block_ctxt(cx, "next"); - let box_ptr = Load(cx, box_ptr_alias); let llbox_ty = T_opaque_obj_ptr(*ccx); box_ptr = PointerCast(cx, box_ptr, llbox_ty); let null_test = IsNull(cx, box_ptr); @@ -1488,7 +1488,7 @@ fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr_alias: ValueRef, Store(rc_adj_cx, rc, rc_ptr); let zero_test = ICmp(rc_adj_cx, lib::llvm::LLVMIntEQ, C_int(0), rc); CondBr(rc_adj_cx, zero_test, free_cx.llbb, next_cx.llbb); - let free_cx = free_ty(free_cx, full_alias, t); + let free_cx = free_ty(free_cx, box_ptr, t); Br(free_cx, next_cx.llbb); ret next_cx; } diff --git a/src/comp/middle/trans_uniq.rs b/src/comp/middle/trans_uniq.rs index def42ecfdd93..e3911de4a7a0 100644 --- a/src/comp/middle/trans_uniq.rs +++ b/src/comp/middle/trans_uniq.rs @@ -53,22 +53,19 @@ fn alloc_uniq(cx: @block_ctxt, uniq_ty: ty::t) ret rslt(bcx, llptr); } -fn make_free_glue(cx: @block_ctxt, v: ValueRef, t: ty::t) +fn make_free_glue(cx: @block_ctxt, vptr: ValueRef, t: ty::t) : type_is_unique_box(cx, t) -> @block_ctxt { let bcx = cx; let free_cx = new_sub_block_ctxt(bcx, "uniq_free"); let next_cx = new_sub_block_ctxt(bcx, "uniq_free_next"); - let vptr = Load(bcx, v); let null_test = IsNull(bcx, vptr); CondBr(bcx, null_test, next_cx.llbb, free_cx.llbb); let bcx = free_cx; let bcx = drop_ty(bcx, vptr, content_ty(cx, t)); let bcx = trans_shared_free(bcx, vptr); - Store(bcx, C_null(val_ty(vptr)), v); Br(bcx, next_cx.llbb); - next_cx }