Skip to content

Commit 9700567

Browse files
committed
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.
1 parent 80faf20 commit 9700567

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

library/alloc/src/boxed.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1730,7 +1730,20 @@ impl<T: Default> Default for Box<T> {
17301730
/// Creates a `Box<T>`, with the `Default` value for T.
17311731
#[inline]
17321732
fn default() -> Self {
1733-
Box::write(Box::new_uninit(), T::default())
1733+
let mut x: Box<mem::MaybeUninit<T>> = Box::new_uninit();
1734+
unsafe {
1735+
// SAFETY: `x` is valid for writing and has the same layout as `T`.
1736+
// If `T::default()` panics, dropping `x` will just deallocate the Box as `MaybeUninit<T>`
1737+
// does not have a destructor.
1738+
//
1739+
// We use `ptr::write` as `MaybeUninit::write` creates
1740+
// extra stack copies of `T` in debug mode.
1741+
//
1742+
// See https://github.com/rust-lang/rust/issues/136043 for more context.
1743+
ptr::write(&raw mut *x as *mut T, T::default());
1744+
// SAFETY: `x` was just initialized above.
1745+
x.assume_init()
1746+
}
17341747
}
17351748
}
17361749

tests/codegen/box-default-debug-copies.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
// four `T` allocas.
66
//
77
// See https://github.com/rust-lang/rust/issues/136043 for more context.
8+
//
9+
// FIXME: This test only wants to ensure that there are at most two allocas of `T` created, instead
10+
// of checking for exactly two.
811

912
#![crate_type = "lib"]
1013

@@ -17,7 +20,7 @@ impl Default for Thing {
1720
}
1821
}
1922

20-
// CHECK-COUNT-4: %{{.*}} = alloca {{.*}}1000000
23+
// CHECK-COUNT-2: %{{.*}} = alloca {{.*}}1000000
2124
// CHECK-NOT: %{{.*}} = alloca {{.*}}1000000
2225
#[no_mangle]
2326
pub fn box_default_single_copy() -> Box<Thing> {

0 commit comments

Comments
 (0)