Skip to content

Commit e0d3cf6

Browse files
committed
auto merge of #15418 : pnkfelix/rust/fsk-revise-VecPerParamSpace, r=pcwalton
In my informal measurements, this brings the peak memory usage when building librustc from 1662M down to 1502M. Since 1662 - 1502 = 160, this may not recover the entirety of the observed memory regression (250M) from PR #14604. (However, according to my local measurements, the regression when building librustc was more like 209M, so perhaps this will still recover the lions share of the lost memory.)
2 parents b00f4ec + 4459fe3 commit e0d3cf6

File tree

16 files changed

+240
-138
lines changed

16 files changed

+240
-138
lines changed

src/librustc/metadata/tyencode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ fn enc_vec_per_param_space<T>(w: &mut MemWriter,
100100
op: |&mut MemWriter, &ctxt, &T|) {
101101
for &space in subst::ParamSpace::all().iter() {
102102
mywrite!(w, "[");
103-
for t in v.get_vec(space).iter() {
103+
for t in v.get_slice(space).iter() {
104104
op(w, cx, t);
105105
}
106106
mywrite!(w, "]");

src/librustc/middle/astencode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ fn encode_vec_per_param_space<T>(ebml_w: &mut Encoder,
810810
v: &subst::VecPerParamSpace<T>,
811811
f: |&mut Encoder, &T|) {
812812
for &space in subst::ParamSpace::all().iter() {
813-
ebml_w.emit_from_vec(v.get_vec(space).as_slice(),
813+
ebml_w.emit_from_vec(v.get_slice(space),
814814
|ebml_w, n| Ok(f(ebml_w, n))).unwrap();
815815
}
816816
}

src/librustc/middle/subst.rs

Lines changed: 135 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use middle::ty_fold;
1515
use middle::ty_fold::{TypeFoldable, TypeFolder};
1616
use util::ppaux::Repr;
1717

18-
use std::iter::Chain;
1918
use std::mem;
2019
use std::raw;
2120
use std::slice::{Items, MutItems};
@@ -191,8 +190,8 @@ impl Substs {
191190
}
192191

193192
pub fn with_method_from(self, substs: &Substs) -> Substs {
194-
self.with_method((*substs.types.get_vec(FnSpace)).clone(),
195-
(*substs.regions().get_vec(FnSpace)).clone())
193+
self.with_method(Vec::from_slice(substs.types.get_slice(FnSpace)),
194+
Vec::from_slice(substs.regions().get_slice(FnSpace)))
196195
}
197196

198197
pub fn with_method(self,
@@ -261,13 +260,44 @@ impl ParamSpace {
261260
*/
262261
#[deriving(PartialEq, Eq, Clone, Hash, Encodable, Decodable)]
263262
pub struct VecPerParamSpace<T> {
264-
vecs: (Vec<T>, Vec<T>, Vec<T>)
263+
// This was originally represented as a tuple with one Vec<T> for
264+
// each variant of ParamSpace, and that remains the abstraction
265+
// that it provides to its clients.
266+
//
267+
// Here is how the representation corresponds to the abstraction
268+
// i.e. the "abstraction function" AF:
269+
//
270+
// AF(self) = (self.content.slice_to(self.type_limit),
271+
// self.content.slice(self.type_limit, self.self_limit),
272+
// self.content.slice_from(self.self_limit))
273+
type_limit: uint,
274+
self_limit: uint,
275+
content: Vec<T>,
276+
}
277+
278+
impl<T:Clone> VecPerParamSpace<T> {
279+
pub fn push_all(&mut self, space: ParamSpace, values: &[T]) {
280+
// FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
281+
for t in values.iter() {
282+
self.push(space, t.clone());
283+
}
284+
}
265285
}
266286

267287
impl<T> VecPerParamSpace<T> {
288+
fn limits(&self, space: ParamSpace) -> (uint, uint) {
289+
match space {
290+
TypeSpace => (0, self.type_limit),
291+
SelfSpace => (self.type_limit, self.self_limit),
292+
FnSpace => (self.self_limit, self.content.len()),
293+
}
294+
}
295+
268296
pub fn empty() -> VecPerParamSpace<T> {
269297
VecPerParamSpace {
270-
vecs: (Vec::new(), Vec::new(), Vec::new())
298+
type_limit: 0,
299+
self_limit: 0,
300+
content: Vec::new()
271301
}
272302
}
273303

@@ -276,8 +306,15 @@ impl<T> VecPerParamSpace<T> {
276306
}
277307

278308
pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
309+
let type_limit = t.len();
310+
let self_limit = t.len() + s.len();
311+
let mut content = t;
312+
content.push_all_move(s);
313+
content.push_all_move(f);
279314
VecPerParamSpace {
280-
vecs: (t, s, f)
315+
type_limit: type_limit,
316+
self_limit: self_limit,
317+
content: content,
281318
}
282319
}
283320

@@ -289,55 +326,98 @@ impl<T> VecPerParamSpace<T> {
289326
result
290327
}
291328

329+
/// Appends `value` to the vector associated with `space`.
330+
///
331+
/// Unlike the `push` method in `Vec`, this should not be assumed
332+
/// to be a cheap operation (even when amortized over many calls).
292333
pub fn push(&mut self, space: ParamSpace, value: T) {
293-
self.get_mut_vec(space).push(value);
334+
let (_, limit) = self.limits(space);
335+
match space {
336+
TypeSpace => { self.type_limit += 1; self.self_limit += 1; }
337+
SelfSpace => { self.self_limit += 1; }
338+
FnSpace => {}
339+
}
340+
self.content.insert(limit, value);
341+
}
342+
343+
pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
344+
let (start, limit) = self.limits(space);
345+
if start == limit {
346+
None
347+
} else {
348+
match space {
349+
TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; }
350+
SelfSpace => { self.self_limit -= 1; }
351+
FnSpace => {}
352+
}
353+
self.content.remove(limit - 1)
354+
}
355+
}
356+
357+
pub fn truncate(&mut self, space: ParamSpace, len: uint) {
358+
// FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
359+
while self.len(space) > len {
360+
self.pop(space);
361+
}
362+
}
363+
364+
pub fn replace(&mut self, space: ParamSpace, elems: Vec<T>) {
365+
// FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
366+
self.truncate(space, 0);
367+
for t in elems.move_iter() {
368+
self.push(space, t);
369+
}
294370
}
295371

296372
pub fn get_self<'a>(&'a self) -> Option<&'a T> {
297-
let v = self.get_vec(SelfSpace);
373+
let v = self.get_slice(SelfSpace);
298374
assert!(v.len() <= 1);
299-
if v.len() == 0 { None } else { Some(v.get(0)) }
375+
if v.len() == 0 { None } else { Some(&v[0]) }
300376
}
301377

302378
pub fn len(&self, space: ParamSpace) -> uint {
303-
self.get_vec(space).len()
379+
self.get_slice(space).len()
380+
}
381+
382+
pub fn is_empty_in(&self, space: ParamSpace) -> bool {
383+
self.len(space) == 0
304384
}
305385

306-
pub fn get_vec<'a>(&'a self, space: ParamSpace) -> &'a Vec<T> {
307-
self.vecs.get(space as uint).unwrap()
386+
pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] {
387+
let (start, limit) = self.limits(space);
388+
self.content.slice(start, limit)
308389
}
309390

