about summary refs log tree commit diff
path: root/library/alloc/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2025-02-21 12:45:22 +0100
committerGitHub <noreply@github.com>2025-02-21 12:45:22 +0100
commit8d52aae968e8a4822e3a4c902c148a2280657eb6 (patch)
tree0e2b270af0dd12a7f704f8bfd578d820cb72c6a1 /library/alloc/src
parente67d4499a61cfe5c4e6ff257e05ced2de652d5b6 (diff)
parent97005678c38fd391c9b502d011cc3f3d4434a18a (diff)
Rollup merge of #136089 - jwong101:box-default-debug-stack-usage, r=Amanieu
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.

Another option would be to mark `Box::write` as `#[inline(always)]`,
and change it's implementation to to avoid calling `MaybeUninit::write`
(which creates a `MaybeUninit<T>` on the stack) and to use `ptr::write` instead.

Fixes: #136043
Diffstat (limited to 'library/alloc/src')
-rw-r--r--library/alloc/src/boxed.rs15
1 files changed, 14 insertions, 1 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 4b124b5a3b3..5a3c1b74dad 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1689,7 +1689,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()
+        }
     }
 }