82
82
83
83
pub use self :: NamedMatch :: * ;
84
84
pub use self :: ParseResult :: * ;
85
- use self :: TokenTreeOrTokenTreeVec :: * ;
85
+ use self :: TokenTreeOrTokenTreeSlice :: * ;
86
86
87
87
use ast:: Ident ;
88
88
use syntax_pos:: { self , BytePos , Span } ;
@@ -97,6 +97,7 @@ use tokenstream::TokenStream;
97
97
use util:: small_vector:: SmallVector ;
98
98
99
99
use std:: mem;
100
+ use std:: ops:: { Deref , DerefMut } ;
100
101
use std:: rc:: Rc ;
101
102
use std:: collections:: HashMap ;
102
103
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -106,12 +107,12 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
106
107
/// Either a sequence of token trees or a single one. This is used as the representation of the
107
108
/// sequence of tokens that make up a matcher.
108
109
#[ derive( Clone ) ]
109
- enum TokenTreeOrTokenTreeVec {
110
+ enum TokenTreeOrTokenTreeSlice < ' a > {
110
111
Tt ( TokenTree ) ,
111
- TtSeq ( Vec < TokenTree > ) ,
112
+ TtSeq ( & ' a [ TokenTree ] ) ,
112
113
}
113
114
114
- impl TokenTreeOrTokenTreeVec {
115
+ impl < ' a > TokenTreeOrTokenTreeSlice < ' a > {
115
116
/// Returns the number of constituent top-level token trees of `self` (top-level in that it
116
117
/// will not recursively descend into subtrees).
117
118
fn len ( & self ) -> usize {
@@ -135,19 +136,19 @@ impl TokenTreeOrTokenTreeVec {
135
136
/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
136
137
/// descended into.
137
138
#[ derive( Clone ) ]
138
- struct MatcherTtFrame {
139
+ struct MatcherTtFrame < ' a > {
139
140
/// The "parent" matcher that we are descending into.
140
- elts : TokenTreeOrTokenTreeVec ,
141
+ elts : TokenTreeOrTokenTreeSlice < ' a > ,
141
142
/// The position of the "dot" in `elts` at the time we descended.
142
143
idx : usize ,
143
144
}
144
145
145
146
/// Represents a single "position" (aka "matcher position", aka "item"), as described in the module
146
147
/// documentation.
147
148
#[ derive( Clone ) ]
148
- struct MatcherPos {
149
+ struct MatcherPos < ' a > {
149
150
/// The token or sequence of tokens that make up the matcher
150
- top_elts : TokenTreeOrTokenTreeVec ,
151
+ top_elts : TokenTreeOrTokenTreeSlice < ' a > ,
151
152
/// The position of the "dot" in this matcher
152
153
idx : usize ,
153
154
/// The beginning position in the source that the beginning of this matcher corresponds to. In
@@ -186,7 +187,7 @@ struct MatcherPos {
186
187
sep : Option < Token > ,
187
188
/// The "parent" matcher position if we are in a repetition. That is, the matcher position just
188
189
/// before we enter the sequence.
189
- up : Option < Box < MatcherPos > > ,
190
+ up : Option < MatcherPosHandle < ' a > > ,
190
191
191
192
// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
192
193
// a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
@@ -195,17 +196,60 @@ struct MatcherPos {
195
196
/// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
196
197
/// that where the bottom of the stack is the outermost matcher.
197
198
// Also, throughout the comments, this "descent" is often referred to as "unzipping"...
198
- stack : Vec < MatcherTtFrame > ,
199
+ stack : Vec < MatcherTtFrame < ' a > > ,
199
200
}
200
201
201
- impl MatcherPos {
202
+ impl < ' a > MatcherPos < ' a > {
202
203
/// Add `m` as a named match for the `idx`-th metavar.
203
204
fn push_match ( & mut self , idx : usize , m : NamedMatch ) {
204
205
let matches = Rc :: make_mut ( & mut self . matches [ idx] ) ;
205
206
matches. push ( m) ;
206
207
}
207
208
}
208
209
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
+
209
253
/// Represents the possible results of an attempted parse.
210
254
pub enum ParseResult < T > {
211
255
/// Parsed successfully.
@@ -241,10 +285,10 @@ fn create_matches(len: usize) -> Vec<Rc<Vec<NamedMatch>>> {
241
285
242
286
/// Generate the top-level matcher position in which the "dot" is before the first token of the
243
287
/// 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 ) ;
246
290
let matches = create_matches ( match_idx_hi) ;
247
- Box :: new ( MatcherPos {
291
+ MatcherPos {
248
292
// Start with the top level matcher given to us
249
293
top_elts : TtSeq ( ms) , // "elts" is an abbr. for "elements"
250
294
// 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> {
267
311
seq_op : None ,
268
312
sep : None ,
269
313
up : None ,
270
- } )
314
+ }
271
315
}
272
316
273
317
/// `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 {
394
438
/// # Returns
395
439
///
396
440
/// A `ParseResult`. Note that matches are kept track of through the items generated.
397
- fn inner_parse_loop (
441
+ fn inner_parse_loop < ' a > (
398
442
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 > > ,
403
447
token : & Token ,
404
448
span : syntax_pos:: Span ,
405
449
) -> ParseResult < ( ) > {
@@ -502,7 +546,7 @@ fn inner_parse_loop(
502
546
}
503
547
504
548
let matches = create_matches ( item. matches . len ( ) ) ;
505
- cur_items. push ( Box :: new ( MatcherPos {
549
+ cur_items. push ( MatcherPosHandle :: Box ( Box :: new ( MatcherPos {
506
550
stack : vec ! [ ] ,
507
551
sep : seq. separator . clone ( ) ,
508
552
seq_op : Some ( seq. op ) ,
@@ -514,7 +558,7 @@ fn inner_parse_loop(
514
558
up : Some ( item) ,
515
559
sp_lo : sp. lo ( ) ,
516
560
top_elts : Tt ( TokenTree :: Sequence ( sp, seq) ) ,
517
- } ) ) ;
561
+ } ) ) ) ;
518
562
}
519
563
520
564
// We need to match a metavar (but the identifier is invalid)... this is an error
@@ -596,7 +640,11 @@ pub fn parse(
596
640
// processes all of these possible matcher positions and produces posible next positions into
597
641
// `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
598
642
// 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) ) ;
600
648
let mut next_items = Vec :: new ( ) ;
601
649
602
650
loop {
0 commit comments