310-
pub fn get_mut_vec<'a>(&'a mut self, space: ParamSpace) -> &'a mut Vec<T> {
311-
self.vecs.get_mut(space as uint).unwrap()
391+
fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
392+
let (start, limit) = self.limits(space);
393+
self.content.mut_slice(start, limit)
312394
}
313395

314396
pub fn opt_get<'a>(&'a self,
315397
space: ParamSpace,
316398
index: uint)
317399
-> Option<&'a T> {
318-
let v = self.get_vec(space);
319-
if index < v.len() { Some(v.get(index)) } else { None }
400+
let v = self.get_slice(space);
401+
if index < v.len() { Some(&v[index]) } else { None }
320402
}
321403

322404
pub fn get<'a>(&'a self, space: ParamSpace, index: uint) -> &'a T {
323-
self.get_vec(space).get(index)
405+
&self.get_slice(space)[index]
324406
}
325407

326408
pub fn get_mut<'a>(&'a mut self,
327409
space: ParamSpace,
328410
index: uint) -> &'a mut T {
329-
self.get_mut_vec(space).get_mut(index)
411+
&mut self.get_mut_slice(space)[index]
330412
}
331413

332-
pub fn iter<'a>(&'a self) -> Chain<Items<'a,T>,
333-
Chain<Items<'a,T>,
334-
Items<'a,T>>> {
335-
let (ref r, ref s, ref f) = self.vecs;
336-
r.iter().chain(s.iter().chain(f.iter()))
414+
pub fn iter<'a>(&'a self) -> Items<'a,T> {
415+
self.content.iter()
337416
}
338417

