Skip to content

Commit a2c82df

Browse files
committed
Auto merge of #76838 - est31:dogfood_uninit_features, r=oli-obk
Dogfood new_uninit and maybe_uninit_slice in rustc_arena Dogfoods a few cool `MaybeUninit` related features in the compiler's rustc_arena crate. Split off from #76821 r? `@oli-obk`
2 parents c6ab8e5 + 2805a05 commit a2c82df

File tree

2 files changed

+28
-25
lines changed

2 files changed

+28
-25
lines changed

compiler/rustc_arena/src/lib.rs

+17-25
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@
1313
)]
1414
#![feature(core_intrinsics)]
1515
#![feature(dropck_eyepatch)]
16-
#![feature(raw_vec_internals)]
16+
#![feature(new_uninit)]
17+
#![feature(maybe_uninit_slice)]
1718
#![cfg_attr(test, feature(test))]
1819
#![allow(deprecated)]
1920

20-
extern crate alloc;
21-
2221
use rustc_data_structures::cold_path;
2322
use smallvec::SmallVec;
2423

@@ -27,12 +26,10 @@ use std::cell::{Cell, RefCell};
2726
use std::cmp;
2827
use std::intrinsics;
2928
use std::marker::{PhantomData, Send};
30-
use std::mem;
29+
use std::mem::{self, MaybeUninit};
3130
use std::ptr;
3231
use std::slice;
3332

34-
use alloc::raw_vec::RawVec;
35-
3633
/// An arena that can hold objects of only one type.
3734
pub struct TypedArena<T> {
3835
/// A pointer to the next object to be allocated.
@@ -52,15 +49,15 @@ pub struct TypedArena<T> {
5249

5350
struct TypedArenaChunk<T> {
5451
/// The raw storage for the arena chunk.
55-
storage: RawVec<T>,
52+
storage: Box<[MaybeUninit<T>]>,
5653
/// The number of valid entries in the chunk.
5754
entries: usize,
5855
}
5956

6057
impl<T> TypedArenaChunk<T> {
6158
#[inline]
6259
unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
63-
TypedArenaChunk { storage: RawVec::with_capacity(capacity), entries: 0 }
60+
TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
6461
}
6562

6663
/// Destroys this arena chunk.
@@ -69,30 +66,25 @@ impl<T> TypedArenaChunk<T> {
6966
// The branch on needs_drop() is an -O1 performance optimization.
7067
// Without the branch, dropping TypedArena<u8> takes linear time.
7168
if mem::needs_drop::<T>() {
72-
let mut start = self.start();
73-
// Destroy all allocated objects.
74-
for _ in 0..len {
75-
ptr::drop_in_place(start);
76-
start = start.offset(1);
77-
}
69+
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len]));
7870
}
7971
}
8072

8173
// Returns a pointer to the first allocated object.
8274
#[inline]
83-
fn start(&self) -> *mut T {
84-
self.storage.ptr()
75+
fn start(&mut self) -> *mut T {
76+
MaybeUninit::slice_as_mut_ptr(&mut self.storage)
8577
}
8678

8779
// Returns a pointer to the end of the allocated space.
8880
#[inline]
89-
fn end(&self) -> *mut T {
81+
fn end(&mut self) -> *mut T {
9082
unsafe {
9183
if mem::size_of::<T>() == 0 {
9284
// A pointer as large as possible for zero-sized elements.
9385
!0 as *mut T
9486
} else {
95-
self.start().add(self.storage.capacity())
87+
self.start().add(self.storage.len())
9688
}
9789
}
9890
}
@@ -226,10 +218,10 @@ impl<T> TypedArena<T> {
226218
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
227219
last_chunk.entries = used_bytes / mem::size_of::<T>();
228220

229-
// If the previous chunk's capacity is less than HUGE_PAGE
221+
// If the previous chunk's len is less than HUGE_PAGE
230222
// bytes, then this chunk will be least double the previous
231223
// chunk's size.
232-
new_cap = last_chunk.storage.capacity();
224+
new_cap = last_chunk.storage.len();
233225
if new_cap < HUGE_PAGE / elem_size {
234226
new_cap = new_cap.checked_mul(2).unwrap();
235227
}
@@ -239,7 +231,7 @@ impl<T> TypedArena<T> {
239231
// Also ensure that this chunk can fit `additional`.
240232
new_cap = cmp::max(additional, new_cap);
241233

242-
let chunk = TypedArenaChunk::<T>::new(new_cap);
234+
let mut chunk = TypedArenaChunk::<T>::new(new_cap);
243235
self.ptr.set(chunk.start());
244236
self.end.set(chunk.end());
245237
chunks.push(chunk);
@@ -301,7 +293,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
301293
chunk.destroy(chunk.entries);
302294
}
303295
}
304-
// RawVec handles deallocation of `last_chunk` and `self.chunks`.
296+
// Box handles deallocation of `last_chunk` and `self.chunks`.
305297
}
306298
}
307299
}
@@ -344,10 +336,10 @@ impl DroplessArena {
344336
// There is no need to update `last_chunk.entries` because that
345337
// field isn't used by `DroplessArena`.
346338

347-
// If the previous chunk's capacity is less than HUGE_PAGE
339+
// If the previous chunk's len is less than HUGE_PAGE
348340
// bytes, then this chunk will be least double the previous
349341
// chunk's size.
350-
new_cap = last_chunk.storage.capacity();
342+
new_cap = last_chunk.storage.len();
351343
if new_cap < HUGE_PAGE {
352344
new_cap = new_cap.checked_mul(2).unwrap();
353345
}
@@ -357,7 +349,7 @@ impl DroplessArena {
357349
// Also ensure that this chunk can fit `additional`.
358350
new_cap = cmp::max(additional, new_cap);
359351

360-
let chunk = TypedArenaChunk::<u8>::new(new_cap);
352+
let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
361353
self.ptr.set(chunk.start());
362354
self.end.set(chunk.end());
363355
chunks.push(chunk);

compiler/rustc_arena/src/tests.rs

+11
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ pub fn bench_typed_arena_clear(b: &mut Bencher) {
121121
})
122122
}
123123

124+
#[bench]
125+
pub fn bench_typed_arena_clear_100(b: &mut Bencher) {
126+
let mut arena = TypedArena::default();
127+
b.iter(|| {
128+
for _ in 0..100 {
129+
arena.alloc(Point { x: 1, y: 2, z: 3 });
130+
}
131+
arena.clear();
132+
})
133+
}
134+
124135
// Drop tests
125136

126137
struct DropCounter<'a> {

0 commit comments

Comments
 (0)