From c60ed5d22c4c2a4885fdfdfa8c6b008d79b0fc29 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Nov 2018 05:35:20 +1100 Subject: [PATCH 1/2] Share empty `Vec`s more within `MatcherPos::matches`. `create_matches` creates a `Vec>>`. Even though all the inner `Vec`s are empty, each one is created separately. This commit changes `create_matches` so it instead creates one empty inner `Vec`, and shares it. The commit also changes `MatcherPos::matches` to a boxed slice, because its length doesn't change. --- src/libsyntax/ext/tt/macro_parser.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 03a8376e76361..bf91a233f7c69 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -168,7 +168,7 @@ struct MatcherPos<'a> { /// all bound matches from the submatcher into the shared top-level `matches` vector. If `sep` /// and `up` are `Some`, then `matches` is _not_ the shared top-level list. Instead, if one /// wants the shared `matches`, one should use `up.matches`. - matches: Vec>>, + matches: Box<[Rc>]>, /// The position in `matches` corresponding to the first metavar in this matcher's sequence of /// token trees. In other words, the first metavar in the first token of `top_elts` corresponds /// to `matches[match_lo]`. @@ -278,9 +278,14 @@ pub fn count_names(ms: &[TokenTree]) -> usize { }) } -/// Initialize `len` empty shared `Vec`s to be used to store matches of metavars. -fn create_matches(len: usize) -> Vec>> { - (0..len).into_iter().map(|_| Rc::new(Vec::new())).collect() +/// `len` `Vec`s (initially shared and empty) that will store matches of metavars. +fn create_matches(len: usize) -> Box<[Rc>]> { + if len == 0 { + vec![] + } else { + let empty_matches = Rc::new(Vec::new()); + vec![empty_matches.clone(); len] + }.into_boxed_slice() } /// Generate the top-level matcher position in which the "dot" is before the first token of the From 0d2abe46ca810dfab7db9e89977b751eca103084 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Nov 2018 08:41:57 +1100 Subject: [PATCH 2/2] Use `SmallVec` for the inner vectors in `MatcherPos::matches`. This avoids some allocations. --- src/libsyntax/ext/tt/macro_parser.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index bf91a233f7c69..38bbfc6b4c375 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -143,6 +143,8 @@ struct MatcherTtFrame<'a> { idx: usize, } +type NamedMatchVec = SmallVec<[NamedMatch; 4]>; + /// Represents a single "position" (aka "matcher position", aka "item"), as described in the module /// documentation. #[derive(Clone)] @@ -168,7 +170,7 @@ struct MatcherPos<'a> { /// all bound matches from the submatcher into the shared top-level `matches` vector. If `sep` /// and `up` are `Some`, then `matches` is _not_ the shared top-level list. Instead, if one /// wants the shared `matches`, one should use `up.matches`. - matches: Box<[Rc>]>, + matches: Box<[Rc]>, /// The position in `matches` corresponding to the first metavar in this matcher's sequence of /// token trees. In other words, the first metavar in the first token of `top_elts` corresponds /// to `matches[match_lo]`. @@ -279,11 +281,11 @@ pub fn count_names(ms: &[TokenTree]) -> usize { } /// `len` `Vec`s (initially shared and empty) that will store matches of metavars. -fn create_matches(len: usize) -> Box<[Rc>]> { +fn create_matches(len: usize) -> Box<[Rc]> { if len == 0 { vec![] } else { - let empty_matches = Rc::new(Vec::new()); + let empty_matches = Rc::new(SmallVec::new()); vec![empty_matches.clone(); len] }.into_boxed_slice() } @@ -337,7 +339,7 @@ fn initial_matcher_pos(ms: &[TokenTree], open: Span) -> MatcherPos { /// token tree it was derived from. #[derive(Debug, Clone)] pub enum NamedMatch { - MatchedSeq(Rc>, DelimSpan), + MatchedSeq(Rc, DelimSpan), MatchedNonterminal(Rc), } @@ -545,7 +547,7 @@ fn inner_parse_loop<'a>( new_item.match_cur += seq.num_captures; new_item.idx += 1; for idx in item.match_cur..item.match_cur + seq.num_captures { - new_item.push_match(idx, MatchedSeq(Rc::new(vec![]), sp)); + new_item.push_match(idx, MatchedSeq(Rc::new(smallvec![]), sp)); } cur_items.push(new_item); }