339-
pub fn all_vecs(&self, pred: |&Vec<T>| -> bool) -> bool {
340-
self.vecs.iter().all(pred)
418+
pub fn all_vecs(&self, pred: |&[T]| -> bool) -> bool {
419+
let spaces = [TypeSpace, SelfSpace, FnSpace];
420+
spaces.iter().all(|&space| { pred(self.get_slice(space)) })
341421
}
342422

343423
pub fn all(&self, pred: |&T| -> bool) -> bool {
@@ -353,9 +433,13 @@ impl<T> VecPerParamSpace<T> {
353433
}
354434

355435
pub fn map<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
356-
VecPerParamSpace::new(self.vecs.ref0().iter().map(|p| pred(p)).collect(),
357-
self.vecs.ref1().iter().map(|p| pred(p)).collect(),
358-
self.vecs.ref2().iter().map(|p| pred(p)).collect())
436+
// FIXME (#15418): this could avoid allocating the intermediate
437+
// Vec's, but note that the values of type_limit and self_limit
438+
// also need to be kept in sync during construction.
439+
VecPerParamSpace::new(
440+
self.get_slice(TypeSpace).iter().map(|p| pred(p)).collect(),
441+
self.get_slice(SelfSpace).iter().map(|p| pred(p)).collect(),
442+
self.get_slice(FnSpace).iter().map(|p| pred(p)).collect())
359443
}
360444

361445
pub fn map_rev<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
@@ -368,29 +452,46 @@ impl<T> VecPerParamSpace<T> {
368452
* can be run to a fixed point
369453
*/
370454

371-
let mut fns: Vec<U> = self.vecs.ref2().iter().rev().map(|p| pred(p)).collect();
455+
let mut fns: Vec<U> = self.get_slice(FnSpace).iter().rev().map(|p| pred(p)).collect();
372456

373457
// NB: Calling foo.rev().map().rev() causes the calls to map
374458
// to occur in the wrong order. This was somewhat surprising
375459
// to me, though it makes total sense.
376460
fns.reverse();
377461

378-
let mut selfs: Vec<U> = self.vecs.ref1().iter().rev().map(|p| pred(p)).collect();
462+
let mut selfs: Vec<U> = self.get_slice(SelfSpace).iter().rev().map(|p| pred(p)).collect();
379463
selfs.reverse();
380-
let mut tys: Vec<U> = self.vecs.ref0().iter().rev().map(|p| pred(p)).collect();
464+
let mut tys: Vec<U> = self.get_slice(TypeSpace).iter().rev().map(|p| pred(p)).collect();
381465
tys.reverse();
382466
VecPerParamSpace::new(tys, selfs, fns)
383467
}
384468

385469
pub fn split(self) -> (Vec<T>, Vec<T>, Vec<T>) {
386-
self.vecs
470+
// FIXME (#15418): this does two traversals when in principle
471+
// one would suffice. i.e. change to use `move_iter`.
472+
let VecPerParamSpace { type_limit, self_limit, content } = self;
473+
let mut i = 0;
474+
let (prefix, fn_vec) = content.partition(|_| {
475+
let on_left = i < self_limit;
476+
i += 1;
477+
on_left
478+
});
479+
480+
let mut i = 0;
481+
let (type_vec, self_vec) = prefix.partition(|_| {
482+
let on_left = i < type_limit;
483+
i += 1;
484+
on_left
485+
});
486+
487+
(type_vec, self_vec, fn_vec)
387488
}
388489

389490
pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
390491
-> VecPerParamSpace<T>
391492
{
392-
assert!(self.get_vec(space).is_empty());
393-
*self.get_mut_vec(space) = vec;
493+
assert!(self.is_empty_in(space));
494+
self.replace(space, vec);
394495
self
395496
}
396497
}

