about summary refs log tree commit diff
path: root/src/comp/middle
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-05-18 17:28:08 -0700
committerGraydon Hoare <graydon@mozilla.com>2011-05-18 17:28:08 -0700
commit6f8b9e176ffb225ebfda95619c2f6d2d87d270e9 (patch)
tree4458cf4423b91c7eccd4ae6a7db8fabf7cd610ec /src/comp/middle
parent0aee8b3bd7994ff0e113fafdcba5e008d607754b (diff)
downloadrust-6f8b9e176ffb225ebfda95619c2f6d2d87d270e9.tar.gz
rust-6f8b9e176ffb225ebfda95619c2f6d2d87d270e9.zip
Factor free paths out of drop glue, into free glue as in rustboot.
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/trans.rs306
1 files changed, 184 insertions, 122 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index d53ad5b8c85..a7c7b5544b6 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -69,6 +69,7 @@ type tydesc_info = rec(ty::t ty,
                        ValueRef align,
                        mutable option::t[ValueRef] take_glue,
                        mutable option::t[ValueRef] drop_glue,
+                       mutable option::t[ValueRef] free_glue,
                        mutable option::t[ValueRef] cmp_glue,
                        vec[uint] ty_params);
 
@@ -1805,6 +1806,8 @@ fn declare_tydesc(&@local_ctxt cx, &ty::t t,
                                           "take");
     auto drop_glue = declare_generic_glue(cx, t, T_glue_fn(cx.ccx.tn),
                                           "drop");
+    auto free_glue = declare_generic_glue(cx, t, T_glue_fn(cx.ccx.tn),
+                                          "free");
     auto cmp_glue = declare_generic_glue(cx, t, T_cmp_glue_fn(cx.ccx.tn),
                                          "cmp");
     auto ccx = cx.ccx;
@@ -1839,6 +1842,7 @@ fn declare_tydesc(&@local_ctxt cx, &ty::t t,
                      align = llalign,
                      mutable take_glue = none[ValueRef],
                      mutable drop_glue = none[ValueRef],
+                     mutable free_glue = none[ValueRef],
                      mutable cmp_glue = none[ValueRef],
                      ty_params = ty_params);
 
@@ -1963,6 +1967,16 @@ fn emit_tydescs(&@crate_ctxt ccx) {
             }
         };
 
