1638: Avoid cloning a TtToken in SubtreeTokenSource::mk_token r=matklad a=lnicola

According to `perf record`, this function is the hottest one while running `ra_cli analysis-stats`:

Before:

```
6.05%  ra_cli  ra_cli        <ra_mbe::subtree_source::SubtreeTokenSource as ra_parser::TokenSource>::lookahead_nth
5.56%  ra_cli  ra_cli        <rowan::green::GreenNode as core:#️⃣:Hash>::hash
4.16%  ra_cli  libc-2.29.so  _int_malloc
3.93%  ra_cli  ra_cli        ra_mbe::subtree_source::SubtreeTokenSource::get

Database loaded, 255 roots, 231.676882ms
Crates in this dir: 27
Total modules found: 282
Total declarations: 9642
Total functions: 3287
Total expressions: 64616
Expressions of unknown type: 9111 (14%)
Expressions of partially unknown type: 3417 (5%)
Analysis: 24.012797561s, 0b allocated 0b resident
target/release/ra_cli analysis-stats  24.60s user 0.56s system 100% cpu 25.125 total
```

After:

```
5.85%  ra_cli  ra_cli        <rowan::green::GreenNode as core:#️⃣:Hash>::hash
4.55%  ra_cli  libc-2.29.so  _int_malloc
4.31%  ra_cli  ra_cli        ra_parser::parser::Parser::nth
3.61%  ra_cli  ra_cli        <ra_syntax::parsing::text_token_source::TextTokenSource as ra_parser::TokenSource>::lookahead_nth
3.54%  ra_cli  ra_cli        ra_syntax::syntax_node::SyntaxTreeBuilder::finish_node
3.46%  ra_cli  libc-2.29.so  _int_free
3.12%  ra_cli  libc-2.29.so  malloc
2.76%  ra_cli  ra_cli        ra_parser::event::process
2.68%  ra_cli  ra_cli        alloc::sync::Arc<T>::drop_slow
2.50%  ra_cli  ra_cli        ra_mbe::subtree_source::SubtreeTokenSource::get
2.31%  ra_cli  ra_cli        <smol_str::SmolStr as core:#️⃣:Hash>::hash
2.04%  ra_cli  libc-2.29.so  __memmove_avx_unaligned_erms
1.92%  ra_cli  ra_cli        <ra_mbe::subtree_source::SubtreeTokenSource as ra_parser::TokenSource>::lookahead_nth

Database loaded, 255 roots, 236.176803ms
Crates in this dir: 27
Total modules found: 282
Total declarations: 9642
Total functions: 3287
Total expressions: 64620
Expressions of unknown type: 9107 (14%)
Expressions of partially unknown type: 3425 (5%)
Analysis: 22.562328486s, 0b allocated 0b resident
target/release/ra_cli analysis-stats  23.12s user 0.57s system 100% cpu 23.659 total
```

r? @edwin0cheng, @matklad 

Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
This commit is contained in:
bors[bot] 2019-08-03 20:07:07 +00:00
commit 0e94d07b9c

View File

@ -1,6 +1,6 @@
use ra_parser::{Token, TokenSource};
use ra_syntax::{classify_literal, SmolStr, SyntaxKind, SyntaxKind::*, T};
use std::cell::{Cell, RefCell};
use std::cell::{Cell, Ref, RefCell};
use tt::buffer::{Cursor, TokenBuffer};
#[derive(Debug, Clone, Eq, PartialEq)]
@ -20,8 +20,8 @@ impl<'a> SubtreeTokenSource<'a> {
// Helper function used in test
#[cfg(test)]
pub fn text(&self) -> SmolStr {
match self.get(self.curr.1) {
Some(tt) => tt.text,
match *self.get(self.curr.1) {
Some(ref tt) => tt.text.clone(),
_ => SmolStr::new(""),
}
}
@ -41,44 +41,46 @@ impl<'a> SubtreeTokenSource<'a> {
}
fn mk_token(&self, pos: usize) -> Token {
match self.get(pos) {
Some(tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next },
match *self.get(pos) {
Some(ref tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next },
None => Token { kind: EOF, is_jointed_to_next: false },
}
}
fn get(&self, pos: usize) -> Option<TtToken> {
let mut cached = self.cached.borrow_mut();
if pos < cached.len() {
return cached[pos].clone();
fn get(&self, pos: usize) -> Ref<Option<TtToken>> {
if pos < self.cached.borrow().len() {
return Ref::map(self.cached.borrow(), |c| &c[pos]);
}
while pos >= cached.len() {
let cursor = self.cached_cursor.get();
if cursor.eof() {
cached.push(None);
continue;
}
{
let mut cached = self.cached.borrow_mut();
while pos >= cached.len() {
let cursor = self.cached_cursor.get();
if cursor.eof() {
cached.push(None);
continue;
}
match cursor.token_tree() {
Some(tt::TokenTree::Leaf(leaf)) => {
cached.push(Some(convert_leaf(&leaf)));
self.cached_cursor.set(cursor.bump());
}
Some(tt::TokenTree::Subtree(subtree)) => {
self.cached_cursor.set(cursor.subtree().unwrap());
cached.push(Some(convert_delim(subtree.delimiter, false)));
}
None => {
if let Some(subtree) = cursor.end() {
cached.push(Some(convert_delim(subtree.delimiter, true)));
match cursor.token_tree() {
Some(tt::TokenTree::Leaf(leaf)) => {
cached.push(Some(convert_leaf(&leaf)));
self.cached_cursor.set(cursor.bump());
}
Some(tt::TokenTree::Subtree(subtree)) => {
self.cached_cursor.set(cursor.subtree().unwrap());
cached.push(Some(convert_delim(subtree.delimiter, false)));
}
None => {
if let Some(subtree) = cursor.end() {
cached.push(Some(convert_delim(subtree.delimiter, true)));
self.cached_cursor.set(cursor.bump());
}
}
}
}
}
cached[pos].clone()
Ref::map(self.cached.borrow(), |c| &c[pos])
}
}
@ -103,8 +105,8 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> {
/// Is the current token a specified keyword?
fn is_keyword(&self, kw: &str) -> bool {
match self.get(self.curr.1) {
Some(t) => t.text == *kw,
match *self.get(self.curr.1) {
Some(ref t) => t.text == *kw,
_ => false,
}
}