@@ -279,17 +279,19 @@ fn fat_lto(cgcx: &CodegenContext,
279279 // and we want to move everything to the same LLVM context. Currently the
280280 // way we know of to do that is to serialize them to a string and them parse
281281 // 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| {
283283 let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
284284 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+ } ) ) ;
287288
288289 // For all serialized bitcode files we parse them and link them in as we did
289290 // above, this is all mostly handled in C++. Like above, though, we don't
290291 // know much about the memory management here so we err on the side of being
291292 // save and persist everything with the original module.
292293 let mut linker = Linker :: new ( llmod) ;
294+ serialized_bitcode. reserve ( serialized_modules. len ( ) ) ;
293295 for ( bc_decoded, name) in serialized_modules {
294296 info ! ( "linking {:?}" , name) ;
295297 time_ext ( cgcx. time_passes , None , & format ! ( "ll link {:?}" , name) , || {
@@ -403,9 +405,10 @@ fn thin_lto(cgcx: &CodegenContext,
403405 . map ( |& ( _, ref wp) | ( wp. cgu_name . clone ( ) , wp. clone ( ) ) )
404406 . collect ( ) ;
405407
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 ( ) ) ;
409412
410413 // FIXME: right now, like with fat LTO, we serialize all in-memory
411414 // modules before working with them and ThinLTO. We really
@@ -414,7 +417,7 @@ fn thin_lto(cgcx: &CodegenContext,
414417 // into the global index. It turns out that this loop is by far
415418 // the most expensive portion of this small bit of global
416419 // analysis!
417- for ( i, module) in modules. iter ( ) . enumerate ( ) {
420+ for ( i, module) in modules. into_iter ( ) . enumerate ( ) {
418421 info ! ( "local module: {} - {}" , i, module. name) ;
419422 let name = CString :: new ( module. name . clone ( ) ) . unwrap ( ) ;
420423 let buffer = ThinBuffer :: new ( module. module_llvm . llmod ( ) ) ;
@@ -460,12 +463,15 @@ fn thin_lto(cgcx: &CodegenContext,
460463 // incremental ThinLTO first where we could actually avoid
461464 // looking at upstream modules entirely sometimes (the contents,
462465 // we must always unconditionally look at the index).
463- let mut serialized = Vec :: new ( ) ;
464-
465466 let cached_modules = cached_modules. into_iter ( ) . map ( |( sm, wp) | {
466467 ( sm, CString :: new ( wp. cgu_name ) . unwrap ( ) )
467468 } ) ;
468469
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+
469475 for ( module, name) in serialized_modules. into_iter ( ) . chain ( cached_modules) {
470476 info ! ( "upstream or cached module {:?}" , name) ;
471477 thin_modules. push ( llvm:: ThinLTOModule {
@@ -521,7 +527,7 @@ fn thin_lto(cgcx: &CodegenContext,
521527 } ) ;
522528
523529 let mut copy_jobs = vec ! [ ] ;
524- let mut opt_jobs = vec ! [ ] ;
530+ let mut opt_jobs = Vec :: with_capacity ( shared . module_names . len ( ) ) ;
525531
526532 info ! ( "checking which modules can be-reused and which have to be re-optimized." ) ;
527533 for ( module_index, module_name) in shared. module_names . iter ( ) . enumerate ( ) {
0 commit comments