From 006c6b6be4499fd999ef3f52996b944263baa220 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 11 Aug 2013 13:42:26 -0400 Subject: [PATCH] trans: Rely on new AutoBorrowObj adjustment to match up object receivers Note: some portions of this commit written by @Sodel-the-Vociferous (Daniel Ralston) --- src/librustc/middle/trans/callee.rs | 1 - src/librustc/middle/trans/context.rs | 5 +- src/librustc/middle/trans/expr.rs | 101 ++++++++++++++++++- src/librustc/middle/trans/meth.rs | 144 +++++++-------------------- 4 files changed, 140 insertions(+), 111 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, - 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) -> 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) */ }) }; }