diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index 265ac975ed7a2..a39c73e8132ba 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -47,20 +47,6 @@ pub enum MonoItem<'tcx> {
 }
 
 impl<'tcx> MonoItem<'tcx> {
-    pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
-        match *self {
-            MonoItem::Fn(instance) => {
-                // Estimate the size of a function based on how many statements
-                // it contains.
-                tcx.instance_def_size_estimate(instance.def)
-            },
-            // Conservatively estimate the size of a static declaration
-            // or assembly to be 1.
-            MonoItem::Static(_) |
-            MonoItem::GlobalAsm(_) => 1,
-        }
-    }
-
     pub fn is_generic_fn(&self) -> bool {
         match *self {
             MonoItem::Fn(ref instance) => {
@@ -248,7 +234,7 @@ pub struct CodegenUnit<'tcx> {
     /// as well as the crate name and disambiguator.
     name: InternedString,
     items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
-    size_estimate: Option<usize>,
+    size_estimate: usize,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
@@ -298,7 +284,7 @@ impl<'tcx> CodegenUnit<'tcx> {
         CodegenUnit {
             name: name,
             items: Default::default(),
-            size_estimate: None,
+            size_estimate: 0,
         }
     }
 
@@ -330,21 +316,17 @@ impl<'tcx> CodegenUnit<'tcx> {
         base_n::encode(hash, base_n::CASE_INSENSITIVE)
     }
 
-    pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) {
-        // Estimate the size of a codegen unit as (approximately) the number of MIR
-        // statements it corresponds to.
-        self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
-    }
-
     pub fn size_estimate(&self) -> usize {
-        // Should only be called if `estimate_size` has previously been called.
-        self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
+        self.size_estimate
     }
 
-    pub fn modify_size_estimate(&mut self, delta: usize) {
-        assert!(self.size_estimate.is_some());
-        if let Some(size_estimate) = self.size_estimate {
-            self.size_estimate = Some(size_estimate + delta);
+    pub fn add_item(
+            &mut self,
+            item: MonoItem<'tcx>,
+            linkage: (Linkage, Visibility),
+            item_size: usize ) {
+        if self.items.insert(item, linkage).is_none() {
+            self.size_estimate += item_size;
         }
     }
 
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index b9d38028b72a8..bab455e696d34 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -136,25 +136,21 @@ where
 {
     let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
 
+    let mut estimator = SizeEstimator::new();
+
     // In the first step, we place all regular monomorphizations into their
     // respective 'home' codegen unit. Regular monomorphizations are all
     // functions and statics defined in the local crate.
-    let mut initial_partitioning = {
+    let initial_partitioning = {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
-        place_root_mono_items(tcx, mono_items)
+        place_root_mono_items(tcx, mono_items, &mut estimator)
     };
 
-    initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
-
-    debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
-
-    // If the partitioning should produce a fixed count of codegen units, merge
-    // until that count is reached.
-    if let PartitioningStrategy::FixedUnitCount(count) = strategy {
-        let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
-        merge_codegen_units(tcx, &mut initial_partitioning, count);
-        debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
-    }
+    debug_dump(
+        tcx,
+        "INITIAL PARTITIONING:",
+        initial_partitioning.codegen_units.iter(),
+        &mut estimator);
 
     // In the next step, we use the inlining map to determine which additional
     // monomorphizations have to go into each codegen unit. These additional
@@ -163,12 +159,18 @@ where
     let mut post_inlining = {
         let _prof_timer =
             tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
-        place_inlined_mono_items(initial_partitioning, inlining_map)
+        place_inlined_mono_items(tcx, initial_partitioning, inlining_map, &mut estimator)
     };
 
-    post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
+    debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter(), &mut estimator);
 
-    debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter());
+    // If the partitioning should produce a fixed count of codegen units, merge
+    // until that count is reached.
+    if let PartitioningStrategy::FixedUnitCount(count) = strategy {
+        let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
+        merge_codegen_units(tcx, &mut post_inlining, count, &mut estimator);
+        debug_dump(tcx, "POST MERGING:", post_inlining.codegen_units.iter(), &mut estimator);
+    }
 
     // Next we try to make as many symbols "internal" as possible, so LLVM has
     // more freedom to optimize.
@@ -181,7 +183,6 @@ where
     // Finally, sort by codegen unit name, so that we get deterministic results.
     let PostInliningPartitioning {
         codegen_units: mut result,
-        mono_item_placements: _,
         internalization_candidates: _,
     } = post_inlining;
 
@@ -192,6 +193,27 @@ where
     result
 }
 
+struct SizeEstimator<'tcx> {
+    cache: FxHashMap<MonoItem<'tcx>, usize>,
+}
+impl<'tcx> SizeEstimator<'tcx> {
+    pub fn new() -> SizeEstimator<'tcx> {
+        SizeEstimator { cache: Default::default() }
+    }
+    pub fn size_estimate(&mut self, tcx: TyCtxt<'tcx>, mono_item: MonoItem<'tcx>) -> usize {
+        *self.cache.entry(mono_item).or_insert_with(|| match mono_item {
+            MonoItem::Fn(instance) => {
+                // Estimate the size of a function based on how many statements
+                // it contains.
+                tcx.instance_def_size_estimate(instance.def)
+            }
+            // Conservatively estimate the size of a static declaration
+            // or assembly to be 1.
+            MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
+        })
+    }
+}
+
 struct PreInliningPartitioning<'tcx> {
     codegen_units: Vec<CodegenUnit<'tcx>>,
     roots: FxHashSet<MonoItem<'tcx>>,
@@ -209,11 +231,14 @@ enum MonoItemPlacement {
 
 struct PostInliningPartitioning<'tcx> {
     codegen_units: Vec<CodegenUnit<'tcx>>,
-    mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
     internalization_candidates: FxHashSet<MonoItem<'tcx>>,
 }
 
-fn place_root_mono_items<'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -> PreInliningPartitioning<'tcx>
+fn place_root_mono_items<'tcx, I>(
+    tcx: TyCtxt<'tcx>,
+    mono_items: I,
+    estimator: &mut SizeEstimator<'tcx>,
+) -> PreInliningPartitioning<'tcx>
 where
     I: Iterator<Item = MonoItem<'tcx>>,
 {
@@ -264,8 +289,8 @@ where
         if visibility == Visibility::Hidden && can_be_internalized {
             internalization_candidates.insert(mono_item);
         }
-
-        codegen_unit.items_mut().insert(mono_item, (linkage, visibility));
+        let item_size = estimator.size_estimate(tcx, mono_item);
+        codegen_unit.add_item(mono_item, (linkage, visibility), item_size);
         roots.insert(mono_item);
     }
 
