Skip to content

Commit 006c6b6

Browse files
committed
trans: Rely on new AutoBorrowObj adjustment to match up object receivers
Note: some portions of this commit written by @Sodel-the-Vociferous (Daniel Ralston)
1 parent 6f31981 commit 006c6b6

File tree

4 files changed

+141
-112
lines changed

4 files changed

+141
-112
lines changed

src/librustc/middle/trans/callee.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ pub struct MethodData {
6060
llfn: ValueRef,
6161
llself: ValueRef,
6262
temp_cleanup: Option<ValueRef>,
63-
self_ty: ty::t,
6463
self_mode: ty::SelfMode,
6564
}
6665

src/librustc/middle/trans/context.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use back::{upcall};
1313
use driver::session;
1414
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
1515
use lib::llvm::{llvm, TargetData, TypeNames};
16-
use lib::llvm::{mk_target_data};
16+
use lib::llvm::{mk_target_data, False};
1717
use metadata::common::LinkMeta;
1818
use middle::astencode;
1919
use middle::resolve;
@@ -22,6 +22,7 @@ use middle::trans::base;
2222
use middle::trans::builder::Builder;
2323
use middle::trans::debuginfo;
2424
use middle::trans::type_use;
25+
use middle::trans::common::{C_i32, C_null};
2526
use middle::ty;
2627

2728
use middle::trans::type_::Type;
@@ -30,6 +31,8 @@ use std::c_str::ToCStr;
3031
use std::hash;
3132
use std::hashmap::{HashMap, HashSet};
3233
use std::local_data;
34+
use std::vec;
35+
use std::libc::c_uint;
3336
use syntax::ast;
3437

3538
use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};

src/librustc/middle/trans/expr.rs

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,8 @@ use middle::trans::meth;
137137
use middle::trans::tvec;
138138
use middle::trans::type_of;
139139
use middle::ty::struct_fields;
140-
use middle::ty::{AutoDerefRef, AutoAddEnv};
141-
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
142-
AutoUnsafe};
140+
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
141+
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
143142
use middle::ty;
144143
use util::common::indenter;
145144
use util::ppaux::Repr;
@@ -223,6 +222,10 @@ pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
223222
datum.ty, Some(adjustment));
224223
unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
225224
}
225+
Some(AutoBorrowObj(*)) => {
226+
unpack_datum!(bcx, auto_borrow_obj(
227+
bcx, adj.autoderefs, expr, datum))
228+
}
226229
};
227230
}
228231
}
@@ -298,6 +301,98 @@ pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
298301
let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
299302
auto_ref(bcx, datum)
300303
}
304+
305+
fn auto_borrow_obj(mut bcx: @mut Block,
306+
autoderefs: uint,
307+
expr: @ast::expr,
308+
source_datum: Datum) -> DatumBlock {
309+
let tcx = bcx.tcx();
310+
let target_obj_ty = expr_ty_adjusted(bcx, expr);
311+
debug!("auto_borrow_obj(target=%s)",
312+
target_obj_ty.repr(tcx));
313+
let scratch = scratch_datum(bcx, target_obj_ty,
314+
"__auto_borrow_obj", false);
315+
316+
// Convert a @Object, ~Object, or &Object pair into an &Object pair.
317+
318+
// Get a pointer to the source object, which is represented as
319+
// a (vtable, data) pair.
320+
let source_llval = source_datum.to_ref_llval(bcx);
321+
322+
// Set the vtable field of the new pair
323+
let vtable_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_vtable]);
324+
let vtable = Load(bcx, vtable_ptr);
325+
Store(bcx, vtable, GEPi(bcx, scratch.val, [0u, abi::trt_field_vtable]));
326+
327+
// Load the data for the source, which is either an @T,
328+
// ~T, or &T, depending on source_obj_ty.
329+
let source_data_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_box]);
330+
let source_data = Load(bcx, source_data_ptr); // always a ptr
331+
let (source_store, source_mutbl) = match ty::get(source_datum.ty).sty {
332+
ty::ty_trait(_, _, s, m, _) => (s, m),
333+
_ => {
334+
bcx.sess().span_bug(
335+
expr.span,
336+
fmt!("auto_borrow_trait_obj expected a trait, found %s",
337+
source_datum.ty.repr(bcx.tcx())));
338+
}
339+
};
340+
let target_data = match source_store {
341+
ty::BoxTraitStore(*) => {
342+
// For deref of @T or @mut T, create a dummy datum and
343+
// use the datum's deref method. This is more work
344+
// than just calling GEPi ourselves, but it ensures
345+
// that any write guards will be appropriate
346+
// processed. Note that we don't know the type T, so
347+
// just substitute `i8`-- it doesn't really matter for
348+
// our purposes right now.
349+
let source_ty =
350+
ty::mk_box(tcx,
351+
ty::mt {
352+
ty: ty::mk_i8(),
353+
mutbl: source_mutbl});
354+
let source_datum =
355+
Datum {val: source_data,
356+
ty: source_ty,
357+
mode: ByValue};
358+
let derefd_datum =
359+
unpack_datum!(bcx,
360+
source_datum.deref(bcx,
361+
expr,
362+
autoderefs));
363+
derefd_datum.to_rptr(bcx).to_value_llval(bcx)
364+
}
365+
ty::UniqTraitStore(*) => {
366+
// For a ~T box, there may or may not be a header,
367+
// depending on whether the type T references managed
368+
// boxes. However, since we do not *know* the type T
369+
// for objects, this presents a hurdle. Our solution is
370+
// to load the "borrow offset" from the type descriptor;
371+
// this value will either be 0 or sizeof(BoxHeader), depending
372+
// on the type T.
373+
let llopaque =
374+
PointerCast(bcx, source_data, Type::opaque().ptr_to());
375+
let lltydesc_ptr_ptr =
376+
PointerCast(bcx, vtable,
377+
bcx.ccx().tydesc_type.ptr_to().ptr_to());
378+
let lltydesc_ptr =
379+
Load(bcx, lltydesc_ptr_ptr);
380+
let borrow_offset_ptr =
381+
GEPi(bcx, lltydesc_ptr,
382+
[0, abi::tydesc_field_borrow_offset]);
383+
let borrow_offset =
384+
Load(bcx, borrow_offset_ptr);
385+
InBoundsGEP(bcx, llopaque, [borrow_offset])
386+
}
387+
ty::RegionTraitStore(*) => {
388+
source_data
389+
}
390+
};
391+
Store(bcx, target_data,
392+
GEPi(bcx, scratch.val, [0u, abi::trt_field_box]));
393+
394+
DatumBlock { bcx: bcx, datum: scratch }
395+
}
301396
}
302397

