diff options
| author | Joshua Wong <joshuawong@anticentri.st> | 2025-01-26 03:36:50 -0500 |
|---|---|---|
| committer | Joshua Wong <joshuawong@anticentri.st> | 2025-01-26 03:48:27 -0500 |
| commit | 97005678c38fd391c9b502d011cc3f3d4434a18a (patch) | |
| tree | 1ba4600fb6a72a6a204c9428db946c8f67f20179 /library/alloc/src | |
| parent | 80faf203515bf3be214ad3ffc019b55b026b1220 (diff) | |
| download | rust-97005678c38fd391c9b502d011cc3f3d4434a18a.tar.gz rust-97005678c38fd391c9b502d011cc3f3d4434a18a.zip | |
reduce `Box::default` stack copies in debug mode
The `Box::new(T::default())` implementation of `Box::default` only had two stack copies in debug mode, compared to the current version, which has four. By avoiding creating any `MaybeUninit<T>`'s and just writing `T` directly to the `Box` pointer, the stack usage in debug mode remains the same as the old version.
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/boxed.rs | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1b5e44a9134..8f43ebc3888 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1730,7 +1730,20 @@ impl<T: Default> Default for Box<T> { /// Creates a `Box<T>`, with the `Default` value for T. #[inline] fn default() -> Self { - Box::write(Box::new_uninit(), T::default()) + let mut x: Box<mem::MaybeUninit<T>> = Box::new_uninit(); + unsafe { + // SAFETY: `x` is valid for writing and has the same layout as `T`. + // If `T::default()` panics, dropping `x` will just deallocate the Box as `MaybeUninit<T>` + // does not have a destructor. + // + // We use `ptr::write` as `MaybeUninit::write` creates + // extra stack copies of `T` in debug mode. + // + // See https://github.com/rust-lang/rust/issues/136043 for more context. + ptr::write(&raw mut *x as *mut T, T::default()); + // SAFETY: `x` was just initialized above. + x.assume_init() + } } } |
