diff options
| author | bors <bors@rust-lang.org> | 2017-06-10 06:50:12 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-06-10 06:50:12 +0000 |
| commit | e1480499b484d142dfa704ae20bd33eae518c1d0 (patch) | |
| tree | 4dbb4b4cbf2eb4144893c30d8dff7b73519e0e12 /src/libsyntax | |
| parent | 60ac9f467cbbf8481a6f09e3e90e470dec85cf65 (diff) | |
| parent | 3d9ebf2916f96c6934a84a5abc2067145e062e75 (diff) | |
| download | rust-e1480499b484d142dfa704ae20bd33eae518c1d0.tar.gz rust-e1480499b484d142dfa704ae20bd33eae518c1d0.zip | |
Auto merge of #42533 - Mark-Simulacrum:macro-parse-speed-small, r=jseyfried
Speed up expansion This reduces duplication, thereby increasing expansion speed. Based on tests with rust-uinput, this produces a 29x performance win (440 seconds to 15 seconds). I want to land this first, since it's a minimal patch, but with more changes to the macro parsing I can get down to 12 seconds locally. There is one FIXME added to the code that I'll keep for now since changing it will spread outward and increase the patch size, I think. Fixes #37074. r? @jseyfried cc @oberien
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/tt/macro_parser.rs | 40 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/transcribe.rs | 17 |
3 files changed, 34 insertions, 27 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 0b6a2eb536a..61d8fc2941a 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -139,13 +139,20 @@ struct MatcherPos { sep: Option<Token>, idx: usize, up: Option<Box<MatcherPos>>, - matches: Vec<Vec<Rc<NamedMatch>>>, + matches: Vec<Rc<Vec<NamedMatch>>>, match_lo: usize, match_cur: usize, match_hi: usize, sp_lo: BytePos, } +impl MatcherPos { + fn push_match(&mut self, idx: usize, m: NamedMatch) { + let matches = Rc::make_mut(&mut self.matches[idx]); + matches.push(m); + } +} + pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>; pub fn count_names(ms: &[TokenTree]) -> usize { @@ -199,14 +206,15 @@ fn initial_matcher_pos(ms: Vec<TokenTree>, lo: BytePos) -> Box<MatcherPos> { /// only on the nesting depth of `ast::TTSeq`s in the originating /// token tree it was derived from. +#[derive(Debug, Clone)] pub enum NamedMatch { - MatchedSeq(Vec<Rc<NamedMatch>>, syntax_pos::Span), + MatchedSeq(Rc<Vec<NamedMatch>>, syntax_pos::Span), MatchedNonterminal(Rc<Nonterminal>) } -fn nameize<I: Iterator<Item=Rc<NamedMatch>>>(sess: &ParseSess, ms: &[TokenTree], mut res: I) +fn nameize<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, ms: &[TokenTree], mut res: I) -> NamedParseResult { - fn n_rec<I: Iterator<Item=Rc<NamedMatch>>>(sess: &ParseSess, m: &TokenTree, mut res: &mut I, + fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, mut res: &mut I, ret_val: &mut HashMap<Ident, Rc<NamedMatch>>) -> Result<(), (syntax_pos::Span, String)> { match *m { @@ -228,7 +236,8 @@ fn nameize<I: Iterator<Item=Rc<NamedMatch>>>(sess: &ParseSess, ms: &[TokenTree], TokenTree::MetaVarDecl(sp, bind_name, _) => { match ret_val.entry(bind_name) { Vacant(spot) => { - spot.insert(res.next().unwrap()); + // FIXME(simulacrum): Don't construct Rc here + spot.insert(Rc::new(res.next().unwrap())); } Occupied(..) => { return Err((sp, format!("duplicated bind name: {}", bind_name))) @@ -280,8 +289,8 @@ fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } } -fn create_matches(len: usize) -> Vec<Vec<Rc<NamedMatch>>> { - (0..len).into_iter().map(|_| Vec::new()).collect() +fn create_matches(len: usize) -> Vec<Rc<Vec<NamedMatch>>> { + (0..len).into_iter().map(|_| Rc::new(Vec::new())).collect() } fn inner_parse_loop(sess: &ParseSess, @@ -320,15 +329,10 @@ fn inner_parse_loop(sess: &ParseSess, // update matches (the MBE "parse tree") by appending // each tree as a subtree. - // I bet this is a perf problem: we're preemptively - // doing a lot of array work that will get thrown away - // most of the time. - // Only touch the binders we have actually bound for idx in ei.match_lo..ei.match_hi { let sub = ei.matches[idx].clone(); - new_pos.matches[idx] - .push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span }))); + new_pos.push_match(idx, MatchedSeq(sub, Span { lo: ei.sp_lo, ..span })); } new_pos.match_cur = ei.match_hi; @@ -362,7 +366,7 @@ fn inner_parse_loop(sess: &ParseSess, new_ei.match_cur += seq.num_captures; new_ei.idx += 1; for idx in ei.match_cur..ei.match_cur + seq.num_captures { - new_ei.matches[idx].push(Rc::new(MatchedSeq(vec![], sp))); + new_ei.push_match(idx, MatchedSeq(Rc::new(vec![]), sp)); } cur_eis.push(new_ei); } @@ -446,7 +450,9 @@ pub fn parse(sess: &ParseSess, /* error messages here could be improved with links to orig. rules */ if token_name_eq(&parser.token, &token::Eof) { if eof_eis.len() == 1 { - let matches = eof_eis[0].matches.iter_mut().map(|mut dv| dv.pop().unwrap()); + let matches = eof_eis[0].matches.iter_mut().map(|mut dv| { + Rc::make_mut(dv).pop().unwrap() + }); return nameize(sess, ms, matches); } else if eof_eis.len() > 1 { return Error(parser.span, "ambiguity: multiple successful parses".to_string()); @@ -479,8 +485,8 @@ pub fn parse(sess: &ParseSess, let mut ei = bb_eis.pop().unwrap(); if let TokenTree::MetaVarDecl(span, _, ident) = ei.top_elts.get_tt(ei.idx) { let match_cur = ei.match_cur; - ei.matches[match_cur].push(Rc::new(MatchedNonterminal( - Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); + ei.push_match(match_cur, + MatchedNonterminal(Rc::new(parse_nt(&mut parser, span, &ident.name.as_str())))); ei.idx += 1; ei.match_cur += 1; } else { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 0472a94e0ce..9c728c9f2eb 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -219,7 +219,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item) let lhses = match *argument_map[&lhs_nm] { MatchedSeq(ref s, _) => { s.iter().map(|m| { - if let MatchedNonterminal(ref nt) = **m { + if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); valid &= check_lhs_nt_follows(sess, features, &tt); @@ -235,7 +235,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item) let rhses = match *argument_map[&rhs_nm] { MatchedSeq(ref s, _) => { s.iter().map(|m| { - if let MatchedNonterminal(ref nt) = **m { + if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { return quoted::parse(tt.clone().into(), false, sess).pop().unwrap(); } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 2a435bdea10..78e755e73fa 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -182,15 +182,16 @@ fn lookup_cur_matched(ident: Ident, repeats: &[(usize, usize)]) -> Option<Rc<NamedMatch>> { interpolations.get(&ident).map(|matched| { - repeats.iter().fold(matched.clone(), |ad, &(idx, _)| { - match *ad { - MatchedNonterminal(_) => { - // end of the line; duplicate henceforth - ad.clone() - } - MatchedSeq(ref ads, _) => ads[idx].clone() + let mut matched = matched.clone(); + for &(idx, _) in repeats { + let m = matched.clone(); + match *m { + MatchedNonterminal(_) => break, + MatchedSeq(ref ads, _) => matched = Rc::new(ads[idx].clone()), } - }) + } + + matched }) } |