+        auto free_glue = alt (ti.free_glue) {
+            case (none[ValueRef]) {
+                ccx.stats.n_null_glues += 1u;
+                C_null(glue_fn_ty)
+            }
+            case (some[ValueRef](?v)) {
+                ccx.stats.n_real_glues += 1u;
+                v
+            }
+        };
 
         auto cmp_glue = alt (ti.cmp_glue) {
             case (none[ValueRef]) {
@@ -1981,7 +1995,7 @@ fn emit_tydescs(&@crate_ctxt ccx) {
                                    ti.align,
                                    take_glue,             // take_glue
                                    drop_glue,             // drop_glue
-                                   C_null(glue_fn_ty),    // free_glue
+                                   free_glue,             // free_glue
                                    C_null(glue_fn_ty),    // sever_glue
                                    C_null(glue_fn_ty),    // mark_glue
                                    C_null(glue_fn_ty),    // obj_drop_glue
@@ -2031,154 +2045,164 @@ fn incr_refcnt_of_boxed(&@block_ctxt cx, ValueRef box_ptr) -> result {
     ret res(next_cx, C_nil());
 }
 
-fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
-    // NB: v0 is an *alias* of type t here, not a direct value.
+fn make_free_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
+    // NB: v is an *alias* of type t here, not a direct value.
     auto rslt;
     alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
+
         case (ty::ty_str) {
             auto v = cx.build.Load(v0);
-            rslt = decr_refcnt_and_if_zero
-                (cx, v, bind trans_non_gc_free(_, v),
-                 "free string",
-                 T_int(), C_int(0));
+            rslt = trans_non_gc_free(cx, v);
         }
 
         case (ty::ty_vec(_)) {
-            fn hit_zero(&@block_ctxt cx, ValueRef v,
-                        ty::t t) -> result {
-                auto res = iter_sequence(cx, v, t,
-                                         bind drop_ty(_,_,_));
-                // FIXME: switch gc/non-gc on layer of the type.
-                ret trans_non_gc_free(res.bcx, v);
-            }
             auto v = cx.build.Load(v0);
-            rslt = decr_refcnt_and_if_zero(cx, v,
-                                          bind hit_zero(_, v, t),
-                                          "free vector",
-                                          T_int(), C_int(0));
+            auto res = iter_sequence(cx, v, t,
+                                     bind drop_ty(_,_,_));
+            // FIXME: switch gc/non-gc on layer of the type.
+            rslt = trans_non_gc_free(res.bcx, v);
         }
 
         case (ty::ty_box(?body_mt)) {
-            fn hit_zero(&@block_ctxt cx, ValueRef v,
-                        ty::t body_ty) -> result {
-                auto body = cx.build.GEP(v,
-                                         [C_int(0),
-                                             C_int(abi::box_rc_field_body)]);
-
-                auto body_val = load_if_immediate(cx, body, body_ty);
-                auto res = drop_ty(cx, body_val, body_ty);
-                // FIXME: switch gc/non-gc on layer of the type.
-                ret trans_non_gc_free(res.bcx, v);
-            }
             auto v = cx.build.Load(v0);
-            rslt = decr_refcnt_and_if_zero(cx, v,
-                                           bind hit_zero(_, v, body_mt.ty),
-                                           "free box",
-                                           T_int(), C_int(0));
+            auto body = cx.build.GEP(v,
+                                     [C_int(0),
+                                      C_int(abi::box_rc_field_body)]);
+            auto body_ty = body_mt.ty;
+            auto body_val = load_if_immediate(cx, body, body_ty);
+            auto res = drop_ty(cx, body_val, body_ty);
+            // FIXME: switch gc/non-gc on layer of the type.
+            rslt = trans_non_gc_free(res.bcx, v);
         }
 
         case (ty::ty_port(_)) {
-            fn hit_zero(&@block_ctxt cx, ValueRef v) -> result {
-                cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_port,
-                    [cx.fcx.lltaskptr,
-                        cx.build.PointerCast(v, T_opaque_port_ptr())]);
-                ret res(cx, C_int(0));
-            }
             auto v = cx.build.Load(v0);
-            rslt = decr_refcnt_and_if_zero(cx, v,
-                                           bind hit_zero(_, v),
-                                           "free port",
-                                           T_int(), C_int(0));
+            cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_port,
+                          [cx.fcx.lltaskptr,
+                           cx.build.PointerCast(v,
+                                                T_opaque_port_ptr())]);
+            rslt = res(cx, C_int(0));
         }
 
         case (ty::ty_chan(_)) {
-            fn hit_zero(&@block_ctxt cx, ValueRef v) -> result {
-                cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_chan,
-                    [cx.fcx.lltaskptr,
-                        cx.build.PointerCast(v, T_opaque_chan_ptr())]);
-                ret res(cx, C_int(0));
-            }
             auto v = cx.build.Load(v0);
-            rslt = decr_refcnt_and_if_zero(cx, v,
-                                           bind hit_zero(_, v),
-                                           "free chan",
-                                           T_int(), C_int(0));
+            cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_chan,
+                          [cx.fcx.lltaskptr,
+                           cx.build.PointerCast(v,
+                                                T_opaque_chan_ptr())]);
+            rslt = res(cx, C_int(0));
         }
 
         case (ty::ty_obj(_)) {
-            fn hit_zero(&@block_ctxt cx, ValueRef b, ValueRef o) -> result {
-                auto body =
-                    cx.build.GEP(b,
-                                 [C_int(0),
-                                     C_int(abi::box_rc_field_body)]);
-                auto tydescptr =
-                    cx.build.GEP(body,
-                                 [C_int(0),
-                                     C_int(abi::obj_body_elt_tydesc)]);
-                auto tydesc = cx.build.Load(tydescptr);
-
-                auto cx_ = maybe_call_dtor(cx, o);
-
-                // Call through the obj's own fields-drop glue first.
-                auto ti = none[@tydesc_info];
-                call_tydesc_glue_full(cx_, body, tydesc,
-                                      abi::tydesc_field_drop_glue, ti);
-
-                // Then free the body.
-                // FIXME: switch gc/non-gc on layer of the type.
-                ret trans_non_gc_free(cx_, b);
-            }
+
             auto box_cell =
                 cx.build.GEP(v0,
                              [C_int(0),
                                  C_int(abi::obj_field_box)]);
 
-            auto boxptr = cx.build.Load(box_cell);
+            auto b = cx.build.Load(box_cell);
+            auto body =
+                cx.build.GEP(b,
+                             [C_int(0),
+                              C_int(abi::box_rc_field_body)]);
+            auto tydescptr =
+                cx.build.GEP(body,
+                             [C_int(0),
+                              C_int(abi::obj_body_elt_tydesc)]);
+            auto tydesc = cx.build.Load(tydescptr);
+
+            auto cx_ = maybe_call_dtor(cx, v0);
+
+            // Call through the obj's own fields-drop glue first.
+            auto ti = none[@tydesc_info];
+            call_tydesc_glue_full(cx_, body, tydesc,
+                                  abi::tydesc_field_drop_glue, ti);
 
-            rslt = decr_refcnt_and_if_zero(cx, boxptr,
-                                           bind hit_zero(_, boxptr, v0),
-                                           "free obj",
-                                           T_int(), C_int(0));
+            // Then free the body.
+            // FIXME: switch gc/non-gc on layer of the type.
+            rslt = trans_non_gc_free(cx_, b);
         }
 
         case (ty::ty_fn(_,_,_)) {
-            fn hit_zero(&@block_ctxt cx, ValueRef v) -> result {
-
-                // Call through the closure's own fields-drop glue first.
-                auto body =
-                    cx.build.GEP(v,
-                                 [C_int(0),
-                                     C_int(abi::box_rc_field_body)]);
-                auto bindings =
-                    cx.build.GEP(body,
-                                 [C_int(0),
-                                     C_int(abi::closure_elt_bindings)]);
-
-                auto tydescptr =
-                    cx.build.GEP(body,
-                                 [C_int(0),
-                                     C_int(abi::closure_elt_tydesc)]);
-
-                auto ti = none[@tydesc_info];
-                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
-                                      abi::tydesc_field_drop_glue, ti);
-
-
-                // Then free the body.
-                // FIXME: switch gc/non-gc on layer of the type.
-                ret trans_non_gc_free(cx, v);
-            }
+
             auto box_cell =
                 cx.build.GEP(v0,
                              [C_int(0),
                                  C_int(abi::fn_field_box)]);
 