src/librustc/middle/trans/callee.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,8 @@ fn resolve_default_method_vtables(bcx: &Block,
216216
bcx.tcx(), &param_substs, &impl_res);
217217

218218
// Now we pull any vtables for parameters on the actual method.
219-
param_vtables
220-
.get_mut_vec(subst::FnSpace)
221-
.push_all(
222-
impl_vtables.get_vec(subst::FnSpace).as_slice());
219+
param_vtables.push_all(subst::FnSpace,
220+
impl_vtables.get_slice(subst::FnSpace));
223221

224222
param_vtables
225223
}

src/librustc/middle/trans/debuginfo.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ impl TypeMap {
554554

555555
// Maybe check that there is no self type here.
556556

557-
let tps = substs.types.get_vec(subst::TypeSpace);
557+
let tps = substs.types.get_slice(subst::TypeSpace);
558558
if tps.len() > 0 {
559559
output.push_char('<');
560560

@@ -1377,9 +1377,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
13771377
}
13781378

13791379
// Handle other generic parameters
1380-
let actual_types = param_substs.substs.types.get_vec(subst::FnSpace);
1380+
let actual_types = param_substs.substs.types.get_slice(subst::FnSpace);
13811381
for (index, &ast::TyParam{ ident: ident, .. }) in generics.ty_params.iter().enumerate() {
1382-
let actual_type = *actual_types.get(index);
1382+
let actual_type = actual_types[index];
13831383
// Add actual type name to <...> clause of function name
13841384
let actual_type_name = compute_debuginfo_type_name(cx,
13851385
actual_type,

src/librustc/middle/trans/type_of.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
209209
// avoids creating more than one copy of the enum when one
210210
// of the enum's variants refers to the enum itself.
211211
let repr = adt::represent_type(cx, t);
212-
let tps = substs.types.get_vec(subst::TypeSpace);
212+
let tps = substs.types.get_slice(subst::TypeSpace);
213213
let name = llvm_type_name(cx, an_enum, did, tps);
214214
adt::incomplete_type_of(cx, &*repr, name.as_slice())
215215
}
@@ -266,7 +266,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
266266
// in *after* placing it into the type cache. This prevents
267267
// infinite recursion with recursive struct types.
268268
let repr = adt::represent_type(cx, t);
269-
let tps = substs.types.get_vec(subst::TypeSpace);
269+
let tps = substs.types.get_slice(subst::TypeSpace);
270270
let name = llvm_type_name(cx, a_struct, did, tps);
271271
adt::incomplete_type_of(cx, &*repr, name.as_slice())
272272
}
@@ -305,7 +305,7 @@ pub enum named_ty { a_struct, an_enum }
305305
pub fn llvm_type_name(cx: &CrateContext,
306306
what: named_ty,
307307
did: ast::DefId,
308-
tps: &Vec<ty::t>)
308+
tps: &[ty::t])
309309
-> String
310310
{
311311
let name = match what {

0 commit comments

Comments
 (0)