Skip to content

Commit a120958

Browse files
committed
rustc_arena: handle recursive allocation, don't trust size_hint
In `DroplessArena::alloc_from_iter`, handle allocating from iterators whose `next` calls may themselves allocate on the arena. Also, do not trust the iterator's `size_hint` implementation for correctness. These changes were already made for `TypedArena` in rust-lang#67003.
1 parent f5230fb commit a120958

File tree

1 file changed

+18
-54
lines changed
  • compiler/rustc_arena/src

1 file changed

+18
-54
lines changed

compiler/rustc_arena/src/lib.rs

+18-54
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ impl<T> TypedArena<T> {
191191
#[inline]
192192
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
193193
assert!(mem::size_of::<T>() != 0);
194+
// To handle the possibility that the act of iterating itself causes allocations on
195+
// the arena, we must collect into a local buffer first, then copy it into the arena.
194196
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
195197
if vec.is_empty() {
196198
return &mut [];
@@ -431,66 +433,26 @@ impl DroplessArena {
431433
}
432434
}
433435

434-
#[inline]
435-
unsafe fn write_from_iter<T, I: Iterator<Item = T>>(
436-
&self,
437-
mut iter: I,
438-
len: usize,
439-
mem: *mut T,
440-
) -> &mut [T] {
441-
let mut i = 0;
442-
// Use a manual loop since LLVM manages to optimize it better for
443-
// slice iterators
444-
loop {
445-
let value = iter.next();
446-
if i >= len || value.is_none() {
447-
// We only return as many items as the iterator gave us, even
448-
// though it was supposed to give us `len`
449-
return slice::from_raw_parts_mut(mem, i);
450-
}
451-
ptr::write(mem.add(i), value.unwrap());
452-
i += 1;
453-
}
454-
}
455-
456436
#[inline]
457437
pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
458438
let iter = iter.into_iter();
459439
assert!(mem::size_of::<T>() != 0);
460440
assert!(!mem::needs_drop::<T>());
461441

462-
let size_hint = iter.size_hint();
463-
464-
match size_hint {
465-
(min, Some(max)) if min == max => {
466-
// We know the exact number of elements the iterator will produce here
467-
let len = min;
468-
469-
if len == 0 {
470-
return &mut [];
471-
}
472-
473-
let mem = self.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
474-
unsafe { self.write_from_iter(iter, len, mem) }
475-
}
476-
(_, _) => {
477-
cold_path(move || -> &mut [T] {
478-
let mut vec: SmallVec<[_; 8]> = iter.collect();
479-
if vec.is_empty() {
480-
return &mut [];
481-
}
482-
// Move the content to the arena by copying it and then forgetting
483-
// the content of the SmallVec
484-
unsafe {
485-
let len = vec.len();
486-
let start_ptr =
487-
self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
488-
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
489-
vec.set_len(0);
490-
slice::from_raw_parts_mut(start_ptr, len)
491-
}
492-
})
493-
}
442+
// To handle the possibility that the act of iterating itself causes allocations on
443+
// the arena, we must collect into a local buffer first, then copy it into the arena.
444+
let mut vec: SmallVec<[_; 8]> = iter.collect();
445+
if vec.is_empty() {
446+
return &mut [];
447+
}
448+
// Move the content to the arena by copying it and then forgetting
449+
// the content of the SmallVec
450+
unsafe {
451+
let len = vec.len();
452+
let start_ptr = self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
453+
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
454+
vec.set_len(0);
455+
slice::from_raw_parts_mut(start_ptr, len)
494456
}
495457
}
496458
}
@@ -542,6 +504,8 @@ impl DropArena {
542504

543505
#[inline]
544506
pub unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
507+
// To handle the possibility that the act of iterating itself causes allocations on
508+
// the arena, we must collect into a local buffer first, then copy it into the arena.
545509
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
546510
if vec.is_empty() {
547511
return &mut [];

0 commit comments

Comments
 (0)