-            auto boxptr = cx.build.Load(box_cell);
+            auto v = cx.build.Load(box_cell);
+
+            // Call through the closure's own fields-drop glue first.
+            auto body =
+                cx.build.GEP(v,
+                             [C_int(0),
+                              C_int(abi::box_rc_field_body)]);
+            auto bindings =
+                cx.build.GEP(body,
+                             [C_int(0),
+                              C_int(abi::closure_elt_bindings)]);
+
+            auto tydescptr =
+                cx.build.GEP(body,
+                             [C_int(0),
+                              C_int(abi::closure_elt_tydesc)]);
+
+            auto ti = none[@tydesc_info];
+            call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
+                                  abi::tydesc_field_drop_glue, ti);
+
+
+            // Then free the body.
+            // FIXME: switch gc/non-gc on layer of the type.
+            rslt = trans_non_gc_free(cx, v);
+        }
+
+        case (_) { rslt = res(cx, C_nil()); }
+    }
+    rslt.bcx.build.RetVoid();
+}
+
+fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
+    // NB: v0 is an *alias* of type t here, not a direct value.
+    auto rslt;
+    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
+        case (ty::ty_str) {
+            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
+        }
+
+        case (ty::ty_vec(_)) {
+            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
+        }
+
+        case (ty::ty_box(_)) {
+            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
+        }
+
+        case (ty::ty_port(_)) {
+            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
+        }
+
+        case (ty::ty_chan(_)) {
+            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
+        }
+
+        case (ty::ty_obj(_)) {
+            auto box_cell =
+                cx.build.GEP(v0,
+                             [C_int(0),
+                                 C_int(abi::obj_field_box)]);
+
+            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
+        }
+
+        case (ty::ty_fn(_,_,_)) {
+
+            auto box_cell =
+                cx.build.GEP(v0,
+                             [C_int(0),
+                                 C_int(abi::fn_field_box)]);
 
-            rslt = decr_refcnt_and_if_zero(cx, boxptr,
-                                           bind hit_zero(_, boxptr),
-                                           "free fn",
-                                           T_int(), C_int(0));
+            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
         }
 
         case (_) {
@@ -2199,17 +2223,18 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
     rslt.bcx.build.RetVoid();
 }
 
