Skip to content

Commit 765a290

Browse files
committed
Avoid double indirection for the "self" arg in methods
Currently we pass all "self" arguments by reference, for the pointer variants this means that we end up with double indirection which causes a unnecessary performance hit. The fix itself is pretty straight-forward and just means that "self" needs to be handled like any other argument, except for by-value "self" which still needs to be passed by reference. This is because non-pointer types can't just be stuffed into the environment slot which is used to pass "self". What made things tricky is that there was also a bug in the typechecker where the method map entries are created. For type impls, that stored the base type instead of the actual self-type in the method map, e.g. Foo instead of &Foo for &self. That worked with pass-by-reference, but fails with pass-by-value which needs the real type. Code that makes use of methods seems to be about 10% faster with this change. Also, build times are reduced by about 4%. Fixes #4355, #4402, #5280, #4406 and #7285
1 parent ba922a4 commit 765a290

File tree

8 files changed

+57
-78
lines changed

8 files changed

+57
-78
lines changed

src/librustc/middle/trans/asm.rs

-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
4141
callee::trans_arg_expr(bcx,
4242
expr_ty(bcx, out),
4343
ty::ByCopy,
44-
ast::sty_static,
4544
out,
4645
&mut cleanups,
4746
None,
@@ -57,7 +56,6 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
5756
callee::trans_arg_expr(bcx,
5857
expr_ty(bcx, e),
5958
ty::ByCopy,
60-
ast::sty_static,
6159
e,
6260
&mut cleanups,
6361
None,
@@ -79,7 +77,6 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
7977
callee::trans_arg_expr(bcx,
8078
expr_ty(bcx, in),
8179
ty::ByCopy,
82-
ast::sty_static,
8380
in,
8481
&mut cleanups,
8582
None,

src/librustc/middle/trans/base.rs

+14-15
Original file line numberDiff line numberDiff line change
@@ -1626,18 +1626,11 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt,
16261626
let _icx = push_ctxt("create_llargs_for_fn_args");
16271627

16281628
match self_arg {
1629-
impl_self(tt) => {
1629+
impl_self(tt, self_mode) => {
16301630
cx.llself = Some(ValSelfData {
16311631
v: cx.llenv,
16321632
t: tt,
1633-
is_owned: false
1634-
});
1635-
}
1636-
impl_owned_self(tt) => {
1637-
cx.llself = Some(ValSelfData {
1638-
v: cx.llenv,
1639-
t: tt,
1640-
is_owned: true
1633+
is_copy: self_mode == ty::ByCopy
16411634
});
16421635
}
16431636
no_self => ()
@@ -1676,12 +1669,18 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
16761669

16771670
match fcx.llself {
16781671
Some(slf) => {
1679-
let self_val = PointerCast(bcx, slf.v, type_of(bcx.ccx(), slf.t).ptr_to());
1680-
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
1672+
let self_val = if slf.is_copy
1673+
&& datum::appropriate_mode(slf.t).is_by_value() {
1674+
let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t));
1675+
let alloc = alloc_ty(bcx, slf.t);
1676+
Store(bcx, tmp, alloc);
1677+
alloc
1678+
} else {
1679+
PointerCast(bcx, slf.v, type_of(bcx.ccx(), slf.t).ptr_to())
1680+
};
16811681

1682-
if slf.is_owned {
1683-
add_clean(bcx, slf.v, slf.t);
1684-
}
1682+
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
1683+
add_clean(bcx, self_val, slf.t);
16851684
}
16861685
_ => {}
16871686
}
@@ -1758,7 +1757,7 @@ pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
17581757
}
17591758
}
17601759

1761-
pub enum self_arg { impl_self(ty::t), impl_owned_self(ty::t), no_self, }
1760+
pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
17621761

17631762
// trans_closure: Builds an LLVM function out of a source function.
17641763
// If the function closes over its environment a closure will be

src/librustc/middle/trans/callee.rs

+12-21
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ pub struct MethodData {
6565
temp_cleanup: Option<ValueRef>,
6666
self_ty: ty::t,
6767
self_mode: ty::SelfMode,
68-
explicit_self: ast::explicit_self_
6968
}
7069

7170
pub enum CalleeData {
@@ -645,7 +644,7 @@ pub fn trans_call_inner(in_cx: block,
645644

646645

647646
// Now that the arguments have finished evaluating, we need to revoke
648-
// the cleanup for the self argument, if it exists
647+
// the cleanup for the self argument
649648
match callee.data {
650649
Method(d) => {
651650
for d.temp_cleanup.iter().advance |&v| {
@@ -771,7 +770,6 @@ pub fn trans_args(cx: block,
771770
trans_arg_expr(bcx,
772771
arg_tys[i],
773772
ty::ByCopy,
774-
ast::sty_static,
775773
*arg_expr,
776774
&mut temp_cleanups,
777775
if i == last { ret_flag } else { None },
@@ -805,18 +803,16 @@ pub enum AutorefArg {
805803
pub fn trans_arg_expr(bcx: block,
806804
formal_arg_ty: ty::t,
807805
self_mode: ty::SelfMode,
808-
ex_self: ast::explicit_self_,
809806
arg_expr: @ast::expr,
810807
temp_cleanups: &mut ~[ValueRef],
811808
ret_flag: Option<ValueRef>,
812809
autoref_arg: AutorefArg) -> Result {
813810
let _icx = push_ctxt("trans_arg_expr");
814811
let ccx = bcx.ccx();
815812

816-
debug!("trans_arg_expr(formal_arg_ty=(%s), explicit_self=%? self_mode=%?, arg_expr=%s, \
813+
debug!("trans_arg_expr(formal_arg_ty=(%s), self_mode=%?, arg_expr=%s, \
817814
ret_flag=%?)",
818815
formal_arg_ty.repr(bcx.tcx()),
819-
ex_self,
820816
self_mode,
821817
arg_expr.repr(bcx.tcx()),
822818
ret_flag.map(|v| bcx.val_to_str(*v)));
@@ -876,9 +872,15 @@ pub fn trans_arg_expr(bcx: block,
876872
val = arg_datum.to_ref_llval(bcx);
877873
}
878874
DontAutorefArg => {
879-
match (self_mode, ex_self) {
880-
(ty::ByRef, ast::sty_value) => {
881-
debug!("by value self with type %s, storing to scratch",
875+
match self_mode {
876+
ty::ByRef => {
877+
// This assertion should really be valid, but because
878+
// the explicit self code currently passes by-ref, it
879+
// does not hold.
880+
//
881+
//assert !bcx.ccx().maps.moves_map.contains_key(
882+
// &arg_expr.id);
883+
debug!("by ref arg with type %s, storing to scratch",
882884
bcx.ty_to_str(arg_datum.ty));
883885
let scratch = scratch_datum(bcx, arg_datum.ty, false);
884886

@@ -895,18 +897,7 @@ pub fn trans_arg_expr(bcx: block,
895897

896898
val = scratch.to_ref_llval(bcx);
897899
}
898-
(ty::ByRef, _) => {
899-
// This assertion should really be valid, but because
900-
// the explicit self code currently passes by-ref, it
901-
// does not hold.
902-
//
903-
//assert !bcx.ccx().maps.moves_map.contains_key(
904-
// &arg_expr.id);
905-
debug!("by ref arg with type %s",
906-
bcx.ty_to_str(arg_datum.ty));
907-
val = arg_datum.to_ref_llval(bcx);
908-
}
909-
(ty::ByCopy, _) => {
900+
ty::ByCopy => {
910901
if ty::type_needs_drop(bcx.tcx(), arg_datum.ty) ||
911902
arg_datum.appropriate_mode().is_by_ref() {
912903
debug!("by copy arg with type %s, storing to scratch",

src/librustc/middle/trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub type ExternMap = HashMap<@str, ValueRef>;
125125
pub struct ValSelfData {
126126
v: ValueRef,
127127
t: ty::t,
128-
is_owned: bool
128+
is_copy: bool,
129129
}
130130

131131
// Here `self_ty` is the real type of the self parameter to this method. It

src/librustc/middle/trans/glue.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,7 @@ pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast:
425425
// just consist of the environment (self)
426426
assert_eq!(params.len(), 1);
427427

428-
// Take a reference to the class (because it's using the Drop trait),
429-
// do so now.
430-
let llval = alloca(bcx, val_ty(v0));
431-
Store(bcx, v0, llval);
432-
433-
let self_arg = PointerCast(bcx, llval, params[0]);
428+
let self_arg = PointerCast(bcx, v0, params[0]);
434429
let args = ~[self_arg];
435430

436431
Call(bcx, dtor_addr, args);
@@ -465,12 +460,7 @@ pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::
465460
// just consist of the environment (self)
466461
assert_eq!(params.len(), 1);
467462

468-
// Take a reference to the class (because it's using the Drop trait),
469-
// do so now.
470-
let llval = alloca(bcx, val_ty(v0));
471-
Store(bcx, v0, llval);
472-
473-
let self_arg = PointerCast(bcx, llval, params[0]);
463+
let self_arg = PointerCast(bcx, v0, params[0]);
474464
let args = ~[self_arg];
475465

476466
Call(bcx, dtor_addr, args);

src/librustc/middle/trans/inline.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::prelude::*;
1212

1313
use metadata::csearch;
1414
use middle::astencode;
15-
use middle::trans::base::{push_ctxt,impl_owned_self, impl_self, no_self};
15+
use middle::trans::base::{push_ctxt, impl_self, no_self};
1616
use middle::trans::base::{trans_item, get_item_val, trans_fn};
1717
use middle::trans::common::*;
1818
use middle::ty;
@@ -114,8 +114,8 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
114114
debug!("calling inline trans_fn with self_ty %s",
115115
ty_to_str(ccx.tcx, self_ty));
116116
match mth.explicit_self.node {
117-
ast::sty_value => impl_owned_self(self_ty),
118-
_ => impl_self(self_ty),
117+
ast::sty_value => impl_self(self_ty, ty::ByRef),
118+
_ => impl_self(self_ty, ty::ByCopy),
119119
}
120120
}
121121
};

src/librustc/middle/trans/meth.rs

+16-19
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use middle::trans::build::*;
2020
use middle::trans::callee::*;
2121
use middle::trans::callee;
2222
use middle::trans::common::*;
23+
use middle::trans::datum::*;
2324
use middle::trans::expr::{SaveIn, Ignore};
2425
use middle::trans::expr;
2526
use middle::trans::glue;
@@ -107,10 +108,8 @@ pub fn trans_method(ccx: @mut CrateContext,
107108
debug!("calling trans_fn with self_ty %s",
108109
self_ty.repr(ccx.tcx));
109110
match method.explicit_self.node {
110-
ast::sty_value => impl_owned_self(self_ty),
111-
_ => {
112-
impl_self(self_ty)
113-
}
111+
ast::sty_value => impl_self(self_ty, ty::ByRef),
112+
_ => impl_self(self_ty, ty::ByCopy),
114113
}
115114
}
116115
};
@@ -138,7 +137,6 @@ pub fn trans_self_arg(bcx: block,
138137
trans_arg_expr(bcx,
139138
self_ty,
140139
mentry.self_mode,
141-
mentry.explicit_self,
142140
base,
143141
temp_cleanups,
144142
None,
@@ -205,7 +203,6 @@ pub fn trans_method_callee(bcx: block,
205203
temp_cleanup: temp_cleanups.head_opt().map(|&v| *v),
206204
self_ty: node_id_type(bcx, this.id),
207205
self_mode: mentry.self_mode,
208-
explicit_self: mentry.explicit_self
209206
})
210207
}
211208
}
@@ -438,7 +435,6 @@ pub fn trans_monomorphized_callee(bcx: block,
438435
temp_cleanup: temp_cleanups.head_opt().map(|&v| *v),
439436
self_ty: node_id_type(bcx, base.id),
440437
self_mode: mentry.self_mode,
441-
explicit_self: mentry.explicit_self
442438
})
443439
}
444440
}
@@ -568,7 +564,8 @@ pub fn trans_trait_callee_from_llval(bcx: block,
568564
// necessary:
569565
let mut llself;
570566
debug!("(translating trait callee) loading second index from pair");
571-
let llbox = Load(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_box]));
567+
let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
568+
let llbox = Load(bcx, llboxptr);
572569

573570
// Munge `llself` appropriately for the type of `self` in the method.
574571
match explicit_self {
@@ -580,8 +577,6 @@ pub fn trans_trait_callee_from_llval(bcx: block,
580577
called on objects");
581578
}
582579
ast::sty_region(*) => {
583-
// As before, we need to pass a pointer to a pointer to the
584-
// payload.
585580
match store {
586581
ty::BoxTraitStore |
587582
ty::UniqTraitStore => {
@@ -596,7 +591,7 @@ pub fn trans_trait_callee_from_llval(bcx: block,
596591
// Bump the reference count on the box.
597592
debug!("(translating trait callee) callee type is `%s`",
598593
bcx.ty_to_str(callee_ty));
599-
bcx = glue::take_ty(bcx, llbox, callee_ty);
594+
glue::incr_refcnt_of_boxed(bcx, llbox);
600595

601596
// Pass a pointer to the box.
602597
match store {
@@ -610,12 +605,15 @@ pub fn trans_trait_callee_from_llval(bcx: block,
610605
ty::UniqTraitStore => llself = llbox,
611606
_ => bcx.tcx().sess.bug("~self receiver with non-~Trait")
612607
}
608+
609+
zero_mem(bcx, llboxptr, ty::mk_opaque_box(bcx.tcx()));
613610
}
614611
}
615612

616-
let llscratch = alloca(bcx, val_ty(llself));
617-
Store(bcx, llself, llscratch);
618-
llself = PointerCast(bcx, llscratch, Type::opaque_box(ccx).ptr_to());
613+
llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to());
614+
let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), false);
615+
Store(bcx, llself, scratch.val);
616+
scratch.add_clean(bcx);
619617

620618
// Load the function from the vtable and cast it to the expected type.
621619
debug!("(translating trait callee) loading method");
@@ -630,11 +628,10 @@ pub fn trans_trait_callee_from_llval(bcx: block,
630628
bcx: bcx,
631629
data: Method(MethodData {
632630
llfn: mptr,
633-
llself: llself,
634-
temp_cleanup: None,
635-
self_ty: ty::mk_opaque_box(bcx.tcx()),
636-
self_mode: ty::ByRef,
637-
explicit_self: explicit_self
631+
llself: scratch.to_value_llval(bcx),
632+
temp_cleanup: Some(scratch.val),
633+
self_ty: scratch.ty,
634+
self_mode: ty::ByCopy,
638635
/* XXX: Some(llbox) */
639636
})
640637
};

src/librustc/middle/typeck/check/method.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -976,9 +976,7 @@ impl<'self> LookupContext<'self> {
976976
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty});
977977
debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty));
978978

979-
// FIXME(#7411): We always pass self by-ref since we stuff it in the environment slot.
980-
// Eventually that should not be the case
981-
let self_mode = ty::ByRef;
979+
let self_mode = get_mode_from_explicit_self(candidate.method_ty.explicit_self);
982980

983981
// before we only checked whether self_ty could be a subtype
984982
// of rcvr_ty; now we actually make it so (this may cause
@@ -998,7 +996,7 @@ impl<'self> LookupContext<'self> {
998996
self.fcx.write_ty(self.callee_id, fty);
999997
self.fcx.write_substs(self.callee_id, all_substs);
1000998
method_map_entry {
1001-
self_ty: candidate.rcvr_ty,
999+
self_ty: rcvr_ty,
10021000
self_mode: self_mode,
10031001
explicit_self: candidate.method_ty.explicit_self,
10041002
origin: candidate.origin,
@@ -1253,3 +1251,10 @@ impl<'self> LookupContext<'self> {
12531251
self.tcx().sess.bug(s)
12541252
}
12551253
}
1254+
1255+
pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMode {
1256+
match explicit_self {
1257+
sty_value => ty::ByRef,
1258+
_ => ty::ByCopy,
1259+
}
1260+
}

0 commit comments

Comments
 (0)