Skip to content

Commit 3c10a88

Browse files
committed
Auto merge of #81494 - cuviper:btree-node-init, r=Mark-Simulacrum
Initialize BTree nodes directly in the heap We can avoid any stack-local nodes entirely by using `Box::new_uninit`, and since the nodes are mostly `MaybeUninit` fields, we only need a couple of actual writes before `assume_init`. This should help with the stack overflows in #81444, and may also improve performance in general. r? `@Mark-Simulacrum` cc `@ssomers`
2 parents 7e0241c + 5a58cf4 commit 3c10a88

File tree

1 file changed

+30
-18
lines changed
  • library/alloc/src/collections/btree

1 file changed

+30
-18
lines changed

library/alloc/src/collections/btree/node.rs

+30-18
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,24 @@ struct LeafNode<K, V> {
6767
}
6868

6969
impl<K, V> LeafNode<K, V> {
70-
/// Creates a new `LeafNode`. Unsafe because all nodes should really be hidden behind
70+
/// Initializes a new `LeafNode` in-place.
71+
unsafe fn init(this: *mut Self) {
72+
// As a general policy, we leave fields uninitialized if they can be, as this should
73+
// be both slightly faster and easier to track in Valgrind.
74+
unsafe {
75+
// parent_idx, keys, and vals are all MaybeUninit
76+
ptr::addr_of_mut!((*this).parent).write(None);
77+
ptr::addr_of_mut!((*this).len).write(0);
78+
}
79+
}
80+
81+
/// Creates a new boxed `LeafNode`. Unsafe because all nodes should really be hidden behind
7182
/// `BoxedNode`, preventing accidental dropping of uninitialized keys and values.
72-
unsafe fn new() -> Self {
73-
LeafNode {
74-
// As a general policy, we leave fields uninitialized if they can be, as this should
75-
// be both slightly faster and easier to track in Valgrind.
76-
keys: MaybeUninit::uninit_array(),
77-
vals: MaybeUninit::uninit_array(),
78-
parent: None,
79-
parent_idx: MaybeUninit::uninit(),
80-
len: 0,
83+
unsafe fn new() -> Box<Self> {
84+
unsafe {
85+
let mut leaf = Box::new_uninit();
86+
LeafNode::init(leaf.as_mut_ptr());
87+
leaf.assume_init()
8188
}
8289
}
8390
}
@@ -99,15 +106,20 @@ struct InternalNode<K, V> {
99106
}
100107

101108
impl<K, V> InternalNode<K, V> {
102-
/// Creates a new `InternalNode`.
109+
/// Creates a new boxed `InternalNode`.
103110
///
104-
/// This is unsafe for two reasons. First, it returns an `InternalNode` by value, risking
111+
/// This is unsafe for two reasons. First, it returns an owned `InternalNode` in a box, risking
105112
/// dropping of uninitialized fields. Second, an invariant of internal nodes is that `len + 1`
106113
/// edges are initialized and valid, meaning that even when the node is empty (having a
107114
/// `len` of 0), there must be one initialized and valid edge. This function does not set up
108115
/// such an edge.
109-
unsafe fn new() -> Self {
110-
InternalNode { data: unsafe { LeafNode::new() }, edges: MaybeUninit::uninit_array() }
116+
unsafe fn new() -> Box<Self> {
117+
unsafe {
118+
let mut node = Box::<Self>::new_uninit();
119+
// We only need to initialize the data; the edges are MaybeUninit.
120+
LeafNode::init(ptr::addr_of_mut!((*node.as_mut_ptr()).data));
121+
node.assume_init()
122+
}
111123
}
112124
}
113125

@@ -133,7 +145,7 @@ impl<K, V> Root<K, V> {
133145

134146
impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
135147
fn new_leaf() -> Self {
136-
Self::from_new_leaf(Box::new(unsafe { LeafNode::new() }))
148+
Self::from_new_leaf(unsafe { LeafNode::new() })
137149
}
138150

139151
fn from_new_leaf(leaf: Box<LeafNode<K, V>>) -> Self {
@@ -143,7 +155,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
143155

144156
impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
145157
fn new_internal(child: Root<K, V>) -> Self {
146-
let mut new_node = Box::new(unsafe { InternalNode::new() });
158+
let mut new_node = unsafe { InternalNode::new() };
147159
new_node.edges[0].write(child.node);
148160
NodeRef::from_new_internal(new_node, child.height + 1)
149161
}
@@ -1075,7 +1087,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
10751087
/// allocated node.
10761088
pub fn split(mut self) -> SplitResult<'a, K, V, marker::Leaf> {
10771089
unsafe {
1078-
let mut new_node = Box::new(LeafNode::new());
1090+
let mut new_node = LeafNode::new();
10791091

10801092
let kv = self.split_leaf_data(&mut new_node);
10811093

@@ -1110,7 +1122,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
11101122
pub fn split(mut self) -> SplitResult<'a, K, V, marker::Internal> {
11111123
let old_len = self.node.len();
11121124
unsafe {
1113-
let mut new_node = Box::new(InternalNode::new());
1125+
let mut new_node = InternalNode::new();
11141126
let kv = self.split_leaf_data(&mut new_node.data);
11151127
let new_len = usize::from(new_node.data.len);
11161128
move_to_slice(

0 commit comments

Comments
 (0)