Auto merge of #70362 - TimDiekmann:alloc-overhaul, r=Amanieu

Overhaul of the `AllocRef` trait to match allocator-wg's latest consens; Take 2

GitHub won't let me reopen #69889 so I make a new PR.

In addition to #69889 this fixes the unsoundness of `RawVec::into_box` when using allocators supporting overallocating. Also it uses `MemoryBlock` in `AllocRef` to unify `_in_place` methods by passing `&mut MemoryBlock`. Additionally, `RawVec` now checks for `size_of::<T>()` again and ignore every ZST. The internal capacity of `RawVec` isn't used by ZSTs anymore, as `into_box` now requires a length to be specified.

r? @Amanieu

fixes rust-lang/wg-allocators#38
fixes rust-lang/wg-allocators#41
fixes rust-lang/wg-allocators#44
fixes rust-lang/wg-allocators#51
This commit is contained in:
bors 2020-04-02 06:08:35 +00:00
commit 127a11a344
21 changed files with 1453 additions and 1627 deletions

View file

@ -7,7 +7,7 @@
extern crate helper;
use std::alloc::{self, Global, AllocRef, System, Layout};
use std::alloc::{self, AllocInit, AllocRef, Global, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
static HITS: AtomicUsize = AtomicUsize::new(0);
@ -37,10 +37,10 @@ fn main() {
unsafe {
let layout = Layout::from_size_align(4, 2).unwrap();
let (ptr, _) = Global.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
let memory = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
helper::work_with(&memory.ptr);
assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
Global.dealloc(ptr, layout.clone());
Global.dealloc(memory.ptr, layout);
assert_eq!(HITS.load(Ordering::SeqCst), n + 2);
let s = String::with_capacity(10);
@ -49,10 +49,10 @@ fn main() {
drop(s);
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
let (ptr, _) = System.alloc(layout.clone()).unwrap();
let memory = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
helper::work_with(&ptr);
System.dealloc(ptr, layout);
helper::work_with(&memory.ptr);
System.dealloc(memory.ptr, layout);
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
}
}

View file

@ -9,8 +9,8 @@
extern crate custom;
extern crate helper;
use std::alloc::{Global, AllocRef, System, Layout};
use std::sync::atomic::{Ordering, AtomicUsize};
use std::alloc::{AllocInit, AllocRef, Global, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
#[global_allocator]
static GLOBAL: custom::A = custom::A(AtomicUsize::new(0));
@ -20,16 +20,16 @@ fn main() {
let n = GLOBAL.0.load(Ordering::SeqCst);
let layout = Layout::from_size_align(4, 2).unwrap();
let (ptr, _) = Global.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
let memory = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
helper::work_with(&memory.ptr);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
Global.dealloc(ptr, layout.clone());
Global.dealloc(memory.ptr, layout);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
let (ptr, _) = System.alloc(layout.clone()).unwrap();
let memory = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
helper::work_with(&ptr);
System.dealloc(ptr, layout);
helper::work_with(&memory.ptr);
System.dealloc(memory.ptr, layout);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
}
}

View file

@ -6,7 +6,7 @@
#![feature(allocator_api)]
use std::alloc::{Global, AllocRef, Layout, handle_alloc_error};
use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout, ReallocPlacement};
use std::ptr::{self, NonNull};
fn main() {
@ -16,17 +16,17 @@ fn main() {
}
unsafe fn test_triangle() -> bool {
static COUNT : usize = 16;
static COUNT: usize = 16;
let mut ascend = vec![ptr::null_mut(); COUNT];
let ascend = &mut *ascend;
static ALIGN : usize = 1;
static ALIGN: usize = 1;
// Checks that `ascend` forms triangle of ascending size formed
// from pairs of rows (where each pair of rows is equally sized),
// and the elements of the triangle match their row-pair index.
unsafe fn sanity_check(ascend: &[*mut u8]) {
for i in 0..COUNT / 2 {
let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
let (p0, p1, size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
for j in 0..size {
assert_eq!(*p0.add(j), i as u8);
assert_eq!(*p1.add(j), i as u8);
@ -34,20 +34,22 @@ unsafe fn test_triangle() -> bool {
}
}
static PRINT : bool = false;
static PRINT: bool = false;
unsafe fn allocate(layout: Layout) -> *mut u8 {
if PRINT {
println!("allocate({:?})", layout);
}
let (ptr, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
let memory = Global
.alloc(layout, AllocInit::Uninitialized)
.unwrap_or_else(|_| handle_alloc_error(layout));
if PRINT {
println!("allocate({:?}) = {:?}", layout, ptr);
println!("allocate({:?}) = {:?}", layout, memory.ptr);
}
ptr.cast().as_ptr()
memory.ptr.cast().as_ptr()
}
unsafe fn deallocate(ptr: *mut u8, layout: Layout) {
@ -63,19 +65,31 @@ unsafe fn test_triangle() -> bool {
println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
}
let (ptr, _) = Global.realloc(NonNull::new_unchecked(ptr), old, new.size())
.unwrap_or_else(|_| handle_alloc_error(
Layout::from_size_align_unchecked(new.size(), old.align())
));
let memory = if new.size() > old.size() {
Global.grow(
NonNull::new_unchecked(ptr),
old,
new.size(),
ReallocPlacement::MayMove,
AllocInit::Uninitialized,
)
} else {
Global.shrink(NonNull::new_unchecked(ptr), old, new.size(), ReallocPlacement::MayMove)
};
let memory = memory.unwrap_or_else(|_| {
handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align()))
});
if PRINT {
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
ptr, old, new, ptr);
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, memory.ptr);
}
ptr.cast().as_ptr()
memory.ptr.cast().as_ptr()
}
fn idx_to_size(i: usize) -> usize { (i+1) * 10 }
fn idx_to_size(i: usize) -> usize {
(i + 1) * 10
}
// Allocate pairs of rows that form a triangle shape. (Hope is
// that at least two rows will be allocated near each other, so
@ -83,13 +97,13 @@ unsafe fn test_triangle() -> bool {
// way.)
for i in 0..COUNT / 2 {
let size = idx_to_size(i);
ascend[2*i] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
ascend[2*i+1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
ascend[2 * i] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
ascend[2 * i + 1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
}
// Initialize each pair of rows to distinct value.
for i in 0..COUNT / 2 {
let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
let (p0, p1, size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
for j in 0..size {
*p0.add(j) = i as u8;
*p1.add(j) = i as u8;
@ -104,8 +118,8 @@ unsafe fn test_triangle() -> bool {
for i in 0..COUNT / 2 {
let size = idx_to_size(i);
deallocate(ascend[2*i], Layout::from_size_align(size, ALIGN).unwrap());
deallocate(ascend[2*i+1], Layout::from_size_align(size, ALIGN).unwrap());
deallocate(ascend[2 * i], Layout::from_size_align(size, ALIGN).unwrap());
deallocate(ascend[2 * i + 1], Layout::from_size_align(size, ALIGN).unwrap());
}
return true;
@ -115,68 +129,68 @@ unsafe fn test_triangle() -> bool {
// realloc'ing each row from top to bottom, and checking all the
// rows as we go.
unsafe fn test_1(ascend: &mut [*mut u8]) {
let new_size = idx_to_size(COUNT-1);
let new_size = idx_to_size(COUNT - 1);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
for i in 0..COUNT / 2 {
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
let (p0, p1, old_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
assert!(old_size < new_size);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
}
}
// Test 2: turn the square back into a triangle, top to bottom.
unsafe fn test_2(ascend: &mut [*mut u8]) {
let old_size = idx_to_size(COUNT-1);
let old_size = idx_to_size(COUNT - 1);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
for i in 0..COUNT / 2 {
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
let (p0, p1, new_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
assert!(new_size < old_size);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
}
}
// Test 3: turn triangle into a square, bottom to top.
unsafe fn test_3(ascend: &mut [*mut u8]) {
let new_size = idx_to_size(COUNT-1);
let new_size = idx_to_size(COUNT - 1);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
for i in (0..COUNT / 2).rev() {
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
let (p0, p1, old_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
assert!(old_size < new_size);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
}
}
// Test 4: turn the square back into a triangle, bottom to top.
unsafe fn test_4(ascend: &mut [*mut u8]) {
let old_size = idx_to_size(COUNT-1);
let old_size = idx_to_size(COUNT - 1);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
for i in (0..COUNT / 2).rev() {
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
let (p0, p1, new_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
assert!(new_size < old_size);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
}
}

View file

@ -1,34 +1,34 @@
// run-pass
#![allow(dead_code)]
#![allow(non_camel_case_types)]
// pretty-expanded FIXME #23616
#![feature(allocator_api)]
use std::alloc::{AllocRef, Global, Layout, handle_alloc_error};
use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout};
use std::ptr::NonNull;
struct arena(());
struct Bcx<'a> {
fcx: &'a Fcx<'a>
fcx: &'a Fcx<'a>,
}
struct Fcx<'a> {
arena: &'a arena,
ccx: &'a Ccx
ccx: &'a Ccx,
}
struct Ccx {
x: isize
x: isize,
}
fn alloc(_bcx: &arena) -> &Bcx<'_> {
unsafe {
let layout = Layout::new::<Bcx>();
let (ptr, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
&*(ptr.as_ptr() as *const _)
let memory = Global
.alloc(layout, AllocInit::Uninitialized)
.unwrap_or_else(|_| handle_alloc_error(layout));
&*(memory.ptr.as_ptr() as *const _)
}
}