about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/rustc/middle/trans/base.rs155
-rw-r--r--src/rustc/middle/trans/closure.rs6
-rw-r--r--src/rustc/middle/trans/common.rs2
-rw-r--r--src/rustc/middle/trans/tvec.rs5
-rw-r--r--src/rustc/middle/trans/type_of.rs7
-rw-r--r--src/rustc/middle/trans/uniq.rs3
6 files changed, 118 insertions, 60 deletions
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index fd13d8fa1ef..ce6669f9799 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -546,18 +546,18 @@ fn make_generic_glue_inner(ccx: @crate_ctxt, t: ty::t,
     let fcx = new_fn_ctxt(ccx, ~[], llfn, none);
     lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
     ccx.stats.n_glues_created += 1u;
-    // Any nontrivial glue is with values passed *by alias*; this is a
+    // All glue functions take values passed *by alias*; this is a
     // requirement since in many contexts glue is invoked indirectly and
     // the caller has no idea if it's dealing with something that can be
     // passed by value.
-
-    let llty = T_ptr(type_of(ccx, t));
+    //
+    // llfn is expected be declared to take a parameter of the appropriate
+    // type, so we don't need to explicitly cast the function parameter.
 
     let bcx = top_scope_block(fcx, none);
     let lltop = bcx.llbb;
     let llrawptr0 = llvm::LLVMGetParam(llfn, 3u as c_uint);
-    let llval0 = BitCast(bcx, llrawptr0, llty);
-    helper(bcx, llval0, t);
+    helper(bcx, llrawptr0, t);
     finish_fn(fcx, lltop);
     return llfn;
 }
