Skip to content

Commit f547a67

Browse files
committed
auto merge of #6373 : nikomatsakis/rust/issue-6355-perf-regression, r=graydon
Fix #6355 and #6272---we were not giving the correct index to the derefs that occur as part of the rooting process, resulting in extra copies and generally bogus behavior. Haven't quite produced the right test for this, but I thought I'd push the fix in the meantime. Test will follow shortly. r? @graydon
2 parents 7675856 + e18ed77 commit f547a67

File tree

6 files changed

+76
-35
lines changed

6 files changed

+76
-35
lines changed

Diff for: src/librustc/middle/borrowck/gather_loans/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ pub impl GatherLoanCtxt {
260260
r)
261261
}
262262
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
263-
let cmt_index = mcx.cat_index(expr, cmt);
263+
let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1);
264264
self.guarantee_valid(expr.id,
265265
expr.span,
266266
cmt_index,
@@ -574,7 +574,7 @@ pub impl GatherLoanCtxt {
574574
let (slice_mutbl, slice_r) =
575575
self.vec_slice_info(slice_pat, slice_ty);
576576
let mcx = self.bccx.mc_ctxt();
577-
let cmt_index = mcx.cat_index(slice_pat, cmt);
577+
let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
578578
self.guarantee_valid(pat.id, pat.span,
579579
cmt_index, slice_mutbl, slice_r);
580580
}

Diff for: src/librustc/middle/borrowck/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,16 @@ pub type LoanMap = @mut HashMap<ast::node_id, @Loan>;
184184
//
185185
// Note that there is no entry with derefs:3---the type of that expression
186186
// is T, which is not a box.
187+
//
188+
// Note that implicit dereferences also occur with indexing of `@[]`,
189+
// `@str`, etc. The same rules apply. So, for example, given a
190+
// variable `x` of type `@[@[...]]`, if I have an instance of the
191+
// expression `x[0]` which is then auto-slice'd, there would be two
192+
// potential entries in the root map, both with the id of the `x[0]`
193+
// expression. The entry with `derefs==0` refers to the deref of `x`
194+
// used as part of evaluating `x[0]`. The entry with `derefs==1`
195+
// refers to the deref of the `x[0]` that occurs as part of the
196+
// auto-slice.
187197
#[deriving(Eq, IterBytes)]
188198
pub struct root_map_key {
189199
id: ast::node_id,
@@ -605,7 +615,7 @@ pub impl BorrowckCtxt {
605615
}
606616
}
607617

608-
LpExtend(lp_base, _, LpInterior(mc::interior_field(fld, _))) => {
618+
LpExtend(lp_base, _, LpInterior(mc::interior_field(fld))) => {
609619
self.append_loan_path_to_str_from_interior(lp_base, out);
610620
str::push_char(out, '.');
611621
str::push_str(out, *self.tcx.sess.intr().get(fld));

Diff for: src/librustc/middle/mem_categorization.rs

+44-20
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub enum categorization {
6666
cat_local(ast::node_id), // local variable
6767
cat_arg(ast::node_id), // formal argument
6868
cat_deref(cmt, uint, ptr_kind), // deref of a ptr
69-
cat_interior(cmt, interior_kind), // something interior
69+
cat_interior(cmt, interior_kind), // something interior
7070
cat_discr(cmt, ast::node_id), // match discriminant (see preserve())
7171
cat_self(ast::node_id), // explicit `self`
7272
}
@@ -94,8 +94,7 @@ pub enum interior_kind {
9494
interior_anon_field, // anonymous field (in e.g.
9595
// struct Foo(int, int);
9696
interior_variant(ast::def_id), // internals to a variant of given enum
97-
interior_field(ast::ident, // name of field
98-
ast::mutability), // declared mutability of field
97+
interior_field(ast::ident), // name of field
9998
interior_index(ty::t, // type of vec/str/etc being deref'd
10099
ast::mutability) // mutability of vec content
101100
}
@@ -395,8 +394,7 @@ pub impl mem_categorization_ctxt {
395394
assert!(!self.method_map.contains_key(&expr.id));
396395

397396
let base_cmt = self.cat_expr(base);
398-
self.cat_field(expr, base_cmt, f_name,
399-
self.expr_ty(expr), expr.id)
397+
self.cat_field(expr, base_cmt, f_name, self.expr_ty(expr))
400398
}
401399

402400
ast::expr_index(base, _) => {
@@ -405,7 +403,7 @@ pub impl mem_categorization_ctxt {
405403
}
406404

407405
let base_cmt = self.cat_expr(base);
408-
self.cat_index(expr, base_cmt)
406+
self.cat_index(expr, base_cmt, 0)
409407
}
410408

411409
ast::expr_path(_) => {
@@ -579,16 +577,12 @@ pub impl mem_categorization_ctxt {
579577
node: N,
580578
base_cmt: cmt,
581579
f_name: ast::ident,
582-
f_ty: ty::t,
583-
field_id: ast::node_id) -> cmt {
584-
let f_mutbl = m_imm;
585-
let m = self.inherited_mutability(base_cmt.mutbl, f_mutbl);
586-
let f_interior = interior_field(f_name, f_mutbl);
580+
f_ty: ty::t) -> cmt {
587581
@cmt_ {
588582
id: node.id(),
589583
span: node.span(),
590-
cat: cat_interior(base_cmt, f_interior),
591-
mutbl: m,
584+
cat: cat_interior(base_cmt, interior_field(f_name)),
585+
mutbl: base_cmt.mutbl.inherit(),
592586
ty: f_ty
593587
}
594588
}
@@ -670,7 +664,39 @@ pub impl mem_categorization_ctxt {
670664

671665
fn cat_index<N:ast_node>(&self,
672666
elt: N,
673-
base_cmt: cmt) -> cmt {
667+
base_cmt: cmt,
668+
derefs: uint) -> cmt {
669+
//! Creates a cmt for an indexing operation (`[]`); this
670+
//! indexing operation may occurs as part of an
671+
//! AutoBorrowVec, which when converting a `~[]` to an `&[]`
672+
//! effectively takes the address of the 0th element.
673+
//!
674+
//! One subtle aspect of indexing that may not be
675+
//! immediately obvious: for anything other than a fixed-length
676+
//! vector, an operation like `x[y]` actually consists of two
677+
//! disjoint (from the point of view of borrowck) operations.
678+
//! The first is a deref of `x` to create a pointer `p` that points
679+
//! at the first element in the array. The second operation is
680+
//! an index which adds `y*sizeof(T)` to `p` to obtain the
681+
//! pointer to `x[y]`. `cat_index` will produce a resulting
682+
//! cmt containing both this deref and the indexing,
683+
//! presuming that `base_cmt` is not of fixed-length type.
684+
//!
685+
//! In the event that a deref is needed, the "deref count"
686+
//! is taken from the parameter `derefs`. See the comment
687+
//! on the def'n of `root_map_key` in borrowck/mod.rs
688+
//! for more details about deref counts; the summary is
689+
//! that `derefs` should be 0 for an explicit indexing
690+
//! operation and N+1 for an indexing that is part of
691+
//! an auto-adjustment, where N is the number of autoderefs
692+
//! in that adjustment.
693+
//!
694+
//! # Parameters
695+
//! - `elt`: the AST node being indexed
696+
//! - `base_cmt`: the cmt of `elt`
697+
//! - `derefs`: the deref number to be used for
698+
//! the implicit index deref, if any (see above)
699+
674700
let mt = match ty::index(base_cmt.ty) {
675701
Some(mt) => mt,
676702
None => {
@@ -698,7 +724,7 @@ pub impl mem_categorization_ctxt {
698724
let deref_cmt = @cmt_ {
699725
id:elt.id(),
700726
span:elt.span(),
701-
cat:cat_deref(base_cmt, 0u, ptr),
727+
cat:cat_deref(base_cmt, derefs, ptr),
702728
mutbl:m,
703729
ty:mt.ty
704730
};
@@ -854,8 +880,7 @@ pub impl mem_categorization_ctxt {
854880
// {f1: p1, ..., fN: pN}
855881
for field_pats.each |fp| {
856882
let field_ty = self.pat_ty(fp.pat); // see (*)
857-
let cmt_field = self.cat_field(pat, cmt, fp.ident,
858-
field_ty, pat.id);
883+
let cmt_field = self.cat_field(pat, cmt, fp.ident, field_ty);
859884
self.cat_pattern(cmt_field, fp.pat, op);
860885
}
861886
}
@@ -878,8 +903,8 @@ pub impl mem_categorization_ctxt {
878903
}
879904

880905
ast::pat_vec(ref before, slice, ref after) => {
906+
let elt_cmt = self.cat_index(pat, cmt, 0);
881907
for before.each |&before_pat| {
882-
let elt_cmt = self.cat_index(pat, cmt);
883908
self.cat_pattern(elt_cmt, before_pat, op);
884909
}
885910
for slice.each |&slice_pat| {
@@ -888,7 +913,6 @@ pub impl mem_categorization_ctxt {
888913
self.cat_pattern(slice_cmt, slice_pat, op);
889914
}
890915
for after.each |&after_pat| {
891-
let elt_cmt = self.cat_index(pat, cmt);
892916
self.cat_pattern(elt_cmt, after_pat, op);
893917
}
894918
}
@@ -1110,7 +1134,7 @@ pub fn ptr_sigil(ptr: ptr_kind) -> ~str {
11101134
impl Repr for interior_kind {
11111135
fn repr(&self, tcx: ty::ctxt) -> ~str {
11121136
match *self {
1113-
interior_field(fld, _) => copy *tcx.sess.str_of(fld),
1137+
interior_field(fld) => copy *tcx.sess.str_of(fld),
11141138
interior_index(*) => ~"[]",
11151139
interior_tuple => ~"()",
11161140
interior_anon_field => ~"<anonymous field>",

Diff for: src/librustc/middle/trans/_match.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,8 @@ pub fn extract_vec_elems(bcx: block,
885885
-> ExtractedBlock {
886886
let _icx = bcx.insn_ctxt("match::extract_vec_elems");
887887
let vec_datum = match_datum(bcx, val, pat_id);
888-
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id);
888+
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span,
889+
pat_id, 0);
889890
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
890891
891892
let mut elems = do vec::from_fn(elem_count) |i| {

Diff for: src/librustc/middle/trans/datum.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -735,13 +735,14 @@ pub impl Datum {
735735
fn get_vec_base_and_len(&self,
736736
mut bcx: block,
737737
span: span,
738-
expr_id: ast::node_id)
738+
expr_id: ast::node_id,
739+
derefs: uint)
739740
-> (block, ValueRef, ValueRef) {
740741
//! Converts a vector into the slice pair. Performs rooting
741742
//! and write guards checks.
742743
743744
// only imp't for @[] and @str, but harmless
744-
bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, 0);
745+
bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
745746
let (base, len) = self.get_vec_base_and_len_no_root(bcx);
746747
(bcx, base, len)
747748
}

Diff for: src/librustc/middle/trans/expr.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,9 @@ use middle::trans::tvec;
144144
use middle::trans::type_of;
145145
use middle::ty::struct_fields;
146146
use middle::ty::{AutoDerefRef, AutoAddEnv};
147-
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
148-
use middle::ty;
149147
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
150148
AutoDerefRef, AutoAddEnv, AutoUnsafe};
149+
use middle::ty;
151150
use util::common::indenter;
152151
use util::ppaux::Repr;
153152

@@ -215,10 +214,12 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
215214
unpack_datum!(bcx, auto_ref(bcx, datum))
216215
}
217216
Some(AutoBorrowVec(*)) => {
218-
unpack_datum!(bcx, auto_slice(bcx, expr, datum))
217+
unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs,
218+
expr, datum))
219219
}
220220
Some(AutoBorrowVecRef(*)) => {
221-
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
221+
unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs,
222+
expr, datum))
222223
}
223224
Some(AutoBorrowFn(*)) => {
224225
let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
@@ -246,7 +247,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
246247
mode: datum.mode, source: datum.source}}
247248
}
248249

249-
fn auto_slice(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock {
250+
fn auto_slice(bcx: block,
251+
autoderefs: uint,
252+
expr: @ast::expr,
253+
datum: Datum) -> DatumBlock {
250254
// This is not the most efficient thing possible; since slices
251255
// are two words it'd be better if this were compiled in
252256
// 'dest' mode, but I can't find a nice way to structure the
@@ -256,9 +260,8 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
256260
let tcx = bcx.tcx();
257261
let unit_ty = ty::sequence_element_type(tcx, datum.ty);
258262

259-
// FIXME(#6272) need to distinguish "auto-slice" from explicit index?
260263
let (bcx, base, len) =
261-
datum.get_vec_base_and_len(bcx, expr.span, expr.id);
264+
datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1);
262265

263266
// this type may have a different region/mutability than the
264267
// real one, but it will have the same runtime representation
@@ -292,9 +295,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
292295
}
293296

294297
fn auto_slice_and_ref(bcx: block,
298+
autoderefs: uint,
295299
expr: @ast::expr,
296300
datum: Datum) -> DatumBlock {
297-
let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
301+
let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
298302
auto_ref(bcx, datum)
299303
}
300304
}
@@ -913,7 +917,8 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
913917
base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
914918

915919
let mut (bcx, base, len) =
916-
base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id);
920+
base_datum.get_vec_base_and_len(bcx, index_expr.span,
921+
index_expr.id, 0);
917922

918923
if ty::type_is_str(base_ty) {
919924
// acccount for null terminator in the case of string

0 commit comments

Comments
 (0)