Skip to content

Commit

Permalink
perf: skip visiting if it's out of range (#3762)
Browse files Browse the repository at this point in the history
Visiting is not necessary for those sub-trees that are already out of range.

## The first code change

For example, we have visitors with `ast_path` like this, and the current index is `1`, and the current path is `Path::A`:

```rust
enum Path {
  A,
  B,
  C,
  D,
  E
}

visitors: vec![(vec![Path::B, Path::C], visitor), (vec![Path::B, Path::D], visitor)]
```

Given the fact that sub-trees that are not matched were already skipped, so there is no possibility for us to have things like this if we are already under `Path::B` and looking for the next path (`ast_path: [Path::B]`): 

```rust
visitors: vec![(vec![Path::B, Path::C], visitor), (vec![Path::C, Path::A], visitor)]
```

Combining all the things above, we can skip visits any furthur where its `kind` is greater than the `kind` for the current index, for the first example, the underlying path is `Path::A`, we can skip the sub-tree `Path::C` and `Path::D` as there's no possibility for the visitor subscribers to do with them.

## The second code change

If the starting point for the partition result is already greater than the underlying `kind`, it's not necessary for us to visit them too.
  • Loading branch information
h-a-n-a committed Feb 14, 2023
1 parent 3fbb505 commit 811f03c
Showing 1 changed file with 16 additions and 2 deletions.
18 changes: 16 additions & 2 deletions crates/turbopack-ecmascript/src/path_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,29 @@ fn find_range<'a, 'b>(
index: usize,
) -> Option<&'b [(&'a AstPath, &'a dyn VisitorFactory)]> {
// Precondition: visitors is never empty
let start = if visitors.first().unwrap().0[index] >= *kind {
// Fast path: It's likely that the whole range is selected
if visitors.first().unwrap().0[index] > *kind || visitors.last().unwrap().0[index] < *kind {
// Fast path: If ast path of the first visitor is already out of range, then we
// can skip the whole visit.
return None;
}

let start = if visitors.first().unwrap().0[index] == *kind {
// Fast path: It looks like the whole range is selected
0
} else {
visitors.partition_point(|(path, _)| path[index] < *kind)
};

if start >= visitors.len() {
return None;
}

if visitors[start].0[index] > *kind {
// Fast path: If the starting point is greater than the given kind, it's
// meaningless to visit later.
return None;
}

let end = if visitors.last().unwrap().0[index] == *kind {
// Fast path: It's likely that the whole range is selected
visitors.len()
Expand Down

0 comments on commit 811f03c

Please sign in to comment.