Skip to content

Commit bcd1e13

Browse files
authored
Rollup merge of rust-lang#37569 - jseyfried:improve_expansion_perf, r=eddyb
macros: improve expansion performance This PR fixes that regression, further improves performance on recursive, `tt`-heavy workloads, and makes a variety of other improvements to parsing and expansion performance. Expansion performance improvements: | Test case | Run-time | Memory usage | | -------------- | -------- | ------------ | | libsyntax | 8% | 10% | | librustc | 15% | 6% | | librustc_trans | 30% | 6% | | rust-lang#37074 | 20% | 15% | | rust-lang#34630 | 40% | 8% | r? @eddyb
2 parents 3842fca + 51104e5 commit bcd1e13

File tree

16 files changed

+353
-448
lines changed

16 files changed

+353
-448
lines changed

src/librustc/hir/lowering.rs

+24-30
Original file line numberDiff line numberDiff line change
@@ -1208,36 +1208,30 @@ impl<'a> LoweringContext<'a> {
12081208
ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)),
12091209
ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)),
12101210
ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))),
1211-
ExprKind::InlineAsm(InlineAsm {
1212-
ref inputs,
1213-
ref outputs,
1214-
ref asm,
1215-
asm_str_style,
1216-
ref clobbers,
1217-
volatile,
1218-
alignstack,
1219-
dialect,
1220-
expn_id,
1221-
}) => hir::ExprInlineAsm(P(hir::InlineAsm {
1222-
inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
1223-
outputs: outputs.iter()
1224-
.map(|out| {
1225-
hir::InlineAsmOutput {
1226-
constraint: out.constraint.clone(),
1227-
is_rw: out.is_rw,
1228-
is_indirect: out.is_indirect,
1229-
}
1230-
})
1231-
.collect(),
1232-
asm: asm.clone(),
1233-
asm_str_style: asm_str_style,
1234-
clobbers: clobbers.clone().into(),
1235-
volatile: volatile,
1236-
alignstack: alignstack,
1237-
dialect: dialect,
1238-
expn_id: expn_id,
1239-
}), outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(),
1240-
inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect()),
1211+
ExprKind::InlineAsm(ref asm) => {
1212+
let hir_asm = hir::InlineAsm {
1213+
inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
1214+
outputs: asm.outputs.iter().map(|out| {
1215+
hir::InlineAsmOutput {
1216+
constraint: out.constraint.clone(),
1217+
is_rw: out.is_rw,
1218+
is_indirect: out.is_indirect,
1219+
}
1220+
}).collect(),
1221+
asm: asm.asm.clone(),
1222+
asm_str_style: asm.asm_str_style,
1223+
clobbers: asm.clobbers.clone().into(),
1224+
volatile: asm.volatile,
1225+
alignstack: asm.alignstack,
1226+
dialect: asm.dialect,
1227+
expn_id: asm.expn_id,
1228+
};
1229+
let outputs =
1230+
asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect();
1231+
let inputs =
1232+
asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect();
1233+
hir::ExprInlineAsm(P(hir_asm), outputs, inputs)
1234+
}
12411235
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
12421236
hir::ExprStruct(self.lower_path(path),
12431237
fields.iter().map(|x| self.lower_field(x)).collect(),

src/libsyntax/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ pub enum ExprKind {
10501050
Ret(Option<P<Expr>>),
10511051

10521052
/// Output of the `asm!()` macro
1053-
InlineAsm(InlineAsm),
1053+
InlineAsm(P<InlineAsm>),
10541054

10551055
/// A macro invocation; pre-expansion
10561056
Mac(Mac),

src/libsyntax/ext/base.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,9 @@ impl<'a> ExtCtxt<'a> {
615615

616616
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
617617
-> parser::Parser<'a> {
618-
parse::tts_to_parser(self.parse_sess, tts.to_vec())
618+
let mut parser = parse::tts_to_parser(self.parse_sess, tts.to_vec());
619+
parser.allow_interpolated_tts = false; // FIXME(jseyfried) `quote!` can't handle these yet
620+
parser
619621
}
620622
pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
621623
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }

src/libsyntax/ext/quote.rs

+32-22
Original file line numberDiff line numberDiff line change
@@ -80,67 +80,71 @@ pub mod rt {
8080

8181
impl ToTokens for ast::Path {
8282
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
83-
vec![TokenTree::Token(DUMMY_SP,
84-
token::Interpolated(token::NtPath(Box::new(self.clone()))))]
83+
let nt = token::NtPath(self.clone());
84+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
8585
}
8686
}
8787

8888
impl ToTokens for ast::Ty {
8989
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
90-
vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
90+
let nt = token::NtTy(P(self.clone()));
91+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
9192
}
9293
}
9394

