1
Fork 0

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
This commit is contained in:
Marijn Haverbeke 2011-10-10 09:51:09 +02:00
parent 96f6a1861c
commit fa1295343f
2 changed files with 67 additions and 70 deletions

View file

@ -46,6 +46,12 @@ import trans_build::*;
import trans_objects::{trans_anon_obj, trans_obj}; import trans_objects::{trans_anon_obj, trans_obj};
import tvec = trans_vec; 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) fn type_of(cx: @crate_ctxt, sp: span, t: ty::t) : type_has_static_size(cx, t)
-> TypeRef { -> TypeRef {
// Should follow from type_has_static_size -- argh. // 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; ret cx;
} }
fn make_free_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) { fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
// NB: v is an *alias* of type t here, not a direct value. // v is a pointer to the actual box component of the type here. The
let bcx = // ValueRef will have the wrong type here (make_generic_glue is casting
alt ty::struct(bcx_tcx(bcx), t) { // everything to a pointer to the type that the glue acts on).
ty::ty_box(body_mt) { let bcx = alt ty::struct(bcx_tcx(bcx), t) {
let v = Load(bcx, v0); ty::ty_box(body_mt) {
let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]); v = PointerCast(bcx, v, type_of_1(bcx, t));
let bcx = drop_ty(bcx, body, body_mt.ty); let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]);
if !bcx_ccx(bcx).sess.get_opts().do_gc { let bcx = drop_ty(bcx, body, body_mt.ty);
trans_non_gc_free(bcx, v) if !bcx_ccx(bcx).sess.get_opts().do_gc {
} else { bcx } trans_non_gc_free(bcx, v)
} } else { bcx }
ty::ty_uniq(content_mt) { }
check trans_uniq::type_is_unique_box(bcx, t); ty::ty_uniq(content_mt) {
trans_uniq::make_free_glue(bcx, v0, t) check trans_uniq::type_is_unique_box(bcx, t);
} v = PointerCast(bcx, v, type_of_1(bcx, t));
ty::ty_obj(_) { trans_uniq::make_free_glue(bcx, v, t)
// Call through the obj's own fields-drop glue first. }
// Then free the body. ty::ty_obj(_) {
let box_cell = // Call through the obj's own fields-drop glue first.
GEP(bcx, v0, [C_int(0), C_int(abi::obj_field_box)]); // Then free the body.
let b = Load(bcx, box_cell); let ccx = bcx_ccx(bcx);
let ccx = bcx_ccx(bcx); let llbox_ty = T_opaque_obj_ptr(*ccx);
let llbox_ty = T_opaque_obj_ptr(*ccx); let b = PointerCast(bcx, v, llbox_ty);
b = PointerCast(bcx, b, llbox_ty); let body = GEP(bcx, b, [C_int(0), C_int(abi::box_rc_field_body)]);
let body = GEP(bcx, b, [C_int(0), C_int(abi::box_rc_field_body)]); let tydescptr =
let tydescptr = GEP(bcx, body, [C_int(0), C_int(abi::obj_body_elt_tydesc)]);
GEP(bcx, body, [C_int(0), C_int(abi::obj_body_elt_tydesc)]); let tydesc = Load(bcx, tydescptr);
let tydesc = Load(bcx, tydescptr); let ti = none;
let ti = none; call_tydesc_glue_full(bcx, body, tydesc,
call_tydesc_glue_full(bcx, body, tydesc, abi::tydesc_field_drop_glue, ti);
abi::tydesc_field_drop_glue, ti); if !bcx_ccx(bcx).sess.get_opts().do_gc {
if !bcx_ccx(bcx).sess.get_opts().do_gc { trans_non_gc_free(bcx, b)
trans_non_gc_free(bcx, b) } else { bcx }
} else { bcx } }
} ty::ty_fn(_, _, _, _, _) {
ty::ty_fn(_, _, _, _, _) { // Call through the closure's own fields-drop glue first.
// Call through the closure's own fields-drop glue first. // Then free the body.
// Then free the body. v = PointerCast(bcx, v, T_opaque_closure_ptr(*bcx_ccx(bcx)));
let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::fn_field_box)]); let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]);
let v = Load(bcx, box_cell); let bindings =
let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]); GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_bindings)]);
let bindings = let tydescptr =
GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_bindings)]); GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_tydesc)]);
let tydescptr = let ti = none;
GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_tydesc)]); call_tydesc_glue_full(bcx, bindings, Load(bcx, tydescptr),
let ti = none; abi::tydesc_field_drop_glue, ti);
call_tydesc_glue_full(bcx, bindings, Load(bcx, tydescptr), if !bcx_ccx(bcx).sess.get_opts().do_gc {
abi::tydesc_field_drop_glue, ti); trans_non_gc_free(bcx, v)
if !bcx_ccx(bcx).sess.get_opts().do_gc { } else { bcx }
trans_non_gc_free(bcx, v) }
} else { bcx } _ { bcx }
} };
_ { bcx }
};
build_return(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) { alt ty::struct(ccx.tcx, t) {
ty::ty_vec(_) { tvec::make_drop_glue(bcx, v0, t) } ty::ty_vec(_) { tvec::make_drop_glue(bcx, v0, t) }
ty::ty_str. { 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_box(_) { decr_refcnt_maybe_free(bcx, Load(bcx, v0), t) }
ty::ty_uniq(_) { ty::ty_uniq(_) { free_ty(bcx, Load(bcx, v0), t) }
free_ty(bcx, v0, t)
}
ty::ty_obj(_) { ty::ty_obj(_) {
let box_cell = let box_cell =
GEP(bcx, v0, [C_int(0), C_int(abi::obj_field_box)]); 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) { ty::ty_res(did, inner, tps) {
trans_res_drop(bcx, v0, did, inner, tps) trans_res_drop(bcx, v0, did, inner, tps)
} }
ty::ty_fn(_, _, _, _, _) { ty::ty_fn(_, _, _, _, _) {
let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::fn_field_box)]); 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) && 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; ret next_cx;
} }
fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr_alias: ValueRef, fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t)
full_alias: ValueRef, t: ty::t) -> @block_ctxt { -> @block_ctxt {
let ccx = bcx_ccx(cx); let ccx = bcx_ccx(cx);
let rc_adj_cx = new_sub_block_ctxt(cx, "rc--"); let rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
let free_cx = new_sub_block_ctxt(cx, "free"); let free_cx = new_sub_block_ctxt(cx, "free");
let next_cx = new_sub_block_ctxt(cx, "next"); 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); let llbox_ty = T_opaque_obj_ptr(*ccx);
box_ptr = PointerCast(cx, box_ptr, llbox_ty); box_ptr = PointerCast(cx, box_ptr, llbox_ty);
let null_test = IsNull(cx, box_ptr); 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); Store(rc_adj_cx, rc, rc_ptr);
let zero_test = ICmp(rc_adj_cx, lib::llvm::LLVMIntEQ, C_int(0), rc); 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); 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); Br(free_cx, next_cx.llbb);
ret next_cx; ret next_cx;
} }

