@@ -279,17 +279,19 @@ fn fat_lto(cgcx: &CodegenContext,
279
279
// and we want to move everything to the same LLVM context. Currently the
280
280
// way we know of to do that is to serialize them to a string and them parse
281
281
// them later. Not great but hey, that's why it's "fat" LTO, right?
282
- for module in modules {
282
+ serialized_modules . extend ( modules. into_iter ( ) . map ( |module| {
283
283
let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
284
284
let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
285
- serialized_modules. push ( ( SerializedModule :: Local ( buffer) , llmod_id) ) ;
286
- }
285
+
286
+ ( SerializedModule :: Local ( buffer) , llmod_id)
287
+ } ) ) ;
287
288
288
289
// For all serialized bitcode files we parse them and link them in as we did
289
290
// above, this is all mostly handled in C++. Like above, though, we don't
290
291
// know much about the memory management here so we err on the side of being
291
292
// save and persist everything with the original module.
292
293
let mut linker = Linker :: new ( llmod) ;
294
+ serialized_bitcode. reserve ( serialized_modules. len ( ) ) ;
293
295
for ( bc_decoded, name) in serialized_modules {
294
296
info ! ( "linking {:?}" , name) ;
295
297
time_ext ( cgcx. time_passes , None , & format ! ( "ll link {:?}" , name) , || {
@@ -403,9 +405,10 @@ fn thin_lto(cgcx: &CodegenContext,
403
405
. map ( |& ( _, ref wp) | ( wp. cgu_name . clone ( ) , wp. clone ( ) ) )
404
406
. collect ( ) ;
405
407
406
- let mut thin_buffers = Vec :: new ( ) ;
407
- let mut module_names = Vec :: new ( ) ;
408
- let mut thin_modules = Vec :: new ( ) ;
408
+ // Reserve memory only partially in order to avoid OOM
409
+ let mut thin_buffers = Vec :: with_capacity ( modules. len ( ) ) ;
410
+ let mut module_names = Vec :: with_capacity ( modules. len ( ) ) ;
411
+ let mut thin_modules = Vec :: with_capacity ( modules. len ( ) ) ;
409
412
410
413
// FIXME: right now, like with fat LTO, we serialize all in-memory
411
414
// modules before working with them and ThinLTO. We really
@@ -414,7 +417,7 @@ fn thin_lto(cgcx: &CodegenContext,
414
417
// into the global index. It turns out that this loop is by far
415
418
// the most expensive portion of this small bit of global
416
419
// analysis!
417
- for ( i, module) in modules. iter ( ) . enumerate ( ) {
420
+ for ( i, module) in modules. into_iter ( ) . enumerate ( ) {
418
421
info ! ( "local module: {} - {}" , i, module. name) ;
419
422
let name = CString :: new ( module. name . clone ( ) ) . unwrap ( ) ;
420
423
let buffer = ThinBuffer :: new ( module. module_llvm . llmod ( ) ) ;
@@ -460,12 +463,15 @@ fn thin_lto(cgcx: &CodegenContext,
460
463
// incremental ThinLTO first where we could actually avoid
461
464
// looking at upstream modules entirely sometimes (the contents,
462
465
// we must always unconditionally look at the index).
463
- let mut serialized = Vec :: new ( ) ;
464
-
465
466
let cached_modules = cached_modules. into_iter ( ) . map ( |( sm, wp) | {
466
467
( sm, CString :: new ( wp. cgu_name ) . unwrap ( ) )
467
468
} ) ;
468
469
470
+ let upstream_cached_len = serialized_modules. len ( ) + cached_modules. len ( ) ;
471
+ let mut serialized = Vec :: with_capacity ( upstream_cached_len) ;
472
+ thin_modules. reserve ( upstream_cached_len) ;
473
+ module_names. reserve ( upstream_cached_len) ;
474
+
469
475
for ( module, name) in serialized_modules. into_iter ( ) . chain ( cached_modules) {
470
476
info ! ( "upstream or cached module {:?}" , name) ;
471
477
thin_modules. push ( llvm:: ThinLTOModule {
@@ -521,7 +527,7 @@ fn thin_lto(cgcx: &CodegenContext,
521
527
} ) ;
522
528
523
529
let mut copy_jobs = vec ! [ ] ;
524
- let mut opt_jobs = vec ! [ ] ;
530
+ let mut opt_jobs = Vec :: with_capacity ( shared . module_names . len ( ) ) ;
525
531
526
532
info ! ( "checking which modules can be-reused and which have to be re-optimized." ) ;
527
533
for ( module_index, module_name) in shared. module_names . iter ( ) . enumerate ( ) {
0 commit comments