]> git.lizzy.rs Git - rust.git/commitdiff
Avoid allocations in `has_any_child_of`.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 18 Jun 2018 04:52:59 +0000 (14:52 +1000)
committerNicholas Nethercote <nnethercote@mozilla.com>
Mon, 18 Jun 2018 23:37:26 +0000 (09:37 +1000)
`has_any_child_of` is hot. It allocates a `Vec` that almost always
doesn't exceed a length of 1.

This patch peels off the first iteration of the loop, avoiding the need
for the `Vec` creation in ~99% of cases.

src/librustc_mir/dataflow/at_location.rs

index 0fbb54e8e0a089abb88178c82b1b9b3cf4b58343..a89d1afae8637bc25e89d876c03365f2b45dfccc 100644 (file)
@@ -204,10 +204,22 @@ impl<'tcx, T> FlowAtLocation<T>
     T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
 {
     pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
+        // We process `mpi` before the loop below, for two reasons:
+        // - it's a little different from the loop case (we don't traverse its
+        //   siblings);
+        // - ~99% of the time the loop isn't reached, and this code is hot, so
+        //   we don't want to allocate `todo` unnecessarily.
+        if self.contains(&mpi) {
+            return Some(mpi);
+        }
         let move_data = self.operator().move_data();
+        let move_path = &move_data.move_paths[mpi];
+        let mut todo = if let Some(child) = move_path.first_child {
+            vec![child]
+        } else {
+            return None;
+        };
 
-        let mut todo = vec![mpi];
-        let mut push_siblings = false; // don't look at siblings of original `mpi`.
         while let Some(mpi) = todo.pop() {
             if self.contains(&mpi) {
                 return Some(mpi);
@@ -216,15 +228,10 @@ pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
             if let Some(child) = move_path.first_child {
                 todo.push(child);
             }
-            if push_siblings {
-                if let Some(sibling) = move_path.next_sibling {
-                    todo.push(sibling);
-                }
-            } else {
-                // after we've processed the original `mpi`, we should
-                // always traverse the siblings of any of its
-                // children.
-                push_siblings = true;
+            // After we've processed the original `mpi`, we should always
+            // traverse the siblings of any of its children.
+            if let Some(sibling) = move_path.next_sibling {
+                todo.push(sibling);
             }
         }
         return None;