about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-08-11 13:42:26 -0400
committerNiko Matsakis <niko@alum.mit.edu>2013-08-11 14:01:19 -0400
commit006c6b6be4499fd999ef3f52996b944263baa220 (patch)
tree7577af1a8bd4d7f6be3c92c1e3a97f3356a59a75
parent6f319812d602fb1d6558b583b80a9326f1cc14b3 (diff)
downloadrust-006c6b6be4499fd999ef3f52996b944263baa220.tar.gz
rust-006c6b6be4499fd999ef3f52996b944263baa220.zip
trans: Rely on new AutoBorrowObj adjustment to match up object receivers
Note: some portions of this commit written by @Sodel-the-Vociferous
(Daniel Ralston)
-rw-r--r--src/librustc/middle/trans/callee.rs1
-rw-r--r--src/librustc/middle/trans/context.rs5
-rw-r--r--src/librustc/middle/trans/expr.rs101
-rw-r--r--src/librustc/middle/trans/meth.rs146
4 files changed, 141 insertions, 112 deletions
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index a0e71bc2272..4caaf384873 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -60,7 +60,6 @@ pub struct MethodData {
     llfn: ValueRef,
     llself: ValueRef,
     temp_cleanup: Option<ValueRef>,
-    self_ty: ty::t,
     self_mode: ty::SelfMode,
 }
 
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 0a69f25c42c..aa56ff3d26e 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -13,7 +13,7 @@ use back::{upcall};
 use driver::session;
 use lib::llvm::{ContextRef, ModuleRef, ValueRef};
 use lib::llvm::{llvm, TargetData, TypeNames};
-use lib::llvm::{mk_target_data};
+use lib::llvm::{mk_target_data, False};
 use metadata::common::LinkMeta;
 use middle::astencode;
 use middle::resolve;
@@ -22,6 +22,7 @@ use middle::trans::base;
 use middle::trans::builder::Builder;
 use middle::trans::debuginfo;
 use middle::trans::type_use;
+use middle::trans::common::{C_i32, C_null};
 use middle::ty;
 
 use middle::trans::type_::Type;
@@ -30,6 +31,8 @@ use std::c_str::ToCStr;
 use std::hash;
 use std::hashmap::{HashMap, HashSet};
 use std::local_data;
+use std::vec;
+use std::libc::c_uint;
 use syntax::ast;
 
 use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 5931b54342f..cb4a7f364da 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -137,9 +137,8 @@ use middle::trans::meth;
 use middle::trans::tvec;
 use middle::trans::type_of;
 use middle::ty::struct_fields;
-use middle::ty::{AutoDerefRef, AutoAddEnv};
-use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
-                 AutoUnsafe};
+use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
+use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
 use middle::ty;
 use util::common::indenter;
 use util::ppaux::Repr;
@@ -223,6 +222,10 @@ pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
                                                     datum.ty, Some(adjustment));
                     unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
                 }
+                Some(AutoBorrowObj(*)) => {
+                    unpack_datum!(bcx, auto_borrow_obj(
+                        bcx, adj.autoderefs, expr, datum))
+                }
             };
         }
     }
@@ -298,6 +301,98 @@ pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
         let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
         auto_ref(bcx, datum)
     }
