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:
parent
6f319812d6
commit
006c6b6be4
@ -60,7 +60,6 @@ pub struct MethodData {
|
||||
llfn: ValueRef,
|
||||
llself: ValueRef,
|
||||
temp_cleanup: Option<ValueRef>,
|
||||
self_ty: ty::t,
|
||||
self_mode: ty::SelfMode,
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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 {
|
||||
|
@ -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) */
|
||||
})
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user