Skip to content

Commit

Permalink
reduce Box::default stack copies in debug mode
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jwong101 committed Jan 26, 2025
1 parent 80faf20 commit 9700567
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
15 changes: 14 additions & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion tests/codegen/box-default-debug-copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
// four `T` allocas.
//
// See https://github.com/rust-lang/rust/issues/136043 for more context.
//
// FIXME: This test only wants to ensure that there are at most two allocas of `T` created, instead
// of checking for exactly two.

#![crate_type = "lib"]

Expand All @@ -17,7 +20,7 @@ impl Default for Thing {
}
}

// CHECK-COUNT-4: %{{.*}} = alloca {{.*}}1000000
// CHECK-COUNT-2: %{{.*}} = alloca {{.*}}1000000
// CHECK-NOT: %{{.*}} = alloca {{.*}}1000000
#[no_mangle]
pub fn box_default_single_copy() -> Box<Thing> {
Expand Down

0 comments on commit 9700567

Please sign in to comment.