Skip to content

Commit 4d45af9

Browse files
committed
Try to reduce codegen complexity of TokenStream's FromIterator and Extend impls
This is an experimental patch to try to reduce the codegen complexity of TokenStream's FromIterator and Extend implementations for downstream crates, by moving the core logic into a helper type. This might help improve build performance of crates which depend on proc_macro as iterators are used less, and the compiler may take less time to do things like attempt specializations or other iterator optimizations. The change intentionally sacrifices some optimization opportunities, such as using the specializations for collecting iterators derived from Vec::into_iter() into Vec. This is one of the simpler potential approaches to reducing the amount of code generated in crates depending on proc_macro, so it seems worth trying before other more-involved changes.
1 parent 0a049fd commit 4d45af9

File tree

2 files changed

+94
-18
lines changed

2 files changed

+94
-18
lines changed

compiler/rustc_expand/src/proc_macro_server.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,8 @@ impl server::TokenStream for Rustc<'_, '_> {
502502
&mut self,
503503
stream: Self::TokenStream,
504504
) -> Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
505-
// XXX: This is a raw port of the previous approach, and can probably be
506-
// optimized.
505+
// FIXME: This is a raw port of the previous approach, and can probably
506+
// be optimized.
507507
let mut cursor = stream.into_trees();
508508
let mut stack = Vec::new();
509509
let mut tts = Vec::new();

library/proc_macro/src/lib.rs

+92-16
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,90 @@ impl From<TokenTree> for TokenStream {
233233
}
234234
}
235235

236+
/// Non-generic helper for implementing `FromIterator<TokenTree>` and
237+
/// `Extend<TokenTree>` with less monomorphization in calling crates.
238+
struct ExtendStreamWithTreesHelper {
239+
trees: Vec<
240+
bridge::TokenTree<
241+
bridge::client::Group,
242+
bridge::client::Punct,
243+
bridge::client::Ident,
244+
bridge::client::Literal,
245+
>,
246+
>,
247+
}
248+
249+
impl ExtendStreamWithTreesHelper {
250+
fn new(capacity: usize) -> Self {
251+
ExtendStreamWithTreesHelper { trees: Vec::with_capacity(capacity) }
252+
}
253+
254+
fn push(&mut self, tree: TokenTree) {
255+
self.trees.push(tree_to_bridge_tree(tree));
256+
}
257+
258+
fn build(self) -> TokenStream {
259+
if self.trees.is_empty() {
260+
TokenStream(None)
261+
} else {
262+
TokenStream(Some(bridge::client::TokenStream::concat_trees(None, self.trees)))
263+
}
264+
}
265+
266+
fn extend(self, stream: &mut TokenStream) {
267+
if self.trees.is_empty() {
268+
return;
269+
}
270+
stream.0 = Some(bridge::client::TokenStream::concat_trees(stream.0.take(), self.trees))
271+
}
272+
}
273+
274+
/// Non-generic helper for implementing `FromIterator<TokenStream>` and
275+
/// `Extend<TokenStream>` with less monomorphization in calling crates.
276+
struct ExtendStreamWithStreamsHelper {
277+
streams: Vec<bridge::client::TokenStream>,
278+
}
279+
280+
impl ExtendStreamWithStreamsHelper {
281+
fn new(capacity: usize) -> Self {
282+
ExtendStreamWithStreamsHelper { streams: Vec::with_capacity(capacity) }
283+
}
284+
285+
fn push(&mut self, stream: TokenStream) {
286+
if let Some(stream) = stream.0 {
287+
self.streams.push(stream);
288+
}
289+
}
290+
291+
fn build(mut self) -> TokenStream {
292+
if self.streams.len() <= 1 {
293+
TokenStream(self.streams.pop())
294+
} else {
295+
TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams)))
296+
}
297+
}
298+
299+
fn extend(mut self, stream: &mut TokenStream) {
300+
if self.streams.is_empty() {
301+
return;
302+
}
303+
let base = stream.0.take();
304+
if base.is_none() && self.streams.len() == 1 {
305+
stream.0 = self.streams.pop();
306+
} else {
307+
stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams));
308+
}
309+
}
310+
}
311+
236312
/// Collects a number of token trees into a single stream.
237313
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
238314
impl iter::FromIterator<TokenTree> for TokenStream {
239315
fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
240-
TokenStream(Some(bridge::client::TokenStream::concat_trees(
241-
None,
242-
trees.into_iter().map(tree_to_bridge_tree).collect(),
243-
)))
316+
let iter = trees.into_iter();
317+
let mut builder = ExtendStreamWithTreesHelper::new(iter.size_hint().0);
318+
iter.for_each(|tree| builder.push(tree));
319+
builder.build()
244320
}
245321
}
246322

@@ -249,30 +325,30 @@ impl iter::FromIterator<TokenTree> for TokenStream {
249325
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
250326
impl iter::FromIterator<TokenStream> for TokenStream {
251327
fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
252-
TokenStream(Some(bridge::client::TokenStream::concat_streams(
253-
None,
254-
streams.into_iter().filter_map(|stream| stream.0).collect(),
255-
)))
328+
let iter = streams.into_iter();
329+
let mut builder = ExtendStreamWithStreamsHelper::new(iter.size_hint().0);
330+
iter.for_each(|stream| builder.push(stream));
331+
builder.build()
256332
}
257333
}
258334

259335
#[stable(feature = "token_stream_extend", since = "1.30.0")]
260336
impl Extend<TokenTree> for TokenStream {
261337
fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, trees: I) {
262-
*self = TokenStream(Some(bridge::client::TokenStream::concat_trees(
263-
self.0.take(),
264-
trees.into_iter().map(|tree| tree_to_bridge_tree(tree)).collect(),
265-
)));
338+
let iter = trees.into_iter();
339+
let mut builder = ExtendStreamWithTreesHelper::new(iter.size_hint().0);
340+
iter.for_each(|tree| builder.push(tree));
341+
builder.extend(self);
266342
}
267343
}
268344

269345
#[stable(feature = "token_stream_extend", since = "1.30.0")]
270346
impl Extend<TokenStream> for TokenStream {
271347
fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
272-
*self = TokenStream(Some(bridge::client::TokenStream::concat_streams(
273-
self.0.take(),
274-
streams.into_iter().filter_map(|stream| stream.0).collect(),
275-
)));
348+
let iter = streams.into_iter();
349+
let mut builder = ExtendStreamWithStreamsHelper::new(iter.size_hint().0);
350+
iter.for_each(|stream| builder.push(stream));
351+
builder.extend(self);
276352
}
277353
}
278354

0 commit comments

Comments
 (0)