+
+    fn auto_borrow_obj(mut bcx: @mut Block,
+                       autoderefs: uint,
+                       expr: @ast::expr,
+                       source_datum: Datum) -> DatumBlock {
+        let tcx = bcx.tcx();
+        let target_obj_ty = expr_ty_adjusted(bcx, expr);
+        debug!("auto_borrow_obj(target=%s)",
+               target_obj_ty.repr(tcx));
+        let scratch = scratch_datum(bcx, target_obj_ty,
+                                    "__auto_borrow_obj", false);
+
+        // Convert a @Object, ~Object, or &Object pair into an &Object pair.
+
+        // Get a pointer to the source object, which is represented as
+        // a (vtable, data) pair.
+        let source_llval = source_datum.to_ref_llval(bcx);
+
+        // Set the vtable field of the new pair
+        let vtable_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_vtable]);
+        let vtable = Load(bcx, vtable_ptr);
+        Store(bcx, vtable, GEPi(bcx, scratch.val, [0u, abi::trt_field_vtable]));
+
+        // Load the data for the source, which is either an @T,
+        // ~T, or &T, depending on source_obj_ty.
+        let source_data_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_box]);
+        let source_data = Load(bcx, source_data_ptr); // always a ptr
+        let (source_store, source_mutbl) = match ty::get(source_datum.ty).sty {
+            ty::ty_trait(_, _, s, m, _) => (s, m),
+            _ => {
+                bcx.sess().span_bug(
+                    expr.span,
+                    fmt!("auto_borrow_trait_obj expected a trait, found %s",
+                         source_datum.ty.repr(bcx.tcx())));
+            }
+        };
+        let target_data = match source_store {
+            ty::BoxTraitStore(*) => {
+                // For deref of @T or @mut T, create a dummy datum and
+                // use the datum's deref method. This is more work
+                // than just calling GEPi ourselves, but it ensures
+                // that any write guards will be appropriate
+                // processed.  Note that we don't know the type T, so
+                // just substitute `i8`-- it doesn't really matter for
+                // our purposes right now.
+                let source_ty =
+                    ty::mk_box(tcx,
+                               ty::mt {
+                                   ty: ty::mk_i8(),
+                                   mutbl: source_mutbl});
+                let source_datum =
+                    Datum {val: source_data,
+                           ty: source_ty,
+                           mode: ByValue};
+                let derefd_datum =
+                    unpack_datum!(bcx,
+                                  source_datum.deref(bcx,
+                                                     expr,
+                                                     autoderefs));
+                derefd_datum.to_rptr(bcx).to_value_llval(bcx)
+            }
+            ty::UniqTraitStore(*) => {
+                // For a ~T box, there may or may not be a header,
+                // depending on whether the type T references managed
+                // boxes. However, since we do not *know* the type T
+                // for objects, this presents a hurdle. Our solution is
+                // to load the "borrow offset" from the type descriptor;
+                // this value will either be 0 or sizeof(BoxHeader), depending
+                // on the type T.
+                let llopaque =
+                    PointerCast(bcx, source_data, Type::opaque().ptr_to());
+                let lltydesc_ptr_ptr =
+                    PointerCast(bcx, vtable,
+                                bcx.ccx().tydesc_type.ptr_to().ptr_to());
+                let lltydesc_ptr =
+                    Load(bcx, lltydesc_ptr_ptr);
+                let borrow_offset_ptr =
+                    GEPi(bcx, lltydesc_ptr,
+                         [0, abi::tydesc_field_borrow_offset]);
+                let borrow_offset =
+                    Load(bcx, borrow_offset_ptr);
+                InBoundsGEP(bcx, llopaque, [borrow_offset])
+            }
+            ty::RegionTraitStore(*) => {
+                source_data
+            }
+        };
+        Store(bcx, target_data,
+              GEPi(bcx, scratch.val, [0u, abi::trt_field_box]));
+
+        DatumBlock { bcx: bcx, datum: scratch }
+    }
 }
 
 pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index 4cc4f8fa696..f5b2ff75596 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -164,7 +164,6 @@ pub fn trans_method_callee(bcx: @mut Block,
                     llfn: callee_fn.llfn,
                     llself: val,
                     temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
-                    self_ty: node_id_type(bcx, this.id),
                     self_mode: mentry.self_mode,
                 })
             }
@@ -187,13 +186,11 @@ pub fn trans_method_callee(bcx: @mut Block,
             }
         }
 
-        typeck::method_trait(_, off, store) => {
+        typeck::method_trait(_, off) => {
             trans_trait_callee(bcx,
                                callee_id,
                                off,
-                               this,
-                               store,
-                               mentry.explicit_self)
+                               this)
         }
     }
 }
@@ -341,7 +338,6 @@ pub fn trans_monomorphized_callee(bcx: @mut Block,
                   llfn: llfn_val,
                   llself: llself_val,
                   temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
-                  self_ty: node_id_type(bcx, base.id),
                   self_mode: mentry.self_mode,
               })
           }
