trans: Rely on new AutoBorrowObj adjustment to match up object receivers

Note: some portions of this commit written by @Sodel-the-Vociferous
(Daniel Ralston)
This commit is contained in:
Niko Matsakis 2013-08-11 13:42:26 -04:00
parent 6f319812d6
commit 006c6b6be4
4 changed files with 140 additions and 111 deletions

View File

@ -60,7 +60,6 @@ pub struct MethodData {
llfn: ValueRef,
llself: ValueRef,
temp_cleanup: Option<ValueRef>,
self_ty: ty::t,
self_mode: ty::SelfMode,
}

View File

@ -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};

View File

@ -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 {

View File

@ -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) */
})
};
}