303398
pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {

src/librustc/middle/trans/meth.rs

Lines changed: 39 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ pub fn trans_method_callee(bcx: @mut Block,
164164
llfn: callee_fn.llfn,
165165
llself: val,
166166
temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
167-
self_ty: node_id_type(bcx, this.id),
168167
self_mode: mentry.self_mode,
169168
})
170169
}
@@ -187,13 +186,11 @@ pub fn trans_method_callee(bcx: @mut Block,
187186
}
188187
}
189188

190-
typeck::method_trait(_, off, store) => {
189+
typeck::method_trait(_, off) => {
191190
trans_trait_callee(bcx,
192191
callee_id,
193192
off,
194-
this,
195-
store,
196-
mentry.explicit_self)
193+
this)
197194
}
198195
}
199196
}
@@ -341,7 +338,6 @@ pub fn trans_monomorphized_callee(bcx: @mut Block,
341338
llfn: llfn_val,
342339
llself: llself_val,
343340
temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
344-
self_ty: node_id_type(bcx, base.id),
345341
self_mode: mentry.self_mode,
346342
})
347343
}
@@ -406,142 +402,78 @@ pub fn combine_impl_and_methods_tps(bcx: @mut Block,
406402
pub fn trans_trait_callee(bcx: @mut Block,
407403
callee_id: ast::NodeId,
408404
n_method: uint,
409-
self_expr: @ast::expr,
410-
store: ty::TraitStore,
411-
explicit_self: ast::explicit_self_)
405+
self_expr: @ast::expr)
412406
-> Callee {
413-
//!
414-
//
415-
// Create a method callee where the method is coming from a trait
416-
// instance (e.g., @Trait type). In this case, we must pull the
417-
// fn pointer out of the vtable that is packaged up with the
418-
// @/~/&Trait instance. @/~/&Traits are represented as a pair, so we
419-
// first evaluate the self expression (expected a by-ref result) and then
420-
// extract the self data and vtable out of the pair.
407+
/*!
408+
* Create a method callee where the method is coming from a trait
409+
* object (e.g., @Trait type). In this case, we must pull the fn
410+
* pointer out of the vtable that is packaged up with the object.
411+
* Objects are represented as a pair, so we first evaluate the self
412+
* expression and then extract the self data and vtable out of the
413+
* pair.
414+
*/
421415

422416
let _icx = push_ctxt("impl::trans_trait_callee");
423417
let mut bcx = bcx;
424-
let self_datum = unpack_datum!(bcx,
425-
expr::trans_to_datum(bcx, self_expr));
426-
let llpair = self_datum.to_ref_llval(bcx);
427-
428-
let llpair = match explicit_self {
429-
ast::sty_region(*) => Load(bcx, llpair),
430-
ast::sty_static | ast::sty_value |
431-
ast::sty_box(_) | ast::sty_uniq => llpair
432-
};
418+
419+
let self_ty = expr_ty_adjusted(bcx, self_expr);
420+
let self_scratch = scratch_datum(bcx, self_ty, "__trait_callee", false);
421+
bcx = expr::trans_into(bcx, self_expr, expr::SaveIn(self_scratch.val));
422+
423+
// Arrange a temporary cleanup for the object in case something
424+
// should go wrong before the method is actually *invoked*.
425+
self_scratch.add_clean(bcx);
433426

434427
let callee_ty = node_id_type(bcx, callee_id);
435428
trans_trait_callee_from_llval(bcx,
436429
callee_ty,
437430
n_method,
438-
llpair,
439-
store,
440-
explicit_self)
431+
self_scratch.val,
432+
Some(self_scratch.val))
441433
}
442434

