about summary refs log tree commit diff
diff options
context:
space:
mode:
authorElliott Slaughter <eslaughter@mozilla.com>2012-08-06 14:14:17 -0700
committerElliott Slaughter <eslaughter@mozilla.com>2012-08-08 12:21:25 -0700
commit166cb1b28bc23303d15e8c1c4a71d0cdff0556a2 (patch)
tree4ae431b8acacee03eb3e568cc1210104fefc6cf3
parent76d04af71a64e9c79ea21c8d4b956ef0591e3c61 (diff)
downloadrust-166cb1b28bc23303d15e8c1c4a71d0cdff0556a2.tar.gz
rust-166cb1b28bc23303d15e8c1c4a71d0cdff0556a2.zip
rustc: Strict enforcement of glue function types.
Make all glue functions take values by alias to remove the need for
bitcasts at the top of every glue function. Use static type
information to produce the correct type for glue functions so that
LLVM can enforce the type system at call sites.
-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);