about summary refs log tree commit diff
path: root/compiler/rustc_data_structures/src/obligation_forest
diff options
context:
space:
mode:
authorThe 8472 <git@infinite-source.de>2023-03-06 15:07:02 +0100
committerThe 8472 <git@infinite-source.de>2023-03-17 19:56:03 +0100
commit7cce618d18c8203369d605d1ccedcfda09d58acc (patch)
treec66fb6e99f48f923502f04644133e71654509e3f /compiler/rustc_data_structures/src/obligation_forest
parent03b01c5bec658081605ab078ad3fbcdb6b30f6c2 (diff)
downloadrust-7cce618d18c8203369d605d1ccedcfda09d58acc.tar.gz
rust-7cce618d18c8203369d605d1ccedcfda09d58acc.zip
Fast path that skips over unchanged obligations in process_obligations
- only borrow the refcell once per loop
- avoid complex matches to reduce branch paths in the hot loop
- use a by-ref fast path that avoids mutations at the expense of having false negatives
Diffstat (limited to 'compiler/rustc_data_structures/src/obligation_forest')
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs19
1 files changed, 16 insertions, 3 deletions
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 91abdaadabd..27a869eb7cd 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -97,7 +97,17 @@ pub trait ObligationProcessor {
     type Error: Debug;
     type OUT: OutcomeTrait<Obligation = Self::Obligation, Error = Error<Self::Obligation, Self::Error>>;
 
-    fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool;
+    /// Implementations can provide a fast-path to obligation-processing
+    /// by counting the prefix of the passed iterator for which
+    /// `needs_process_obligation` would return false.
+    fn skippable_obligations<'a>(
+        &'a self,
+        _it: impl Iterator<Item = &'a Self::Obligation>,
+    ) -> usize {
+        0
+    }
+
+    fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool;
 
     fn process_obligation(
         &mut self,
@@ -416,6 +426,10 @@ impl<O: ForestObligation> ObligationForest<O> {
         loop {
             let mut has_changed = false;
 
+            // This is the super fast path for cheap-to-check conditions.
+            let mut index =
+                processor.skippable_obligations(self.nodes.iter().map(|n| &n.obligation));
+
             // Note that the loop body can append new nodes, and those new nodes
             // will then be processed by subsequent iterations of the loop.
             //
@@ -424,9 +438,8 @@ impl<O: ForestObligation> ObligationForest<O> {
             // `for index in 0..self.nodes.len() { ... }` because the range would
             // be computed with the initial length, and we would miss the appended
             // nodes. Therefore we use a `while` loop.
-            let mut index = 0;
             while let Some(node) = self.nodes.get_mut(index) {
-                // This test is extremely hot.
+                // This is the moderately fast path when the prefix skipping above didn't work out.
                 if node.state.get() != NodeState::Pending
                     || !processor.needs_process_obligation(&node.obligation)
                 {