@@ -477,11 +502,12 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
 
 fn merge_codegen_units<'tcx>(
     tcx: TyCtxt<'tcx>,
-    initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+    partitioning: &mut PostInliningPartitioning<'tcx>,
     target_cgu_count: usize,
+    estimator: &mut SizeEstimator<'tcx>,
 ) {
     assert!(target_cgu_count >= 1);
-    let codegen_units = &mut initial_partitioning.codegen_units;
+    let codegen_units = &mut partitioning.codegen_units;
 
     // Note that at this point in time the `codegen_units` here may not be in a
     // deterministic order (but we know they're deterministically the same set).
@@ -501,9 +527,9 @@ fn merge_codegen_units<'tcx>(
         let mut smallest = codegen_units.pop().unwrap();
         let second_smallest = codegen_units.last_mut().unwrap();
 
-        second_smallest.modify_size_estimate(smallest.size_estimate());
-        for (k, v) in smallest.items_mut().drain() {
-            second_smallest.items_mut().insert(k, v);
+        for (mono_item, v) in smallest.items_mut().drain() {
+            let item_size = estimator.size_estimate(tcx, mono_item);
+            second_smallest.add_item(mono_item, v, item_size);
         }
         debug!("CodegenUnit {} merged in to CodegenUnit {}",
                smallest.name(),
@@ -516,11 +542,12 @@ fn merge_codegen_units<'tcx>(
     }
 }
 
-fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
-                                  inlining_map: &InliningMap<'tcx>)
-                                  -> PostInliningPartitioning<'tcx> {
+fn place_inlined_mono_items<'tcx>(tcx: TyCtxt<'tcx>,
+                                  initial_partitioning: PreInliningPartitioning<'tcx>,
+                                  inlining_map: &InliningMap<'tcx>,
+                                  estimator: &mut SizeEstimator<'tcx>,
+) -> PostInliningPartitioning<'tcx> {
     let mut new_partitioning = Vec::new();