@@ -581,28 +581,44 @@ fn make_generic_glue(ccx: @crate_ctxt, t: ty::t, llfn: ValueRef,
 fn emit_tydescs(ccx: @crate_ctxt) {
     let _icx = ccx.insn_ctxt(~"emit_tydescs");
     for ccx.tydescs.each |key, val| {
-        let glue_fn_ty = T_ptr(T_glue_fn(ccx));
+        let glue_fn_ty = T_ptr(T_generic_glue_fn(ccx));
         let ti = val;
 
+        // Each of the glue functions needs to be cast to a generic type
+        // before being put into the tydesc because we only have a singleton
+        // tydesc type. Then we'll recast each function to its real type when
+        // calling it.
         let take_glue =
             match copy ti.take_glue {
               none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
-              some(v) => { ccx.stats.n_real_glues += 1u; v }
+              some(v) => {
+                ccx.stats.n_real_glues += 1u;
+                llvm::LLVMConstPointerCast(v, glue_fn_ty)
+              }
             };
         let drop_glue =
             match copy ti.drop_glue {
               none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
-              some(v) => { ccx.stats.n_real_glues += 1u; v }
+              some(v) => {
+                ccx.stats.n_real_glues += 1u;
+                llvm::LLVMConstPointerCast(v, glue_fn_ty)
+              }
             };
         let free_glue =
             match copy ti.free_glue {
               none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
-              some(v) => { ccx.stats.n_real_glues += 1u; v }
+              some(v) => {
+                ccx.stats.n_real_glues += 1u;
+                llvm::LLVMConstPointerCast(v, glue_fn_ty)
+              }
             };
         let visit_glue =
             match copy ti.visit_glue {
               none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
-              some(v) => { ccx.stats.n_real_glues += 1u; v }
+              some(v) => {
+                ccx.stats.n_real_glues += 1u;
+                llvm::LLVMConstPointerCast(v, glue_fn_ty)
+              }
             };
 
         let shape = shape_of(ccx, key);
@@ -692,20 +708,20 @@ fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
 
 
 fn make_free_glue(bcx: block, 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).
+    // NB: v0 is an *alias* of type t here, not a direct value.
     let _icx = bcx.insn_ctxt(~"make_free_glue");
     let ccx = bcx.ccx();
     let bcx = match ty::get(t).struct {
       ty::ty_box(body_mt) => {
-        let v = PointerCast(bcx, v, type_of(ccx, t));
+        let v = Load(bcx, v);
         let body = GEPi(bcx, v, ~[0u, abi::box_field_body]);
+        // Cast away the addrspace of the box pointer.
+        let body = PointerCast(bcx, body, T_ptr(type_of(ccx, body_mt.ty)));
         let bcx = drop_ty(bcx, body, body_mt.ty);
         trans_free(bcx, v)
       }
       ty::ty_opaque_box => {
-        let v = PointerCast(bcx, v, type_of(ccx, t));
+        let v = Load(bcx, v);
         let td = Load(bcx, GEPi(bcx, v, ~[0u, abi::box_field_tydesc]));
         let valptr = GEPi(bcx, v, ~[0u, abi::box_field_body]);
         // Generate code that, dynamically, indexes into the
@@ -715,7 +731,6 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
         trans_free(bcx, v)
       }
       ty::ty_uniq(content_mt) => {
-        let v = PointerCast(bcx, v, type_of(ccx, t));
         uniq::make_free_glue(bcx, v, t)
       }
       ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
@@ -785,7 +800,7 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
       }
       ty::ty_uniq(_) |
       ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
-        free_ty(bcx, Load(bcx, v0), t)
+        free_ty(bcx, v0, t)
       }
       ty::ty_unboxed_vec(_) => {
         tvec::make_drop_glue_unboxed(bcx, v0, t)
@@ -861,14 +876,12 @@ fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t) -> block {
     let ccx = bcx.ccx();
     maybe_validate_box(bcx, box_ptr);
 
-    let llbox_ty = T_opaque_box_ptr(ccx);
-    let box_ptr = PointerCast(bcx, box_ptr, llbox_ty);
     do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| {
         let rc_ptr = GEPi(bcx, box_ptr, ~[0u, abi::box_field_refcnt]);
         let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
         Store(bcx, rc, rc_ptr);
         let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
-        with_cond(bcx, zero_test, |bcx| free_ty(bcx, box_ptr, t))
+        with_cond(bcx, zero_test, |bcx| free_ty_immediate(bcx, box_ptr, t))
     }
 }
 
@@ -1097,17 +1110,16 @@ fn lazily_emit_all_tydesc_glue(ccx: @crate_ctxt,
 fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
                            ti: @tydesc_info) {
     let _icx = ccx.insn_ctxt(~"lazily_emit_tydesc_glue");
+    let llfnty = type_of_glue_fn(ccx, ti.ty);
     if field == abi::tydesc_field_take_glue {
         match ti.take_glue {
           some(_) => (),
           none => {
             debug!{"+++ lazily_emit_tydesc_glue TAKE %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
-            let glue_fn = declare_generic_glue
-                (ccx, ti.ty, T_glue_fn(ccx), ~"take");
+            let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"take");
             ti.take_glue = some(glue_fn);
-            make_generic_glue(ccx, ti.ty, glue_fn,
-                              make_take_glue, ~"take");
+            make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, ~"take");
             debug!{"--- lazily_emit_tydesc_glue TAKE %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
           }
@@ -1118,11 +1130,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
           none => {
             debug!{"+++ lazily_emit_tydesc_glue DROP %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
-            let glue_fn =
-                declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"drop");
+            let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"drop");
             ti.drop_glue = some(glue_fn);
-            make_generic_glue(ccx, ti.ty, glue_fn,
-                              make_drop_glue, ~"drop");
+            make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, ~"drop");
             debug!{"--- lazily_emit_tydesc_glue DROP %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
           }
@@ -1133,11 +1143,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
           none => {
             debug!{"+++ lazily_emit_tydesc_glue FREE %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
-            let glue_fn =
-                declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"free");
+            let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"free");
             ti.free_glue = some(glue_fn);
-            make_generic_glue(ccx, ti.ty, glue_fn,
-                              make_free_glue, ~"free");
+            make_generic_glue(ccx, ti.ty, glue_fn, make_free_glue, ~"free");
             debug!{"--- lazily_emit_tydesc_glue FREE %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
           }
@@ -1148,11 +1156,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
           none => {
             debug!{"+++ lazily_emit_tydesc_glue VISIT %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
-            let glue_fn =
-                declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"visit");
+            let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"visit");
             ti.visit_glue = some(glue_fn);
-            make_generic_glue(ccx, ti.ty, glue_fn,
-                              make_visit_glue, ~"visit");
+            make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, ~"visit");
             debug!{"--- lazily_emit_tydesc_glue VISIT %s",
                    ppaux::ty_to_str(ccx.tcx, ti.ty)};
           }
@@ -1161,43 +1167,63 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
 }
 
 // See [Note-arg-mode]
-fn call_tydesc_glue_full(++cx: block, v: ValueRef, tydesc: ValueRef,
+fn call_tydesc_glue_full(++bcx: block, v: ValueRef, tydesc: ValueRef,
                          field: uint, static_ti: option<@tydesc_info>) {
-    let _icx = cx.insn_ctxt(~"call_tydesc_glue_full");
-        if cx.unreachable { return; }
+    let _icx = bcx.insn_ctxt(~"call_tydesc_glue_full");
+        if bcx.unreachable { return; }
+    let ccx = bcx.ccx();
 
-    let mut static_glue_fn = none;
-    match static_ti {
-      none => {/* no-op */ }
+    let static_glue_fn = match static_ti {
+      none => none,
       some(sti) => {
-        lazily_emit_tydesc_glue(cx.ccx(), field, sti);
+        lazily_emit_tydesc_glue(ccx, field, sti);
         if field == abi::tydesc_field_take_glue {
-            static_glue_fn = sti.take_glue;
+            sti.take_glue
         } else if field == abi::tydesc_field_drop_glue {
-            static_glue_fn = sti.drop_glue;
+            sti.drop_glue
         } else if field == abi::tydesc_field_free_glue {
-            static_glue_fn = sti.free_glue;
+            sti.free_glue
         } else if field == abi::tydesc_field_visit_glue {
-            static_glue_fn = sti.visit_glue;
+            sti.visit_glue
+        } else {
+            none
         }
       }
-    }
+    };
+
+    // When available, use static type info to give glue the right type.
+    let static_glue_fn = match static_ti {
+      none => none,
+      some(sti) => {
+        match static_glue_fn {
+          none => none,
+          some(sgf) => some(
+              PointerCast(bcx, sgf, T_ptr(type_of_glue_fn(ccx, sti.ty))))
+        }
+      }
+    };
 
-    let llrawptr = PointerCast(cx, v, T_ptr(T_i8()));
+    // When static type info is available, avoid casting parameter because the
+    // function already has the right type. Otherwise cast to generic pointer.
+    let llrawptr = if is_none(static_ti) || is_none(static_glue_fn) {
+        PointerCast(bcx, v, T_ptr(T_i8()))
+    } else {
+        v
+    };
 
     let llfn = {
         match static_glue_fn {
           none => {
             // Select out the glue function to call from the tydesc
-            let llfnptr = GEPi(cx, tydesc, ~[0u, field]);
-            Load(cx, llfnptr)
+            let llfnptr = GEPi(bcx, tydesc, ~[0u, field]);
+            Load(bcx, llfnptr)
           }
           some(sgf) => sgf
         }
     };
 
-    Call(cx, llfn, ~[C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
-                    C_null(T_ptr(T_ptr(cx.ccx().tydesc_type))), llrawptr]);
+    Call(bcx, llfn, ~[C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
+                      C_null(T_ptr(T_ptr(bcx.ccx().tydesc_type))), llrawptr]);
 }
 
 // See [Note-arg-mode]
@@ -1231,6 +1257,7 @@ fn call_cmp_glue(bcx: block, lhs: ValueRef, rhs: ValueRef, t: ty::t,
 }
 
 fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
+    // NB: v is an *alias* of type t here, not a direct value.
     let _icx = cx.insn_ctxt(~"take_ty");
     if ty::type_needs_drop(cx.tcx(), t) {
         return call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
@@ -1239,6 +1266,7 @@ fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
 }
 
 fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
+    // NB: v is an *alias* of type t here, not a direct value.
     let _icx = cx.insn_ctxt(~"drop_ty");
     if ty::type_needs_drop(cx.tcx(), t) {
         return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
@@ -1252,7 +1280,7 @@ fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
       ty::ty_uniq(_) |
       ty::ty_evec(_, ty::vstore_uniq) |
       ty::ty_estr(ty::vstore_uniq) => {
-        free_ty(bcx, v, t)
+        free_ty_immediate(bcx, v, t)
       }
       ty::ty_box(_) | ty::ty_opaque_box |
       ty::ty_evec(_, ty::vstore_box) |
@@ -1284,6 +1312,7 @@ fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> result {
 }
 
 fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
+    // NB: v is an *alias* of type t here, not a direct value.
     let _icx = cx.insn_ctxt(~"free_ty");
     if ty::type_needs_drop(cx.tcx(), t) {
         return call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
@@ -1291,6 +1320,24 @@ fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
     return cx;
 }
 
+fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
+    let _icx = bcx.insn_ctxt(~"free_ty_immediate");
+    match ty::get(t).struct {
+      ty::ty_uniq(_) |
+      ty::ty_evec(_, ty::vstore_uniq) |
+      ty::ty_estr(ty::vstore_uniq) |
+      ty::ty_box(_) | ty::ty_opaque_box |
+      ty::ty_evec(_, ty::vstore_box) |
+      ty::ty_estr(ty::vstore_box) |
+      ty::ty_opaque_closure_ptr(_) => {
+        let vp = alloca_zeroed(bcx, type_of(bcx.ccx(), t));
+        Store(bcx, v, vp);
+        free_ty(bcx, vp, t)
+      }
+      _ => bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty")
+    }
+}
+
 fn call_memmove(cx: block, dst: ValueRef, src: ValueRef,
                 n_bytes: ValueRef) {
     // FIXME (Related to #1645, I think?): Provide LLVM with better
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index 752ce97427c..d5af4e181a7 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -492,7 +492,7 @@ fn make_opaque_cbox_drop_glue(
                                ty::mk_opaque_closure_ptr(bcx.tcx(), ck))
       }
       ty::ck_uniq => {
-        free_ty(bcx, Load(bcx, cboxptr),
+        free_ty(bcx, cboxptr,
                 ty::mk_opaque_closure_ptr(bcx.tcx(), ck))
       }
     }
@@ -501,7 +501,7 @@ fn make_opaque_cbox_drop_glue(
 fn make_opaque_cbox_free_glue(
     bcx: block,
     ck: ty::closure_kind,
-    cbox: ValueRef)     // ptr to the opaque closure
+    cbox: ValueRef)     // ptr to ptr to the opaque closure
     -> block {
     let _icx = bcx.insn_ctxt(~"closure::make_opaque_cbox_free_glue");
     match ck {
@@ -513,7 +513,7 @@ fn make_opaque_cbox_free_glue(
     do with_cond(bcx, IsNotNull(bcx, cbox)) |bcx| {
         // Load the type descr found in the cbox
         let lltydescty = T_ptr(ccx.tydesc_type);
-        let cbox = PointerCast(bcx, cbox, T_opaque_cbox_ptr(ccx));
+        let cbox = Load(bcx, cbox);
         let tydescptr = GEPi(bcx, cbox, ~[0u, abi::box_field_tydesc]);
         let tydesc = Load(bcx, tydescptr);
         let tydesc = PointerCast(bcx, tydesc, lltydescty);
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index 7e48297f12e..20573eff4cc 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -655,7 +655,7 @@ fn T_tydesc_field(cx: @crate_ctxt, field: uint) -> TypeRef unsafe {
     return t;
 }
 
-fn T_glue_fn(cx: @crate_ctxt) -> TypeRef {
+fn T_generic_glue_fn(cx: @crate_ctxt) -> TypeRef {
     let s = ~"glue_fn";
     match name_has_type(cx.tn, s) {
       some(t) => return t,
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index aa92c96a686..94c48ace749 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -175,10 +175,13 @@ fn trans_evec(bcx: block, elements: evec_elements,
             let ty = ty::mk_evec(bcx.tcx(),
                                  {ty: unit_ty, mutbl: ast::m_mutbl},
                                  ty::vstore_fixed(count));
+            let llty = T_ptr(type_of::type_of(bcx.ccx(), ty));
 
             let n = C_uint(ccx, count);
             let vp = base::arrayalloca(bcx, llunitty, n);
-            add_clean(bcx, vp, ty);
+            // Cast to the fake type we told cleanup to expect.
+            let vp0 = BitCast(bcx, vp, llty);
+            add_clean(bcx, vp0, ty);
 
             let len = Mul(bcx, n, unit_sz);
 
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index 86c9cb0ff97..06f3b179536 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -10,6 +10,7 @@ export type_of_dtor;
 export type_of_explicit_args;
 export type_of_fn_from_ty;
 export type_of_fn;
+export type_of_glue_fn;
 export type_of_non_gc_box;
 
 fn type_of_explicit_args(cx: @crate_ctxt,
@@ -244,3 +245,9 @@ fn type_of_dtor(ccx: @crate_ctxt, self_ty: ty::t) -> TypeRef {
          llvm::LLVMVoidType())
 }
 
+fn type_of_glue_fn(ccx: @crate_ctxt, t: ty::t) -> TypeRef {
+    let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
+    let llty = T_ptr(type_of(ccx, t));
+    return T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, llty],
+                T_void());
+}
diff --git a/src/rustc/middle/trans/uniq.rs b/src/rustc/middle/trans/uniq.rs
index e66ae41e5c6..e9374dbb05e 100644
--- a/src/rustc/middle/trans/uniq.rs
+++ b/src/rustc/middle/trans/uniq.rs
@@ -7,9 +7,10 @@ import shape::llsize_of;
 
 export make_free_glue, autoderef, duplicate;
 
-fn make_free_glue(bcx: block, vptr: ValueRef, t: ty::t)
+fn make_free_glue(bcx: block, vptrptr: ValueRef, t: ty::t)
     -> block {
     let _icx = bcx.insn_ctxt(~"uniq::make_free_glue");
+    let vptr = Load(bcx, vptrptr);
     do with_cond(bcx, IsNotNull(bcx, vptr)) |bcx| {
         let content_ty = content_ty(t);
         let body_ptr = opaque_box_body(bcx, content_ty, vptr);