9495
impl ToTokens for ast::Block {
9596
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
96-
vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
97+
let nt = token::NtBlock(P(self.clone()));
98+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
9799
}
98100
}
99101

100102
impl ToTokens for ast::Generics {
101103
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
102-
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))]
104+
let nt = token::NtGenerics(self.clone());
105+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
103106
}
104107
}
105108

106109
impl ToTokens for ast::WhereClause {
107110
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
108-
vec![TokenTree::Token(DUMMY_SP,
109-
token::Interpolated(token::NtWhereClause(self.clone())))]
111+
let nt = token::NtWhereClause(self.clone());
112+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
110113
}
111114
}
112115

113116
impl ToTokens for P<ast::Item> {
114117
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
115-
vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))]
118+
let nt = token::NtItem(self.clone());
119+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
116120
}
117121
}
118122

119123
impl ToTokens for ast::ImplItem {
120124
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
121-
vec![TokenTree::Token(self.span,
122-
token::Interpolated(token::NtImplItem(P(self.clone()))))]
125+
let nt = token::NtImplItem(self.clone());
126+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
123127
}
124128
}
125129

126130
impl ToTokens for P<ast::ImplItem> {
127131
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
128-
vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
132+
let nt = token::NtImplItem((**self).clone());
133+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
129134
}
130135
}
131136

132137
impl ToTokens for ast::TraitItem {
133138
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
134-
vec![TokenTree::Token(self.span,
135-
token::Interpolated(token::NtTraitItem(P(self.clone()))))]
139+
let nt = token::NtTraitItem(self.clone());
140+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
136141
}
137142
}
138143

139144
impl ToTokens for ast::Stmt {
140145
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
141-
let mut tts = vec![
142-
TokenTree::Token(self.span, token::Interpolated(token::NtStmt(P(self.clone()))))
143-
];
146+
let nt = token::NtStmt(self.clone());
147+
let mut tts = vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))];
144148

145149
// Some statements require a trailing semicolon.
146150
if classify::stmt_ends_with_semi(&self.node) {
@@ -153,31 +157,36 @@ pub mod rt {
153157

154158
impl ToTokens for P<ast::Expr> {
155159
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
156-
vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))]
160+
let nt = token::NtExpr(self.clone());
161+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
157162
}
158163
}
159164

160165
impl ToTokens for P<ast::Pat> {
161166
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
162-
vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))]
167+
let nt = token::NtPat(self.clone());
168+
vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]
163169
}
164170
}
165171

166172
impl ToTokens for ast::Arm {
167173
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
168-
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
174+
let nt = token::NtArm(self.clone());
175+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
169176
}
170177
}
171178

172179
impl ToTokens for ast::Arg {
173180
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
174-
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))]
181+
let nt = token::NtArg(self.clone());
182+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
175183
}
176184
}
177185

178186
impl ToTokens for P<ast::Block> {
179187
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
180-
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))]
188+
let nt = token::NtBlock(self.clone());
189+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
181190
}
182191
}
183192

@@ -204,7 +213,8 @@ pub mod rt {
204213

205214
impl ToTokens for P<ast::MetaItem> {
206215
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
207-
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
216+
let nt = token::NtMeta(self.clone());
217+
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))]
208218
}
209219
}
210220

src/libsyntax/ext/tt/macro_parser.rs

+32-29
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ use parse::token::{DocComment, MatchNt, SubstNt};
8989
use parse::token::{Token, Nonterminal};
9090
use parse::token;
9191
use print::pprust;
92-
use ptr::P;
9392
use tokenstream::{self, TokenTree};
9493
use util::small_vector::SmallVector;
9594

@@ -198,7 +197,7 @@ pub fn initial_matcher_pos(ms: Vec<TokenTree>, sep: Option<Token>, lo: BytePos)
198197
199198
pub enum NamedMatch {
200199
MatchedSeq(Vec<Rc<NamedMatch>>, syntax_pos::Span),
201-
MatchedNonterminal(Nonterminal)
200+
MatchedNonterminal(Rc<Nonterminal>)
202201
}
203202

204203
pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
@@ -279,17 +278,16 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
279278
}
280279
}
281280

282-
pub fn parse(sess: &ParseSess, mut rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult {
283-
let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(),
284-
None,
285-
rdr.peek().sp.lo));
281+
pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult {
282+
let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true);
283+
let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), None, parser.span.lo));
286284

