8282
8383pub use self :: NamedMatch :: * ;
8484pub use self :: ParseResult :: * ;
85- use self :: TokenTreeOrTokenTreeVec :: * ;
85+ use self :: TokenTreeOrTokenTreeSlice :: * ;
8686
8787use ast:: Ident ;
8888use syntax_pos:: { self , BytePos , Span } ;
@@ -97,6 +97,7 @@ use tokenstream::TokenStream;
9797use util:: small_vector:: SmallVector ;
9898
9999use std:: mem;
100+ use std:: ops:: { Deref , DerefMut } ;
100101use std:: rc:: Rc ;
101102use std:: collections:: HashMap ;
102103use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -106,12 +107,12 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
106107/// Either a sequence of token trees or a single one. This is used as the representation of the
107108/// sequence of tokens that make up a matcher.
108109#[ derive( Clone ) ]
109- enum TokenTreeOrTokenTreeVec {
110+ enum TokenTreeOrTokenTreeSlice < ' a > {
110111 Tt ( TokenTree ) ,
111- TtSeq ( Vec < TokenTree > ) ,
112+ TtSeq ( & ' a [ TokenTree ] ) ,
112113}
113114
114- impl TokenTreeOrTokenTreeVec {
115+ impl < ' a > TokenTreeOrTokenTreeSlice < ' a > {
115116 /// Returns the number of constituent top-level token trees of `self` (top-level in that it
116117 /// will not recursively descend into subtrees).
117118 fn len ( & self ) -> usize {
@@ -135,19 +136,19 @@ impl TokenTreeOrTokenTreeVec {
135136/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
136137/// descended into.
137138#[ derive( Clone ) ]
138- struct MatcherTtFrame {
139+ struct MatcherTtFrame < ' a > {
139140 /// The "parent" matcher that we are descending into.
140- elts : TokenTreeOrTokenTreeVec ,
141+ elts : TokenTreeOrTokenTreeSlice < ' a > ,
141142 /// The position of the "dot" in `elts` at the time we descended.
142143 idx : usize ,
143144}
144145
145146/// Represents a single "position" (aka "matcher position", aka "item"), as described in the module
146147/// documentation.
147148#[ derive( Clone ) ]
148- struct MatcherPos {
149+ struct MatcherPos < ' a > {
149150 /// The token or sequence of tokens that make up the matcher
150- top_elts : TokenTreeOrTokenTreeVec ,
151+ top_elts : TokenTreeOrTokenTreeSlice < ' a > ,
151152 /// The position of the "dot" in this matcher
152153 idx : usize ,
153154 /// The beginning position in the source that the beginning of this matcher corresponds to. In
@@ -186,7 +187,7 @@ struct MatcherPos {
186187 sep : Option < Token > ,
187188 /// The "parent" matcher position if we are in a repetition. That is, the matcher position just
188189 /// before we enter the sequence.
189- up : Option < Box < MatcherPos > > ,
190+ up : Option < MatcherPosHandle < ' a > > ,
190191
191192 // Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
192193 // a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
@@ -195,17 +196,60 @@ struct MatcherPos {
195196 /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
196197 /// that where the bottom of the stack is the outermost matcher.
197198 // Also, throughout the comments, this "descent" is often referred to as "unzipping"...
198- stack : Vec < MatcherTtFrame > ,
199+ stack : Vec < MatcherTtFrame < ' a > > ,
199200}
200201
201- impl MatcherPos {
202+ impl < ' a > MatcherPos < ' a > {
202203 /// Add `m` as a named match for the `idx`-th metavar.
203204 fn push_match ( & mut self , idx : usize , m : NamedMatch ) {
204205 let matches = Rc :: make_mut ( & mut self . matches [ idx] ) ;
205206 matches. push ( m) ;
206207 }
207208}
208209
210+ // Lots of MatcherPos instances are created at runtime. Allocating them on the
211+ // heap is slow. Furthermore, using SmallVec<MatcherPos> to allocate them all
212+ // on the stack is also slow, because MatcherPos is quite a large type and
213+ // instances get moved around a lot between vectors, which requires lots of
214+ // slow memcpy calls.
215+ //
216+ // Therefore, the initial MatcherPos is always allocated on the stack,
217+ // subsequent ones (of which there aren't that many) are allocated on the heap,
218+ // and this type is used to encapsulate both cases.
219+ enum MatcherPosHandle < ' a > {
220+ Ref ( & ' a mut MatcherPos < ' a > ) ,
221+ Box ( Box < MatcherPos < ' a > > ) ,
222+ }
223+
224+ impl < ' a > Clone for MatcherPosHandle < ' a > {
225+ // This always produces a new Box.
226+ fn clone ( & self ) -> Self {
227+ MatcherPosHandle :: Box ( match * self {
228+ MatcherPosHandle :: Ref ( ref r) => Box :: new ( ( * * r) . clone ( ) ) ,
229+ MatcherPosHandle :: Box ( ref b) => b. clone ( ) ,
230+ } )
231+ }
232+ }
233+
234+ impl < ' a > Deref for MatcherPosHandle < ' a > {
235+ type Target = MatcherPos < ' a > ;
236+ fn deref ( & self ) -> & Self :: Target {
237+ match * self {
238+ MatcherPosHandle :: Ref ( ref r) => r,
239+ MatcherPosHandle :: Box ( ref b) => b,
240+ }
241+ }
242+ }
243+
244+ impl < ' a > DerefMut for MatcherPosHandle < ' a > {
245+ fn deref_mut ( & mut self ) -> & mut MatcherPos < ' a > {
246+ match * self {
247+ MatcherPosHandle :: Ref ( ref mut r) => r,
248+ MatcherPosHandle :: Box ( ref mut b) => b,
249+ }
250+ }
251+ }
252+
209253/// Represents the possible results of an attempted parse.
210254pub enum ParseResult < T > {
211255 /// Parsed successfully.
@@ -241,10 +285,10 @@ fn create_matches(len: usize) -> Vec<Rc<Vec<NamedMatch>>> {
241285
242286/// Generate the top-level matcher position in which the "dot" is before the first token of the
243287/// matcher `ms` and we are going to start matching at position `lo` in the source.
244- fn initial_matcher_pos ( ms : Vec < TokenTree > , lo : BytePos ) -> Box < MatcherPos > {
245- let match_idx_hi = count_names ( & ms [ .. ] ) ;
288+ fn initial_matcher_pos ( ms : & [ TokenTree ] , lo : BytePos ) -> MatcherPos {
289+ let match_idx_hi = count_names ( ms ) ;
246290 let matches = create_matches ( match_idx_hi) ;
247- Box :: new ( MatcherPos {
291+ MatcherPos {
248292 // Start with the top level matcher given to us
249293 top_elts : TtSeq ( ms) , // "elts" is an abbr. for "elements"
250294 // The "dot" is before the first token of the matcher
@@ -267,7 +311,7 @@ fn initial_matcher_pos(ms: Vec<TokenTree>, lo: BytePos) -> Box<MatcherPos> {
267311 seq_op : None ,
268312 sep : None ,
269313 up : None ,
270- } )
314+ }
271315}
272316
273317/// `NamedMatch` is a pattern-match result for a single `token::MATCH_NONTERMINAL`:
@@ -394,12 +438,12 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
394438/// # Returns
395439///
396440/// A `ParseResult`. Note that matches are kept track of through the items generated.
397- fn inner_parse_loop (
441+ fn inner_parse_loop < ' a > (
398442 sess : & ParseSess ,
399- cur_items : & mut SmallVector < Box < MatcherPos > > ,
400- next_items : & mut Vec < Box < MatcherPos > > ,
401- eof_items : & mut SmallVector < Box < MatcherPos > > ,
402- bb_items : & mut SmallVector < Box < MatcherPos > > ,
443+ cur_items : & mut SmallVector < MatcherPosHandle < ' a > > ,
444+ next_items : & mut Vec < MatcherPosHandle < ' a > > ,
445+ eof_items : & mut SmallVector < MatcherPosHandle < ' a > > ,
446+ bb_items : & mut SmallVector < MatcherPosHandle < ' a > > ,
403447 token : & Token ,
404448 span : syntax_pos:: Span ,
405449) -> ParseResult < ( ) > {
@@ -502,7 +546,7 @@ fn inner_parse_loop(
502546 }
503547
504548 let matches = create_matches ( item. matches . len ( ) ) ;
505- cur_items. push ( Box :: new ( MatcherPos {
549+ cur_items. push ( MatcherPosHandle :: Box ( Box :: new ( MatcherPos {
506550 stack : vec ! [ ] ,
507551 sep : seq. separator . clone ( ) ,
508552 seq_op : Some ( seq. op ) ,
@@ -514,7 +558,7 @@ fn inner_parse_loop(
514558 up : Some ( item) ,
515559 sp_lo : sp. lo ( ) ,
516560 top_elts : Tt ( TokenTree :: Sequence ( sp, seq) ) ,
517- } ) ) ;
561+ } ) ) ) ;
518562 }
519563
520564 // We need to match a metavar (but the identifier is invalid)... this is an error
@@ -596,7 +640,11 @@ pub fn parse(
596640 // processes all of these possible matcher positions and produces posible next positions into
597641 // `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
598642 // and we start over again.
599- let mut cur_items = SmallVector :: one ( initial_matcher_pos ( ms. to_owned ( ) , parser. span . lo ( ) ) ) ;
643+ //
644+ // This MatcherPos instance is allocated on the stack. All others -- and
645+ // there are frequently *no* others! -- are allocated on the heap.
646+ let mut initial = initial_matcher_pos ( ms, parser. span . lo ( ) ) ;
647+ let mut cur_items = SmallVector :: one ( MatcherPosHandle :: Ref ( & mut initial) ) ;
600648 let mut next_items = Vec :: new ( ) ;
601649
602650 loop {
0 commit comments