Skip to content

Commit 4459fe3

Browse files
committed
Revise VecPerParamSpace to use a one Vec rather than three.
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 rust-lang#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.)
1 parent 952dded commit 4459fe3

File tree

1 file changed

+116
-41
lines changed

1 file changed

+116
-41
lines changed

src/librustc/middle/subst.rs

+116-41
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,19 +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>,
265276
}
266277

267278
impl<T:Clone> VecPerParamSpace<T> {
268279
pub fn push_all(&mut self, space: ParamSpace, values: &[T]) {
269-
self.get_mut_vec(space).push_all(values);
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+
}
270284
}
271285
}
272286

273287
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+
274296
pub fn empty() -> VecPerParamSpace<T> {
275297
VecPerParamSpace {
276-
vecs: (Vec::new(), Vec::new(), Vec::new())
298+
type_limit: 0,
299+
self_limit: 0,
300+
content: Vec::new()
277301
}
278302
}
279303

@@ -282,8 +306,15 @@ impl<T> VecPerParamSpace<T> {
282306
}
283307

284308
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);
285314
VecPerParamSpace {
286-
vecs: (t, s, f)
315+
type_limit: type_limit,
316+
self_limit: self_limit,
317+
content: content,
287318
}
288319
}
289320

@@ -295,75 +326,98 @@ impl<T> VecPerParamSpace<T> {
295326
result
296327
}
297328

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).
298333
pub fn push(&mut self, space: ParamSpace, value: T) {
299-
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);
300341
}
301342

302343
pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
303-
self.get_mut_vec(space).pop()
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+
}
304355
}
305356

306357
pub fn truncate(&mut self, space: ParamSpace, len: uint) {
307-
self.get_mut_vec(space).truncate(len)
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+
}
308362
}
309363

310364
pub fn replace(&mut self, space: ParamSpace, elems: Vec<T>) {
311-
*self.get_mut_vec(space) = elems;
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+
}
312370
}
313371

314372
pub fn get_self<'a>(&'a self) -> Option<&'a T> {
315-
let v = self.get_vec(SelfSpace);
373+
let v = self.get_slice(SelfSpace);
316374
assert!(v.len() <= 1);
317-
if v.len() == 0 { None } else { Some(v.get(0)) }
375+
if v.len() == 0 { None } else { Some(&v[0]) }
318376
}
319377

320378
pub fn len(&self, space: ParamSpace) -> uint {
321-
self.get_vec(space).len()
379+
self.get_slice(space).len()
322380
}
323381

324382
pub fn is_empty_in(&self, space: ParamSpace) -> bool {
325-
self.get_vec(space).len() == 0
383+
self.len(space) == 0
326384
}
327385

328386
pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] {
329-
self.get_vec(space).as_slice()
330-
}
331-
332-
fn get_vec<'a>(&'a self, space: ParamSpace) -> &'a Vec<T> {
333-
self.vecs.get(space as uint).unwrap()
387+
let (start, limit) = self.limits(space);
388+
self.content.slice(start, limit)
334389
}
335390

336-
fn get_mut_vec<'a>(&'a mut self, space: ParamSpace) -> &'a mut Vec<T> {
337-
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)
338394
}
339395

340396
pub fn opt_get<'a>(&'a self,
341397
space: ParamSpace,
342398
index: uint)
343399
-> Option<&'a T> {
344-
let v = self.get_vec(space);
345-
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 }
346402
}
347403

348404
pub fn get<'a>(&'a self, space: ParamSpace, index: uint) -> &'a T {
349-
self.get_vec(space).get(index)
405+
&self.get_slice(space)[index]
350406
}
351407

352408
pub fn get_mut<'a>(&'a mut self,
353409
space: ParamSpace,
354410
index: uint) -> &'a mut T {
355-
self.get_mut_vec(space).get_mut(index)
411+
&mut self.get_mut_slice(space)[index]
356412
}
357413

358-
pub fn iter<'a>(&'a self) -> Chain<Items<'a,T>,
359-
Chain<Items<'a,T>,
360-
Items<'a,T>>> {
361-
let (ref r, ref s, ref f) = self.vecs;
362-
r.iter().chain(s.iter().chain(f.iter()))
414+
pub fn iter<'a>(&'a self) -> Items<'a,T> {
415+
self.content.iter()
363416
}
364417

365418
pub fn all_vecs(&self, pred: |&[T]| -> bool) -> bool {
366-
self.vecs.iter().map(|v|v.as_slice()).all(pred)
419+
let spaces = [TypeSpace, SelfSpace, FnSpace];
420+
spaces.iter().all(|&space| { pred(self.get_slice(space)) })
367421
}
368422

369423
pub fn all(&self, pred: |&T| -> bool) -> bool {
@@ -379,9 +433,13 @@ impl<T> VecPerParamSpace<T> {
379433
}
380434

381435
pub fn map<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
382-
VecPerParamSpace::new(self.vecs.ref0().iter().map(|p| pred(p)).collect(),
383-
self.vecs.ref1().iter().map(|p| pred(p)).collect(),
384-
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())
385443
}
386444

387445
pub fn map_rev<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
@@ -394,29 +452,46 @@ impl<T> VecPerParamSpace<T> {
394452
* can be run to a fixed point
395453
*/
396454

397-
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();
398456

399457
// NB: Calling foo.rev().map().rev() causes the calls to map
400458
// to occur in the wrong order. This was somewhat surprising
401459
// to me, though it makes total sense.
402460
fns.reverse();
403461

404-
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();
405463
selfs.reverse();
406-
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();
407465
tys.reverse();
408466
VecPerParamSpace::new(tys, selfs, fns)
409467
}
410468

411469
pub fn split(self) -> (Vec<T>, Vec<T>, Vec<T>) {
412-
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)
413488
}
414489

415490
pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
416491
-> VecPerParamSpace<T>
417492
{
418-
assert!(self.get_vec(space).is_empty());
419-
*self.get_mut_vec(space) = vec;
493+
assert!(self.is_empty_in(space));
494+
self.replace(space, vec);
420495
self
421496
}
422497
}

0 commit comments

Comments
 (0)