@@ -406,142 +402,78 @@ pub fn combine_impl_and_methods_tps(bcx: @mut Block,
 pub fn trans_trait_callee(bcx: @mut Block,
                           callee_id: ast::NodeId,
                           n_method: uint,
-                          self_expr: @ast::expr,
-                          store: ty::TraitStore,
-                          explicit_self: ast::explicit_self_)
+                          self_expr: @ast::expr)
                           -> Callee {
-    //!
-    //
-    // Create a method callee where the method is coming from a trait
-    // instance (e.g., @Trait type).  In this case, we must pull the
-    // fn pointer out of the vtable that is packaged up with the
-    // @/~/&Trait instance.  @/~/&Traits are represented as a pair, so we
-    // first evaluate the self expression (expected a by-ref result) and then
-    // extract the self data and vtable out of the pair.
+    /*!
+     * Create a method callee where the method is coming from a trait
+     * object (e.g., @Trait type).  In this case, we must pull the fn
+     * pointer out of the vtable that is packaged up with the object.
+     * Objects are represented as a pair, so we first evaluate the self
+     * expression and then extract the self data and vtable out of the
+     * pair.
+     */
 
     let _icx = push_ctxt("impl::trans_trait_callee");
     let mut bcx = bcx;
-    let self_datum = unpack_datum!(bcx,
-        expr::trans_to_datum(bcx, self_expr));
-    let llpair = self_datum.to_ref_llval(bcx);
-
-    let llpair = match explicit_self {
-        ast::sty_region(*) => Load(bcx, llpair),
-        ast::sty_static | ast::sty_value |
-        ast::sty_box(_) | ast::sty_uniq => llpair
-    };
+
+    let self_ty = expr_ty_adjusted(bcx, self_expr);
+    let self_scratch = scratch_datum(bcx, self_ty, "__trait_callee", false);
+    bcx = expr::trans_into(bcx, self_expr, expr::SaveIn(self_scratch.val));
+
+    // Arrange a temporary cleanup for the object in case something
+    // should go wrong before the method is actually *invoked*.
+    self_scratch.add_clean(bcx);
 
     let callee_ty = node_id_type(bcx, callee_id);
     trans_trait_callee_from_llval(bcx,
                                   callee_ty,
                                   n_method,
-                                  llpair,
-                                  store,
-                                  explicit_self)
+                                  self_scratch.val,
+                                  Some(self_scratch.val))
 }
 
 pub fn trans_trait_callee_from_llval(bcx: @mut Block,
                                      callee_ty: ty::t,
                                      n_method: uint,
                                      llpair: ValueRef,
-                                     store: ty::TraitStore,
-                                     explicit_self: ast::explicit_self_)
+                                     temp_cleanup: Option<ValueRef>)
                                   -> Callee {
-    //!
-    //
-    // Same as `trans_trait_callee()` above, except that it is given
-    // a by-ref pointer to the @Trait pair.
+    /*!
+     * Same as `trans_trait_callee()` above, except that it is given
+     * a by-ref pointer to the object pair.
+     */
 
     let _icx = push_ctxt("impl::trans_trait_callee");
     let ccx = bcx.ccx();
 
-    // Load the vtable from the @Trait pair
-    debug!("(translating trait callee) loading vtable from pair %s",
-           bcx.val_to_str(llpair));
-    let llvtable = Load(bcx,
-                      PointerCast(bcx,
-                                  GEPi(bcx, llpair,
-                                       [0u, abi::trt_field_vtable]),
-                                  Type::vtable().ptr_to().ptr_to()));
-
-    // Load the box from the @Trait pair and GEP over the box header if
-    // necessary:
-    let mut llself;
+    // Load the data pointer from the object.
     debug!("(translating trait callee) loading second index from pair");
     let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
     let llbox = Load(bcx, llboxptr);
-
-    // Munge `llself` appropriately for the type of `self` in the method.
-    match explicit_self {
-        ast::sty_static => {
-            bcx.tcx().sess.bug("shouldn't see static method here");
-        }
-        ast::sty_value => {
-            bcx.tcx().sess.bug("methods with by-value self should not be \
-                                called on objects");
-        }
-        ast::sty_region(*) => {
-            match store {
-                ty::UniqTraitStore
-                    if !ty::type_contents(bcx.tcx(), callee_ty).contains_managed() => {
-                    llself = llbox;
-                }
-                ty::BoxTraitStore |
-                ty::UniqTraitStore => {
-                    llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
-                }
-                ty::RegionTraitStore(_) => {
-                    llself = llbox;
-                }
-            }
-        }
-        ast::sty_box(_) => {
-            // Bump the reference count on the box.
-            debug!("(translating trait callee) callee type is `%s`",
-                   bcx.ty_to_str(callee_ty));
-            glue::incr_refcnt_of_boxed(bcx, llbox);
-
-            // Pass a pointer to the box.
-            match store {
-                ty::BoxTraitStore => llself = llbox,
-                _ => bcx.tcx().sess.bug("@self receiver with non-@Trait")
-            }
-        }
-        ast::sty_uniq => {
-            // Pass the unique pointer.
-            match store {
-                ty::UniqTraitStore => llself = llbox,
-                _ => bcx.tcx().sess.bug("~self receiver with non-~Trait")
-            }
-
-            zero_mem(bcx, llboxptr, ty::mk_opaque_box(bcx.tcx()));
-        }
-    }
-
-    llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to());
-    let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()),
-                                "__trait_callee", false);
-    Store(bcx, llself, scratch.val);
-    scratch.add_clean(bcx);
+    let llself = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
 
     // Load the function from the vtable and cast it to the expected type.
     debug!("(translating trait callee) loading method");
     let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty);
-
-    // Plus one in order to skip past the type descriptor.
+    let llvtable = Load(bcx,
+                        PointerCast(bcx,
+                                    GEPi(bcx, llpair,
+                                         [0u, abi::trt_field_vtable]),
+                                    Type::vtable().ptr_to().ptr_to()));
     let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));
-
     let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
 
     return Callee {
         bcx: bcx,
         data: Method(MethodData {
             llfn: mptr,
-            llself: scratch.to_value_llval(bcx),
-            temp_cleanup: Some(scratch.val),
-            self_ty: scratch.ty,
+            llself: llself,
+            temp_cleanup: temp_cleanup,
+
+                // We know that the func declaration is &self, ~self,
+                // or @self, and such functions are always by-copy
+                // (right now, at least).
             self_mode: ty::ByCopy,
-            /* XXX: Some(llbox) */
         })
     };
 }