443435
pub fn trans_trait_callee_from_llval(bcx: @mut Block,
444436
callee_ty: ty::t,
445437
n_method: uint,
446438
llpair: ValueRef,
447-
store: ty::TraitStore,
448-
explicit_self: ast::explicit_self_)
439+
temp_cleanup: Option<ValueRef>)
449440
-> Callee {
450-
//!
451-
//
452-
// Same as `trans_trait_callee()` above, except that it is given
453-
// a by-ref pointer to the @Trait pair.
441+
/*!
442+
* Same as `trans_trait_callee()` above, except that it is given
443+
* a by-ref pointer to the object pair.
444+
*/
454445

455446
let _icx = push_ctxt("impl::trans_trait_callee");
456447
let ccx = bcx.ccx();
457448

458-
// Load the vtable from the @Trait pair
459-
debug!("(translating trait callee) loading vtable from pair %s",
460-
bcx.val_to_str(llpair));
461-
let llvtable = Load(bcx,
462-
PointerCast(bcx,
463-
GEPi(bcx, llpair,
464-
[0u, abi::trt_field_vtable]),
465-
Type::vtable().ptr_to().ptr_to()));
466-
467-
// Load the box from the @Trait pair and GEP over the box header if
468-
// necessary:
469-
let mut llself;
449+
// Load the data pointer from the object.
470450
debug!("(translating trait callee) loading second index from pair");
471451
let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
472452
let llbox = Load(bcx, llboxptr);
473-
474-
// Munge `llself` appropriately for the type of `self` in the method.
475-
match explicit_self {
476-
ast::sty_static => {
477-
bcx.tcx().sess.bug("shouldn't see static method here");
478-
}
479-
ast::sty_value => {
480-
bcx.tcx().sess.bug("methods with by-value self should not be \
481-
called on objects");
482-
}
483-
ast::sty_region(*) => {
484-
match store {
485-
ty::UniqTraitStore
486-
if !ty::type_contents(bcx.tcx(), callee_ty).contains_managed() => {
487-
llself = llbox;
488-
}
489-
ty::BoxTraitStore |
490-
ty::UniqTraitStore => {
491-
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
492-
}
493-
ty::RegionTraitStore(_) => {
494-
llself = llbox;
495-
}
496-
}
497-
}
498-
ast::sty_box(_) => {
499-
// Bump the reference count on the box.
500-
debug!("(translating trait callee) callee type is `%s`",
501-
bcx.ty_to_str(callee_ty));
502-
glue::incr_refcnt_of_boxed(bcx, llbox);
503-
504-
// Pass a pointer to the box.
505-
match store {
506-
ty::BoxTraitStore => llself = llbox,
507-
_ => bcx.tcx().sess.bug("@self receiver with non-@Trait")
508-
}
509-
}
510-
ast::sty_uniq => {
511-
// Pass the unique pointer.
512-
match store {
513-
ty::UniqTraitStore => llself = llbox,
514-
_ => bcx.tcx().sess.bug("~self receiver with non-~Trait")
515-
}
516-
517-
zero_mem(bcx, llboxptr, ty::mk_opaque_box(bcx.tcx()));
518-
}
519-
}
520-
521-
llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to());
522-
let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()),
523-
"__trait_callee", false);
524-
Store(bcx, llself, scratch.val);
525-
scratch.add_clean(bcx);
453+
let llself = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
526454

527455
// Load the function from the vtable and cast it to the expected type.
528456
debug!("(translating trait callee) loading method");
529457
let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty);
530-
531-
// Plus one in order to skip past the type descriptor.
458+
let llvtable = Load(bcx,
459+
PointerCast(bcx,
460+
GEPi(bcx, llpair,
461+
[0u, abi::trt_field_vtable]),
462+
Type::vtable().ptr_to().ptr_to()));
532463
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));
533-
534464
let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
535465

536466
return Callee {
537467
bcx: bcx,
538468
data: Method(MethodData {
539469
llfn: mptr,
540-
llself: scratch.to_value_llval(bcx),
541-
temp_cleanup: Some(scratch.val),
542-
self_ty: scratch.ty,
470+
llself: llself,
471+
temp_cleanup: temp_cleanup,
472+
473+
// We know that the func declaration is &self, ~self,
474+
// or @self, and such functions are always by-copy
475+
// (right now, at least).
543476
self_mode: ty::ByCopy,
544-
/* XXX: Some(llbox) */
545477
})
546478
};
547479
}

0 commit comments

Comments
 (0)