]> git.lizzy.rs Git - rust.git/commitdiff
Avoid repeated HashMap lookups in `opt_normalize_projection_type`.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 16 May 2018 10:59:27 +0000 (20:59 +1000)
committerNicholas Nethercote <nnethercote@mozilla.com>
Wed, 16 May 2018 23:34:20 +0000 (09:34 +1000)
There is a hot path through `opt_normalize_projection_type`:
- `try_start` does a cache lookup (#1).
- The result is a `NormalizedTy`.
- There are no unresolved type vars, so we call `complete`.
- `complete` does *another* cache lookup (#2), then calls
  `SnapshotMap::insert`.
- `insert` does *another* cache lookup (#3), inserting the same value
  that's already in the cache.

This patch optimizes this hot path by introducing `complete_normalized`,
for use when the value is known in advance to be a `NormalizedTy`. It
always avoids lookup #2. Furthermore, if the `NormalizedTy`'s
obligations are empty (the common case), we know that lookup #3 would be
a no-op, so we avoid it, while inserting a Noop into the `SnapshotMap`'s
undo log.

src/librustc/traits/project.rs
src/librustc_data_structures/snapshot_map/mod.rs

index bfa32f8e7faf3393058be9bc51da36c956081c1e..da8f086b9c55db24bee085291802f22274e5f546 100644 (file)
@@ -596,7 +596,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             // Once we have inferred everything we need to know, we
             // can ignore the `obligations` from that point on.
             if !infcx.any_unresolved_type_vars(&ty.value) {
-                infcx.projection_cache.borrow_mut().complete(cache_key);
+                infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty);
                 ty.obligations = vec![];
             }
 
@@ -1682,6 +1682,23 @@ pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
         }));
     }
 
+    /// A specialized version of `complete` for when the key's value is known
+    /// to be a NormalizedTy.
+    pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) {
+        // We want to insert `ty` with no obligations. If the existing value
+        // already has no obligations (as is common) we can use `insert_noop`
+        // to do a minimal amount of work -- the HashMap insertion is skipped,
+        // and minimal changes are made to the undo log.
+        if ty.obligations.is_empty() {
+            self.map.insert_noop();
+        } else {
+            self.map.insert(key, ProjectionCacheEntry::NormalizedTy(Normalized {
+                value: ty.value,
+                obligations: vec![]
+            }));
+        }
+    }
+
     /// Indicates that trying to normalize `key` resulted in
     /// ambiguity. No point in trying it again then until we gain more
     /// type information (in which case, the "fully resolved" key will
index cede6f147821bf8e3c2e49c72e0068229a9e5fc1..6ee8c3579f5437c4d0f4602dd5bc339a2abebaee 100644 (file)
@@ -67,6 +67,12 @@ pub fn insert(&mut self, key: K, value: V) -> bool {
         }
     }
 
+    pub fn insert_noop(&mut self) {
+        if !self.undo_log.is_empty() {
+            self.undo_log.push(UndoLog::Noop);
+        }
+    }
+
     pub fn remove(&mut self, key: K) -> bool {
         match self.map.remove(&key) {
             Some(old_value) => {