-fn decr_refcnt_and_if_zero(&@block_ctxt cx,
-                           ValueRef box_ptr,
-                           &fn(&@block_ctxt cx) -> result inner,
-                           &str inner_name,
-                           TypeRef t_else, ValueRef v_else) -> result {
+fn decr_refcnt_maybe_free(&@block_ctxt cx,
+                          ValueRef box_ptr_alias,
+                          ValueRef full_alias,
+                          &ty::t t) -> result {
 
     auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
     auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
-    auto inner_cx = new_sub_block_ctxt(cx, inner_name);
+    auto free_cx = new_sub_block_ctxt(cx, "free");
     auto next_cx = new_sub_block_ctxt(cx, "next");
 
+    auto box_ptr = cx.build.Load(box_ptr_alias);
+
     auto null_test = cx.build.IsNull(box_ptr);
     cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
 
@@ -2227,17 +2252,20 @@ fn decr_refcnt_and_if_zero(&@block_ctxt cx,
     rc = rc_adj_cx.build.Sub(rc, C_int(1));
     rc_adj_cx.build.Store(rc, rc_ptr);
     auto zero_test = rc_adj_cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(0), rc);
-    rc_adj_cx.build.CondBr(zero_test, inner_cx.llbb, next_cx.llbb);
+    rc_adj_cx.build.CondBr(zero_test, free_cx.llbb, next_cx.llbb);
 
-    auto inner_res = inner(inner_cx);
-    inner_res.bcx.build.Br(next_cx.llbb);
+    auto free_res = free_ty(free_cx,
+                            load_if_immediate(free_cx, full_alias, t), t);
+    free_res.bcx.build.Br(next_cx.llbb);
 
+    auto t_else = T_nil();
+    auto v_else = C_nil();
     auto phi = next_cx.build.Phi(t_else,
-                                 [v_else, v_else, v_else, inner_res.val],
+                                 [v_else, v_else, v_else, free_res.val],
                                  [cx.llbb,
                                      load_rc_cx.llbb,
                                      rc_adj_cx.llbb,
-                                     inner_res.bcx.llbb]);
+                                     free_res.bcx.llbb]);
 
     ret res(next_cx, phi);
 }
@@ -2903,6 +2931,7 @@ fn lazily_emit_all_tydesc_glue(&@block_ctxt cx,
                                &option::t[@tydesc_info] static_ti) {
     lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, static_ti);
     lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, static_ti);
+    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, static_ti);
     lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, static_ti);
 }
 
@@ -2960,6 +2989,26 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field,
                     }
                 }
 
+            } else if (field == abi::tydesc_field_free_glue)  {
+                alt (ti.free_glue) {
+                    case (some[ValueRef](_)) { }
+                    case (none[ValueRef]) {
+                        log #fmt("+++ lazily_emit_tydesc_glue FREE %s",
+                                 ty::ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
+                        auto lcx = cx.fcx.lcx;
+                        auto glue_fn =
+                            declare_generic_glue(lcx, ti.ty,
+                                                 T_glue_fn(lcx.ccx.tn),
+                                                 "free");
+                        ti.free_glue = some[ValueRef](glue_fn);
+                        auto dg = make_free_glue;
+                        make_generic_glue(lcx, ti.ty, glue_fn,
+                                          mgghf_single(dg), ti.ty_params);
+                        log #fmt("--- lazily_emit_tydesc_glue FREE %s",
+                                 ty::ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
+                    }
+                }
+
             } else if (field == abi::tydesc_field_cmp_glue) {
                 alt (ti.cmp_glue) {
                     case (some[ValueRef](_)) { }
@@ -3111,6 +3160,16 @@ fn drop_ty(&@block_ctxt cx,
     ret res(cx, C_nil());
 }
 
+fn free_ty(&@block_ctxt cx,
+           ValueRef v,
+           ty::t t) -> result {
+
+    if (!ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
+        ret call_tydesc_glue(cx, v, t, false, abi::tydesc_field_free_glue);
+    }
+    ret res(cx, C_nil());
+}
+
 fn call_memmove(&@block_ctxt cx,
                 ValueRef dst,
                 ValueRef src,
@@ -3419,6 +3478,7 @@ fn trans_vec_append(&@block_ctxt cx, &ty::t t,
     auto llelt_tydesc = get_tydesc(bcx, elt_ty, false, ti);
     lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, ti);
     lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, ti);
+    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
     bcx = llelt_tydesc.bcx;
 
     auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
@@ -4910,6 +4970,7 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
             auto ti = none[@tydesc_info];
             auto bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti);
             lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
+            lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
             bcx = bindings_tydesc.bcx;
             bcx.build.Store(bindings_tydesc.val, bound_tydesc);
 
@@ -6747,6 +6808,7 @@ fn trans_obj(@local_ctxt cx, &ast::_obj ob, ast::def_id oid,
         auto ti = none[@tydesc_info];
         auto body_td = get_tydesc(bcx, body_ty, true, ti);
         lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
+        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
 
         auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn)));
         alt (ob.dtor) {