-    let mut mono_item_placements = FxHashMap::default();
 
     let PreInliningPartitioning {
         codegen_units: initial_cgus,
@@ -528,8 +555,6 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
         internalization_candidates,
     } = initial_partitioning;
 
-    let single_codegen_unit = initial_cgus.len() == 1;
-
     for old_codegen_unit in initial_cgus {
         // Collect all items that need to be available in this codegen unit.
         let mut reachable = FxHashSet::default();
@@ -543,7 +568,8 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
         for mono_item in reachable {
             if let Some(linkage) = old_codegen_unit.items().get(&mono_item) {
                 // This is a root, just copy it over.
-                new_codegen_unit.items_mut().insert(mono_item, *linkage);
+                let item_size = estimator.size_estimate(tcx, mono_item);
+                new_codegen_unit.add_item(mono_item, *linkage, item_size);
             } else {
                 if roots.contains(&mono_item) {
                     bug!("GloballyShared mono-item inlined into other CGU: \
@@ -551,32 +577,11 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
                 }
 
                 // This is a CGU-private copy.
-                new_codegen_unit.items_mut().insert(
+                let item_size = estimator.size_estimate(tcx, mono_item);
+                new_codegen_unit.add_item(
                     mono_item,
                     (Linkage::Internal, Visibility::Default),
-                );
-            }
-
-            if !single_codegen_unit {
-                // If there is more than one codegen unit, we need to keep track
-                // in which codegen units each monomorphization is placed.
-                match mono_item_placements.entry(mono_item) {
-                    Entry::Occupied(e) => {
-                        let placement = e.into_mut();
-                        debug_assert!(match *placement {
-                            MonoItemPlacement::SingleCgu { ref cgu_name } => {
-                                *cgu_name != *new_codegen_unit.name()
-                            }
-                            MonoItemPlacement::MultipleCgus => true,
-                        });
-                        *placement = MonoItemPlacement::MultipleCgus;
-                    }
-                    Entry::Vacant(e) => {
-                        e.insert(MonoItemPlacement::SingleCgu {
-                            cgu_name: new_codegen_unit.name().clone()
-                        });
-                    }
-                }
+                    item_size);
             }
         }
 
@@ -585,7 +590,6 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
 
     return PostInliningPartitioning {
         codegen_units: new_partitioning,
-        mono_item_placements,
         internalization_candidates,
     };
 
@@ -632,7 +636,24 @@ fn internalize_symbols<'tcx>(
         }
     });
 
-    let mono_item_placements = &partitioning.mono_item_placements;
+    // If there is more than one codegen unit, we need to keep track
+    // in which codegen units each monomorphization is placed.
+    let mut mono_item_placements = FxHashMap::default();
+
+    for cgu in &partitioning.codegen_units {
+        for mono_item in cgu.items().keys() {
+            match mono_item_placements.entry(*mono_item) {
+                Entry::Occupied(e) => {
+                    *e.into_mut() = MonoItemPlacement::MultipleCgus;
+                }
+                Entry::Vacant(e) => {
+                    e.insert(MonoItemPlacement::SingleCgu {
+                        cgu_name: cgu.name().clone()
+                    });
+                }
+            }
+        }
+    }
 
     // For each internalization candidates in each codegen unit, check if it is
     // accessed from outside its defining codegen unit.
@@ -781,7 +802,10 @@ fn numbered_codegen_unit_name(
     name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
 }
 
-fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
+fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>,
+    label: &str,
+    cgus: I,
+    estimator: &mut SizeEstimator<'tcx>)
 where
     I: Iterator<Item = &'a CodegenUnit<'tcx>>,
     'tcx: 'a,
@@ -801,7 +825,7 @@ where
                        mono_item.to_string(tcx, true),
                        linkage,
                        symbol_hash,
-                       mono_item.size_estimate(tcx));
+                       estimator.size_estimate(tcx, *mono_item));
             }
 
             debug!("");