287285
loop {
288286
let mut bb_eis = Vec::new(); // black-box parsed by parser.rs
289287
let mut next_eis = Vec::new(); // or proceed normally
290288
let mut eof_eis = Vec::new();
291289

292-
let TokenAndSpan { tok, sp } = rdr.peek();
290+
let (sp, tok) = (parser.span, parser.token.clone());
293291

294292
/* we append new items to this while we go */
295293
loop {
@@ -474,23 +472,19 @@ pub fn parse(sess: &ParseSess, mut rdr: TtReader, ms: &[TokenTree]) -> NamedPars
474472
while !next_eis.is_empty() {
475473
cur_eis.push(next_eis.pop().unwrap());
476474
}
477-
rdr.next_token();
475+
parser.bump();
478476
} else /* bb_eis.len() == 1 */ {
479-
rdr.next_tok = {
480-
let mut rust_parser = Parser::new(sess, Box::new(&mut rdr));
481-
let mut ei = bb_eis.pop().unwrap();
482-
if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) {
483-
let match_cur = ei.match_cur;
484-
(&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal(
485-
parse_nt(&mut rust_parser, span, &ident.name.as_str()))));
486-
ei.idx += 1;
487-
ei.match_cur += 1;
488-
} else {
489-
unreachable!()
490-
}
491-
cur_eis.push(ei);
492-
Some(TokenAndSpan { tok: rust_parser.token, sp: rust_parser.span })
493-
};
477+
let mut ei = bb_eis.pop().unwrap();
478+
if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) {
479+
let match_cur = ei.match_cur;
480+
(&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal(
481+
Rc::new(parse_nt(&mut parser, span, &ident.name.as_str())))));
482+
ei.idx += 1;
483+
ei.match_cur += 1;
484+
} else {
485+
unreachable!()
486+
}
487+
cur_eis.push(ei);
494488
}
495489
}
496490

@@ -502,10 +496,19 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
502496
match name {
503497
"tt" => {
504498
p.quote_depth += 1; //but in theory, non-quoted tts might be useful
505-
let res: ::parse::PResult<'a, _> = p.parse_token_tree();
506-
let res = token::NtTT(P(panictry!(res)));
499+
let mut tt = panictry!(p.parse_token_tree());
507500
p.quote_depth -= 1;
508-
return res;
501+
loop {
502+
let nt = match tt {
503+
TokenTree::Token(_, token::Interpolated(ref nt)) => nt.clone(),
504+
_ => break,
505+
};
506+
match *nt {
507+
token::NtTT(ref sub_tt) => tt = sub_tt.clone(),
508+
_ => break,
509+
}
510+
}
511+
return token::NtTT(tt);
509512
}
510513
_ => {}
511514
}
@@ -521,7 +524,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
521524
},
522525
"block" => token::NtBlock(panictry!(p.parse_block())),
523526
"stmt" => match panictry!(p.parse_stmt()) {
524-
Some(s) => token::NtStmt(P(s)),
527+
Some(s) => token::NtStmt(s),
525528
None => {
526529
p.fatal("expected a statement").emit();
527530
panic!(FatalError);
@@ -534,7 +537,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
534537
"ident" => match p.token {
535538
token::Ident(sn) => {
536539
p.bump();
537-
token::NtIdent(Box::new(Spanned::<Ident>{node: sn, span: p.span}))
540+
token::NtIdent(Spanned::<Ident>{node: sn, span: p.span})
538541
}
539542
_ => {
540543
let token_str = pprust::token_to_string(&p.token);
@@ -544,7 +547,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
544547
}
545548
},
546549
"path" => {
547-
token::NtPath(Box::new(panictry!(p.parse_path(PathStyle::Type))))
550+
token::NtPath(panictry!(p.parse_path(PathStyle::Type)))
548551
},
549552
"meta" => token::NtMeta(panictry!(p.parse_meta_item())),
550553
// this is not supposed to happen, since it has been checked

src/libsyntax/ext/tt/macro_rules.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -236,22 +236,28 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
236236
// Extract the arguments:
237237
let lhses = match **argument_map.get(&lhs_nm).unwrap() {
238238
MatchedSeq(ref s, _) => {
239-
s.iter().map(|m| match **m {
240-
MatchedNonterminal(NtTT(ref tt)) => {
241-
valid &= check_lhs_nt_follows(sess, tt);
242-
(**tt).clone()
239+
s.iter().map(|m| {
240+
if let MatchedNonterminal(ref nt) = **m {
241+
if let NtTT(ref tt) = **nt {
242+
valid &= check_lhs_nt_follows(sess, tt);
243+
return (*tt).clone();
244+
}
243245
}
244-
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
246+
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
245247
}).collect::<Vec<TokenTree>>()
246248
}
247249
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
248250
};
249251

250252
let rhses = match **argument_map.get(&rhs_nm).unwrap() {
251253
MatchedSeq(ref s, _) => {
252-
s.iter().map(|m| match **m {
253-
MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(),
254-
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
254+
s.iter().map(|m| {
255+
if let MatchedNonterminal(ref nt) = **m {
256+
if let NtTT(ref tt) = **nt {
257+
return (*tt).clone();
258+
}
259+
}
260+
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
255261
}).collect()
256262
}
257263
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")

0 commit comments

Comments
 (0)