From c39a95da90a3d8247e011f6a42f0c53ced34de97 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 29 Apr 2011 13:34:30 +0200 Subject: [PATCH] Implement destructors in rustc Unlike rustboot, rustc keeps it destructors in vtables. Entry 0 holds either the destructor for the obj or a NULL pointer. The method offsets start at 1. --- src/comp/back/abi.rs | 1 + src/comp/middle/trans.rs | 100 +++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs index f43e74ef2eb..39c176dce64 100644 --- a/src/comp/back/abi.rs +++ b/src/comp/back/abi.rs @@ -38,6 +38,7 @@ const int tydesc_field_drop_glue = 4; const int tydesc_field_free_glue = 5; const int tydesc_field_sever_glue = 6; const int tydesc_field_mark_glue = 7; +// FIXME no longer used in rustc, drop when rustboot is gone const int tydesc_field_obj_drop_glue = 8; const int tydesc_field_is_stateful = 9; const int tydesc_field_cmp_glue = 10; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 335614d2e15..aea6b8e9433 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -359,6 +359,11 @@ fn T_glue_fn(type_names tn) -> TypeRef { ret t; } +fn T_dtor(@crate_ctxt ccx, TypeRef llself_ty) -> TypeRef { + ret type_of_fn_full(ccx, ast.proto_fn, some[TypeRef](llself_ty), + _vec.empty[ty.arg](), ty.mk_nil(ccx.tcx), 0u); +} + fn T_cmp_glue_fn(type_names tn) -> TypeRef { auto s = "cmp_glue_fn"; if (tn.name_has_type(s)) { @@ -763,7 +768,7 @@ fn type_of_inner(@crate_ctxt cx, ty.t t) -> TypeRef { auto th = mk_type_handle(); auto self_ty = llvm.LLVMResolveTypeHandle(th.llth); - let vec[TypeRef] mtys = vec(); + let vec[TypeRef] mtys = vec(T_ptr(T_i8())); for (ty.method m in meths) { let TypeRef mty = type_of_fn_full(cx, m.proto, @@ -1618,7 +1623,8 @@ fn get_tydesc(&@block_ctxt cx, ty.t t) -> result { // Otherwise, generate a tydesc if necessary, and return it. let vec[uint] tps = vec(); - ret res(cx, get_static_tydesc(cx, t, tps).tydesc); + auto st = get_static_tydesc(cx, t, tps).tydesc; + ret res(cx, st); } fn get_static_tydesc(&@block_ctxt cx, @@ -1901,25 +1907,26 @@ fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) { } case (ty.ty_obj(_)) { - fn hit_zero(@block_ctxt cx, ValueRef v) -> result { - - // Call through the obj's own fields-drop glue first. + fn hit_zero(@block_ctxt cx, ValueRef b, ValueRef o) -> result { auto body = - cx.build.GEP(v, + cx.build.GEP(b, vec(C_int(0), C_int(abi.box_rc_field_body))); - auto tydescptr = cx.build.GEP(body, vec(C_int(0), C_int(abi.obj_body_elt_tydesc))); + auto tydesc = cx.build.Load(tydescptr); - call_tydesc_glue_full(cx, body, cx.build.Load(tydescptr), + auto cx_ = maybe_call_dtor(cx, o); + + // Call through the obj's own fields-drop glue first. + call_tydesc_glue_full(cx_, body, tydesc, abi.tydesc_field_drop_glue); // Then free the body. // FIXME: switch gc/non-gc on layer of the type. - ret trans_non_gc_free(cx, v); + ret trans_non_gc_free(cx_, b); } auto box_cell = cx.build.GEP(v0, @@ -1929,7 +1936,7 @@ fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) { auto boxptr = cx.build.Load(box_cell); rslt = decr_refcnt_and_if_zero(cx, boxptr, - bind hit_zero(_, boxptr), + bind hit_zero(_, boxptr, v0), "free obj", T_int(), C_int(0)); } @@ -2704,6 +2711,27 @@ fn call_tydesc_glue(@block_ctxt cx, ValueRef v, ret res(td.bcx, C_nil()); } +fn maybe_call_dtor(@block_ctxt cx, ValueRef v) -> @block_ctxt { + auto vtbl = cx.build.GEP(v, vec(C_int(0), C_int(abi.obj_field_vtbl))); + vtbl = cx.build.Load(vtbl); + auto dtor_ptr = cx.build.GEP(vtbl, vec(C_int(0), C_int(0))); + dtor_ptr = cx.build.Load(dtor_ptr); + dtor_ptr = cx.build.BitCast(dtor_ptr, + T_ptr(T_dtor(cx.fcx.lcx.ccx, val_ty(v)))); + + auto dtor_cx = new_sub_block_ctxt(cx, "dtor"); + auto after_cx = new_sub_block_ctxt(cx, "after_dtor"); + auto test = cx.build.ICmp(lib.llvm.LLVMIntNE, dtor_ptr, + C_null(val_ty(dtor_ptr))); + cx.build.CondBr(test, dtor_cx.llbb, after_cx.llbb); + + // FIXME need to pass type params (?) + dtor_cx.build.FastCall(dtor_ptr, vec(C_null(T_ptr(T_nil())), + cx.fcx.lltaskptr, v)); + dtor_cx.build.Br(after_cx.llbb); + ret after_cx; +} + fn call_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t, ValueRef llop) -> result { // We can't use call_tydesc_glue_full() and friends here because compare @@ -4110,12 +4138,13 @@ fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, ty.t t0, vec(C_int(0), C_int(abi.obj_field_vtbl))); vtbl = r.bcx.build.Load(vtbl); + // +1 because slot #0 contains the destructor auto v = r.bcx.build.GEP(vtbl, vec(C_int(0), - C_int(ix as int))); + C_int((ix + 1u) as int))); auto lvo = lval_mem(r.bcx, v); let ty.t fn_ty = ty.method_ty_to_fn_ty(cx.fcx.lcx.ccx.tcx, - methods.(ix)); + methods.(ix)); ret rec(llobj = some[ValueRef](r.val), method_ty = some[ty.t](fn_ty) with lvo); @@ -6102,7 +6131,6 @@ fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, self_vt llself) { fn trans_fn(@local_ctxt cx, &ast._fn f, ast.def_id fid, option.t[tup(TypeRef, ty.t)] ty_self, &vec[ast.ty_param] ty_params, &ast.ann ann) { - auto llfndecl = cx.ccx.item_ids.get(fid); auto fcx = new_fn_ctxt(cx, llfndecl); @@ -6145,7 +6173,15 @@ fn trans_vtbl(@local_ctxt cx, ty.t self_ty, &ast._obj ob, &vec[ast.ty_param] ty_params) -> ValueRef { - let vec[ValueRef] methods = vec(); + auto dtor = C_null(T_ptr(T_i8())); + alt (ob.dtor) { + case (some[@ast.method](?d)) { + auto dtor_1 = trans_dtor(cx, llself_ty, self_ty, ty_params, d); + dtor = llvm.LLVMConstBitCast(dtor_1, val_ty(dtor)); + } + case (none[@ast.method]) {} + } + let vec[ValueRef] methods = vec(dtor); fn meth_lteq(&@ast.method a, &@ast.method b) -> bool { ret _str.lteq(a.node.ident, b.node.ident); @@ -6195,16 +6231,7 @@ fn trans_dtor(@local_ctxt cx, &vec[ast.ty_param] ty_params, &@ast.method dtor) -> ValueRef { - auto llfnty = T_nil(); - alt (ty.struct(cx.ccx.tcx, node_ann_type(cx.ccx, dtor.node.ann))) { - case (ty.ty_fn(?proto, ?inputs, ?output)) { - llfnty = type_of_fn_full(cx.ccx, proto, - some[TypeRef](llself_ty), - inputs, output, - _vec.len[ast.ty_param](ty_params)); - } - } - + auto llfnty = T_dtor(cx.ccx, llself_ty); let @local_ctxt dcx = extend_path(cx, "drop"); let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop"); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); @@ -6235,18 +6262,19 @@ fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid, auto fcx = new_fn_ctxt(cx, llctor_decl); create_llargs_for_fn_args(fcx, ast.proto_fn, none[tup(TypeRef, ty.t)], - ret_ty_of_fn(cx.ccx, ann), + ret_ty_of_fn(ccx, ann), fn_args, ty_params); - let vec[ty.arg] arg_tys = arg_tys_of_fn(cx.ccx, ann); + let vec[ty.arg] arg_tys = arg_tys_of_fn(ccx, ann); copy_args_to_allocas(fcx, fn_args, arg_tys); auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; - auto self_ty = ret_ty_of_fn(cx.ccx, ann); + auto self_ty = ret_ty_of_fn(ccx, ann); auto llself_ty = type_of(ccx, self_ty); auto pair = bcx.fcx.llretptr; + auto vtbl = trans_vtbl(cx, llself_ty, self_ty, ob, ty_params); auto pair_vtbl = bcx.build.GEP(pair, vec(C_int(0), @@ -6270,19 +6298,19 @@ fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid, } // Synthesize an obj body type. - auto tydesc_ty = ty.mk_type(cx.ccx.tcx); + auto tydesc_ty = ty.mk_type(ccx.tcx); let vec[ty.t] tps = vec(); for (ast.ty_param tp in ty_params) { _vec.push[ty.t](tps, tydesc_ty); } - let ty.t typarams_ty = ty.mk_imm_tup(cx.ccx.tcx, tps); - let ty.t fields_ty = ty.mk_imm_tup(cx.ccx.tcx, obj_fields); - let ty.t body_ty = ty.mk_imm_tup(cx.ccx.tcx, + let ty.t typarams_ty = ty.mk_imm_tup(ccx.tcx, tps); + let ty.t fields_ty = ty.mk_imm_tup(ccx.tcx, obj_fields); + let ty.t body_ty = ty.mk_imm_tup(ccx.tcx, vec(tydesc_ty, typarams_ty, fields_ty)); - let ty.t boxed_body_ty = ty.mk_imm_box(cx.ccx.tcx, body_ty); + let ty.t boxed_body_ty = ty.mk_imm_box(ccx.tcx, body_ty); // Malloc a box for the body. auto box = trans_malloc_boxed(bcx, body_ty); @@ -6301,14 +6329,6 @@ fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid, vec(0, abi.obj_body_elt_tydesc)); bcx = body_tydesc.bcx; - auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn))); - alt (ob.dtor) { - case (some[@ast.method](?d)) { - dtor = trans_dtor(cx, llself_ty, self_ty, ty_params, d); - } - case (none[@ast.method]) {} - } - auto body_td = get_tydesc(bcx, body_ty); bcx = body_td.bcx; bcx.build.Store(body_td.val, body_tydesc.val);