Skip to content

Commit 71993c7

Browse files
author
Julian Wollersberger
committed
To avoid monomorphizing psm::on_stack::with_on_stack 1500 times in rustc, convert the callback passed to grow _grow to dyn FnMut().
This should improve rustc's compile time a bit, and surprisingly also improves runtime in some cases. https://perf.rust-lang.org/compare.html?start=7402a394471a6738a40fea7d4f1891666e5a80c5&end=f242334c1e2e719cf1cba923923ad8ec62affb71
1 parent 7a1d421 commit 71993c7

File tree

1 file changed

+19
-3
lines changed

1 file changed

+19
-3
lines changed

src/lib.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,27 @@ pub fn maybe_grow<R, F: FnOnce() -> R>(red_zone: usize, stack_size: usize, callb
5959
/// The closure will still be on the same thread as the caller of `grow`.
6060
/// This will allocate a new stack with at least `stack_size` bytes.
6161
pub fn grow<R, F: FnOnce() -> R>(stack_size: usize, callback: F) -> R {
62+
// Measuring with cargo-llvm-lines revealed that `psm::on_stack::with_on_stack`
63+
// was monomorphized 1552 times in rustc and was responsible for 1.5% of
64+
// rustc's total llvm IR lines. That takes time for LLVM to process.
65+
// Converting the generic callback to a dynamic one removes all that duplication.
66+
let mut opt_callback = Some(callback);
6267
let mut ret = None;
6368
let ret_ref = &mut ret;
64-
_grow(stack_size, move || {
65-
*ret_ref = Some(callback());
66-
});
69+
70+
// This wrapper around `callback` achieves two things:
71+
// * It converts the `impl FnOnce` to a `dyn FnMut`.
72+
// `dyn` because we want it to not be generic, and
73+
// `FnMut` because we can't pass a `dyn FnOnce` around without boxing it.
74+
// * It eliminates the generic return value, by writing it to the stack of this function.
75+
// Otherwise the closure would have to return an unsized value, which isn't possible.
76+
let dyn_callback: &mut dyn FnMut() = &mut || {
77+
let taken_callback = opt_callback.take().unwrap();
78+
*ret_ref = Some(taken_callback());
79+
};
80+
81+
// _grow is only monomorphized once with a `dyn` argument.
82+
_grow(stack_size, dyn_callback);
6783
ret.unwrap()
6884
}
6985

0 commit comments

Comments
 (0)