Skip to content

Commit b52d335

Browse files
committed
Auto merge of #140023 - cjgillot:arena-try-alloc, r=<try>
Introduce Arena::try_alloc_from_iter. r? `@ghost` for perf
2 parents 191df20 + d0d3021 commit b52d335

File tree

2 files changed

+47
-33
lines changed

2 files changed

+47
-33
lines changed

Diff for: compiler/rustc_arena/src/lib.rs

+45-23
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
#![feature(decl_macro)]
2222
#![feature(dropck_eyepatch)]
2323
#![feature(maybe_uninit_slice)]
24+
#![feature(never_type)]
2425
#![feature(rustc_attrs)]
2526
#![feature(rustdoc_internals)]
27+
#![feature(unwrap_infallible)]
2628
// tidy-alphabetical-end
2729

2830
use std::alloc::Layout;
@@ -200,6 +202,18 @@ impl<T> TypedArena<T> {
200202
/// storing the elements in the arena.
201203
#[inline]
202204
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
205+
self.try_alloc_from_iter(iter.into_iter().map(Ok::<T, !>)).into_ok()
206+
}
207+
208+
/// Allocates the elements of this iterator into a contiguous slice in the `TypedArena`.
209+
///
210+
/// Note: for reasons of reentrancy and panic safety we collect into a `SmallVec<[_; 8]>` before
211+
/// storing the elements in the arena.
212+
#[inline]
213+
pub fn try_alloc_from_iter<E>(
214+
&self,
215+
iter: impl IntoIterator<Item = Result<T, E>>,
216+
) -> Result<&mut [T], E> {
203217
// Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason
204218
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
205219
// reference to `self` and adding elements to the arena during iteration.
@@ -214,18 +228,19 @@ impl<T> TypedArena<T> {
214228
// doesn't need to be hyper-optimized.
215229
assert!(size_of::<T>() != 0);
216230

217-
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
231+
let vec: Result<SmallVec<[T; 8]>, E> = iter.into_iter().collect();
232+
let mut vec = vec?;
218233
if vec.is_empty() {
219-
return &mut [];
234+
return Ok(&mut []);
220235
}
221236
// Move the content to the arena by copying and then forgetting it.
222237
let len = vec.len();
223238
let start_ptr = self.alloc_raw_slice(len);
224-
unsafe {
239+
Ok(unsafe {
225240
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
226241
vec.set_len(0);
227242
slice::from_raw_parts_mut(start_ptr, len)
228-
}
243+
})
229244
}
230245

231246
/// Grows the arena.
@@ -566,27 +581,34 @@ impl DroplessArena {
566581
// `drop`.
567582
unsafe { self.write_from_iter(iter, len, mem) }
568583
}
569-
(_, _) => {
570-
outline(move || -> &mut [T] {
571-
// Takes care of reentrancy.
572-
let mut vec: SmallVec<[_; 8]> = iter.collect();
573-
if vec.is_empty() {
574-
return &mut [];
575-
}
576-
// Move the content to the arena by copying it and then forgetting
577-
// the content of the SmallVec
578-
unsafe {
579-
let len = vec.len();
580-
let start_ptr =
581-
self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
582-
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
583-
vec.set_len(0);
584-
slice::from_raw_parts_mut(start_ptr, len)
585-
}
586-
})
587-
}
584+
(_, _) => outline(move || self.try_alloc_from_iter(iter.map(Ok::<T, !>)).into_ok()),
588585
}
589586
}
587+
588+
#[inline]
589+
pub fn try_alloc_from_iter<T, E>(
590+
&self,
591+
iter: impl IntoIterator<Item = Result<T, E>>,
592+
) -> Result<&mut [T], E> {
593+
// Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we
594+
// cannot know the minimum length of the iterator in this case.
595+
assert!(size_of::<T>() != 0);
596+
597+
// Takes care of reentrancy.
598+
let vec: Result<SmallVec<[T; 8]>, E> = iter.into_iter().collect();
599+
let mut vec = vec?;
600+
if vec.is_empty() {
601+
return Ok(&mut []);
602+
}
603+
// Move the content to the arena by copying and then forgetting it.
604+
let len = vec.len();
605+
Ok(unsafe {
606+
let start_ptr = self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
607+
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
608+
vec.set_len(0);
609+
slice::from_raw_parts_mut(start_ptr, len)
610+
})
611+
}
590612
}
591613

592614
/// Declare an `Arena` containing one dropless arena and many typed arenas (the

Diff for: compiler/rustc_mir_transform/src/jump_threading.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,8 @@ impl<'a> ConditionSet<'a> {
181181
arena: &'a DroplessArena,
182182
f: impl Fn(Condition) -> Option<Condition>,
183183
) -> Option<ConditionSet<'a>> {
184-
let mut all_ok = true;
185-
let set = arena.alloc_from_iter(self.iter().map_while(|c| {
186-
if let Some(c) = f(c) {
187-
Some(c)
188-
} else {
189-
all_ok = false;
190-
None
191-
}
192-
}));
193-
all_ok.then_some(ConditionSet(set))
184+
let set = arena.try_alloc_from_iter(self.iter().map(|c| f(c).ok_or(()))).ok()?;
185+
Some(ConditionSet(set))
194186
}
195187
}
196188

0 commit comments

Comments
 (0)