View file

@ -53,22 +53,19 @@ fn alloc_uniq(cx: @block_ctxt, uniq_ty: ty::t)
ret rslt(bcx, llptr); 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 { : type_is_unique_box(cx, t) -> @block_ctxt {
let bcx = cx; let bcx = cx;
let free_cx = new_sub_block_ctxt(bcx, "uniq_free"); let free_cx = new_sub_block_ctxt(bcx, "uniq_free");
let next_cx = new_sub_block_ctxt(bcx, "uniq_free_next"); let next_cx = new_sub_block_ctxt(bcx, "uniq_free_next");
let vptr = Load(bcx, v);
let null_test = IsNull(bcx, vptr); let null_test = IsNull(bcx, vptr);
CondBr(bcx, null_test, next_cx.llbb, free_cx.llbb); CondBr(bcx, null_test, next_cx.llbb, free_cx.llbb);
let bcx = free_cx; let bcx = free_cx;
let bcx = drop_ty(bcx, vptr, content_ty(cx, t)); let bcx = drop_ty(bcx, vptr, content_ty(cx, t));
let bcx = trans_shared_free(bcx, vptr); let bcx = trans_shared_free(bcx, vptr);
Store(bcx, C_null(val_ty(vptr)), v);
Br(bcx, next_cx.llbb); Br(bcx, next_cx.llbb);
next_cx next_cx
} }